!******************************************************************************!
! Macro to test "KEYWORD" intrinsic
! DependsOn: HEADERMOD/CREATE
! @author Jay P. Hallam / Neon Ngo
!******************************************************************************!
startmacro s:func[""]
  switch BASELINE    baseline GET DEF=FALSE SDEF=TRUE
  switch INTERACTIVE interAct GET DEF=TRUE  SDEF=TRUE
  switch ASCIIRES useAsciiRes GET "FALSE" "TRUE"
  if useAsciiRes isFalse then
    info "^reg.main.name: Use of A: is deprecated, testing with S: (use /ASCIIRES to test with A:)"
  endif

  ! allow some tests to run even with "thin" NeXtMidas, based on dependencies available
  invoke convertExists reg.shell.M.dictionary.isDictionaryEntry(CONVERT)
  invoke rampExists reg.shell.M.dictionary.isDictionaryEntry(RAMP)
  if convertExists isFalse OR rampExists isFalse then
    info "^reg.main.name: Skipping some tests due to running in LIBNXM version of NeXtMidas"
    res z:interAct False
  endif

  result testfile               "ram:test_keyword_1000"
  result testfile_add           "ram:test_keyword_add_1000"
  result testfile_put           "ram:test_keyword_put"
  result testfile_get_multi     "ram:test_keyword_get_multi"
  result testfile_main          "ram:test_keyword_main"
  result testfile_scope         "ram:test_keyword_scope_multi"
  result testfile_scope_special "ram:test_keyword_scope_special_syntax"
  result testfile_main_noop     "ram:test_keyword_main_noop"
  result testfile_3000          "ram:test_keyword_3000"
  result testfile_add_3000      "ram:test_keyword_add_3000"

  call buildAnswers ! Build the answers table

  ! SET the keywords in the test file
  call buildTestFile testFile testfile_3000
  ! create other test files
  header/create testfile_add
  header/create testfile_put
  header/create testfile_get_multi
  header/create testfile_main
  header/create testfile_scope
  header/create testfile_scope_special
  header/create testfile_add_3000 SR=(NAME/1A,ABSC/SD,ORD/SD)

if func NEQS "" then
  call test_^{func}
else
  call test_SET_GET   testfile             ! This really tests SET and GET
  call test_SET_GET   testfile_3000        ! This really tests SET and GET on type 3000 file
  call test_PUT_GET   testfile_put         ! This really tests PUT and GET
  call test_GET_multi testfile_get_multi   ! Test the GET for multiple keywords
  call test_ADD_DEL   testfile_add         ! Test the ADD and DELete functions
  call test_ADD_DEL   testfile_add_3000    ! Test the ADD and DELete functions on type 3000 file
  call test_TGET      testfile             ! Test the TGET function
  call test_FGET      testfile             ! Test the FSET and FGET functions
  call test_FPUT      testfile             ! Test the FPUT and FGET functions
  call test_FSET_DUPS                      ! Test the FSET / FGET with duplicate keywords
  call test_TimeLine                       ! Tests use of TimeLine in the extended header
  if rampExists then call test_bad_packet_keyword ! Tests a file with bad PACKET keyword
  call test_ext_start                      ! Tests file for valid ext_start in header
  call test_ver_io ! Tests handling of IO= and VER= keywords
  call test_short_key_in_main              ! Test for a short ASCII keyword block in main
  call test_FSET_overwrite                 ! Test overwriting existing keywords in MAIN header (Bug 2599)
  call test_putAll_addAll_API
  call test_insert_mult                    ! ADD and PUT multiple keywords in at once (Bug 2614)
  call test_TCGET   ! Tests TCSET and TCGET
  call test_SVGET ! Tests SVSET and SVGET
  if rampExists then call test_ByteOrder        ! since 3.7.0 for Bug 3009

  ! Test the GET /SCOPE=MAIN function
  ! This test must go last so that a known number of extended
  ! header keywords are in the test file for the previous tests
  call test_scope_main     testfile_main
  call test_scope_extended testfile_scope testfile_scope_special

  if interAct then
    %test_keyword_list ! Interactive test for LIST function
  endif

  %test_keyword_bad/interactive=^interAct
  %test_keyword_propagation_ieee_eeei
  if convertExists then
    %test_keyword_tcdel
  endif
  %test_keyword_ntcdel

  %test_keyword_autoconvert ! Since NextMidas 4.1.0 for NXM-3787
  %test_keyword_putall_main ! Since NextMidas 4.1.3 for NXM-4003
endif

  ! cleanup
  erase/warn=n test_keyword_fget.key testfile testfile_add testfile_put testfile_get_multi testfile_main &
    testfile_scope testfile_scope_special testfile_main_noop testfile_3000 testfile_add_3000

endmacro

!******************************************************************************!
! Build table of answers
!******************************************************************************!
procedure buildAnswers
  result T:answers {}
  result I:answers.ikey 1
  result L:answers.lkey 100000
  result D:answers.dkey 99.0
  if useAsciiRes isTrue then
    result A:answers.akey "ASCII_TEXT"
  else
    result S:answers.akey "ASCII_TEXT"
  endif
  result S:answers.skey "STRING_TEXT"
return

!******************************************************************************!
! Build a keyword test files (1000 and 3000) for the functions
!******************************************************************************!
procedure buildTestFile S:testFile S:testFile3000
  header/create testFile
  header/create testFile3000 SR=(NAME/1A,ABSC/SD,ORD/SD)

  for file INLIST "^{testFile},^{testFile3000}"
    key file SET I:IKEY answers.ikey
    key file SET L:LKEY answers.lkey
    key file SET D:DKEY answers.dkey
    key file SET A:AKEY answers.akey
    key file SET S:SKEY answers.skey
  endfor

return

!******************************************************************************!
! test the set and get functions
!******************************************************************************!
procedure test_SET_GET S:testfile
  key testfile GET IKEY I:outi
  key testfile GET LKEY L:outl
  key testfile GET DKEY D:outd
  if useAsciiRes isTrue then
    key testfile GET AKEY A:outa
  else
    key testfile GET AKEY S:outa
  endif
  key testfile GET SKEY S:outs

  ASSERT/TEXT="KEYWORD: SET/GET on ^testfile" &
                                 outi EQ answers.ikey  AND &
                                 outl EQ answers.lkey  AND &
                                 outd EQ answers.dkey  AND &
                                 outa EQS answers.akey AND &
                                 outs EQS answers.skey

  ! test getting "VER" from MAIN header (for Bug 1942)
  key testfile GET VER ver
  ASSERT/TEXT="KEYWORD: GET from MAIN Header on ^testfile" ver NISNULL
return

!******************************************************************************!
! Insert (ADD) keywords of the same name, delete the first and then get the second.
!******************************************************************************!
procedure test_ADD_DEL fn:testfile_add
  key testfile_add ADD DUP "DUPLICATE"
  key testfile_add ADD DUP "DUPLICATE2"
  key testfile_add GET DUP S:out
  ASSERT/TEXT="KEYWORD: ADD on ^testfile_add" out EQS "DUPLICATE"

  key testfile_add DEL DUP
  key testfile_add GET DUP S:out
  ASSERT/TEXT="KEYWORD: DEL on ^testfile_add" out EQS "DUPLICATE2"

return

!******************************************************************************!
! Replace (PUT) keywords of the same name, get should be the second entry.
!******************************************************************************!
procedure test_PUT_GET fn:testfile_put
  key testfile_put PUT PUTKEY "FIRSTPUT"
  key testfile_put PUT PUTKEY "SECONDPUT"
  key testfile_put GET PUTKEY S:out
  key testfile_put GET PUTKEY S:out

  ASSERT/TEXT="KEYWORD: PUT/GET" out EQS "SECONDPUT"

  set D:dvalOrig 1089.0
  key testfile_put PUT DVAL D:dvalOrig
  key testfile_put GET DVAL D:dvalFromKey

  calc d1 dvalOrig 1 *
  calc d2 dvalFromKey 1 *

  ASSERT/TEXT="KEYWORD: PUT/GET double value" d1 EQ d2
  remove dvalOrig dvalFromKey
return

!******************************************************************************!
! Test the ability to get multiple keywords in one line
!******************************************************************************!
procedure test_GET_multi fn:testfile_get_multi
  key testfile_get_multi PUT KEY1 1 KEY2 "Second keyword"
  key testfile_get_multi GET KEY1 key1 KEY2 key2
  ASSERT/TEXT="KEYWORD: GET - multiple KEY/LABELs" key1 EQ 1 AND key2 EQS "Second keyword"

return

!******************************************************************************!
! test the set/put and get functions in MAIN header
!******************************************************************************!
procedure test_scope_main S:testfile_main
  res answer "A_MAIN_KEY"
  key/scope=main testfile_main SET MAINKEY "^answer" /WARN=NO ! Disable warnings since this belongs in extended header
  key/scope=main testfile_main GET MAINKEY out

  ASSERT/TEXT="KEYWORD: SET/GET /SCOPE=MAIN" out EQS answer

  ! Test for "a file that has its' main header full" moved to test_ver_io
return

!******************************************************************************!
! Test to see that VER= and IO= are being set in header. Also check CREATOR= which
! is deprecated, but still inserted so that an SP file can be read in NeXtMidas 2.4.2
!******************************************************************************!
procedure test_ver_io
  wave ram:mywave10{BLUEVER="1.0"}
  wave ram:mywave11{BLUEVER="1.1"}
  wave ram:mywave12{BLUEVER="1.2"} ! added in 3.9.4 for NXM-3570 new BLUE VER for 'Z' type

  ! Should have added IO=, VER=, CREATOR=
  keyword/scope=main ram:mywave11 GET VER      blueVerKW
  keyword/scope=main ram:mywave11 GET IO       blueIOKW
  keyword/scope=main ram:mywave11 GET CREATOR  creatorKW

  info "^reg.main.name: The following line may give a deprecation warning."
  status ram:mywave11 BLUEVER=blueVer BLUEIO=blueIO CREATOR=creator

  ASSERT/TEXT="KEYWORD: Added VER='^blueVer' to main header"                       blueVerKW EQS blueVer
  ASSERT/TEXT="KEYWORD: Added IO='^blueIO' to main header"                         blueIOKW  EQS blueIO
  ASSERT/TEXT="KEYWORD: Added CREATOR='^creator' to main header (for legacy apps)" creatorKW EQS creator

  status ram:mywave10 BLUEVER=blueVer10
  status ram:mywave11 BLUEVER=blueVer11
  status ram:mywave12 BLUEVER=blueVer12
  ASSERT/TEXT="KEYWORD: Able to override VER= and use VER='1.0'" blueVer10 EQS "1.0"
  ASSERT/TEXT="KEYWORD: Able to override VER= and use VER='1.1'" blueVer11 EQS "1.1"
  ASSERT/TEXT="KEYWORD: Able to override VER= and use VER='1.2'" blueVer12 EQS "1.2"

  ! Test to see that VER= and IO= are being set in header when we open it for input+output.
  wave ram:mywaveXX
  file open/w tag ram:mywaveXX
    invoke ,, tag.setBlueVer("1.0",true)
    invoke ,, tag.setBlueIO("X-Midas",true)
  file close tag
  status ram:mywaveXX BLUEVER=blueVerXX BLUEIO=blueIOXX
  ASSERT/TEXT="KEYWORD: Able to set VER='1.0' via invoke"    blueVerXX EQS "1.0"
  ASSERT/TEXT="KEYWORD: Able to set IO='X-Midas' via invoke" blueIOXX  EQS "X-Midas"

  file open/a tag ram:mywaveXX
    ! Just use the open/close with /a to force opening for I/O which causes IO= and VER= to update
  file close tag
  status ram:mywaveXX BLUEVER=blueVerXX BLUEIO=blueIOXX
  res  blueVerXX
  res blueVer
  ASSERT/TEXT="KEYWORD: Updates VER= on output" blueVerXX EQS blueVer
  ASSERT/TEXT="KEYWORD: Updates IO= on output" blueIOXX  EQS blueIO

  ! Noop a file that has its' main header full with keywords without error
  !
  ! IMPORTANT NOTE: This test changed between 2.5.2 and 2.5.3 due to Bug 1181 (DataFile: Add
  !                 support for VER= and IO= keywords, drop CREATOR=) which supports PLATINUM.
  info "^reg.main.name: The warnings on the next two lines are expected."
  noop nxm.sys.test.test_keyword_main_full.prm ram:tempNoop

  ! Should have added IO= and VER=
  keyword/scope=main ram:tempNoop GET VER blueVerKW
  keyword/scope=main ram:tempNoop GET IO  blueIOKW

  status ram:tempNoop BLUEVER=blueVer BLUEIO=blueIO

  ASSERT/TEXT="KEYWORD: Added VER='^blueVer' to main header" blueVerKW EQS blueVer
  ASSERT/TEXT="KEYWORD: Added IO='^blueIO' to main header"   blueIOKW  EQS blueIO
  ASSERT/TEXT="KEYWORD: Able to NOOP file with full keywords"  ram:tempNoop FEQ/D nxm.sys.test.test_keyword_main_full.prm
return

!******************************************************************************!
procedure test_scope_extended cs:testfile_scope cs:testfile_scope_special
  ! Multi-scope test
  keyword testfile_scope PUT DUMMY DUMMY1
  keyword testfile_scope PUT TAG NAME
  keyword testfile_scope PUT NODE MYNODE
  keyword testfile_scope ADD DUMMY DUMMY2
  keyword testfile_scope GET DUMMY out
  ASSERT/TEXT="KEYWORD: MULTI-SCOPE  - no /SCOPE switch" out EQS "DUMMY1"
  keyword/scope="TAG=NAME,NODE=MYNODE" testfile_scope GET DUMMY out
  ASSERT/TEXT="KEYWORD: MULTI-SCOPE /SCOPE=TAG=NAME,NODE=MYNODE" out EQS "DUMMY2"
  keyword/scope="TAG=NAME,NODE=MYNODE" testfile_scope GET DUMMY out
  ASSERT/TEXT="KEYWORD: MULTI-SCOPE /SCOPE=(TAG=NAME,NODE=MYNODE)" out EQS "DUMMY2"

  ! Special syntax test
  keyword testfile_scope_special ADD TIME "12:00"
  keyword testfile_scope_special ADD FREQ 31e6
  keyword testfile_scope_special ADD AMPL 1.0
  keyword testfile_scope_special ADD TIME "13:00"
  keyword testfile_scope_special ADD FREQ 32e6
  keyword testfile_scope_special ADD AMPL 2.0
  keyword testfile_scope_special ADD TIME "14:00"
  keyword testfile_scope_special ADD FREQ 33e6
  keyword testfile_scope_special ADD AMPL 3.0

  rem out
  keyword/scope="TIME=13:00" testfile_scope_special GET TIME out
  ASSERT/TEXT="KEYWORD: Special syntax /SCOPE=TIME=13:00" out EQS "13:00"

  rem out
  keyword/scope="TIME-=13:00" testfile_scope_special GET TIME out
  ASSERT/TEXT="KEYWORD: Special syntax /SCOPE=TIME-=13:00" out EQS "NULL"

  rem out
  keyword/scope="TIME+=13:00" testfile_scope_special GET TIME out
  ASSERT/TEXT="KEYWORD: Special syntax /SCOPE=TIME+=13:00" out EQS "14:00"

  ! In X-Midas the real and fixed point numbers are treated the same as far as
  ! scope.  Thus /SCOPE=DVAL=1 is treated the same as /SCOPE=DVAL=1.0
  ! If the actual entry is a D:DVAL==1.0
  !
  rem out
  key/scope=AMPL=2 testfile_scope_special get time out
  ASSERT/TEXT="KEYWORD: SCOPE double as fixed number /SCOPE=AMPL=2" out EQS "14:00"

  rem out
  key/scope=AMPL=2.0 testfile_scope_special get time out
  ASSERT/TEXT="KEYWORD: SCOPE double as floating point number /SCOPE=AMPL=2.0" out EQS "14:00"

  !
  ! In X-Midas, a " " is used to indicate SCOPE everywhere( or scope reset).
  !
!  file open tag testfile_scope_special
!    set keywObj tag.getKeywordsObject()  ! Initial scope should get first FREQ keyword
!    set freqInitial keywObj.get("FREQ")

!    set keywobj.setScope("TIME=13:00")   ! Scope to different FREQ
!    set freqNext keywObj.get("FREQ")

!    set keywobj.setScope(" ")             ! This should reset the scope
!    set freqFirst keywObj.get("FREQ")

!  file close tag
!  ASSERT/TEXT="KEYWORD: persistent SCOPE. Use space ' ' as in XMIDAS" freqInitial EQ freqFirst

  !
  ! Use a "ALL" to indicate SCOPE everywhere (or scope reset).
  !
  file open tag testfile_scope_special
    set keywObj tag.getKeywordsObject()  ! Initial scope should get first FREQ keyword
    set freqInitial keywObj.get("FREQ")

    set keywobj.setScope("TIME=13:00")   ! Scope to different FREQ
    set freqNext keywObj.get("FREQ")

    set keywobj.setScope("ALL")             ! This should reset the scope
    set freqFirst keywObj.get("FREQ")

  file close tag
  ASSERT/TEXT="KEYWORD: persistent SCOPE. Use empty '' to clear scope" freqInitial EQ freqFirst

return

!******************************************************************************!
procedure test_TGET S:testfile
  !
  !  This TGET gets a flat table with MAIN and EXTENDED header keywords mixed
  !
  key testfile TGET outTable
  call isT1inT2 answers outTable status
  ASSERT/TEXT="KEYWORD: TGET" status GT 0
  rem outTable

  !
  !  This TGET gets a flat table with MAIN and EXTENDED header keywords mixed
  !  from a Platinum file
  !
  !  NXM-3892 NeXtMidas 4.1.2
  !
  res testfile_plat1001 "ram:test_keyword_plat1001"
  file copy nxm.sys.test.testplat1001.cdif testfile_plat1001
  file unprotect testfile_plat1001
  key testfile_plat1001 PUT "KEYA.KEYB" "test"
  key testfile_plat1001 TGET plat1001OutTable
  ASSERT/TEXT="KEYWORD: TGET - Platinum" ^{plat1001OutTable.KEYA->KEYB} EQS "test"
  rem plat1001OutTable

  !
  !  This TGET uses /FLAT=F to get a table with MAIN and EXTENDED inner tables
  !  with main header and extended header keywords, respectively
  !
  key/flat=f testfile TGET nestedTab
  res outTable ^{nestedTab.main}^{nestedTab.extended} ! Merge the two tables
  call isT1inT2 answers outTable status
  ASSERT/TEXT="KEYWORD: TGET with /FLAT=F" status GT 0

  !
  !  This TGET/F gets a flat table FILE MAIN and EXTENDED header keywords mixed
  !
  key testfile TGET/F test_keyword_tget_output.tbl
  if test_keyword_tget_output.tbl FEXISTS then
    rem outTable
    res T:outTable test_keyword_tget_output.tbl
    call isT1inT2 answers outTable status
    ASSERT/TEXT="KEYWORD: TGET/F - Table file" status GT 0
    erase test_keyword_tget_output.tbl
  else
    ASSERT/TEXT="KEYWORD: TGET/F - Table file creation" false
  endif

return

!******************************************************************************!
! test FSET and FGET functions
! DEPENDS ON TABLE GET (TGET) FUNCTION
! Note: this is pretty much same as the test_FPUT procedure
!******************************************************************************!
procedure test_FGET S:testfile
  result testfile_ascii "test_keyword_fget.key"
  result testfile_bin "test_keyword_fset.tmp"
  header/create testfile_bin
  key testfile FGET testfile_ascii
  ASSERT/TEXT="KEYWORD: FGET FEXISTS"/stat=status testfile_ascii FEXISTS
  if status EQS "PASS" then
    key testfile_bin FSET testfile_ascii
    key testfile_bin TGET tab
    call isT1inT2 answers tab status
    ASSERT/TEXT="KEYWORD: FGET/FSET values" status EQ 1
  endif
  erase testfile_bin
  erase testfile_ascii
return

!******************************************************************************!
! test FPUT (alias for FSET) and FGET functions
! DEPENDS ON TABLE GET (TGET) FUNCTION
! Note: this is pretty much same as the test_FGET procedure
!******************************************************************************!
procedure test_FPUT S:testfile
  result testfile_ascii "test_keyword_fget.key"
  result testfile_bin "test_keyword_fset.tmp"
  header/create testfile_bin
  key testfile FGET testfile_ascii
  ASSERT/TEXT="KEYWORD: FGET FEXISTS"/stat=status testfile_ascii FEXISTS
  if status EQS "PASS" then
    key testfile_bin FPUT testfile_ascii
    key testfile_bin TGET tab
    call isT1inT2 answers tab status
    ASSERT/TEXT="KEYWORD: FGET/FPUT values" status EQ 1
  endif
  erase testfile_bin
  erase testfile_ascii
return

!***************************************************************************
procedure test_FSET_DUPS
!
! Can I set/get keywords with duplicate names?
!
  result testfile_ascii "test_keyword_dups.key{FLAGS=FORCEABORT}"
  result testfile_bin "test_keyword_dups.tmp"
  header/create testfile_bin
  file open/T/N tag testfile_ascii
  !!   The text below was changed in 3.1.2 (Bug 2599) from a single '=' to the
  !!   double '==' to denote putting the KW in the EXT header, as intended.
  file write tag "S:TAG1==SCOPE"
  file write tag "L:WIDTH==1"
  file write tag "S:COLOR==COLOR1"
  file write tag "S:TAG2==SCOPE"
  file write tag "L:WIDTH==2"
  file write tag "S:COLOR==COLOR2"
  file close tag
  key testfile_bin FSET testfile_ascii

  remove lwidth lwidth2
  key testfile_bin GET WIDTH lwidth1
  key testfile_bin GET WIDTH lwidth2 /SCOPE=TAG2=SCOPE
  ASSERT/TEXT="KEYWORD: FSET dups(L:) got = ^lwidth1, ^lwidth2 " &
       lwidth1 EQ 1 AND lwidth2 EQ 2

  remove scolor1 scolor2
  key testfile_bin GET COLOR scolor1
  key testfile_bin GET COLOR scolor2 /SCOPE=TAG2=SCOPE
  ASSERT/TEXT="KEYWORD: FSET dups(S:) got ^scolor1, ^scolor2" &
           scolor1 EQS "COLOR1" AND scolor2 EQS "COLOR2"

  erase testfile_bin
  erase testfile_ascii
return

!******************************************************************************!
! Test for FSET overwriting existing keywords when using FSET (Bug 2599)
procedure test_FSET_overwrite
  !result testKeyFile "testKeyFile.key"
  header/create ram:testKWFile
  key ram:testKWFile SET name=TC_PREC value=1.5e6 /scope=main
  key ram:testKWFile SET name=JUNKKEY value="JUNKDATA"

  file open/T/N tag testKeyFile.key
  file write tag "S:VER=1.1"
  file write tag "S:IO=NeXtMidas"
  file write tag "S:CREATOR=NXM3.1.1"
  file write tag "S:TC_PREC=1600000.0"   ! Change from original value of 1.5e6
  file write tag "S:JUNKKEY==NEWDATA"
  file close tag

  INFO "!!!!! TEST_KEYWORD: It is ok to see a warning that CREATOR should be set in the EXTENDED header !!!!!"
  KEY ram:testKWFile FSET testKeyFile.key

  remove tcprec jdata
  key ram:testKWFile GET NAME="TC_PREC" VALUE=tcprec
  key ram:testKWFile GET NAME="JUNKKEY" VALUE=jdata

  assert/text="KEYWORD: FSET Overwrites MAIN Keys: Expected 1600000.0, Got ^tcprec" tcprec eqs "1600000.0"
  assert/text="KEYWORD: FSET Overwrites EXTENDED Keys: Expected NEWDATA, Got ^jdata" jdata eqs "NEWDATA"

  erase testKeyFile.key ram:testKWFile
return

!******************************************************************************!
procedure isT1inT2 T:t1 T:t2 U:returnVal
  result status 1
  foreach key INTABLE t1
    !!!say "Key = ^key, t1 value ^t1.^key, t2 value ^t2.^key"
    if t2.^key NREXISTS OR "^{t1.^key}" NEQS "^{t2.^key}" then
      result status -1
      break
    endif
  endfor

  result ^returnVal status
return

!******************************************************************************!
procedure test_TimeLine
  set fname "temp_with_timeline{AUX=RAM}"

  header/create fname
  set FILE(fname).setTimeAt(0) 2007:01:01::00:00:00

  keyword fname GET NAME="TIMELINE" VALUE=tl
  assert/text="KEYWORD: File has a  TimeLine (getTimeAt(0) != 0)" FILE(fname).getTimeAt(0) eq 2007:01:01::00:00:00
  assert/text="KEYWORD: File has a  TimeLine (TIMELINE  REXISTS)" tl rexists

  keyword fname del TIMELINE

  keyword fname GET NAME="TIMELINE" VALUE=tl
  assert/text="KEYWORD: File has no TimeLine (getTimeAt(0) == 0)" FILE(fname).getTimeAt(0) eq 0
  assert/text="KEYWORD: File has no TimeLine (TIMELINE NREXISTS)" tl rexists
return

!******************************************************************************!
! Tests a file with bad PACKET keyword this tests Bug 1047 (KEYWORD: Invalid
! PACKET keyword crashed NeXtMidas)
!******************************************************************************!
procedure test_bad_packet_keyword
  set fname ram:test_bad_packet_keyword

  ramp fname elem=16
  assert/text="KEYWORD: Can read file with no PACKET keyword"       FILE(^fname).getSize() eq 16

  key/scope=main fname add    name=packet value="ICE/FS=1048576/DET"
  key/scope=main fname delete name=packet ! <-- This errored out in NXM 2.4.1

  assert/text="KEYWORD: Can read after removing bad PACKET keyword" FILE(^fname).getSize() eq 16

  erase fname
return

!******************************************************************************!
! Tests file for valid ext_start in header, this tests Bug 960 (Invalid ext_start
! in BLUE file header) which results in an invalid ext_start value in the header
! after deleting all extended header keywords
!******************************************************************************!
procedure test_ext_start
  set fname ram:test_ext_start

  header/create fname
  assert/text="KEYWORD: ext_start is 0 with no ext keywords" FILE(^fname).getExtStart() eq 0
  assert/text="KEYWORD: ext_size  is 0 with no ext keywords" FILE(^fname).getExtSize()  eq 0

  key/scope=ext fname add name=MY_KEY value="MY_VAL"
  assert/text="KEYWORD: ext_start is not 0 with ext keywords" FILE(^fname).getExtStart() neq 0
  assert/text="KEYWORD: ext_size  is not 0 with ext keywords" FILE(^fname).getExtSize()  neq 0

  key/scope=ext fname del name=MY_KEY
  assert/text="KEYWORD: ext_start is 0 with no ext keywords" FILE(^fname).getExtStart() eq 0
  assert/text="KEYWORD: ext_size  is 0 with no ext keywords" FILE(^fname).getExtSize()  eq 0

  erase fname
return

!******************************************************************************!
! Test for a short ASCII keyword block (length < 8) in main header.
! Since 3.1.1 as part of regression testing for valid ASCII KEYWORD blocks in
! the main header.
! Requires: GET and TGET functions to work properly
!******************************************************************************!
subroutine test_short_key_in_main S:test_file["nxm.sys.test.lots_of_keywords.tmp"]
  keyword test_file GET TEST testVal
  assert/text="^reg.main.name: Got very SHORT keyword block from MAIN header" testVal eq 2
  keyword nxm.sys.test.lots_of_keywords.tmp TGET tAllKeywords
  assert/text="^reg.main.name: Got all 104 keywords from file with lots of keywords" tAllKeywords.getsize eqs 104
return

!******************************************************************************!
! Tests Keywords addAll/putAll/setAll APIs
! Since 3.1.2
!******************************************************************************!
subroutine test_putAll_addAll_API
  set fname ram:test_keyword

  header/create fname
  new java.util.HashMap map
  invoke ,, map.put("KEY1","DATA1")
  invoke ,, map.put("KEY2","DATA2")
  invoke ,, map.put("KEY3","DATA3_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ")

  res keywordsObj FILE(^fname).getKeywordsObject()
  invoke str=keywordsObj.toString() kwLenOrig=str.length()

  ! putAll(Map) - duplicates are NOT allowed
  invoke ,, keywordsObj.putAll(map)
  invoke str=keywordsObj.toString() kwLenAfterPutAll=str.length()
  assert/text="KEYWORD: size should increase after calling putAll(Map)" kwLenAfterPutAll > kwLenOrig
  assert/text="KEYWORD: after putAll(Map) - value at KEY1" keywordsObj.getKey("KEY1") eqs map.get("KEY1")
  assert/text="KEYWORD: after putAll(Map) - value at KEY2" keywordsObj.getKey("KEY2") eqs map.get("KEY2")
  assert/text="KEYWORD: after putAll(Map) - value at KEY3" keywordsObj.getKey("KEY3") eqs map.get("KEY3")

  ! 2nd call to putAll(Map) - replaces existing keys with below values
  ! NOTE: key/values in updated map SHOULD be SAME LENGTH to NOT mess with test case
  invoke ,, map.put("KEY1","DATA4")
  invoke ,, map.put("KEY2","DATA5")
  invoke ,, map.put("KEY3","DATA6_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  invoke ,, keywordsObj.putAll(map)
  invoke str=keywordsObj.toString() kwLenAfter2ndPutAll=str.length()
  assert/text="KEYWORD: size should NOT after calling putAll(Map) 2nd time" kwLenAfter2ndPutAll == kwLenAfterPutAll
  assert/text="KEYWORD: after putAll(Map) 2nd time - value at KEY1" keywordsObj.getKey("KEY1") eqs map.get("KEY1")
  assert/text="KEYWORD: after putAll(Map) 2nd time - value at KEY2" keywordsObj.getKey("KEY2") eqs map.get("KEY2")
  assert/text="KEYWORD: after putAll(Map) 2nd time - value at KEY3" keywordsObj.getKey("KEY3") eqs map.get("KEY3")

  ! addAll(Map) allows duplicates
  invoke ,, keywordsObj.addAll(map)
  invoke str=keywordsObj.toString() kwLenAfterAddAll=str.length()
  ! this is a crude way to test that we have "duplicate" keys added for "KEY1", "KEY2", "KEY3"
  assert/text="KEYWORD: size should increase again after calling addAll(Map)" kwLenAfterAddAll > kwLenAfterPutAll

  erase fname
return

!******************************************************************************!
! Tests Keyword ADDing and SETting multiple keywords at once
! Since 3.1.3
!******************************************************************************!
procedure test_insert_mult
  key testfile_add ADD FIRST "first" SECOND "second" THIRD "third" fourth "fourth"
  key testfile_add ADD FIFTH "fifth" SIXTH "sixth" /scope=MAIN /warn=false

  key testfile_add GET FIRST  out
  key testfile_add GET THIRD  out3
  key testfile_add GET FOURTH out4
  key testfile_add GET SIXTH  out6

  ASSERT/TEXT="KEYWORD: MULTI-ADD on ^testfile_add" out EQS "first" AND &
    out3 EQS "third" AND out4 eqs "fourth" AND out6 eqs "sixth"

  key testfile_add DEL FIFTH
  key testfile_add DEL SIXTH

  key testfile_add PUT ALPHA "alpha" BRAVO "bravo" CHARLIE "charlie" DELTA "delta"
  INFO "KEYWORD: Warnings on the next two lines for adding keywords to MAIN are expected"
  key testfile_add PUT ECHO "echo" FOXTROT "foxtrot" /scope=MAIN

  key testfile_add GET ALPHA   out
  key testfile_add GET CHARLIE out3
  key testfile_add GET DELTA   out4
  key testfile_add GET FOXTROT out6

  ASSERT/TEXT="KEYWORD: MULTI-PUT on ^testfile_add first entry" out EQS "alpha" AND &
    out3 EQS "charlie" AND out4 eqs "delta" AND out6 eqs "foxtrot"

  key testfile_add DEL ECHO
  key testfile_add DEL FOXTROT

return


!******************************************************************************!
! Tests SVGET and SVSET functions
! Since 3.3.0
!******************************************************************************!
procedure test_SVGET
  ! TEST SVSET/E ===============================================================
  waveform ram:sample_data_e SF 4k
  keyword  ram:sample_data_e SVSET/E nxm.sys.test.sv1_acc.prm

  keyword/FLAT=F ram:sample_data_e TGET keywords
  res kwds keywords.EXTENDED

  file open f nxm.sys.test.sv1_acc.prm
    table kwds GETSIZE actSize
    calc expSize f.size 10 * 1 +
    assert/text="SVSET/E correct number of keywords" expSize EQ actSize
    assert/text="SVSET/E has USE_SV_KEYWORDS=1.0"    1.0     EQ kwds.USE_SV_KEYWORDS

    do i 0 f.size-1 1
      calc L:j i 1 +
      invoke expTime f.getTimeAt(i)
      invoke expData f.getDataTable(i)

      assert/text="SVSET/E ETIM^{j}" expTime        EQ kwds.ETIM^{j}
      assert/text="SVSET/E POSX^{j}" expData.POS(0) EQ kwds.POSX^{j}
      assert/text="SVSET/E POSY^{j}" expData.POS(1) EQ kwds.POSY^{j}
      assert/text="SVSET/E POSZ^{j}" expData.POS(2) EQ kwds.POSZ^{j}
      assert/text="SVSET/E VELX^{j}" expData.VEL(0) EQ kwds.VELX^{j}
      assert/text="SVSET/E VELY^{j}" expData.VEL(1) EQ kwds.VELY^{j}
      assert/text="SVSET/E VELZ^{j}" expData.VEL(2) EQ kwds.VELZ^{j}
      assert/text="SVSET/E ACCX^{j}" expData.ACC(0) EQ kwds.ACCX^{j}
      assert/text="SVSET/E ACCY^{j}" expData.ACC(1) EQ kwds.ACCY^{j}
      assert/text="SVSET/E ACCZ^{j}" expData.ACC(2) EQ kwds.ACCZ^{j}
    enddo
  file close f

  ! TEST SVGET/E ===============================================================
  keyword ram:sample_data_e SVGET/E ram:sample_sv_e
  call checkOutputSV "SVGET/E" nxm.sys.test.sv1_acc.prm ram:sample_sv_e

  ! TEST SVSET/P ===============================================================
  waveform ram:sample_data_p SF 4k
  keyword  ram:sample_data_p PUT S:TIME_EPOCH "1994-01-01" D:TIME_DELTA 1e-9
  keyword  ram:sample_data_p SVSET/P nxm.sys.test.sv1_acc.prm

  assert/text="SVSET/P"/NOOP=MISS

  ! TEST SVGET/P ===============================================================
  keyword ram:sample_data_p SVGET/P ram:sample_sv_p
  call checkOutputSV "SVGET/P" nxm.sys.test.sv1_acc.prm ram:sample_sv_p

  ! TEST SVSET/V ===============================================================
  waveform ram:sample_data_v SF 4k
  keyword  ram:sample_data_v SVSET/V nxm.sys.test.sv1_acc.prm

  assert/text="SVSET/V"/NOOP=MISS

  ! TEST SVGET/V ===============================================================
  keyword ram:sample_data_v SVGET/V ram:sample_sv_v
  call checkOutputSV "SVGET/V" nxm.sys.test.sv1_acc.prm ram:sample_sv_v

  ! TEST SVGET/L ===============================================================
  assert/text="SVGET/L"/NOOP=MISS

  ! TEST SVSET/L ===============================================================
  assert/text="SVSET/L"/NOOP=MISS


  ! TEST SVGET (small delta) ===================================================
  ! This was an issue seen in the NeXtMidas 3.3.0rc2 where a Platinum file with
  ! a very small delta did not work properly, also note that the first EPH_TIME
  ! is slightly before the start of the data in the file. There was also in issue
  ! in NeXtMidas 3.3.0rc3 where only the ".UNIT" form worked, and this should
  ! work with ".UNITS" too.
  timex             1994:01:01::00:00:00 EPOCH       ! <-- convert from
  timex/FMT=ISO8601 1994:01:01::00:00:00 TIME_EPOCH

  res  D:EPH_TIME     (2012:01:01::12:00:00.1834938165,&
                       2012:01:01::12:00:00.3257115445,&
                       2012:01:01::12:00:00.4679292725,&
                       2012:01:01::12:00:00.6101470005,&
                       2012:01:01::12:00:00.7523647285,&
                       2012:01:01::12:00:00.8945824565)
  res  X:TIME_TICKS   (-1,-1,-1,-1,-1,-1)
  res  D:EPH_POS_X    (5000000,-1,-1,-1,-1,-1)
  res  D:EPH_POS_Y    (5000,-1,-1,-1,-1,-1)
  res  D:EPH_POS_Z    (500,-1,-1,-1,-1,-1)
  res  D:EPH_VEL_X    (100,100,100,100,100,100)
  res  D:EPH_VEL_Y    (100,100,100,100,100,100)
  res  D:EPH_VEL_Z    (100,100,100,100,100,100)
  res  D:EPH_ACC_X    (0,0,0,0,0,0)
  res  D:EPH_ACC_Y    (0,0,0,0,0,0)
  res  D:EPH_ACC_Z    (0,0,0,0,0,0)
  calc D:dt           EPH_TIME(1) EPH_TIME(0) -
  res  S:START_TIME   2012:01:01::12:00:00.250
  calc D:TIMETAG_TIME START_TIME EPOCH -
  res  D:TIME_DELTA   1e-9

  do i 0 6-1 1
    timex EPH_TIME(i) t
    invoke ticks t.toTimeTicks(EPOCH,TIME_DELTA)
    invoke ,, TIME_TICKS.setNumber(i,ticks)

    !calc D:EPH_TIME(i) D:EPH_TIME(i) EPOCH -

    calc tt D:EPH_TIME(i) EPOCH -
    invoke tt nxm.sys.lib.Convert.o2d(tt)
    invoke ,, EPH_TIME.setNumber(i,tt)
  enddo

  do i 1 6-1 1
    !calc D:EPH_POS_X(i) EPH_POS_X(i-1) 100 dt * +
    !calc D:EPH_POS_Y(i) EPH_POS_Y(i-1) 100 dt * +
    !calc D:EPH_POS_Z(i) EPH_POS_Z(i-1) 100 dt * +

    calc x EPH_POS_X(i-1) 100 dt * +
    calc y EPH_POS_Y(i-1) 100 dt * +
    calc z EPH_POS_Z(i-1) 100 dt * +
    invoke x nxm.sys.lib.Convert.o2d(x)
    invoke y nxm.sys.lib.Convert.o2d(y)
    invoke z nxm.sys.lib.Convert.o2d(z)

    invoke ,, EPH_POS_X.setNumber(i,x)
    invoke ,, EPH_POS_Y.setNumber(i,y)
    invoke ,, EPH_POS_Z.setNumber(i,z)
  enddo

  waveform ram:test_plat_unit
  timex START_TIME FILE=ram:test_plat_unit
  noop ram:test_plat_unit ram:test_plat_units

  key ram:test_plat_unit PUT S:TIME_EPOCH   TIME_EPOCH
  key ram:test_plat_unit PUT D:TIME_DELTA   TIME_DELTA
  key ram:test_plat_unit PUT D:TIMETAG.TIME TIMETAG_TIME  L:TIMETAG.TIME.UNIT  1
  key ram:test_plat_unit PUT D:EPH.TIME     EPH_TIME      L:EPH.TIME.UNIT      1
  key ram:test_plat_unit PUT D:EPH_POS.X    EPH_POS_X     L:EPH_POS.X.UNIT     5
  key ram:test_plat_unit PUT D:EPH_POS.Y    EPH_POS_Y     L:EPH_POS.Y.UNIT     5
  key ram:test_plat_unit PUT D:EPH_POS.Z    EPH_POS_Z     L:EPH_POS.Z.UNIT     5
  key ram:test_plat_unit PUT D:EPH_VEL.X    EPH_VEL_X     L:EPH_VEL.X.UNIT     6
  key ram:test_plat_unit PUT D:EPH_VEL.Y    EPH_VEL_Y     L:EPH_VEL.Y.UNIT     6
  key ram:test_plat_unit PUT D:EPH_VEL.Z    EPH_VEL_Z     L:EPH_VEL.Z.UNIT     6
  key ram:test_plat_unit PUT D:EPH_ACC.X    EPH_ACC_X     L:EPH_ACC.X.UNIT     7
  key ram:test_plat_unit PUT D:EPH_ACC.Y    EPH_ACC_Y     L:EPH_ACC.Y.UNIT     7
  key ram:test_plat_unit PUT D:EPH_ACC.Z    EPH_ACC_Z     L:EPH_ACC.Z.UNIT     7

  key ram:test_plat_units PUT S:TIME_EPOCH   TIME_EPOCH
  key ram:test_plat_units PUT D:TIME_DELTA   TIME_DELTA
  key ram:test_plat_units PUT D:TIMETAG.TIME TIMETAG_TIME  L:TIMETAG.TIME.UNITS  1
  key ram:test_plat_units PUT D:EPH.TIME     EPH_TIME      L:EPH.TIME.UNITS      1
  key ram:test_plat_units PUT D:EPH_POS.X    EPH_POS_X     L:EPH_POS.X.UNITS     5
  key ram:test_plat_units PUT D:EPH_POS.Y    EPH_POS_Y     L:EPH_POS.Y.UNITS     5
  key ram:test_plat_units PUT D:EPH_POS.Z    EPH_POS_Z     L:EPH_POS.Z.UNITS     5
  key ram:test_plat_units PUT D:EPH_VEL.X    EPH_VEL_X     L:EPH_VEL.X.UNITS     6
  key ram:test_plat_units PUT D:EPH_VEL.Y    EPH_VEL_Y     L:EPH_VEL.Y.UNITS     6
  key ram:test_plat_units PUT D:EPH_VEL.Z    EPH_VEL_Z     L:EPH_VEL.Z.UNITS     6
  key ram:test_plat_units PUT D:EPH_ACC.X    EPH_ACC_X     L:EPH_ACC.X.UNITS     7
  key ram:test_plat_units PUT D:EPH_ACC.Y    EPH_ACC_Y     L:EPH_ACC.Y.UNITS     7
  key ram:test_plat_units PUT D:EPH_ACC.Z    EPH_ACC_Z     L:EPH_ACC.Z.UNITS     7

  file copy/b ram:test_plat_unit  ram:test_plat_tt_unit
  file copy/b ram:test_plat_units ram:test_plat_tt_units
  key ram:test_plat_tt_unit  PUT D:TIMETAG.TIME TIME_TICKS  L:TIMETAG.TIME.UNIT  32
  key ram:test_plat_tt_units PUT D:TIMETAG.TIME TIME_TICKS  L:TIMETAG.TIME.UNITS 32

  key ram:test_plat_unit     SVGET ram:test_sv_unit
  key ram:test_plat_units    SVGET ram:test_sv_units
  key ram:test_plat_tt_unit  SVGET ram:test_sv_tt_unit
  key ram:test_plat_tt_units SVGET ram:test_sv_tt_units

  assert/text="SVGET using EPH.TIME.UNIT=32  matches EPH.TIME.UNIT=1" ram:test_sv_unit FEQ/D/H/S ram:test_sv_tt_unit
  assert/text="SVGET using EPH.TIME.UNITS=32 matches EPH.TIME.UNIT=1" ram:test_sv_unit FEQ/D/H/S ram:test_sv_tt_units
  assert/text="SVGET using EPH.TIME.UNITS=1  matches EPH.TIME.UNIT=1" ram:test_sv_unit FEQ/D/H/S ram:test_sv_units

  file open f ram:test_sv_unit
    assert/text="SVGET with small time delta: size"     f.size     EQ 6
    assert/text="SVGET with small time delta: timecode" f.timecode EQ 2012:01:01::00:00:00
    assert/text="SVGET with small time delta: start"    f.start    EQ 12:00:00.183494 ! rounds to 1 usec
    assert/text="SVGET with small time delta: delta"    f.delta    EQ 0.142218        ! rounds to 1 usec

    do i 0 f.size-1 1
      invoke T:actRow  f.getDataTable(i)
      calc   D:expPos  (5000000,5000,500) (100,100,100) i 0.142218 * * +
      calc   D:expVel  (100,100,100)
      calc   D:expAcc  (0,0,0)
      calc   D:expTime 2012:01:01::12:00:00.183494 0.142218 i * +

      assert/text="SVGET with small time delta: POS  @ ^{i}" ^{actRow.POS}  EQ/V/T expPos  /TOL=1e-5
      assert/text="SVGET with small time delta: VEL  @ ^{i}" ^{actRow.VEL}  EQ/V   expVel
      assert/text="SVGET with small time delta: ACC  @ ^{i}" ^{actRow.ACC}  EQ/V   expAcc
      assert/text="SVGET with small time delta: TIME @ ^{i}" ^{actRow.TIME} EQ/T   expTime
    enddo
  file close f
return

procedure checkOutputSV S:testName FN:expFile FN:actFile
  file open f expFile
    file open sv actFile
      res recDefs sv.RecordDefs

      call checkRecDefPRM "^{testName}" recDefs "POS"  "VD"  0 "CARTESIAN" "DISTANCE_M"
      call checkRecDefPRM "^{testName}" recDefs "VEL"  "VD" 24 "CARTESIAN" "SPEED_M_S"
      call checkRecDefPRM "^{testName}" recDefs "ACC"  "VD" 48 "CARTESIAN" "ACCELERATION_M_S2"
      call checkRecDefPRM "^{testName}" recDefs "TIME" "SD" 72 "SCALAR"    "TIME_S"


      assert/text="^{testName} correct file size" f.size EQ sv.size

      do i 0 f.size-1 1
        invoke expTime f.getTimeAt(i)
        invoke actTime sv.getTimeAt(i)
        invoke expData f.getDataTable(i)
        invoke actData sv.getDataTable(i)


        assert/text="^{testName} POS    @ ^{i}" expData.POS  EQ/V actData.POS
        assert/text="^{testName} VEL    @ ^{i}" expData.VEL  EQ/V actData.VEL
        assert/text="^{testName} ACC    @ ^{i}" expData.ACC  EQ/V actData.ACC
        assert/text="^{testName} TIME   @ ^{i}" expTime      EQ   actData.TIME
        assert/text="^{testName} TimeAt @ ^{i}" expTime      EQ   actTime
      enddo

    file close sv
  file close f
return


!******************************************************************************!
! Tests TCGET and TCSET functions
! Since 3.3.0
!******************************************************************************!
procedure test_TCGET
  calc T0 "2012:11:12::12:00:00"
  set T:KWDS {D:TC_WHOLE_1=^{T0}+0,D:TC_FRAC_1=0.000,D:TC_OFFSET_1=0,D:TCSAMPLE_1=0K+1,&
              D:TC_WHOLE_2=^{T0}+1,D:TC_FRAC_2=0.024,D:TC_OFFSET_2=0,D:TCSAMPLE_2=1K+1,&
              D:TC_WHOLE_3=^{T0}+2,D:TC_FRAC_3=0.048,D:TC_OFFSET_3=0,D:TCSAMPLE_3=2K+1,&
              D:TC_WHOLE_4=^{T0}+3,D:TC_FRAC_4=0.072,D:TC_OFFSET_4=0,D:TCSAMPLE_4=3K+1}

  ! TEST TCGET =================================================================
  waveform  ram:sample_data SF 4k
  headermod ram:sample_data XD=0.001

  for key inTable KWDS
    keyword ram:sample_data PUT "D:^{key}" KWDS.^{KEY}
  endfor

  keyword ram:sample_data TCGET/X/I ram:sample_pkt

  invoke B:dataRep nxm.sys.lib.Shell.rep
  res    B:dataBPA   4 ! BPA("SF")=4
  res    B:dataMode 83 ! 83='S'
  res    B:dataType 70 ! 70='F'

  file open f ram:sample_pkt
    assert/text="TCGET/X/I -> File Size" 4     EQ f.size
    assert/text="TCGET/X/I -> Start"     0     EQ f.start
    assert/text="TCGET/X/I -> Delta"     1.024 EQ f.delta
    assert/text="TCGET/X/I -> Units"     1     EQ f.units  ! 1=TIME_S

    do i 0 f.size-1 1
      calc   L:j      i 1 +
      res    D:TCO    ^{KWDS.TC_OFFSET_^{j}}
      res    D:TCWS   ^{KWDS.TC_WHOLE_^{j}}
      res    D:TCFS   ^{KWDS.TC_FRAC_^{j}}
      calc   L:ELEM   1K
      res    T:expTbl {KEYS=(101,102,103,0),CNT=^{j},ELEM=^{ELEM},USER=0,CHAN=0,SID=(0,0),&
                       REP=^{dataRep},BPA=^{dataBPA},MODE=^{dataMode},TYPE=^{dataType},&
                       TCM=0,TCS=1,TCO=^{TCO},TCWS=^{TCWS},TCFS=^{TCFS},&
                       RBST=0,RBSZ=0,RBDO=0,RBDS=0}
      invoke T:actTbl f.getDataTable(i)

      for key inTable expTbl
        assert/text="TCGET/X/I -> ^{i}: ^{KEY}" expTbl.^{key} EQ/V actTbl.^{key}
      endfor
    enddo
  file close f

  ! TEST TCSET =================================================================
  waveform  ram:sample_out SF 4k
  headermod ram:sample_out XD=0.001

  keyword ram:sample_out TCSET/I/X ram:sample_pkt

  for key inTable KWDS
    keyword ram:sample_out GET "^{key}" value
    assert/text="TCSET/I/X -> ^{KEY}" KWDS.^{KEY} EQ value
  endfor
return

!******************************************************************************!
! Taken from %TEST_FILE
procedure checkRecDefPRM s:descr T:recDef S:expName S:expFormat L:expOffset S:expType S:expUnits
  assert/text="^{descr} got ^{expName}.NAME"   recDef.^{expName}.NAME   EQS expName
  assert/text="^{descr} got ^{expName}.FORMAT" recDef.^{expName}.FORMAT EQS expFormat
  assert/text="^{descr} got ^{expName}.OFFSET" recDef.^{expName}.OFFSET EQ  expOffset
  assert/text="^{descr} got ^{expName}.TYPE"   recDef.^{expName}.TYPE   EQS expType
  assert/text="^{descr} got ^{expName}.UNITS"  recDef.^{expName}.UNITS  EQS expUnits
return

! Taken from %TEST_FILE
procedure checkRecDefCSV s:descr T:recDef S:expName S:expFormat
  assert/text="^{descr} got ^{expName}.NAME"   recDef.^{expName}.NAME   EQS expName

  if (expFormat EQS "") then
    ! Should be omitted
  else
    assert/text="^{descr} got ^{expName}.FORMAT" recDef.^{expName}.FORMAT EQS expFormat
  endif
return

!******************************************************************************!
! since 3.7.0 byte order test
! Bug 3009 - Keywords: set method does not properly convert byte order after first element
procedure test_ByteOrder
  set data1 1.0
  set data2 (2.0, 3.0)
  set data3 (3, 4, 5)
  set file ram:test_keyword_byte_order

  foreach byteOrder inlist "IEEE,EEEI"
    ! create test file with proper header byte order
    headermod/create file
    convert file CONV=^byteOrder

    remove val1 val2 val3
    ! Note: need to get a copy of Data, b/c if the byte order is swapped, it would touch original Data object
    keyword file PUT "KEY1" data1.copy() "KEY2" data2.copy() "KEY3" data3.copy()
    keyword file GET "KEY1" val1         "KEY2" val2         "KEY3" val3
    if /debug then status/key file

    assert/text="^reg.main.name: ^byteOrder header byte order exp=^data1 act=^val1" val1 rexists AND val1 eq data1
    assert/text="^reg.main.name: ^byteOrder header byte order exp=^data2 act=^val2" val2 rexists AND val2 eq data2
    assert/text="^reg.main.name: ^byteOrder header byte order exp=^data3 act=^val3" val3 rexists AND val3 eq data3

    erase file
  endfor
return
