!******************************************************************************!
!  Macro to test "Files" intrinsic
!  Author:  J. Hallam
!******************************************************************************!
startmacro
  switch INTERACTIVE interAct GET DEF=TRUE  SDEF=TRUE
  switch BASELINE    baseline GET DEF=FALSE SDEF=TRUE
  switch KEEP    keep  GET DEF=FALSE SDEF=TRUE

  call setDatDir
  ! Allow some of the tests to run in a thinned NeXtMidas by skipping only ones needing missing dependencies - 4.0.0
  invoke panelExists reg.shell.M.dictionary.isDictionaryEntry(PANEL)
  invoke httpservExists reg.shell.M.dictionary.isDictionaryEntry(HTTPSERV)

  call createAndDeleteTempFiles
  call test_exclude       ! Bug 2482 (since 3.1.0)
  call test_outputToText  ! Bug 2004 (since 3.1.1)
  call test_fswitch
  if httpservExists then call test_list_files_from_web ! BUG 2262 (since 2.9.0)

  noop ^{datDir}.apenny.prm   ram:rampenny
  noop ^{datDir}.sinewave.prm ram:ramsine
  noop ^{datDir}.fftdemo.prm  ram:myfft

  call test_list_nameonly ! BUG 1889: must be called after copying to ram files above (since 2.7.2)
  
  ! create temp dir under write AUX instead of using /tmp since that dir normally does not exist on Windows platform
  FNAME writeAuxDir AREA=^aux.write OPT=AUX
  FILE NAME tempWriteDir (^{writeAuxDir},test_files_^{env.pid})
  if tempWriteDir ndexists then
    new java.io.File(tempWriteDir) dirFile
    invoke retval dirFile.mkdirs()
    assert/text="^reg.main.name: Created temp dir ^tempWriteDir" retval isTrue
    remove dirFile
  endif

  if interAct AND panelExists then
!    call test_list_wildcards

    waveform "TEST_FILES_mixedcase"
    waveform "TEST_FILES_ALLUPPER"
    waveform "test_files_loweronly"
    FILE NAME mixedCaseFile2 (^{tempWriteDir}) "TEST_FILES_mixedcase"
    file COPY/L "TEST_FILES_mixedcase" "^{mixedCaseFile2}"

    res inst "See the INFO statement/instructions before each FILES command in the SHELLGUI. &
              You may have to scroll up to see everything."

    pipe on
      panel/msgid=MAIN/setup/controls=gc
      gcontrol label  macro   "MACRO"
      gcontrol menu main "Exit with Status = " "PASS,FAIL" /tleft
      set gc.main.itemColors {PASS=GREEN,FAIL=RED}
      gcontrol text idtext "INSTRUCTIONS" "^inst" 24 24 /title

      shellgui/id=idshellgui/attach
      if "^{reg.shell.class}" eqs "class nxm.sys.libxm.XmShell" then
        warn "Skipping tests requiring a named AUX while run from X-Midas"
      else
        aux/store
        res AUX.TEMP_TEST_FILES "^{AUX.^{aux.write}}"
        aux ,, ^{aux.write}|TEMP_TEST_FILES
        info "Verify that three files (test_files_loweronly, TEST_FILES_ALLUPPER, TEST_FILES_mixedcase) are listed below."
        say "nM> FILES 'test_files*' AUX=AUX.WRITE"
        FILES "test_files*" AUX=AUX.WRITE
        say ""
!        say "================================================================================"
        info "Verify that three files (test_files_loweronly, TEST_FILES_ALLUPPER, TEST_FILES_mixedcase) are listed below."
        say "nM> FILES 'TEST_FILES*' AUX=AUX.WRITE"
        FILES "TEST_FILES*" AUX=AUX.WRITE
        say ""
 !       say "================================================================================"
        info "Verify that three files (test_files_loweronly, TEST_FILES_ALLUPPER, TEST_FILES_mixedcase) are listed below."
        info "Also verify that it says AUX=TEMP_TEST_FILES is the same as AUX=1 below"
        say "nM> FILES 'TEST_files*'"
        FILES "TEST_files*"
        say ""
!        say "================================================================================"
        info "Verify that only 'TEST_FILES_mixedcase.tmp' is listed below"
        say "nM> FILES '^{tempWriteDir}TEST_FILES*'"
        FILES "^{tempWriteDir}TEST_FILES*"
        say ""
!        say "================================================================================"
        info "Verify that three files (test_files_loweronly, TEST_FILES_ALLUPPER, TEST_FILES_mixedcase) &
              are listed below along with their type, form, elements, etc."
        say "nM> FILES/H 'TEST_FILES*' AUX=AUX.WRITE"
        FILES/H "TEST_FILES*" AUX=AUX.WRITE
        say ""

        say ""
        info "Verify that 'Sunset.jpg' and 'sv2.prm' are listed below"
        say "nM> FILES NAME=|S*.jpg|*v2.prm| AUX=dat /strict"
        files name=|S*.jpg|*v2.prm| aux=dat /strict

        aux/restore

        rem res AUX.TEMP_TEST_FILES
      endif

      say ""
 !     say "================================================================================"
      ! Also test /V switch here for BUG 2192
      ! Also testing displaying headers of an AUX NOT in the READ AUX list for Bug 2093
      !   by removing RAM from the READ AUX list
      AUX/STORE
      AUX ,, -RAM
      info "Verify that 'rampenny' and 'ramsine' and their headers are listed below (and there are no warnings/exceptions)"
      say "nM> FILES/V ram* AUX=RAM"
      FILES/V ram* AUX=RAM
      AUX/RESTORE

      call test_handleExceptions   ! Bug 2171, 2172
    pipe off
    erase "TEST_FILES_mixedcase"
    erase "TEST_FILES_ALLUPPER"
    erase "test_files_loweronly"
    erase mixedCaseFile2
    invoke ,, nxm.sys.lib.FileUtil.recursiveDelete(tempWriteDir)
  endif

endmacro

!******************************************************************************!
procedure processMessage m:msg
  if msg.name eqs "MAIN" then
    assert/text="^reg.main.name: User indicated tests" msg.data eqss "PASS"
    pipe stop
  else
    say "^reg.main.name: Unhandled message name: ^msg.name from fid: ^msg.fid data: ^msg.data"
  endif
return

!******************************************************************************!
! If an unexpected exception is caught, mark test as failed, unless it is expected
!******************************************************************************!
procedure processException m:emsg
  if expectedException REXISTS then
    assert/text="^reg.main.name: Expected ERROR starts with: ^{expectedException}" expectedException EQSS emsg.data.message
    remove expectedException
  else
    assert/text="^reg.main.name: Caught unexpected exception ^{emsg.data}" "FALSE" isTrue
    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

!******************************************************************************!
procedure test_fswitch
  ! Create a file (/F=) without /form (should default to XA)
  set testfile "test_files_fswitch_out"
  files/v=f/f=testfile "DO_NOT_WANT_TOFIND_ANY*"
  assert/text="^reg.main.name: FILES/F=testfile" &
         testfile FEXIST AND FILE(testfile).format eqs "XA"
  erase testfile

  set testfile "test_files_form_ta_out"
  files/v=f/f="^testfile"/form=TA "P*"
  assert/text="^reg.main.name: FILES/F=^testfile/FORM=TA" &
         testfile FEXIST AND FILE(^testfile).format eqs "TA"
  erase testfile

  ! since 3.1.1: to test that FILE/F should default output to "files.tmp"
  set testfile "files.tmp"
  erase/warn=n testfile ! ensure that we don't have previous file hanging around
  files/f "A*"
  assert/text="^reg.main.name: FILES/F should write to files.tmp" &
         testfile FEXIST AND FILE(testfile).format eqs "XA"
  erase testfile

return

!******************************************************************************!
! THIS IS AN INTERACTIVE terminal TEST ... to ensure listing of files is
! case insensitive
procedure test_list_wildcards

  ! Case should be ignored when listing files with a wildcard.
  waveform "TEST_FILES_mixedcase"
  waveform "TEST_FILES_ALLUPPER"
  waveform "test_files_loweronly"
  say " "

  info "files test_files*...."
  say "-----"
  files "test_files*" AUX=AUX.WRITE
  say "-----"
  say "Do you see all three files listed: "
  ask s:yesNo "      TEST_FILES_mixedcase, TEST_FILES_ALLUPPER, test_files_loweronly ? [Y]"
  assert/text="Listing entered as lower case" yesNo eqss "Y"
  say " "

  info "files TEST_FILES*...."
  say "-----"
  files "TEST_FILES*" AUX=AUX.WRITE
  say "-----"
  say "Do you see all three files listed: "
  ask s:yesNo "      TEST_FILES_mixedcase, TEST_FILES_ALLUPPER, test_files_loweronly ? [Y]"
  assert/text="Listing entered as UPPER CASE" yesNo eqss "Y"
  say " "


  if "^{reg.shell.class}" eqs "class nxm.sys.libxm.XmShell" then
    res temp_aux "101"
  else
    res temp_aux "TEMP_TEST_FILES"
  endif

  ! Save the current AUX values
  res read_aux "^{AUX.READ}"
  if aux.^{temp_aux} rexists then
    res old_temp_aux "^{AUX.^{temp_aux}}"
  endif

  ! Set temp AUX values
  res AUX.^{temp_aux} "^{AUX.1}"
  aux ,, 1|^{temp_aux}

  ! Test
  say "-----"
  files "TEST_FILES*"
  say "-----"
  say "Are any of the following files listed more than once: "
  ask s:yesNo "      TEST_FILES_mixedcase, TEST_FILES_ALLUPPER, test_files_loweronly ? [N]"
  assert/text="Duplicate files listed" yesNo eqss "N"

  ! Restore previous AUX values
  rem AUX.^{temp_aux}
  if old_temp_aux rexists then
    res AUX.^{temp_aux} "^{old_temp_aux}"
  endif
  aux ,, ^read_aux
  say " "

  erase "TEST_FILES_mixedcase"
  erase "TEST_FILES_ALLUPPER"
  erase "test_files_loweronly"
return

!******************************************************************************!
!   Verify that temporary files can be created and deleted successfully
!******************************************************************************!
procedure createAndDeleteTempFiles
  ! create a unique filename based on the current process id
  result tempfile "temp^{env.pid}"

  ! create the temporary file and make sure it exists on disk
  waveform ^tempfile
  assert/text="^reg.main.name: Creation of temp file" ^tempfile fexists

  ! now erase the file from disk and make sure it is gone
  erase/quiet "^tempfile"
  assert/text="^reg.main.name: Deletion of temp file" ^tempfile nfexists
return

!******************************************************************************!
! Get a List Files by Name Only. Added for BUG 1889
!******************************************************************************!
procedure test_list_nameonly
  new java.util.HashSet() expSet
  invoke ,, expSet.add("rampenny")
  invoke ,, expSet.add("ramsine")

  files/list=myfiles/nameonly ram* aux=ram
  foreach name inList myfiles
    invoke removed expSet.remove(name)
    assert/text="^reg.main.name: Found expected file listing: ^name" removed isTrue
  endfor

  assert/text="^reg.main.name: Found ALL expected file listing, remaining=^expSet is empty" expSet.isEmpty() isTrue
return

!******************************************************************************!
! Handle file exceptions when listing header with /H switch
! since 2.9.0 for BUG 2171 & Bug 2172
!******************************************************************************!
procedure test_handleExceptions
  ! put the files in WRITE AUX
  fname writeDir area=^aux.write opt="AUX"

  if env.ostype neqs "DOS" then ! colon is an invalid filename char under Windows (skip test)   
    ! Bug 2171 - Filename is invalid / incompatible
    file name invalidFN (^writeDir) "ram:bug2171.tmp"
    new java.io.File(invalidFN) testFile1
    invoke ,, testFile1.createNewFile()
  endif

  ! Bug 2172 - File has the same name as a result name
  res rambo_bug2172 "A string"
  file name fn2 (^writeDir) "rambo_bug2172.tmp"
  new java.io.File(fn2) testFile2
  invoke ,, testFile2.createNewFile()

  ! Another test case (with a text file with a BLUE file extension)
  ! this should display TYPE as "ERROR" and only display the size in bytes
  file copy/f ^{datDir}.cities.txt rambo_test_text_file.tmp

  ! Another test case (regular text file with TXT extension)
  file copy/f ^{datDir}.cities.txt ram_test_file.txt

  say ""
  info "Verify that a file named 'rambo_bug2172.tmp' is displayed with a size of zero bytes."
  if env.ostype neqs "DOS" then ! colon is an invalid filename char under Windows (skip test)  
    info "Verify that a file named 'ram:bug2171.tmp' is displayed with a size of zero bytes." !new behavior introduced in 3.5.2 (10/14/15 commit)/3.5.3
  endif
  say "nM> FILES/H name=ram* aux=^aux.write"
  files/h name="ram*" aux=^aux.write

  if env.ostype neqs "DOS" then ! colon is an invalid filename char under Windows   
    invoke ,, testFile1.delete()
  endif
  invoke ,, testFile2.delete()
  erase/quiet rambo_test_text_file.tmp ram_test_file.txt

return

!******************************************************************************!
! list files from a web server
! since 2.9.0: for BUG 2262 FILES to list files on directory served by HTTPSERV
procedure test_list_files_from_web
  set inNeXtOpt TEST("^{reg.shell.class}",eqs,"class nxm.sys.libxm.XmShell")
  if inNeXtOpt isTrue then
    ! cannot read named AUXes in NeXtOpt (inside X-Midas) -
    info "Skipping test_list_files_from_web under NeXtOpt."
    return
  endif

  ! create temp file in write aux
  set testfile "test_files_junk1.tmp"
  waveform testfile{aux=^aux.write}

  fname auxdir aux.write opt=aux
  HTTPSERV/id=hs/bg port=0 dir=auxdir name=mydir/

  ! test case to list files from directory served by HTTPSERV
  files/nameonly/list=webfileslist aux="http://localhost:^{reg.hs.port}/mydir/"
  assert/text="^reg.main.name: LISTING files from HTTPSERV directory" webfileslist.length GT 0
  assert/text="^reg.main.name: LISTING files from HTTPSERV directory contains testfile" testfile SUBS webfileslist

  ! list non-existent directory (no files should come back)
  ! FYI: info "It is ok to see an error for Getting EntryList for a non-existent directory on web server on next line."
  set expectedException "Getting EntryList"
  files/nameonly/list=webfileslist2 aux="http://localhost:^{reg.hs.port}/nonexistenttestdir/"
  assert/text="^reg.main.name: LISTING files from HTTPSERV directory (no files)" webfileslist2 nrexists OR webfileslist2.length EQ 0

  ! TODO: for future DR to list files under AUXes specified under /auxlist

  ! shutdown test HTTPSERV
  message send id="HS" name="EXIT"

  if baseline isTRUE then
    ! todo list files on apache web server (nextmidas.com)
  endif

  ! cleanup
  erase/quiet testfile{aux=^aux.write}

return

!******************************************************************************!
! test excluding certain auxes from the files search list for BUG 2482
! NOTE: since 3.6.0, skip if apenny*.[tmp|prm] if found somewhere in READ AUX list (-DAT)
!       since that would cause a false positive failure
procedure test_exclude
  files/exclude="DAT"/list=apennyFiles apenny*
  if apennyFiles.isEmpty isFalse then
    warn "^reg.main.name: Skipping exclude tests, since apenny* found in READ AUX list (-DAT). Please remove these files to run this test: ^apennyFiles"
    return
  endif

  noop ^{datDir}.apenny.prm ram:apennyRAM  ! for searching later
  noop ^{datDir}.apenny.prm apennyWRITEAUX.tmp ! for searching later

  ! Added exclude of AUX 101 for NeXtOpt confidence testing
  ! Added exclude AUX CWD just in case it is same as AUX 1 under Windows
  set excludeWriteAuxList "^{aux.write}|DAT|101|CWD"
  set excludeRamAuxList   "RAM|DAT|101|CWD"

  files/exclude=excludeWriteAuxList/list=filelist/nameonly apenn*
  assert/text="^reg.main.name: Exclude searching (write) ^excludeWriteAuxList AUXes: ^filelist" filelist eqs "apennyRAM"

  files/exclude=excludeRamAuxList/list=filelist2/nameonly apenny*
  assert/text="^reg.main.name: Exclude searching ^excludeRamAuxList AUXes: ^filelist2" filelist2 eqs "apennyWRITEAUX.tmp"

  ! save the current excluded AUXes
  if aux._COMPLETIONAUXEXCLUDE_ rexists then
    res origExclude aux._COMPLETIONAUXEXCLUDE_
  endif

  ! test without the EXCLUDE switch but with items in AUX._COMPLETIONAUXEXCLUDE_
  env set COMPLETIONAUXEXCLUDE ^excludeRamAuxList        ! set new excluded AUX list
  files/list=filelist3/nameonly apenny*
  assert/text="^reg.main.name: Exclude via ENV setting:" filelist3 eqs "apennyWRITEAUX.tmp"

  ! reset back to original excluded list, if there was one, or else remove what we added
  if origExclude rexists then
    env set COMPLETIONAUXEXCLUDE origExclude
  else
    rem aux._COMPLETIONAUXEXCLUDE_
  endif

  ! cleanup
  erase/quiet apennyWRITEAUX.tmp{aux=^aux.write}

return

!******************************************************************************!
! Tests conducted to determine whether the FILES command can output to text
! files (instead of BLUE file) as well as to ensure the file names that are read
! in are written properly. For BUG 2004.
!
! Author: Edward R. Cable
!******************************************************************************!
procedure test_outputToText
  ! NOTE: Most file systems (NTFS, ext3, etc.) have filename length limit of 255.
  set longFileNamePrefix "test_files_longFileName_0123456789_0123456789_0123456789&
    _0123456789_0123456789_0123456789_0123456789_0123456789_0123456789_0123456789&
    _0123456789_0123456789_0123456789_0123456789_0123456789_0123456789_0123456789&
    _0123456789_0123456789_0123456789_012"   ! len of 247
  sedit longFileNamePrefix fnMinLength LEN

  ! Create several file(s) with long file name length (247 + 7 (for __<ii>.txt)) = 254 chars for test case
  set numFiles 3
  do ii 1 numFiles
    headermod/create "^{longFileNamePrefix}__^{ii}.txt"
  enddo

  set outputTextFile "test_files_temp.txt"
  files/f=outputTextFile "^{longFileNamePrefix}*"

  ! Assert test to determine if output file exists
  assert/text="^reg.main.name: Output results to text file (fexists)" outputTextFile fexists

  file open tag outputTextFile

  ! Assert test to ensure the output file is a TextFile
  assert/text="Output file is a TextFile" tag INSTANCEOF nxm.sys.lib.TextFile

  do ii 1 numFiles
    FILE next tag line

    ! verify the long filename, after being written to the output file, has not been truncated
    assert/text="Length check on input written to outputTextFile at line ^ii" line.length >= fnMinLength

    ! verify the file name that has been written to the output file is in fact one and the same
    ! as the file name read, either as single string or part of its path as well
    assert/text="Name of file read is part of string name written at line ^ii" longFileNamePrefix SUBS line
  enddo

  call test2_nameonly

  ! Clean up test files
  if keep isfalse then
    erase outputTextFile
    files/e "^{longFileNamePrefix}*"
  endif
return

!******************************************************************************!
! Procedure to allow alternative test on outputToText
! to compare exactly the output to the file name read (testing /NAMEONLY switch)
!******************************************************************************!
procedure test2_nameonly
  set outputTextFile2 "test_files_nameonly.txt"
  files/f=outputTextFile2/nameonly "^{longFileNamePrefix}*"
  file open tag outputTextFile2

  ! Assert test to ensure the output file is a TextFile
  assert/text="Output file is a Textfile: " tag INSTANCEOF nxm.sys.lib.TextFile

  FILE next tag line
  file close tag

  ! determine if the file name that has been written to the output file is in fact one and
  ! the same as the file name read, as a single string
  assert/text="/NameOnly of file read is identical to file name written: " line EQSS longFileNamePrefix

  ! Clean up test files
  if keep isfalse then
    erase outputTextFile2
  endif
return
