!******************************************************************************!
! Macro for testing the FILE intrinsic and IOResources
!
! Author : Jay Hallam / Neon Ngo
!
! Dependencies:
!******************************************************************************!
startmacro s:rootIn[""] s:func[""]
  switch INTERACTIVE interAct   GET DEF=TRUE  SDEF=TRUE
  switch BASELINE    baseline   GET DEF=FALSE SDEF=TRUE
  switch DEBUG       debug      GET DEF=true  SDEF=TRUE
  switch ALTTESTENV  alttestenv GET DEF=FALSE SDEF=TRUE
  set OperatingSystem ENV GET OSNAME
  set z:exceptionExpected false

  invoke isGradleBuildCommand nxm.sys.lib.Shell.isGradleBuildCommand()

  ! Only change aux.dat when dealing the specialty case of dat being at nxm/sys/test/dat
  ! Setting aux.dat when run in nextopt does not behave as expected - NXM-3809 since NeXtMidas 4.1.1
  call setDatDir
  if datDirSlash eqs "nxm/sys/test/dat" then
    res origDatAux "^{aux.dat}"
    invoke nm_root nxm.sys.lib.Shell.getNmRoot()
    res aux.dat "^{nm_root}^{datDirSlash}"
    invoke datDir nxm.sys.test.DatLocator.getDatDirLocation()
    invoke datDirSlash nxm.sys.test.DatLocator.getDatDirSlashLocation()
  endif

  if rootIn EQS "" AND baseline isTRUE then
    set s:root "http://nextmidas.com/nm/"
  else
    set s:root "^rootIn"
  endif
  info "r00t = ^root"

  if func NEQS "" then
    call test_^{func}
  else
    ! Test the BaseFile.exists() method added in NeXtMidas 2.1.1
    invoke myfile nxm.sys.lib.BaseFile.getInstanceFor(this.M,junk.prm)
    assert/text="^reg.main.name: File existence check for junk.prm"    myfile.exists() isFalse
    invoke myfile nxm.sys.lib.BaseFile.getInstanceFor(this.M,fftdemo.prm)
    assert/text="^reg.main.name: File existence check for fftdemo.prm" myfile.exists() isTrue

    call test_create_1000
    call test_getData_syntax

    set testfile "test_file_command_3000"
    call createTestFile3000 "^testfile"
    call test_create_3000   "^testfile"

    assert/text="^reg.main.name: get type-3000 row, table exists?"/stat=tempStatus "^testfile" FEXISTS
    if tempStatus NEQS "PASS" then
      WARNING "^testfile does not exist, bypassing other type-3000 tests"
    else
      call test_getDataTable      "^testfile"  ! Type 3000, 5000, 6000, ListFile
      call test_setDataTable      "^testfile"  ! Type 3000, 5000, 6000, ListFile
      call test_alterRecord_3000  "^testfile"
      call test_addRecord_3000    "^testfile"
      call test_insertRecord_3000 "3000"
      call test_insertRecord_3000 "5000"
      call test_insertRecord_3000 "6000"
      call test_insertRecord_2000
      erase testfile
    endif

    if sysTestDatExists then
      warn "skipping test_copy_basefile because DAT files are in nxm.sys.test.dat"
    else
      call test_copy_basefile
    endif
    call test_copy_listfile
    call test_copy_native
    call test_text_write_read
    call test_text_long_line
    call test_rename
    call test_name
    call test_csv_files
    call test_protect_unprotect
    call test_detach
    call test_dataframesize
    call test_append
    call test_type3000
    call test_type5000 "IEEE"
    call test_type5000 "EEEI"
    call test_close
    call test_read_from_tar
    if alttestenv then
      warn "^reg.main.name: skipping HTTP tests because in alternate test environment"
    else
      call test_http
    endif
    call test_url_of_ramd_file
    call test_use_native_qualifier
    call test_bug2076
    call test_ramfile_isfile
    call test_IOResource_getType
    call test_JarResource_leak
    call test_deleteOnExit
    call test_read
    if (reg.main.M.logger NREXISTS) then  ! These tests should not be run if logging is on - updated in 3.7.1
      call test_jnlp_file_specification_version "6.0.18"   ""
      call test_jnlp_file_specification_version "7.0"      ""
      call test_jnlp_file_specification_version "4.99"     "WARN: Specification version 4.99"
      call test_jnlp_file_specification_version "8"        "WARN: Specification version 8"
      call test_jnlp_file_specification_version ""         "WARN: JNLP file has malformed specification version"
      call test_jnlp_file_specification_version "Bad Spec" "WARN: JNLP file has malformed specification version"
    endif
    %test_file_byte_order
    %test_datafile/interactive=^interAct
    %test_basefile/interactive=^interAct
    %test_basefile_filename_os_prompt/interactive=^interAct ! NXM-4106
  endif

  if origDatAux rexists then res aux.dat "^origDatAux"  ! restore original AUX.DAT

endmacro

!******************************************************************************!
! If an unexpected exception is caught, mark test as failed, unless it is expected
!******************************************************************************!
procedure  processException m:emsg
  if exceptionExpected isTRUE AND emsg.name eqs "ERROR" then
    if "Use DETACH/F modifier to overwrite existing file" SUBS emsg.data.message then
      res z:gotExceptionForDetach true
    elseif "Could not open" SUBS emsg.data.message then
      res z:gotExceptionForCantOpenFile true
    endif
    set z:exceptionExpected false
  else
    assert/text="^reg.main.name: (exceptionExpected=^exceptionExpected) Unexpected exception: ^emsg.data" FALSE
    if "Trace" SUBS ENV.DEBUG then invoke ,, emsg.data.printStackTrace()
  endif
return

!******************************************************************************!
! Set the dat directory
!******************************************************************************!
procedure setDatDir
  invoke nxmMajor env.nmversion.subString(0,1)
  invoke major java.lang.Integer.valueOf(nxmMajor)
  if major GE 4 then
    invoke s:datDir           nxm.sys.test.DatLocator.getDatDirLocation()
    invoke s:datDirSlash      nxm.sys.test.DatLocator.getDatDirSlashLocation()
    invoke z:sysDatFull       nxm.sys.test.DatLocator.sysDatFull()
    invoke z:sysTestDatExists nxm.sys.test.DatLocator.sysTestDatExists()
  else
    set s:datDir           "nxm.sys.dat"
    set s:datDirSlash      "nxm/sys/dat"
    set z:sysDatFull       true
    set z:sysTestDatExists false
  endif
return

!******************************************************************************!
! Calls the HTTP tests if we have access to HTTP resources
!
procedure test_http
  if root.length() le 5 or root neqss "http:" then
    warn "^reg.main.name: Skipping URL test, input URL = '^root'"

  elseif root nfexists then
    warn "^reg.main.name: Can not access '^root', skipping HTTP tests."

  elseif "^{reg.shell.class}" eqs "class nxm.sys.libxm.XmShell" then
    warn "^reg.main.name: HTTP tests for FILE skipped when running as an X-Midas option tree."

  else
    assert/text="^reg.main.name: FEXISTS for root=^root" true
    call test_http_copy
    call test_http_equals
  endif
return

!******************************************************************************!
procedure test_create_1000
  result myErr ""
  result testfile "test_file_command_1000"
  result L:nels 10
!
! Test NEW type 1000 file
!
  file open/d/n tag testfile
  forall #=1:^nels res tag.setdata(#-) #
  file close tag

  status testfile size=size
  if size eq nels then
    file open/d tag testfile
    do i 1 nels
      res x tag.getdata(^i-)
      if i neq x then
        result myErr "data not correct"
        break
      endif
    enddo
    file close tag

  else
    result myErr "size not correct"
  endif
  erase testfile

  assert/text="^reg.main.name: CREATE1000 ^myErr" myErr eqs ""

return

!******************************************************************************!
procedure test_getData_syntax
!
!  Test the syntax for getting data, should not have to carot or quote
!  the record name

  result testfile "test_file_command_3000"
!
! Unquoted record name - where NAME is also a result
!
  file open/d/n tag testfile{SR=(NAME/SA)}
  result tag.setdata(0,NAME) "HOMER"
  file close tag

  result NAME "DUMMY" ! This should screw up the translation!
  file open/d tag testfile
  result x tag.getdata(0,NAME)
  file close tag

  assert/text="^reg.main.name: getData/unquoted rec is also a result" x NEQS "HOMER"
  erase testfile

!
! Unquoted record name - where NAME is NOT a result
!
  remove name  ! This assures the record name, NAME, will be translated correctly

  file open/d/n tag testfile{SR=(NAME/SA)}
  result tag.setdata(0,NAME) "HOMER"
  file close tag

  file open/d tag testfile
  result x tag.getdata(0,NAME)
  file close tag

  assert/text="^reg.main.name: getData/unquoted rec is NOT a result" x EQS "HOMER"
  erase testfile

!
! Quoted record name
!
  file open/d/n tag testfile{SR=(NAME/SA)}
  result tag.setdata(0,"NAME") "HOMER"
  file close tag

  file open/d tag testfile
  result x tag.getdata(0,"NAME")
  file close tag

  assert/text="^reg.main.name: getData/quoted record; val = ^x" x EQS "HOMER"

  erase testfile

return

!******************************************************************************!
procedure createTestFile3000 fn:testfile
  if "^testfile" FEXISTS erase "^testfile"
  result truth {}
  result L:truth.nels 2
  result truth.numSubRecs 5
!
! For ASCII (string data) we use the format 2A instead of SA to perform
! a more general test.
!
    file open/d/n tag testfile{SR=(BYTE/SB,INT/SI,LONG/SL,DBLE/SD,ASCI/2A)}
    do i 0 truth.nels-1
      res tag.setdata(i,BYTE) 1
      res tag.setdata(i,INT)  2
      res tag.setdata(i,LONG) 3
      res tag.setdata(i,DBLE) 4
      res tag.setdata(i,ASCI) "A234567890123456"
    enddo
  file close tag

return

!******************************************************************************!
procedure test_create_3000 fn:testfile
!
!  Test NEW non-homogeneous TYPE 3000 file
!
  result myErr ""
  !
  status testfile size=size nsr=numsubrecs
  if size eq truth.nels then
    if numsubrecs eq truth.numSubRecs then
      file open/d tag testfile
      do i 1 truth.nels
        result elem i-1
        ! Test the numeric value(s)
        do j 1 numsubrecs
          ! Record names are indexed from 0!
          !
          result L:recindex j-1
          res recname tag.getrecname(recindex)
          res x tag.getdata(elem,^{recname})
          if j LT numsubrecs then
            if x neq j then
              result myErr " ^myKey, data, elem = ^i, subrec = ^j"
              goto LAB_CREATE3000
            endif
          else
            ! ASCII compare
            if x neqs "A234567890123456" then
              result myErr "^macroName: ^myKey, ASCII data, elem = ^i, &
                           subrec = ^j"
              goto LAB_CREATE3000
            endif
          endif
        enddo
        ! Now test the ascii value(s)
      enddo
      file close tag
    else
      result myErr "num subrecords not correct"
    endif
  else
    result myErr "size ^size NE truth.nels ^truth.nels"
  endif

  label LAB_CREATE3000
  assert/text="^reg.main.name: CREATE3000 ^myErr" myErr eqs ""

return

!******************************************************************************!
procedure test_setDataTable fn:testfile
  set t:ellipse5000_data {}
  set t:ellipse5000_data.0 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,0.0),NAME="TONY"}
  set t:ellipse5000_data.1 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,15.0),NAME="TONY"}
  set t:ellipse5000_data.2 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,30.0),NAME="TONY"}
  set t:ellipse5000_data.3 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,45.0),NAME="TONY"}
  set t:ellipse5000_data.4 {POS=(0.0,15.0,60.0),ELPS=(300000.0,70000.0,60.0),NAME="TONY5"}
  set t:ellipse5000_data.5 {POS=(0.0,15.0,75.0),ELPS=(300000.0,70000.0,75.0),NAME="TONY6"}
  set t:ellipse5000_data.6 {POS=(0.0,15.0,90.0),ELPS=(300000.0,70000.0,90.0),NAME="TONY7"}
  set t:ellipse5000_data.7 {POS=(0.0,15.0,105.0),ELPS=(300000.0,70000.0,105.0),NAME="TONY8"}
  set t:ellipse5000_data.8 {POS=(0.0,60.0,0.0),ELPS=(300000.0,70000.0,45.0),NAME="TONY9"}

  file open/n out ram:temp_ellipse5000{COMPONENTS=(POS/VD,ELPS/VD,NAME/9A),SIZE=9}
    ! Do evens in order then odds in reverse order to prove that we have random-access into the
    ! file when using getDataTable(..)
    do i 0 8 2
      invoke ,, out.setData(^i,ellipse5000_data.^i)
    enddo
    do i 7 1 -2
      invoke ,, out.setData(^i,ellipse5000_data.^i)
    enddo
  file close out

  file open in ram:temp_ellipse5000
    do i 0 8 1
      set    expected ellipse5000_data.^i
      set    actual   {}
      invoke numRead  in.readDataTable(actual)

      assert/text="^reg.main.name: setData(..) at ^i (numRead)" numRead          eq      1
      assert/text="^reg.main.name: setData(..) at ^i (getSize)" expected.getSize eq      actual.getSize
      assert/text="^reg.main.name: setData(..) at ^i (POS)"     expected.POS     eq/s/v  actual.POS
      assert/text="^reg.main.name: setData(..) at ^i (ELPS)"    expected.ELPS    eq/s/v  actual.ELPS
      assert/text="^reg.main.name: setData(..) at ^i (NAME)"    expected.NAME    eqs     actual.NAME
    enddo
    set    actual   {}
    invoke numRead  in.readDataTable(actual)
    assert/text="^reg.main.name: setData(..) at ^i (EndOfFile)" numRead eq -1
  file close in


  file open/n out ram:test_ellipse5000{COMPONENTS=(POS/VD,ELPS/VD,NAME/9A),SIZE=9}
    ! Do evens in order then odds in reverse order to prove that we have random-access into the
    ! file when using getDataTable(..)
    do i 0 8 1
      invoke ,, out.writeDataTable(ellipse5000_data.^i)
    enddo
  file close out

  file open in ram:test_ellipse5000
    do i 0 8 1
      set    expected ellipse5000_data.^i
      set    actual   {}
      invoke numRead  in.readDataTable(actual)

      assert/text="^reg.main.name: writeDataTable(..) at ^i (numRead)" numRead          eq      1
      assert/text="^reg.main.name: writeDataTable(..) at ^i (getSize)" expected.getSize eq      actual.getSize
      assert/text="^reg.main.name: writeDataTable(..) at ^i (POS)"     expected.POS     eq/s/v  actual.POS
      assert/text="^reg.main.name: writeDataTable(..) at ^i (ELPS)"    expected.ELPS    eq/s/v  actual.ELPS
      assert/text="^reg.main.name: writeDataTable(..) at ^i (NAME)"    expected.NAME    eqs     actual.NAME
    enddo
    set    actual   {}
    invoke numRead  in.readDataTable(actual)
    assert/text="^reg.main.name: writeDataTable(..) at ^i (EndOfFile)" numRead eq -1
  file close in
return

!******************************************************************************!
procedure test_getDataTable fn:testfile
  set t:ellipse5000_data {}
  set t:ellipse5000_data.0 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,0.0),NAME="TONY"}
  set t:ellipse5000_data.1 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,15.0),NAME="TONY"}
  set t:ellipse5000_data.2 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,30.0),NAME="TONY"}
  set t:ellipse5000_data.3 {POS=(0.0,0.0,45.0),ELPS=(300000.0,70000.0,45.0),NAME="TONY"}
  set t:ellipse5000_data.4 {POS=(0.0,15.0,60.0),ELPS=(300000.0,70000.0,60.0),NAME="TONY5"}
  set t:ellipse5000_data.5 {POS=(0.0,15.0,75.0),ELPS=(300000.0,70000.0,75.0),NAME="TONY6"}
  set t:ellipse5000_data.6 {POS=(0.0,15.0,90.0),ELPS=(300000.0,70000.0,90.0),NAME="TONY7"}
  set t:ellipse5000_data.7 {POS=(0.0,15.0,105.0),ELPS=(300000.0,70000.0,105.0),NAME="TONY8"}
  set t:ellipse5000_data.8 {POS=(0.0,60.0,0.0),ELPS=(300000.0,70000.0,45.0),NAME="TONY9"}

  file open in ellipse5000.prm
    ! Do evens in order then odds in reverse order to prove that we have random-access into the
    ! file when using getDataTable(..)
    do i 0 8 2
      set    expected ellipse5000_data.^i
      invoke actual   in.getDataTable(^i)

      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (getSize)" expected.getSize eq      actual.getSize
      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (POS)"     expected.POS     eq/s/v  actual.POS
      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (ELPS)"    expected.ELPS    eq/s/v  actual.ELPS
      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (NAME)"    expected.NAME    eqs     actual.NAME
    enddo
    do i 7 1 -2
      set    expected ellipse5000_data.^i
      invoke actual   in.getDataTable(^i)

      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (getSize)" expected.getSize eq      actual.getSize
      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (POS)"     expected.POS     eq/s/v  actual.POS
      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (ELPS)"    expected.ELPS    eq/s/v  actual.ELPS
      assert/text="^reg.main.name: getDataTable(^i) from ellipse5000.prm (NAME)"    expected.NAME    eqs     actual.NAME
    enddo
  file close in

  file open in ellipse5000.prm
    ! When using readDataTable(..) we need to go in order.
    do i 0 8 1
      set    expected ellipse5000_data.^i
      set    actual   {}
      invoke numRead  in.readDataTable(actual)

      assert/text="^reg.main.name: readDataTable(..) at ^i from ellipse5000.prm (numRead)" numRead          eq      1
      assert/text="^reg.main.name: readDataTable(..) at ^i from ellipse5000.prm (getSize)" expected.getSize eq      actual.getSize
      assert/text="^reg.main.name: readDataTable(..) at ^i from ellipse5000.prm (POS)"     expected.POS     eq/s/v  actual.POS
      assert/text="^reg.main.name: readDataTable(..) at ^i from ellipse5000.prm (ELPS)"    expected.ELPS    eq/s/v  actual.ELPS
      assert/text="^reg.main.name: readDataTable(..) at ^i from ellipse5000.prm (NAME)"    expected.NAME    eqs     actual.NAME
    enddo
    set    actual   {}
    invoke numRead  in.readDataTable(actual)
    assert/text="^reg.main.name: readDataTable(..) at ^i from ellipse5000.prm (EndOfFile)" numRead eq -1
  file close in

  !
  ! Test getting a row of data into a Table.
  !
  if table REXISTS rem table
  file open/d tag testfile
  result t:table tag.getDataTable(1)
  file close tag
  assert/text="^reg.main.name: get type-3000 row, table exists?" table REXISTS

  result allPass "TRUE"
  result s:myMsg "type-3000 getDataTable"
  do i 1 truth.numSubRecs
    if i EQ 1 then
      res S:key "BYTE"
    elseif i EQ 2 then
      res S:key "INT"
    elseif i EQ 3 then
      res S:key "LONG"
    elseif i EQ 4 then
      res S:key "DBLE"
    elseif i EQ 5 then
      res S:key "ASCI"
    endif
    if i NE truth.numSubRecs then
      if table.^{key} NEQ i then
        result allPass "FALSE"
        result s:myMsg "type-3000 getDataTable, ^key"
        break
      endif
    else
      if table.^{key} NEQS "A234567890123456" then
        result allPass "FALSE"
        result s:myMsg "type-3000 getDataTable, ^key"
        break
      endif
    endif
  enddo

  assert/text="^reg.main.name: ^myMsg" allPass
return

!******************************************************************************!
!  Test altering a type-3000 record with a table
procedure test_alterRecord_3000 fn:testfile
  if table REXISTS rem table
  result t:tableTrue {BYTE=11,INT=12,LONG=13,DBLE=14,ASCI="ALTERREC"}

  ! Alter the record in the file
  file open/d/w tag testfile
    result tag.setData(1) ^tableTrue
  file close tag

  ! Read the new record from the file
  file open/d tag testfile
    result table tag.getDataTable(1)
  file close tag

  result allPass "TRUE"
  result s:myMsg "type-3000 alter record w/ table"
  result L:entry 1
  foreach key INTABLE tableTrue
    result tempStatus "PASS"
    if entry NEQ truth.numSubRecs
      if table.^{key} NEQ tableTrue.^{key} then
        result tempStatus "FAIL"
      endif
    else
      if "^{table.^{key}}" NEQS "^{tableTrue.^{key}}" then
        result tempStatus "FAIL"
      endif
    endif
    if tempStatus isFalse then
      result S:allPass "FALSE"
      result S:myMsg "type-3000 alter record, &
                      ^key; ^{table.^{key}} NE ^{tableTrue.^{key}}"
      break
    endif
    calc L:entry entry 1 +
  endfor
  assert/text="^reg.main.name: ^myMsg" allPass

  ! Alter the record in the file with the set syntax
  set FILE(testfile).setData(0,BYTE) 21
  set FILE(testfile).setData(0,INT)  22
  set FILE(testfile).setData(0,LONG) 23
  set FILE(testfile).setData(0,DBLE) 24
  set FILE(testfile).setData(0,ASCI) "ABC"
  set FILE(testfile).setData(1,ASCI) "abcdEFGH1234567890" ! string too long will trim off "90"

  ! Read the new record from the file
  result table0 FILE(testfile).getDataTable(0)
  result table1 FILE(testfile).getDataTable(1)
  assert/text="^reg.main.name: Update to BYTE field"         table0.BYTE eq  21
  assert/text="^reg.main.name: Update to INT  field"         table0.INT  eq  22
  assert/text="^reg.main.name: Update to LONG field"         table0.LONG eq  23
  assert/text="^reg.main.name: Update to DBLE field"         table0.DBLE eq  24
  assert/text="^reg.main.name: Update to ASCI field (short)" table0.ASCI eqs "ABC"
  assert/text="^reg.main.name: Update to ASCI field (long)"  table1.ASCI eqs "abcdEFGH12345678"

  ! Tests for Bug 857 ("DataFile: Error when setting ASCII field with <2 characters.")
  set longString "abcdefghijklmnopqrstuvwxyz"
  do chars 0 16 1
    invoke shortString longString.substring(0,chars)
    set FILE(testfile).setData(1,ASCI) shortString

    result table FILE(testfile).getDataTable(1)
    assert/text="^reg.main.name: Set 2A field with '^shortString'"  table.ASCI eqs shortString
  enddo
return

!******************************************************************************!
procedure test_addRecord_3000 fn:testfile
!
!  Test altering a type-3000 record with a table
!
  if table REXISTS rem table
  result t:tableTrue {BYTE=21,INT=22,LONG=23,DBLE=24,ASCI="ADDREC"}

  status ^testfile size=size
  ! Add the record to the end of the file
  file open/d/w tag testfile
  result tag.setData(size) tableTrue
  file close tag

  ! Read the new record from the file
  file open/d tag testfile
  result table tag.getDataTable(size)
  file close tag

  result allPass "TRUE"
  result s:myMsg "type-3000 add record w/ table"
  result L:entry 1
  foreach key INTABLE tableTrue
    result tempStatus "PASS"
    if entry NEQ truth.numSubRecs
      if table.^{key} NEQ tableTrue.^{key} then
        result tempStatus "FAIL"
      endif
    else
      if "^{table.^{key}}" NEQS "^{tableTrue.^{key}}" then
        result tempStatus "FAIL"
      endif
    endif
    if tempStatus isFalse then
      result S:allPass "FALSE"
      result S:myMsg "type-3000 add record, &
                      ^key; ^{table.^{key}} NE ^{tableTrue.^{key}}"
      break
    endif
    calc L:entry entry 1 +
  endfor

  assert/text="^reg.main.name: ^myMsg" allPass
return

!******************************************************************************!
procedure test_insertRecord_3000 s:type
!
!  Test inserting a type-3000/5000/6000 record with a table
!
  res testTable {0={NAME="ONE",POS=(0,0,0)},&
                 1={NAME="TWO",POS=(1,2,3)},&
                 2={NAME="THREE",POS=(3,2,1)},&
                 3={NAME="FOUR",POS=(9,9,9)}}
  res testStrLen   {NAME="123456781234567812345678",POS=(0,0,0)}
  res resTable2 {0={NAME="ONE",POS=(0,0,0)},&
                 1={NAME="TWO",POS=(1,2,3)},&
                 2={NAME="THREE",POS=(3,2,1)},&
                 3={NAME="FOUR",POS=(9,9,9)},&
                 4={NAME="THREE",POS=(3,2,1)},&
                 5={NAME="TWO",POS=(1,2,3)},&
                 6={NAME="ONE",POS=(0,0,0)},&
                 7={NAME="FOUR",POS=(9,9,9)},&
                 8={NAME="1234567812345678",POS=(0,0,0)}}

  if type eqs "5000" then
    header/create ram:testfile2 TYPE=^type COMPONENTS=(NAME/2A,POS/VD)
  else
    header/create ram:testfile2 TYPE=^type SR=(NAME/2A,POS/VD)
  endif
  file open/d/w temp3000tag ram:testfile2{FLAGS="FLUSH"}

  foreach key intable testTable
    invoke ,, temp3000tag.insertData(-1,testTable.^{key})
  endfor

  foreach key intable testTable
    invoke fromFile temp3000tag.getDataTable(^{KEY})
    assert/text="^reg.main.name: Test record Type ^{type} ^{key}.NAME" testTable.^{key}.name EQS    fromFile.name
    assert/text="^reg.main.name: Test record Type ^{type} ^{key}.POS"  testTable.^{key}.pos  EQ/S/V fromFile.pos
  endfor

  foreach key intable testTable
    invoke ,, temp3000tag.insertData(3,testTable.^{key})
  endfor
  invoke ,, temp3000tag.insertData(-1,testStrLen) ! Test insert length of ASCII value

  foreach key intable resTable2
    invoke fromFile temp3000tag.getDataTable(^{KEY})
    assert/text="^reg.main.name: Test record Type ^{type} ^{key}.NAME" resTable2.^{key}.name EQS    fromFile.name
    assert/text="^reg.main.name: Test record Type ^{type} ^{key}.POS"  resTable2.^{key}.pos  EQ/S/V fromFile.pos
  endfor

  file close temp3000tag
  erase ram:testfile2
return

!******************************************************************************!
procedure test_insertRecord_2000
!
!  Test inserting a type-2000 record with a table
!
  res testTableSF {0={F1=1,F2=2,F3=3},&
                   1={F1=1.1,F2=2.2,F4=4.4}}
  res resTableSF  {0={F1=F:1,F2=F:2,F3=F:3},&
                   1={F1=F:1.1,F2=F:2.2,F3=F:0.0}}

  res testTableVD {0={F1=(1,1,1),F2=(2,2,2),F3=(3,3,3)},&
                   1={F1=(1,2,3),F2=(1,2,3),F3=(1,2,3)},&
                   2={A=(1,1,1),B=(2,2,2),C=(3,3,3)},&
                   3={F1=(1,0,0),F2=(2,2,2),F3=(3,3,3)}}
  res resTableVD  {0={F1=D:(1,1,1),F2=D:(2,2,2),F3=D:(3,3,3)},&
                   1={F1=D:(1,2,3),F2=D:(1,2,3),F3=D:(1,2,3)},&
                   2={F1=D:(0,0,0),F2=D:(0,0,0),F3=D:(0,0,0)},&
                   3={F1=D:(1,0,0),F2=D:(2,2,2),F3=D:(3,3,3)}}

  res testTable2A {0={F1="1",F2="2",F3="3"},&
                   1={F1="123456781234567812345678",F2="12345678",F4="12345678"}}
  res resTable2A  {0={F1="1",F2="2",F3="3"},&
                   1={F1="1234567812345678",F2="12345678",F3=""}}

  call test_insert2000 testTableSF resTableSF "false" "SF"
  call test_insert2000 testTableVD resTableVD "false" "VD"
  call test_insert2000 testTable2A resTable2A "true"  "2A"
return

!******************************************************************************!
! Tests inserting into a type 2000 file with frame size = 3.
! toInsert - The records to insert.
! answer   - The expected results.
! isString - Should string compare be used.
! format   - The format of the file.
procedure test_insert2000 t:toInsert t:answer s:isString s:format
  header/create ram:testfile3 TYPE=2000 FORM=^{format} FS=3
  file open/d/w temp2000tag ram:testfile3{FLAGS="FLUSH"}

  foreach key intable toInsert
    invoke ,, temp2000tag.insertData(-1,toInsert.^{key})
  endfor

  foreach key intable answer
    invoke fromFile temp2000tag.getDataTable(^{KEY})
    if isString then
      assert/text="^reg.main.name: Test Type 2000 ^{format} ^{key}.F1" answer.^{key}.F1 EQS fromFile.F1
      assert/text="^reg.main.name: Test Type 2000 ^{format} ^{key}.F2" answer.^{key}.F2 EQS fromFile.F2
      assert/text="^reg.main.name: Test Type 2000 ^{format} ^{key}.F3" answer.^{key}.F3 EQS fromFile.F3
    else
      assert/text="^reg.main.name: Test Type 2000 ^{format} ^{key}.F1" answer.^{key}.F1 EQ/V/S fromFile.F1
      assert/text="^reg.main.name: Test Type 2000 ^{format} ^{key}.F2" answer.^{key}.F2 EQ/V/S fromFile.F2
      assert/text="^reg.main.name: Test Type 2000 ^{format} ^{key}.F3" answer.^{key}.F3 EQ/V/S fromFile.F3
    endif
  endfor

  file close temp2000tag
  erase ram:testfile3
return

!******************************************************************************!
!  Test the file copy/... command(s)
procedure test_copy_basefile
  ! Basic Tests
  result myErr ""
  result inRoot "world"
  result outRoot "temp_filecopytest_world"
  fname label=inFile area=dat name=^inRoot ext=prm opt=sys
  fname label=tempName area=aux.write name="" ext="" opt=aux
  file "NAME" outFile "(^tempName,temp)" "^outRoot" "tmp"
  sedit outFile targetDir "PATH"

  if ^inFile NFEXISTS then
    assert/text="^reg.main.name: unable to find ^inroot for COPY test" 1 EQ 2
  else

    if ^outFile FEXISTS then
      ! If the output file exists remove it and the target directory
      erase ^outFile
    endif
    call removeDir "^targetDir"

    ! Copy a file with creation directories
    file copy/m ^inFile ^outFile
    if ^outFile NFEXISTS then
      result myErr "copy/m - output file existence"
    else
      if ^inFile NFEQ ^outFile then
        result myErr "copy/m - out=in"
      endif
    endif
    call removeDir "^targetDir"

  endif

  assert/text="^reg.main.name: COPY ^myErr" myErr eqs ""

  if ^outFile FEXISTS erase ^outFile

  ! Tests for Bug 1074 (FILE: File after COPY has wrong size)
  !  - Before fixing Bug 1074, the last of these asserts would fail.
  res tempfile "temp_test_file.prm"

  waveform smallwave{AUX=RAM} elem=1k form=sl
  waveform bigwave{AUX=RAM}   elem=4k form=sl
  status smallwave{AUX=RAM}{FG=RAW} size=smallsize  ! includes header
  status bigwave{AUX=RAM}{FG=RAW}   size=bigsize    ! includes header

  file copy/f smallwave{AUX=RAM} tempfile
  status tempfile{FG=RAW} size=fsize
  assert/text="^reg.main.name: Check size after smallwave{AUX=RAM} -> tempfile" fsize eq smallsize

  file copy/f bigwave{AUX=RAM} tempfile
  status tempfile{FG=RAW} size=fsize
  assert/text="^reg.main.name: Check size after bigwave{AUX=RAM}   -> tempfile" fsize eq bigsize

  file copy/f smallwave{AUX=RAM} tempfile
  status tempfile{FG=RAW} size=fsize
  assert/text="^reg.main.name: Check size after smallwave{AUX=RAM} -> tempfile" fsize eq smallsize

  erase tempfile
return

!******************************************************************************!
!  Test the file copy/... command(s)
procedure test_copy_listfile
  set inFileNames  "testxy3000.prm,&
                    nxm.sys.test.test_list2_colors.csv{COLUMNNAMES=\"ID,COLR\"}"
  set outFileNames "test_file_prm{AUX=RAM,FG=PRM},&
                    test_file_csv{AUX=RAM,FG=CSV,HEADERROWS=1}"

  foreach inFileName inList inFileNames
    foreach outFileName inList outFileNames
      file copy/f/l inFileName outFileName

      file open oldFile inFileName
      file open newFile outFileName

      do i 0 oldFile.getNumberOfRows()-1 1
        set oldTable oldFile.getDataTable(i)
        set newTable newFile.getDataTable(i)

        table oldTable EQUALS newTable val
        assert/text="FILE COPY/L copying ^{inFileName} to ^{outFileName} row=^{i} matches " val isTrue
        if val isFalse then
          say "row ^{i} oldTable = ^{oldTable}"
          say "row ^{i} newTable = ^{newTable}"
        endif
      enddo

      file close oldFile
      file close newFile
      erase/quiet outFileName
    endfor
  endfor

  ! Tests for /PROPAGATE=FALSE
  file/propagate=false copy/l testxy3000.prm &
                              test_file_csv{AUX=RAM,FG=CSV,HEADERROWS=1,COLUMNNAMES="ABSC,ORD"}

  file open newFile test_file_csv{AUX=RAM,FG=CSV,HEADERROWS=1}
    set newColumns newFile.getRecordDefs()
  file close newFile

  assert/text="FILE COPY/L using /PROPAGATE=FALSE num columns is 2" newColumns.getsize eq 2
  assert/text="FILE COPY/L using /PROPAGATE=FALSE contains ABSC"    newColumns.absc rexists
  assert/text="FILE COPY/L using /PROPAGATE=FALSE contains ORD"     newColumns.ord  rexists

  ! Tests for /PROPMASK=NONE (default) and /PROPMASK=ALL (added NeXtMidas 3.3.0)
  file copy/L sv1.prm sv1_default{AUX=RAM}
  file copy/L sv1.prm sv1_none{AUX=RAM}     /PROPMASK=NONE
  file copy/L sv1.prm sv1_all{AUX=RAM}      /PROPMASK=ALL

  assert/text="FILE COPY/L using /PROPMASK=NONE is default" sv1_default{AUX=RAM} FEQ/B sv1_none{AUX=RAM}
  assert/text="FILE COPY/L using /PROPMASK=NONE got default type"  FILE(sv1_none{AUX=RAM}).type  EQ 3000
  assert/text="FILE COPY/L using /PROPMASK=NONE got default start" FILE(sv1_none{AUX=RAM}).start EQ 0.0
  assert/text="FILE COPY/L using /PROPMASK=NONE got default delta" FILE(sv1_none{AUX=RAM}).delta EQ 1.0
  assert/text="FILE COPY/L using /PROPMASK=NONE got default units" FILE(sv1_none{AUX=RAM}).units EQ 0
  assert/text="FILE COPY/L using /PROPMASK=ALL got correct type"  FILE(sv1_all{AUX=RAM}).type  EQ 5001
  assert/text="FILE COPY/L using /PROPMASK=ALL got correct start" FILE(sv1_all{AUX=RAM}).start EQ 0.0
  assert/text="FILE COPY/L using /PROPMASK=ALL got correct delta" FILE(sv1_all{AUX=RAM}).delta EQ 300.0
  assert/text="FILE COPY/L using /PROPMASK=ALL got correct units" FILE(sv1_all{AUX=RAM}).units EQ 1

  erase/quiet sv1_default{AUX=RAM}
  erase/quiet sv1_none{AUX=RAM}
  erase/quiet sv1_all{AUX=RAM}


  ! Tests for TIME_NAME=, ABSC_NAME=, INDEX_NAME= (added NeXtMidas 3.3.0)
  !   Note: The checking of OFFSET within checkRecDefPRM implicitly checks
  !         Bug 2665 (this test case was how the bug was uncovered).
  file copy/L sv1.prm{TIMECODE=2000:01:01::00:00:00} sv1_prm{AUX=RAM,FG=PRM,TIME_NAME=TIME,ABSC_NAME=ABSC,INDEX_NAME=IDX} /PROPMASK=ALL
  file copy/L sv1.prm{TIMECODE=2000:01:01::00:00:00} sv1_csv{AUX=RAM,FG=CSV,TIME_NAME=TIME,ABSC_NAME=ABSC,INDEX_NAME=IDX,HEADERROWS=1} /PROPMASK=ALL

  file open oldFile sv1.prm{TIMECODE=2000:01:01::00:00:00}
  file open prmFile sv1_prm{AUX=RAM,FG=PRM}
  file open csvFile sv1_csv{AUX=RAM,FG=CSV,HEADERROWS=1}

  res recDefsPRM prmFile.RecordDefs
  res recDefsCSV csvFile.RecordDefs

  call checkRecDefPRM "FILE COPY/L using TIME_NAME=, etc. (PRM)" recDefsPRM "POS"  "VD"  0 "CARTESIAN" "DISTANCE_M"
  call checkRecDefPRM "FILE COPY/L using TIME_NAME=, etc. (PRM)" recDefsPRM "VEL"  "VD" 24 "CARTESIAN" "SPEED_M_S"
  call checkRecDefPRM "FILE COPY/L using TIME_NAME=, etc. (PRM)" recDefsPRM "TIME" "SD" 48 "SCALAR"    "TIME_S"
  call checkRecDefPRM "FILE COPY/L using TIME_NAME=, etc. (PRM)" recDefsPRM "ABSC" "SD" 56 "SCALAR"    "TIME_S"
  call checkRecDefPRM "FILE COPY/L using TIME_NAME=, etc. (PRM)" recDefsPRM "IDX"  "SL" 64 "SCALAR"    "NONE"

  call checkRecDefCSV "FILE COPY/L using TIME_NAME=, etc. (CSV)" recDefsCSV "POS"  "VD"
  call checkRecDefCSV "FILE COPY/L using TIME_NAME=, etc. (CSV)" recDefsCSV "VEL"  "VD"
  call checkRecDefCSV "FILE COPY/L using TIME_NAME=, etc. (CSV)" recDefsCSV "TIME" ""
  call checkRecDefCSV "FILE COPY/L using TIME_NAME=, etc. (CSV)" recDefsCSV "ABSC" "SD"
  call checkRecDefCSV "FILE COPY/L using TIME_NAME=, etc. (CSV)" recDefsCSV "IDX"  "SL"

  do i 0 FILE(sv1.prm).size-1 1
    set oldTable oldFile.getDataTable(i)
    set prmTable prmFile.getDataTable(i)
    set csvTable csvFile.getDataTable(i)

    calc absc oldFile.start oldFile.delta i * +
    calc time absc 2000:01:01::00:00:00 +

    timex time time_str

    assert/text="FILE COPY/L using TIME_NAME=, etc. (PRM) POS  ^i" oldTable.POS  EQ/V prmTable.POS
    assert/text="FILE COPY/L using TIME_NAME=, etc. (PRM) VAL  ^i" oldTable.VEL  EQ/V prmTable.VEL
    assert/text="FILE COPY/L using TIME_NAME=, etc. (PRM) TIME ^i" time          EQ   prmTable.TIME
    assert/text="FILE COPY/L using TIME_NAME=, etc. (PRM) ABSC ^i" absc          EQ   prmTable.ABSC
    assert/text="FILE COPY/L using TIME_NAME=, etc. (PRM) IDX  ^i" i             EQ   prmTable.IDX

    assert/text="FILE COPY/L using TIME_NAME=, etc. (CSV) POS  ^i" oldTable.POS  EQ/V csvTable.POS
    assert/text="FILE COPY/L using TIME_NAME=, etc. (CSV) VAL  ^i" oldTable.VEL  EQ/V csvTable.VEL
    assert/text="FILE COPY/L using TIME_NAME=, etc. (CSV) TIME ^i" "^time_str"   EQS  csvTable.TIME
    assert/text="FILE COPY/L using TIME_NAME=, etc. (CSV) ABSC ^i" absc          EQ   csvTable.ABSC
    assert/text="FILE COPY/L using TIME_NAME=, etc. (CSV) IDX  ^i" i             EQ   csvTable.IDX
  enddo

  file close oldFile
  file close prmFile
  file close csvFile


  ! Specific test for an issue seen in the 28 Sept 2012 baseline where copying
  ! sv1.prm created a TIMELINE which was bad.
  res timeline NULL
  keyword sv1_prm{AUX=RAM,FG=PRM} GET TIMELINE timeline
  assert/text="FILE COPY/L using /PROPMASK=ALL did not create unnecessary TIMELINE=" timeline isNull

  erase/quiet sv1_prm{AUX=RAM,FG=PRM}
  erase/quiet sv1_csv{AUX=RAM,FG=CSV,HEADERROWS=1}
return

!******************************************************************************!
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

!******************************************************************************!
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

!******************************************************************************!
procedure createTextFile fn:infile
  ! Create the text file
  result numLines 2
  file OPEN/N tag infile
    do i 1 numLines
      file WRITE tag "line ^i"
    enddo
  file CLOSE tag
return

!******************************************************************************!
! Test for Bug 1473 (TextFile: Unable to read lines with length >8K)
procedure test_text_long_line
  res testFile "test_file_long_line{AUX=RAM,FG=TXT}"

  res lines {}
  res lines.1K  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&
                 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
  res lines.2K  "^{lines.1K}^{lines.1K}"
  res lines.4K  "^{lines.2K}^{lines.2K}"
  res lines.8K  "^{lines.4K}^{lines.4K}"
  res lines.16K "^{lines.8K}^{lines.8K}"
  res lines.32K "^{lines.16K}^{lines.16K}"

  file open/n out testFile
    foreach line inTable/v lines
      invoke ,, out.writeln(line)
    endfor
  file close out

  file open in testFile
    calc L:lineNum 0
    foreach key inTable lines
      invoke str in.read()
      assert/text="Reading ^key line from ^testFile" str eqs lines.^{key}
      calc L:lineNum lineNum 1 +
    endfor
  file close in
return

!******************************************************************************!
procedure test_text_write_read fn:testfile

  res testFile "temp_test_file_text.txt{FLAGS=FORCEABORT}"

  call createTextFile "^testFile"

  if testfile NFEXISTS then
    assert/text="^reg.main.name: TEXT open/write, bypassing other TEXT tests" FALSE
  else
    assert/text="^reg.main.name: TEXT open/write" TRUE

    ! Read the text file with NEXT verb
    file OPEN/T tag testfile
      result numRead 0
      result numLinesNotMatch 0
      file NEXT tag line
      while line NEQS "NULL"
        calc L:numRead numRead 1 +
        if numRead GT numLines then
          assert/text="^reg.main.name: TEXT next, more lines READ than WRITTEN!!" FALSE
          break
        else
          if "^line" NEQS "line ^numRead" then
            calc numLinesNotMatch numLinesNotMatch 1 +
          endif
        endif
        file NEXT tag line
      endwhile
    file CLOSE tag
    assert/text="^reg.main.name: TEXT next; lines not matching = ^numLinesNotMatch" &
              numLinesNotMatch EQ 0
    assert/text="^reg.main.name: TEXT next; num lines read = ^numRead" &
              numRead EQ numLines

   ! Read the text file with READ verb
    file OPEN/T tag testfile
      result numLinesNotMatch 0
      do i 1 numLines+1
        file READ tag line
        if i GT numLines then
          assert/text="^reg.main.name: TEXT read; expected NULL" line EQS "NULL"
        else
          if "^line" NEQS "line ^i" then
            calc numLinesNotMatch numLinesNotMatch 1 +
          endif
        endif
      enddo
    file CLOSE tag
    assert/text="^reg.main.name: TEXT read; lines not matching = ^numLinesNotMatch" &
              numLinesNotMatch EQ 0

  endif
  if testfile FEXISTS erase testfile

return

!******************************************************************************!
procedure test_rename

  set testFile  "temp_file_text.txt{AUX=^{aux.write}}"
  call createTextFile "^testFile"
  if testfile FEXISTS then
    !
    !  RENAME a .txt file to a file w/ a .tmp extension
    !
    fname label=destFile area=^{AUX.WRITE} name="temp_file_rename_tmp" ext="tmp" OPT="AUX"
    if destFile FEXISTS erase/all destFile
    file rename testfile destFile
    assert/text="^reg.main.name: RENAME .txt to .tmp file " destFile FEXISTS
    if destFile FEXISTS erase/all destfile
    if testFile FEXISTS erase/all testfile
    call createTextFile "^testFile" ! Must re-create the file after renaming
    if testfile FEXISTS then
      !
      !  RENAME a .txt file to a file w/o an extension
      !
      fname label=destFile area=^{AUX.WRITE} name="temp_file_rename_wo_ext" ext="" OPT="AUX"
      if destFile FEXISTS erase/all destFile
      file rename testfile destFile
      assert/text="^reg.main.name: RENAME .txt to file w/o extension" destFile FEXISTS
      if destFile FEXISTS erase/all destfile
      if testFile FEXISTS erase/all testfile
      call createTextFile "^testFile"
    else
      assert/text="^reg.main.name: Unable to create text file, RENAME to .tmp skipped" FALSE
    endif
  else
    assert/text="^reg.main.name: Unable to create text file, RENAME w/o EXT skipped" FALSE
  endif

  ! Test RENAME/F
  call createTextFile "^testFile"
  if testfile FEXISTS then
    !  RENAME a .txt file to a file w/ a .tmp extension
    fname label=destFile area=^{AUX.WRITE} name="temp_file_rename_tmp" ext="tmp" OPT="AUX"
    if destFile FEXISTS erase/all destFile
    file rename/f testfile destFile
    assert/text="^reg.main.name: RENAME/F .txt to .tmp file" destFile FEXISTS

    call createTextFile "^testFile"

    if testfile FEXISTS then
      ! if destFile FEXISTS erase/all destFile <----- NTN: I don't think this line should be here if we are testing rename/f
      file rename/f testfile destFile
      assert/text="^reg.main.name: RENAME/F .txt to .tmp file" destFile FEXISTS
      assert/text="^reg.main.name: RENAME/F .txt to .tmp file" testfile NFEXISTS
      if destFile FEXISTS erase/all destfile
      if testFile FEXISTS erase/all testfile
    else
      assert/text="^reg.main.name: Unable to create text file, RENAME/F to .tmp skipped" FALSE
    endif
  else
    assert/text="^reg.main.name: Unable to create text file, RENAME/F to .tmp skipped" FALSE
  endif

  call test_rename_bug_447
return

!******************************************************************************!
! Test file RENAME across filesystems on UNIX (Linux) systems - BUG 447
procedure test_rename_bug_447

  if env.ostype eqs "UNIX"
    set testFile2  "temp_rename_file.tmp{AUX=^{aux.write}}"
    call createTestFile3000 "^testFile2"
    if testfile2 FEXISTS then
      ! RENAME file from write AUX to another filesystem (/tmp is usually on different filesystem
      ! than aux.write
      set destFile "/tmp/temp_renamed_dest.tmp"
      if destFile FEXISTS erase/all destFile

      file rename testFile destFile
      assert/text="^reg.main.name: RENAME across filesystems" destFile FEXISTS AND testFile NFEXISTS

      ! cleanup
      if destFile FEXISTS erase/all destfile
      if testFile2 FEXISTS erase/all testFile2
    else
      assert/text="^reg.main.name: Unable to create test file, RENAME across filesystems skipped" FALSE
    endif
  endif
return

!******************************************************************************!
procedure test_name

if env.OSTYPE EQS "UNIX" then
  set expectedString "/home/user/temp/myfile.ext"
  file NAME fullname (home,user,temp) myfile ext
  assert/text="^reg.main.name: NAME '^fullname'" "^fullname" eqs "^expectedString"

  set expectedString2 "/home/user/temp/myfile.ext"
  file NAME fullname2 (/home,user,temp) myfile ext
  assert/text="^reg.main.name: NAME '^fullname2'" "^fullname2" eqs "^expectedString2"

  set expectedString3 "/home/user/temp/xyz/"
  file NAME fullname3 (/home/user,temp,xyz) "" ""
  assert/text="^reg.main.name: NAME '^fullname3'" "^fullname3" eqs "^expectedString3"

elseif env.OSTYPE EQS "DOS" then
  invoke sep java.io.File.separator
  set expectedString "C:^{sep}home^{sep}user^{sep}temp^{sep}myfile.ext"
  file NAME fullname "(C:^{sep},home,user,temp)" myfile ext
  assert/text="^reg.main.name: NAME '^fullname'" "^fullname" eqs "^expectedString"

  set expectedString2 "^{sep}home^{sep}user^{sep}temp^{sep}myfile.ext"
  file NAME fullname2 "(^{sep}home,user,temp)" myfile ext
  assert/text="^reg.main.name: NAME '^fullname2'" "^fullname2" eqs "^expectedString2"

  set expectedString3 "C:^{sep}home^{sep}user^{sep}temp^{sep}xyz^{sep}"
  file NAME fullname3 "(C:^{sep}home^{sep}user,temp,xyz)" "" ""
  assert/text="^reg.main.name: NAME '^fullname3'" "^fullname3" eqs "^expectedString3"

else
  info "^reg.main.name: no NAME test for OS = ^env.ostype"
endif

return

!******************************************************************************!
procedure removeDir S:targetDir
  ! a platform neutral way to delete files/directories
  invoke ,, nxm.sys.lib.FileUtil.recursiveDelete(targetDir)
return

!******************************************************************************!
! Test the file copy/... command(s)
procedure test_http_copy
  file copy ^{root}apenny.prm ram:mypenny
  assert/text="^reg.main.name: HTTP: COPY of apenny.prm" ram:mypenny fexists AND ram:mypenny feq apenny.prm

  ! test copy without .prm extension over HTTP (which should get implicitly added if root name without extension does not exist)
  file copy ^{root}^{datDirSlash}/apenny ram:newpenny
  assert/text="^reg.main.name: HTTP: COPY of apenny w/o extension (.prm implicitly added)" ram:newpenny fexists AND ram:newpenny feq ^{datDir}.apenny.prm

  file copy ^{root}^{datDirSlash}/cities.prm ram:mycities_prm
  assert/text="^reg.main.name: HTTP: COPY of cities.prm" ram:mycities_prm fexists AND ram:mycities_prm feq ^{datDir}.cities.prm

  file copy ^{root}^{datDirSlash}/cities.txt ram:mycities_txt
  file open/T tag ram:mycities_txt
  file next tag firstLine
  if OperatingSystem.OSNAME SEQS "Windows" AND firstLine contains "\r" then
    say "Warning: Testing (^reg.main.name: HTTP: FEQ of cities.txt) was skipped because cities.txt contains carriage returns in the line ending"
  else
    assert/text="^reg.main.name: HTTP: COPY of cities.txt" ram:mycities_txt fexists AND ram:mycities_txt{fg=txt} feq ^{datDir}.cities.txt
  endif
  file close tag
return

!******************************************************************************!
! Test the file FEQ comparisons
procedure test_http_equals
  assert/text="^reg.main.name: HTTP: FEQ of apenny.prm"   ^{root}^{datDirSlash}/apenny.prm feq ^{datDir}.apenny.prm
  assert/text="^reg.main.name: HTTP: FEQ of apenny(.prm)" ^{root}^{datDirSlash}/apenny     feq ^{datDir}.apenny.prm
  assert/text="^reg.main.name: HTTP: FEQ of cities(.prm)" ^{root}^{datDirSlash}/cities     feq ^{datDir}.cities.prm
  file open/T tag ^{datDir}.cities.txt
  file next tag firstLine
  if OperatingSystem.OSNAME SEQS "Windows" AND firstLine contains "\r" then
    say "Warning: Testing (^reg.main.name: HTTP: FEQ of cities.txt) was skipped because cities.txt contains carriage returns in the line ending"
  else
    assert/text="^reg.main.name: HTTP: FEQ of cities.txt"   ^{root}^{datDirSlash}/cities.txt{fg=txt} feq/t ^{datDir}.cities.txt
  endif
  file close tag
return

!******************************************************************************!
! Test accessing CSV files.
procedure test_csv_files
  ! ==== Test reading an existing CSV file ====
  file open filetag ^{datDir}.airports.csv{HEADERROWS=1}
  res t:tbl filetag.toTable(ROW_)

  assert/text="^reg.main.name: CSV Files: toTable() (Test 1)" "^{tbl.row_1.airport_name}" eqs "Abu Dhabi"
  assert/text="^reg.main.name: CSV Files: toTable() (Test 2)" "^{tbl.row_1.code}"         eqs "AUH"
  assert/text="^reg.main.name: CSV Files: toTable() (Test 3)"  ^{tbl.row_1.latitude}      eqt 24.43333
  assert/text="^reg.main.name: CSV Files: toTable() (Test 4)"  ^{tbl.row_1.longitude}     eqt 54.65000

  assert/text="^reg.main.name: CSV Files: toTable() (Test 5)" "^{tbl.row_484.airport_name}" eqs "Miami"
  assert/text="^reg.main.name: CSV Files: toTable() (Test 6)" "^{tbl.row_484.code}"         eqs "MIA"
  assert/text="^reg.main.name: CSV Files: toTable() (Test 7)"  ^{tbl.row_484.latitude}      eqt 25.80000
  assert/text="^reg.main.name: CSV Files: toTable() (Test 8)"  ^{tbl.row_484.longitude}     eqt -80.28333

  file close filetag

  ! ==== Test writing to a new CSV file ====
  file open/n filetag temp_test_file.csv{HEADERROWS=1,COLUMNNAMES="SF:ONE|SF:TEN|1A:TXT"}
  invoke ,, filetag.insertData(-1.0, {ONE="0",TEN="00",TXT="ZERO"})
  invoke ,, filetag.insertData(-1.0, {ONE="1",TEN="10",TXT="ONE"})
  invoke ,, filetag.insertData(-1.0, {ONE="2",TEN="20",TXT="TWO"})
  invoke ,, filetag.insertData(-1.0, {ONE="3",TEN="30",TXT="THREE"})
  invoke ,, filetag.insertData(-1.0, {ONE="4",TEN="40",TXT="FOUR"})
  invoke ,, filetag.insertData(-1.0, {})                                    ! Missing values should become ONE=0 TEN=0 and TXT=""
  invoke ,, filetag.insertData(-1.0, {ONE="6",TEN="60",TXT="SIX",FOO="42"}) ! Extra values should be ignored
  invoke ,, filetag.insertData(-1.0, {TEN="70",TXT="SEVEN",ONE="7"})        ! Order should not affect it
  file close filetag

  file open fileTag2 temp_test_file.csv{HEADERROWS=1}
  call checkRowValues "Writing to a CSV file" 0 {ONE=0,TEN=0,TXT="ZERO"}
  call checkRowValues "Writing to a CSV file" 1 {ONE=1,TEN=10,TXT="ONE"}
  call checkRowValues "Writing to a CSV file" 2 {ONE=2,TEN=20,TXT="TWO"}
  call checkRowValues "Writing to a CSV file" 3 {ONE=3,TEN=30,TXT="THREE"}
  call checkRowValues "Writing to a CSV file" 4 {ONE=4,TEN=40,TXT="FOUR"}
  call checkRowValues "Writing to a CSV file" 5 {ONE=0,TEN=0,TXT=""}       ! Missing values
  call checkRowValues "Writing to a CSV file" 6 {ONE=6,TEN=60,TXT="SIX"}   ! Extra values
  call checkRowValues "Writing to a CSV file" 7 {ONE=7,TEN=70,TXT="SEVEN"} ! Ordering
  file close fileTag2

  erase/warn=FALSE temp_test_file.csv

  ! ==== Test writing to a CSV file with additional header information ====
  set headerData0 "First line of header data."
  set headerData1 "Second line of header data."

  file open/n filetag ram:my_csv_file{FG=CSV,HEADERROWS=3,COLUMNNAMES="SF:ONE|SF:TEN|1A:TXT"}
  invoke ,, filetag.setHeaderData(0,headerData0)
  invoke ,, filetag.setHeaderData(1,headerData1)

  invoke ,, filetag.insertData(-1.0, {ONE="0",TEN="00",TXT="ZERO"})
  invoke ,, filetag.insertData(-1.0, {ONE="1",TEN="10",TXT="ONE"})
  invoke ,, filetag.insertData(-1.0, {ONE="2",TEN="20",TXT="TWO"})
  invoke ,, filetag.insertData(-1.0, {ONE="3",TEN="30",TXT="THREE"})
  invoke ,, filetag.insertData(-1.0, {ONE="4",TEN="40",TXT="FOUR"})
  invoke ,, filetag.insertData(-1.0, {})                                    ! Missing values should become ONE=0 TEN=0 and TXT=""
  invoke ,, filetag.insertData(-1.0, {ONE="6",TEN="60",TXT="SIX",FOO="42"}) ! Extra values should be ignored
  invoke ,, filetag.insertData(-1.0, {TEN="70",TXT="SEVEN",ONE="7"})        ! Order should not affect it
  file close filetag

  file open fileTag2 ram:my_csv_file{FG=CSV,HEADERROWS=3}
  invoke hd0 filetag2.getHeaderData(0)
  invoke hd1 filetag2.getHeaderData(1)

  assert/text="^reg.main.name: Writing to a CSV file (header row 0)" headerData0 eqs hd0
  assert/text="^reg.main.name: Writing to a CSV file (header row 1)" headerData1 eqs hd1
  call checkRowValues "Writing to a CSV file" 0 {ONE=0,TEN=0,TXT="ZERO"}
  call checkRowValues "Writing to a CSV file" 1 {ONE=1,TEN=10,TXT="ONE"}
  call checkRowValues "Writing to a CSV file" 2 {ONE=2,TEN=20,TXT="TWO"}
  call checkRowValues "Writing to a CSV file" 3 {ONE=3,TEN=30,TXT="THREE"}
  call checkRowValues "Writing to a CSV file" 4 {ONE=4,TEN=40,TXT="FOUR"}
  call checkRowValues "Writing to a CSV file" 5 {ONE=0,TEN=0,TXT=""}       ! Missing values
  call checkRowValues "Writing to a CSV file" 6 {ONE=6,TEN=60,TXT="SIX"}   ! Extra values
  call checkRowValues "Writing to a CSV file" 7 {ONE=7,TEN=70,TXT="SEVEN"} ! Ordering
  file close fileTag2
return

!******************************************************************************!
procedure checkRowValues s:msg L:rowNum t:tbl
  invoke row fileTag2.getDataTable(rowNum)
  TABLE tbl EQUALS row match

  assert/text="^reg.main.name: ^msg (row ^rowNum)" ^match isTrue
  if ^match isFalse then
    warn "  Expected: ^tbl"
    warn "  Got:      ^row"
  endif
return

!******************************************************************************!
! Test the file FEQ comparisons
procedure test_protect_unprotect
  file copy ^{datDir}.fftdemo.prm ram:ramfft

  file open filetag ram:ramfft
  assert/text="^reg.main.name: PROTECT/UNPROTECT: Initially protected" fileTag.getProtected() isTrue
  file close filetag

  file unprotect ram:ramfft
  file open filetag ram:ramfft
  assert/text="^reg.main.name: PROTECT/UNPROTECT: Changed to unprotected" fileTag.getProtected() isFalse
  file close filetag

  file protect ram:ramfft
  file open filetag ram:ramfft
  assert/text="^reg.main.name: PROTECT/UNPROTECT: Changed to protected" fileTag.getProtected() isTrue
  file close filetag
return

!******************************************************************************!
procedure test_dataframesize
!
!  tests the setting of data frame size, which is like FORCE1000
!
noop ^{datDir}.alaskat.prm temp_file_dataframesize{AUX=RAM}

! Read in the entire frame
res frame FILE(^{datDir}.alaskat.prm).data(15)

file open tag temp_file_dataframesize(15:+1)
  set tag.dfs 0 ! treat as 1000
  res trimVal15 tag.data(15)
file close tag

assert/text="^reg.main.name: set DataFrameSize ^frame.15 , ^trimVal15" frame.15 EQ trimVal15

return

!******************************************************************************!
!  tests appending to a file.
procedure test_append
  noop ^{datDir}.testxy3000.prm ram:xy3000
  calc newSize FILE(ram:xy3000).getSize() 1 +

  file open/a tag ram:xy3000
  file write tag {ABSC=9,ORD=1,ORD2=2,ORD3=3}
! This is not supported at this time...
!  assert/text="^reg.main.name: FILE append, new size=7" newSize eq tag.getSize()
  file close tag

  file open tag ram:xy3000
  invoke row tag.getDataTable(6)
  assert/text="^reg.main.name: FILE append, new size=7" newSize eq tag.getSize()
  assert/text="^reg.main.name: FILE append, row.absc=9" 9       eq row.absc
  assert/text="^reg.main.name: FILE append, row.ord=1"  1       eq row.ord
  assert/text="^reg.main.name: FILE append, row.ord2=2" 2       eq row.ord2
  assert/text="^reg.main.name: FILE append, row.ord3=3" 3       eq row.ord3
  file close tag

  ! since 3.1.3: start of test appending to a TEXT file for BUG 2624
  set testTextFile "ram:temp_file_text.txt"
  set expLine1 "One__001"
  set expLine2 "Two__002"
  set expLine3 "Three__003"
  ! create text file with two lines
  file open/t/n tag testTextFile
  file write tag expLine1
  file write tag expLine2
  file close tag
  ! append a line to it
  file open/t/a tag testTextFile
  file write tag expLine3
  file close tag
  ! now read it back and verify contents
  file open/t tag testTextFile
  do ii 1 3
    file read tag line
    assert/text="^reg.main.name: FILE append to text file, line ^ii" ^{expLine^{ii}} eqs line /cs
  enddo
  file close tag
  !since 3.1.3: end of test appending to a TEXT file for BUG 2624
return

!******************************************************************************!
!  Test adding to a Type 3000 file - this test exposes the problem fixed in Bug 1014
!  where DataFile was incorrectly computing byte offsets due to rounding errors.
procedure test_type3000

  set outfile1 ram:test_type3000_out1 ! TEST CASE #1 (FAILS IN NXM 2.5.0)
  set outfile2 ram:test_type3000_out2 ! TEST CASE #2 (FAILS IN NXM 2.5.0, 2.4.0, etc.)

  header/create outfile1 sr=(key/2a,elem/sl,fram/sl,r1/sf,r2/sf,x1/sf,x2/sf,y1/sf,y2/sf,file/ta)
  header/create outfile2 sr=(key/2a,elem/sl,fram/sl,r1/sf,r2/sf,x1/sf,x2/sf,y1/sf,y2/sf,file/ta)

  file open/d/w fout1 outfile1
  file open/d/w fout2 outfile2
  do i 0 50
    file write fout1 {KEY=NXM,ELEM=1,FRAM=1,R1=1,R2=2,X1=3,X2=4,Y1=5,Y2=6,FILE="fakefile^i"}

    invoke ,, fout2.setData(^i,"KEY","NXM")
    invoke ,, fout2.setData(^i,"ELEM",1)
    invoke ,, fout2.setData(^i,"FRAM",1)
    invoke ,, fout2.setData(^i,"R1",1)
    invoke ,, fout2.setData(^i,"R2",2)
    invoke ,, fout2.setData(^i,"X1",3)
    invoke ,, fout2.setData(^i,"X2",4)
    invoke ,, fout2.setData(^i,"Y1",5)
    invoke ,, fout2.setData(^i,"Y2",6)
    invoke ,, fout2.setData(^i,"FILE","fakefile^i")
  enddo
  file close fout1
  file close fout2

  ! display data at last good record
  !datalist outfile1 31 3
  !datalist outfile2 31 3

  set actual1   FILE(outfile1).getDataTable(33)
  set actual2   FILE(outfile2).getDataTable(33)
  set expected  {KEY=NXM,ELEM=1,FRAM=1,R1=1,R2=2,X1=3,X2=4,Y1=5,Y2=6,FILE="fakefile33"}
  foreach key inTable expected
    if key eqs "KEY" or key eqs "FILE" then
      assert/text="^reg.main.name: Writing to Type 3000 file #1 key=^key" actual1.^key eqs expected.^key
      assert/text="^reg.main.name: Writing to Type 3000 file #2 key=^key" actual2.^key eqs expected.^key
    else
      assert/text="^reg.main.name: Writing to Type 3000 file #1 key=^key" actual1.^key eq  expected.^key
      assert/text="^reg.main.name: Writing to Type 3000 file #2 key=^key" actual2.^key eq  expected.^key
    endif
  endfor

  info "^reg.main.name: white space in field name test will issue a warning"
  set outfile3 ram:test_type3000_whitespace
  file open/d/n tag outfile3{sr=(LAT/SD,LON/SD)}
    res tag.setdata(0,"LAT ") 77.7
    res tag.setdata(0,"LON") 99.9
  file close tag
  res actual FILE(outfile3).getDataTable(0)
  assert/text="^reg.main.name: white space in field name" actual.LAT neq 77.7 AND actual.LON eq 99.9

return

!******************************************************************************!
!  Test adding to a Type 5000 file - this test exposes the problem noted in Bug 1154 where an 8B
!  field is not written properly.
!
!  This tests creates a file identical to coneflags5000.prm in RAM and then checks to see that
!  it matches coneflags5000.prm.
!
!     nM> status/d coneflags5000.prm
!     DataFile (BLUE)    :  file:/home/jxc/projects/nextmidas/^{datDirSlash}/coneflags5000.prm
!     Data Rep (H/D)     :  EEEI / EEEI
!     Number of Elements :  3.0
!     File Type          :  5000
!     Data Format        :  NH - Non Homogeneous
!     Write Protect      :  false
!     Abscissa units     :  None (U)
!     Abscissa start     :  0.0
!     Abscissa delta     :  1.0
!     Number Components  :  5
!     Bytes per Record   :  88
!     Frame of Reference :  ECR
!     Component Name=POS   Format=VD  Type=GEODETIC  Units=DISTANCE_M
!     Component Name=POSP   Format=VD  Type=GEODETIC  Units=DISTANCE_M
!     Component Name=CONE   Format=VD  Type=UNDEFINED  Units=DISTANCE_M
!     Component Name=NAME   Format=1A  Type=UNDEFINED  Units=NONE
!     Component Name=FLAG   Format=8B  Type=UNDEFINED  Units=NONE
!       0: POS=(0.19970000000000002,34.3982,67.0013)  POSP=(3.481502E7,-3.9757000000000002,16.7008)
!          CONE=(-1.0,0.6332,0.6332)  NAME=LABEL1 FLAG=(6,0,2,2,-9,1,4,4)
!       1: POS=(0.006568699999999999,18.7478,33.612500000000004)  POSP=(3.481502E7,-3.9757000000000002,16.7008)
!          CONE=(-1.0,0.6332,0.6332)  NAME=LABEL2  FLAG=(6,0,4,2,-9,1,4,4)
!       2: POS=(1.0E7,-3.9085,16.7182)  POSP=(3.485394E7,-3.9085,16.7182)
!          CONE=(-1.0,0.6332,0.6332)  NAME=LABEL3XX  FLAG=(6,0,3,2,0,1,2,4)
!
procedure test_type5000 s:rep
  set t:data {}
  set t:data.row0 {}
  set d:data.row0.POS  (0.19970000000000002,34.3982,67.0013)
  set d:data.row0.POSP (3.481502E7,-3.9757000000000002,16.7008)
  set d:data.row0.CONE (-1.0,0.6332,0.6332)
  set s:data.row0.NAME LABEL1
  set b:data.row0.FLAG (6,0,2,2,-9,1,4,4)
  set t:data.row1 {}
  set d:data.row1.POS  (0.006568699999999999,18.7478,33.612500000000004)
  set d:data.row1.POSP (3.481502E7,-3.9757000000000002,16.7008)
  set d:data.row1.CONE (-1.0,0.6332,0.6332)
  set s:data.row1.NAME LABEL2
  set b:data.row1.FLAG (6,0,4,2,-9,1,4,4)
  set t:data.row2 {}
  set d:data.row2.POS  (1.0E7,-3.9085,16.7182)
  set d:data.row2.POSP (3.485394E7,-3.9085,16.7182)
  set d:data.row2.CONE (-1.0,0.6332,0.6332)
  set s:data.row2.NAME LABEL3XX
  set b:data.row2.FLAG (6,0,3,2,0,1,2,4)

  header/create ram:coneflags TYPE=5000 RF=ECR DATAREP=^rep COMPONENTS=(POS/VD/GEODETIC/DISTANCE_M,&
                                                            POSP/VD/GEODETIC/DISTANCE_M,&
                                                            CONE/VD/UNDEFINED/DISTANCE_M,&
                                                            NAME/1A/UNDEFINED/NONE,&
                                                            FLAG/8B/UNDEFINED/NONE)

  file open/d/a conetag ram:coneflags
    set hrep conetag.headRep
    set drep conetag.dataRep
    set conetag.setData(0) data.row0
    set conetag.setData(1) data.row1
    set conetag.setData(2) data.row2
  file close conetag

  assert/text="^reg.main.name: Checking ram:coneflags (FEQ/H, ^hrep)" ram:coneflags FEQ/H ^{datDir}.coneflags5000.prm
  assert/text="^reg.main.name: Checking ram:coneflags (FEQ/D, ^drep)" ram:coneflags FEQ/D ^{datDir}.coneflags5000.prm
return

!******************************************************************************!
! Verify that the tag is removed from the results table after the file is closed
! see Bug 1077 for details
procedure test_close
  file open tag ^{datDir}.testxy3000.prm
    assert/text="^reg.main.name: File opened, tag exists"   tag rexists
    assert/text="^reg.main.name: File opened, file is open" tag.isOpen isTrue
  file close tag
  assert/text="^reg.main.name: File closed, tag removed" tag nrexists

return

!******************************************************************************!
! Test case for DETACH and DETACH/D functions for BUG 2182
procedure test_detach FN:testfile[test_file_detach.tmp]
  res expdetfile "^{testfile.root}.det"
  res expSize      1234
  res expStart     5.0
  res expDelta     1.1
  res expDataStart 512
  res expKwValue   "value of keyword in extended header"
  res expTcPrec    0.00000011
  res expTestFile "test_file_detach_orig.tmp"
  waveform testfile form=SB elem=expsize amp=127 start=expStart delta=expDelta
  keyword  testfile set mykeyword expKwValue
  keyword  testfile set "TC_PREC" expTcPrec /scope=main
  noop testfile expTestFile
  status testfile{fg=raw} size=origFileSize

  if expdetfile fexists then
    warn "^expdetfile file exists, removing it before running test case..."
    erase/all expdetfile
  endif

  ! ----- test #1 detach function -----
  file detach testfile
  status  testfile detached=detached size=size datastart=dataStart start=start delta=delta
  status  expdetfile{fg=raw} size=fileSize
  assert/text="^reg.main.name: DETACH - size(^size)"              expSize      eq size
  assert/text="^reg.main.name: DETACH - start(^start)"            expStart     eq start
  assert/text="^reg.main.name: DETACH - delta(^delta)"            expDelta     eq delta
  assert/text="^reg.main.name: DETACH - detached(^detached)"      detached     eq 1
  assert/text="^reg.main.name: DETACH - dataStart(^dataStart)"    expDataStart eq dataStart
  assert/text="^reg.main.name: DETACH - .det filesize(^filesize)" origFileSize eq fileSize
  keyword testfile get name=TC_PREC   value=tcprec
  keyword testfile get name=mykeyword value=kwvalue
  assert/text="^reg.main.name: DETACH - main keyword"     expTcPrec  eq  tcprec
  assert/text="^reg.main.name: DETACH - extended keyword" expKwValue eqs kwvalue
  assert/text="^reg.main.name: DETACH - extended keyword" expKwValue eqs kwvalue
  assert/text="^reg.main.name: DETACH - file header/data contents"    expTestFile feq/h/d testfile

  if /debug1 then
    status testfile
  endif

  ! ----- test #2a detach/d -----
  res expSize 2345
  res expKwValue   "another value of keyword in ext header"
  res expTcPrec    0.00000022
  waveform testfile form=SB elem=expsize amp=127 start=expStart delta=expDelta
  keyword  testfile set mykeyword expKwValue
  keyword  testfile set "TC_PREC" expTcPrec /scope=main
  noop testfile expTestFile

  ! this should fail since we have existing .det from first test case above
  set z:gotExceptionForDetach false
  set z:exceptionExpected     true
  file detach/d testfile
  assert/text="^reg.main.name: DETACH/D - overwrite .det without /F should error" gotExceptionForDetach isTrue

  ! ----- test #2b detach/d/f -----
  file detach/d/f testfile
  status  testfile detached=detached size=size datastart=datastart start=start delta=delta
  status  expdetfile{fg=raw} size=filesize
  assert/text="^reg.main.name: DETACH/D - size(^size)"              expSize  eq size
  assert/text="^reg.main.name: DETACH/D - start(^start)"            expStart eq start
  assert/text="^reg.main.name: DETACH/D - delta(^delta)"            expDelta eq delta
  assert/text="^reg.main.name: DETACH/D - detached(^detached)"      detached eq 1
  assert/text="^reg.main.name: DETACH/D - dataStart(^dataStart)"    0        eq datastart
  assert/text="^reg.main.name: DETACH/D - .det filesize(^filesize)" expSize  eq filesize
  keyword testfile get name=TC_PREC   value=tcprec   /scope=main
  keyword testfile get name=mykeyword value=kwvalue  /scope=ext
  assert/text="^reg.main.name: DETACH/D - main keyword"              expTcPrec   eq  tcprec
  assert/text="^reg.main.name: DETACH/D - extended keyword"          expKwValue  eqs kwvalue
  assert/text="^reg.main.name: DETACH/D - file header/data contents" expTestFile feq/h/d testfile

  if /debug2 then
    status testfile
  endif

  ! test warning message when have existing
  info "The following should print a warning that header file is already detached."
  file detach testfile

  erase/warn=no testfile
  assert/text="^reg.main.name: erase BLUE (header) with detached header " testfile   nfexists
  assert/text="^reg.main.name: erase BLUE (data)   with detached header"  expdetfile nfexists

  ! ----- test #3 detach dataExt -----
  noop expTestFile testfile
  status testfile{fg=raw} size=expFileSize
  res expdetfile "^{testfile.root}.bin"

  file detach/f testfile bin
  status  testfile detached=detached detachExt=dataExt size=size datastart=datastart start=start delta=delta
  status  expdetfile{fg=raw} size=filesize
  assert/text="^reg.main.name: DETACH data to .bin - size(^size)"              expSize  eq size
  assert/text="^reg.main.name: DETACH data to .bin - start(^start)"            expStart eq start
  assert/text="^reg.main.name: DETACH data to .bin - delta(^delta)"            expDelta eq delta
  assert/text="^reg.main.name: DETACH data to .bin - detached(^detached)"      0        lt detached
  assert/text="^reg.main.name: DETACH data to .bin - detachExt(^dataExt)"      "bin"    eqs dataExt
  assert/text="^reg.main.name: DETACH data to .bin - dataStart(^dataStart)"    expDataStart eq datastart
  assert/text="^reg.main.name: DETACH data to .bin - filesize(^filesize)"      expFileSize  eq filesize
  keyword testfile get name=TC_PREC   value=tcprec   /scope=main
  keyword testfile get name=mykeyword value=kwvalue  /scope=ext
  assert/text="^reg.main.name: DETACH data to .bin - main keyword"              expTcPrec   eq  tcprec
  assert/text="^reg.main.name: DETACH data to .bin - extended keyword"          expKwValue  eqs kwvalue
  assert/text="^reg.main.name: DETACH data to .bin - file header/data contents" expTestFile feq/h/d testfile

  erase/warn=no testfile
  assert/text="^reg.main.name: erase BLUE (header in .tmp) with detached header " testfile   nfexists
  assert/text="^reg.main.name: erase BLUE (data   in .bin) with detached header"  expdetfile nfexists

  erase/warn=no expTestFile
return

!******************************************************************************!
! Tests reading from a TAR file
procedure test_read_from_tar
  if ^{env.NMROOT} EQS "classpath:" then
    warn "SKIPPING ^reg.main.name known issue of accessing a tar file within the jar. TODO - can we make a fix to access a tar file inside the jar?"
    return
  endif
  assert/text="^reg.main.name: Test reading from a TAR file." "tar:nxm.sys.test.test_tar.tar!testxy3000.prm" FEQ ^{datDir}.testxy3000.prm

  ! Test basename of TAR file is correct
  new nxm.sys.lib.FileName("tar:file:nxm.sys.test.test_tar.tar!testxy3000.prm") fn
  assert/text="^reg.main.name: Test finding basename from a TAR file." fn.basename eqs "testxy3000.prm"

return

!******************************************************************************!
! Test for Bug 1824 to verify URL of "ramd:/" file for ICE Ram Disk Resource
! Test shows the problem without the RamDiskResource in the ICE option tree,
! since problem was in FileResource.getURL().
procedure test_url_of_ramd_file
  set fileurl "ramd:/midas/icedisk/test_url_of_ramd_file.tmp"
  file open tag fileurl{FLAGS=NOABORT}
  assert/text="^reg.main.name: URL of file in 'ramd:'" tag.url eqs fileurl
  file close tag
return

!******************************************************************************!
! Test for Bug 1828 IOResource.getInstance(..) does not obey {usenative=false}
! file qualifier
procedure test_use_native_qualifier
  file open tag ^{datDir}.apenny.prm{usenative=false}
  assert/text="^reg.main.name: {USENATIVE=False} file qualifier" tag.io ninstanceof nxm.sys.lib.NFileResource
  file close tag
  if ^{env.NMROOT} EQS "classpath:" then
    info "SKIPPING ^reg.main.name this test will try to use native code which will be filtered out of the JAR."
    return
  endif
  ! NTN: THIS SHOULD WORK, BUT DOES NOT ==> invoke canUseNativeIO=nxm.sys.lib.Native.getUse().contains("|IO|")
  invoke use=nxm.sys.lib.Native.getUse() canUseNativeIO=use.contains("|IO|")
  if canUseNativeIO then
    ! NTN: this block of test cases will probably NOT work correctly under Web Start
    !      since NMROOT will be in JarResource and hence the fielURL will be jar:http://...
    !      instead of file:/...
    file open tag ^{datDir}.apenny.prm{usenative=true}
    assert/text="^reg.main.name: {USENATIVE=True} file qualifier" tag.io instanceof nxm.sys.lib.NFileResource
    res fileURL tag.url
    file close tag

    ! Checks for proper NFileResource behavior with error condition - since NXM-3814 NextMidas 4.1.1
    if ENV.OSNAME EQSS "Windows" then
      info "^reg.main.name: Cannot run file open status test since unable to chmod in Windows."
    else
      file copy/f ^{datDir}.apenny.prm apennynoread.prm
      res auxWrite aux.Write
      invoke auxWritePath nxm.sys.lib.Shell.getAuxPath(^{auxWrite})
      chmod 000 ^{auxWritePath}apennynoread.prm      ! trigger error condition by making file not have read permission
      set z:gotExceptionForCantOpenFile false
      set z:exceptionExpected true
      file open tag apennynoread.prm{usenative=true}
      erase apennynoread.prm
      assert/text="^reg.main.name: {USENATIVE=True} file open status correct for error conditions" &
                   gotExceptionForCantOpenFile isTrue AND tag.io ninstanceof nxm.sys.lib.NFileResource
    endif

    ! unit test case for Bug 2197 (to make sure NFileResource is used)
    file open tag ^{fileURL}{usenative=true}
    assert/text="^reg.main.name: file:/.../apenny.prm{USENATIVE=T} is Native File Resource" tag.io instanceof nxm.sys.lib.NFileResource
    file close tag
  else
    info "^reg.main.name: Native IO must be enabled to test {USENATIVE=True} file qualifier"
  endif
return

!******************************************************************************!
! Test for Bug 1827 FILE COPY fails on native file resource, e.g. when
! {usenative=true} file qualifier is specified.
procedure test_copy_native
  ! NTN: THIS SHOULD WORK, BUT DOES NOT ==> invoke canUseNativeIO=nxm.sys.lib.Native.getUse().contains("|IO|")
  invoke use=nxm.sys.lib.Native.getUse() canUseNativeIO=use.contains("|IO|")
  if canUseNativeIO then
    if debug then INFO "Starting FILE COPY on native file resource. This should NOT hang!"
    file copy ^{datDir}.apenny.prm{usenative=true} ram:test_copy_native
    assert/text="^reg.main.name: FILE COPY on native file resource" ram:test_copy_native FEQ/H/D/S ^{datDir}.apenny.prm
  else
    info "^reg.main.name: Native IO must be enabled to test FILE COPY on native file resource"
  endif
return



!******************************************************************************!
! Unit Test for Bug 2076 cannot create file when a directory of same name exist
procedure test_bug2076
  if ^{env.NMROOT} EQS "classpath:" then
    call test_classpath_file_or_dir_exists
    return
  endif
  res dir "^{env.nmroot}"
  new nxm.sys.lib.CoreIO() coreio
  invoke retval1 coreio.fexists(dir,TRUE)
  invoke retval2 coreio.fexists(dir,FALSE)
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,true)  should be TRUE for ^{dir}"  retval1 isTrue
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,false) should be FALSE for ^{dir}" retval2 isFalse
return

!******************************************************************************!
! Test case for directory and file having same name while nmroot = classpath:
! note: classpath: is not enough for a valid directory/file, for example classpath:/ is not valid. classpath:/nxm/ is valid if the directory nxm exists.
procedure test_classpath_file_or_dir_exists
  res dir "^{env.nmroot}/^{datDirSlash}/apenny.prm"
  new nxm.sys.lib.CoreIO() coreio
  invoke retval1 coreio.fexists(dir,TRUE)
  invoke retval2 coreio.fexists(dir,FALSE)
  ! NXM-3755 since NeXtMidas 4.0.1
  if isGradleBuildCommand isFalse then
    assert/text="^reg.main.name: CoreIO.fexists(existing_dir,true)  should be FALSE for ^{dir}" retval1 isFalse
    assert/text="^reg.main.name: CoreIO.fexists(existing_dir,false) should be TRUE for ^{dir}"  retval2 isTrue
  else
    info "SKIPPING ^reg.main.name: CoreIO.fexists(existing_dir,true)  should be FALSE for ^{dir} since fails inside Gradle build command"
    info "SKIPPING ^reg.main.name: CoreIO.fexists(existing_dir,false) should be TRUE for ^{dir} since fails inside Gradle build command"
  endif
  
  res dir "^{env.nmroot}/^{datDirSlash}/apenny.prm/"
  invoke retval1 coreio.fexists(dir,TRUE)
  invoke retval2 coreio.fexists(dir,FALSE)
  ! NXM-3755 since NeXtMidas 4.0.1
  if isGradleBuildCommand isFalse then
    assert/text="^reg.main.name: CoreIO.fexists(existing_dir,true)  should be FALSE for ^{dir}"  retval1 isFalse
  else
    info "SKIPPING ^reg.main.name: CoreIO.fexists(existing_dir,true)  should be FALSE for ^{dir} since fails inside Gradle build command"
  endif
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,false) should be FALSE for ^{dir}" retval2 isFalse

  res dir "^{env.nmroot}/^{datDirSlash}"
  invoke retval1 coreio.fexists(dir,TRUE)
  invoke retval2 coreio.fexists(dir,FALSE)
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,true)  should be TRUE for ^{dir}"  retval1 isTrue
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,false) should be FALSE for ^{dir}" retval2 isFalse

  res dir "^{env.nmroot}/^{datDirSlash}/"
  invoke retval1 coreio.fexists(dir,TRUE)
  invoke retval2 coreio.fexists(dir,FALSE)
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,true)  should be TRUE for ^{dir}"  retval1 isTrue
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,false) should be FALSE for ^{dir}" retval2 isFalse

  res dir "^{env.nmroot}/"
  invoke retval1 coreio.fexists(dir,TRUE)
  invoke retval2 coreio.fexists(dir,FALSE)
  ! NXM-3755 since NeXtMidas 4.0.1
  if isGradleBuildCommand isFalse then
    assert/text="^reg.main.name: CoreIO.fexists(existing_dir,true)  should be FALSE for ^{dir}"  retval1 isFalse
  else
    info "SKIPPING ^reg.main.name: CoreIO.fexists(existing_dir,true)  should be FALSE for ^{dir} since fails inside Gradle build command"
  endif
  assert/text="^reg.main.name: CoreIO.fexists(existing_dir,false) should be FALSE for ^{dir}" retval2 isFalse

return

!******************************************************************************!
! Test case for Bug 2129 (a RAM file is a file)
procedure test_ramfile_isfile
  file open/n/d tag ram:testramfile
  assert/text="^reg.main.name: RAM file is a File (BUG 2129)" tag.isFile isTRUE
return

!******************************************************************************!
! Test case for Bug 2197 IOResource: ICE RAMD detached DataFile not able to use
!   Native File I/O causing degraded performance
procedure test_IOResource_getType
  set    filetype 1  ! hard coding since nxm.sys.lib.IOResource.isFile() exists causing invoke to fail :(
  invoke type nxm.sys.lib.IOResource.getType("file:/test_ioresource_gettype.tmp")
  assert/text="^reg.main.name: IOResource.getType('file:/..') returned ^type, should be 1 (FILE)" type eq filetype
return

!******************************************************************************!
! Test case for DeleteOnExit local file qualifier for Bug 2538.
procedure test_deleteOnExit
  set testfile "test_file_deleteOnExit_qualifier.tmp"
  file open/n tag ^testfile{DeleteOnExit=true}
  file close tag
  assert/text="^reg.main.name: created test file for FileResource DeleteOnExit qualifer" testfile fexist
  info "^reg.main.name: Once JVM exits normally, verify that ^testfile is deleted."
return

!******************************************************************************!
! Test case for DataFile: readDataTable(..) and getDataTable(..) do not return
! null at EOF for Type 1000/2000 files (Bug 2667).
procedure test_read
  res t:fileData {0={ABSC=1.0,ORD=1.0,ORD2=12.0,ORD3=14.0},&
                  1={ABSC=3.0,ORD=2.0,ORD2=7.0,ORD3=12.0},&
                  2={ABSC=4.0,ORD=4.0,ORD2=9.0,ORD3=8.0},&
                  3={ABSC=3.0,ORD=15.0,ORD2=4.0,ORD3=3.0},&
                  4={ABSC=1.0,ORD=16.0,ORD2=7.0,ORD3=9.0},&
                  5={ABSC=2.0,ORD=6.0,ORD2=3.0,ORD3=10.0}}
  table fileData GETSIZE fileSize
  file open/D in ^{datDir}.testxy3000.prm{FORMAT=SF}
    do i 0 fileSize-1
      res T:expTable fileData.^{i}
      res F:expData (^{expTable.ABSC},^{expTable.ORD},^{expTable.ORD2},^{expTable.ORD3})

      file read in inData
      res F:actData ^inData       ! <-- trick to convert SFx4 to QFx1
      assert/text="FILE READ ^i" expData EQ/V actData
    enddo

    ! Bug 2667 read after EOF should return null
    file read in actData
    assert/text="FILE READ after EOF is null" actData isNull
  file close in

return

!******************************************************************************!
! Test case for BUG 2863 JarResource.exists() memory leak
! @since 3.5.4
procedure test_JarResource_leak
  fname destdir ^{aux.write} OPT=AUX
  if destdir eqs "ram:" then
    warning "Skipping test_jarResource_leak, cannot run this test case with WRITE AUX set to RAM."
    return
  endif

  ! copy small jar file from JARS area in SYS to write AUX for testing
  fname label=origJarFN area=jars name="wbp-support.jar" opt=sys
  if origJarFN nfexists then
    warning "Skipping test_jarResource_leak, unable to locate input jar: ^origJarFN"
    return
  endif
  fname label=testJarFN AREA="^{aux.write}" NAME="testjar_^{env.pid}" EXT="jar" OPT="AUX"
  file copy/f origJarFN testJarFN

  set fnInJar1 "jar:file://^{testJarFN}!/wbp-meta/org.eclipse.wb.swing.wbp-palette.xml"
  assert/text="^reg.main.name: existing file in jar exists" fnInJar1 fexists

  ! NOTE: enabling the next two lines causes another resource leak (TODO: another resource leak to hunt down)
  ! set fnInJar2 "jar:file://^{testJarFN}!/wbp-meta/nonExistentFile.txt"
  ! assert/text="^reg.main.name: non-existent file in jar does not exists" fnInJar2 nfexists

  erase testJarFN
  assert/text="^reg.main.name: able to remove test jar file (resource leak check)" testJarFN nfexists
  
return

!******************************************************************************!
! Test cases for jnlp files
! Supported versions, as defined in JnlpFile.java should not return Warnings
! Unsupported versions and malformed versions should return Warnings.
procedure test_jnlp_file_specification_version s:spec s:expText

  ! Create a test file containing the specification version argument
    file OPEN/T tag nxm.sys.test.jnlp_file_test.jnlp
    file READ tag line
    res origtext ""
    while line NEQS "NULL"
      res origtext "^origtext\n^line"
      file READ tag line
    endwhile
    file CLOSE tag
    sedit origtext newtext SUB "MAJOR.MINOR.UPDATE" ^spec
    file OPEN/T/N tag unsupported_version.jnlp{DeleteOnExit=true}
    file WRITE tag "^newtext"
    file CLOSE tag

  ! Perform test
    res testName "test_jnlp_supported_version ^spec"
    res expText ^expText
    res foundWarn false

    archive to MAIN
    file OPEN tag unsupported_version.jnlp
    archive/echo=on off

    if expText EQS ""
      assert/text="^reg.main.name: ^testName" foundWarn ISFALSE
    else
     assert/text="^reg.main.name: ^testName" foundWarn
    endif

return

!******************************************************************************!
procedure processMessage m:msg

  if msg.name eqs "TEXT" then
    ! For test_jnlp_file_specification_version
    if testName eqss "test_jnlp"
      if msg.data eqss expText then
        res foundWarn true
      endif
      archive/echo=off off
    endif
  endif

return