#include "MAPL_Generic.h" #if defined(I_AM_PFUNIT) # undef I_AM_PFUNIT #endif #define I_AM_PFUNIT module Test_ExtDataUpdatePointer use MAPL_ExtDataPointerUpdate use funit use esmf use MAPL_ExceptionHandling implicit none integer, parameter :: SUCCESS = 0 integer, parameter :: TIME_STEP_IN_SECONDS = 1 integer, parameter :: REFERENCE_TIME_FIELDS(*) = [2024, 12, 31, 20, 0, 0] integer, parameter :: NF = size(REFERENCE_TIME_FIELDS) integer, parameter :: START_TIME_FIELDS(*) = [2024, 01, 01, 0, 0, 0] integer, parameter :: DEFAULT_TIME_FIELDS(*) = [REFERENCE_TIME_FIELDS(1:3), 0, 0, 0] integer, parameter :: UPDATE_TIME_FIELDS(*) = [0, 1, 1, REFERENCE_TIME_FIELDS(4:)] integer, parameter :: STRLEN = 32 character(len=*), parameter :: UPDATE_TIMESTRING = 'T20:00:00' character(len=*), parameter :: UPDATE_FREQ_STRING = '-' character(len=*), parameter :: ERR_MSG = 'Actual offset does match expected offset.' type(ESMF_Time) :: start_time type(ESMF_TimeInterval) :: timestep type(ESMF_Clock) :: clock type(ESMF_Time) :: default_time type(ESMF_TimeInterval) :: time_interval type(ESMF_Time) :: update_time type(ESMF_Time) :: reference_time contains @Before subroutine set_up() integer :: status, rc logical :: uninitialized status = SUCCESS uninitialized = .not. ESMF_IsInitialized(_RC) if(uninitialized) then call ESMF_Initialize(defaultCalKind=ESMF_CALKIND_GREGORIAN, logKindFlag=ESMF_LOGKIND_NONE, defaultLogKindFlag=ESMF_LOGKIND_NONE, _RC) end if call ESMF_TimeIntervalSet(time_interval, _RC) call ESMF_TimeIntervalSet(timestep, s=TIME_STEP_IN_SECONDS, _RC) call make_esmf_time(START_TIME_FIELDS, start_time, _RC) call make_esmf_time(DEFAULT_TIME_FIELDS, default_time, _RC) call make_esmf_time(UPDATE_TIME_FIELDS, update_time, _RC) call make_esmf_time(REFERENCE_TIME_FIELDS, reference_time, _RC) clock = ESMF_ClockCreate(timestep=timestep, startTime=start_time, _RC) end subroutine set_up @After subroutine tear_down() integer :: status, rc call ESMF_TimeSet(start_time, _RC) call ESMF_TimeIntervalSet(timestep, _RC) call ESMF_ClockDestroy(clock, _RC) call ESMF_TimeSet(default_time, _RC) call ESMF_TimeIntervalSet(time_interval, _RC) call ESMF_TimeSet(update_time, _RC) call ESMF_TimeSet(reference_time, _RC) end subroutine tear_down ! Set ESMF_Time using an integer array of datetime fields. subroutine make_esmf_time(f, datetime, rc) integer, intent(in) :: f(NF) type(ESMF_Time), intent(inout) :: datetime integer, optional, intent(out) :: rc integer :: status status = 0 call ESMF_TimeSet(datetime, yy=f(1), mm=f(2), dd=f(3), h=f(4), m=f(5), s=f(6), _RC) _RETURN(_SUCCESS) end subroutine make_esmf_time ! Put ESMF_Time output args into an integer array. subroutine get_int_time(datetime, n, rc) type(ESMF_Time), intent(in) :: datetime integer, intent(inout) :: n(NF) integer, optional, intent(out) :: rc integer :: status status = 0 n = -1 call ESMF_TimeGet(datetime, yy=n(1), mm=n(2), dd=n(3), h=n(4), m=n(5), s=n(6), _RC) _RETURN(_SUCCESS) end subroutine get_int_time subroutine make_offset_string(offset, offset_string, rc) integer, intent(in) :: offset character(len=*), intent(out) :: offset_string integer, optional, intent(out) :: rc integer :: status write(offset_string, fmt='("PT", I03, "S")', iostat=status) offset _VERIFY(status) end subroutine make_offset_string @Test subroutine test_get_adjusted_time type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=STRLEN) :: offset_string type(ESMF_TimeInterval) :: offset integer :: ios integer, parameter :: OFFSET_IN_SECONDS = 300 integer :: expected(NF), actual(NF) write(offset_string, fmt='("PT", I03, "S")', iostat=ios) OFFSET_IN_SECONDS _VERIFY(ios) call ESMF_TimeIntervalSet(offset, s=OFFSET_IN_SECONDS, _RC) call get_int_time(default_time+offset, expected, _RC) call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, offset_string, default_time, clock, _RC) call get_int_time(ex%get_adjusted_time(default_time), actual, _RC) @assertEqual(expected, actual, 'Adjusted time does match expected time.') end subroutine test_get_adjusted_time @Test subroutine test_create_from_parameters_string_positive() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=STRLEN) :: offset_string integer, parameter :: OFFSET_IN_SECONDS = 300 integer :: expected, actual type(ESMF_TimeInterval) :: interval call make_offset_string(OFFSET_IN_SECONDS, offset_string, _RC) expected = OFFSET_IN_SECONDS call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, offset_string, default_time, clock, _RC) interval = ex%get_offset() call ESMF_TimeIntervalGet(interval, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_create_from_parameters_string_positive @Test subroutine test_create_from_parameters_string_negative() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=STRLEN) :: offset_string integer, parameter :: OFFSET_IN_SECONDS = 300 integer :: expected, actual type(ESMF_TimeInterval) :: interval call make_offset_string(OFFSET_IN_SECONDS, offset_string, _RC) offset_string = '-' // offset_string expected = -OFFSET_IN_SECONDS call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, offset_string, default_time, clock, _RC) interval = ex%get_offset() call ESMF_TimeIntervalGet(interval, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_create_from_parameters_string_negative @Test subroutine test_create_from_parameters_heartbeat_positive() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=*), parameter :: OFFSET_STRING = HEARTBEAT_STRING type(ESMF_TimeInterval) :: offset, interval integer :: expected, actual offset = timestep call ESMF_TimeIntervalGet(offset, s=expected, _RC) call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, OFFSET_STRING, default_time, clock, _RC) interval = ex%get_offset() call ESMF_TimeIntervalGet(interval, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_create_from_parameters_heartbeat_positive @Test subroutine test_create_from_parameters_heartbeat_negative() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=*), parameter :: OFFSET_STRING = '-' // HEARTBEAT_STRING type(ESMF_TimeInterval) :: offset, interval integer :: expected, actual offset = -timestep call ESMF_TimeIntervalGet(offset, s=expected, _RC) call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, OFFSET_STRING, default_time, clock, _RC) interval = ex%get_offset() call ESMF_TimeIntervalGet(interval, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_create_from_parameters_heartbeat_negative @Test subroutine test_compare_positive_string_to_positive_heartbeat() type(ExtDataPointerUpdate) :: ex_str, ex_hb integer :: status, rc type(ESMF_TimeInterval) :: intv_str, intv_hb integer :: expected, actual character(len=STRLEN) :: offset_string call make_offset_string(TIME_STEP_IN_SECONDS, offset_string, _RC) call ex_str%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, offset_string, default_time, clock, _RC) intv_str = ex_str%get_offset() call ESMF_TimeIntervalGet(intv_str, s=expected, _RC) call ex_hb%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, HEARTBEAT_STRING, default_time, clock, _RC) intv_hb = ex_hb%get_offset() call ESMF_TimeIntervalGet(intv_hb, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_compare_positive_string_to_positive_heartbeat @Test subroutine test_compare_negative_string_to_negative_heartbeat() type(ExtDataPointerUpdate) :: ex_str, ex_hb integer :: status, rc type(ESMF_TimeInterval) :: intv_str, intv_hb integer :: expected, actual character(len=STRLEN) :: offset_string call make_offset_string(TIME_STEP_IN_SECONDS, offset_string, _RC) offset_string = '-' // offset_string call ex_str%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, offset_string, default_time, clock, _RC) intv_str = ex_str%get_offset() call ESMF_TimeIntervalGet(intv_str, s=expected, _RC) call ex_hb%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, '-' // HEARTBEAT_STRING, default_time, clock, _RC) intv_hb = ex_hb%get_offset() call ESMF_TimeIntervalGet(intv_hb, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_compare_negative_string_to_negative_heartbeat @Test subroutine test_create_from_parameters_heartbeat_positive_explicit() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=*), parameter :: OFFSET_STRING = '+' // HEARTBEAT_STRING type(ESMF_TimeInterval) :: offset, interval integer :: expected, actual offset = timestep call ESMF_TimeIntervalGet(offset, s=expected, _RC) call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, OFFSET_STRING, default_time, clock, _RC) interval = ex%get_offset() call ESMF_TimeIntervalGet(interval, s=actual, _RC) @assertEqual(expected, actual, ERR_MSG) end subroutine test_create_from_parameters_heartbeat_positive_explicit @Test subroutine test_create_from_parameters_heartbeat_positive_negative() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=*), parameter :: OFFSET_STRING = '+-' // HEARTBEAT_STRING type(ESMF_TimeInterval) :: offset, interval integer :: expected, actual offset = timestep call ESMF_TimeIntervalGet(offset, s=expected, _RC) call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, OFFSET_STRING, default_time, clock, rc=status) @assertFalse(status == 0, 'An exception should have been thrown.') end subroutine test_create_from_parameters_heartbeat_positive_negative @Test subroutine test_create_from_parameters_heartbeat_negative_positive() type(ExtDataPointerUpdate) :: ex integer :: status, rc character(len=*), parameter :: OFFSET_STRING = '-+' // HEARTBEAT_STRING type(ESMF_TimeInterval) :: offset, interval integer :: expected, actual offset = timestep call ESMF_TimeIntervalGet(offset, s=expected, _RC) call ex%create_from_parameters(UPDATE_TIMESTRING, UPDATE_FREQ_STRING, OFFSET_STRING, default_time, clock, rc=status) @assertFalse(status == 0, 'An exception should have been thrown.') end subroutine test_create_from_parameters_heartbeat_negative_positive end module Test_ExtDataUpdatePointer