!******************************************************************************!
! Macro to test "GENERATE" command
!******************************************************************************!
startmacro S:func[""]
  switch BASELINE    baseline GET DEF=TRUE SDEF=TRUE  ! for defects or more obscure test case(s)

  if func NEQS "" then
    call test_^{func}
  else
    call test_jnlp
    call test_exp
    call test_oper
    call test_sign
    invoke optionExists reg.shell.M.dictionary.isDictionaryEntry(OPTION)
    if baseline AND optionExists then
      call test_jars
      call test_jars_uppercase
    endif
  endif
endmacro

!******************************************************************************!
procedure test_exp

  if ^{env.NMROOT} EQS "classpath:" then
    warn "SKIPPING ^reg.main.name Skipping explain stub as it is generated by searching .java files.  - TODO change the way the exp file is generated. .java files are not included in jar file"
    return
  endif
  fname LABEL=expMaster AREA=TEST NAME="exp_plot_master" EXT="exp" OPT=SYS
  fname LABEL=expFullName AREA=aux.write NAME="test_generate_exp" EXT="exp" OPT=aux
  if expFullName FEXISTS erase expFullName

  ! Explain file generated from comments between first /** */
  generate EXP if expFullName
  if expFullName FEXISTS then
    !!!assert/text="^reg.main.name: EXP = MASTER " expFullName FEQ/B expMaster
    if /NOERASE isFalse then
      erase expFullName
    endif
  else
    assert/text="^reg.main.name: EXP exists " 0 EQ 1
  endif

  ! Explain stub, generated by searching code
  fname LABEL=expMaster AREA=TEST NAME="exps_plot_master" EXT="exp" OPT=SYS
  fname LABEL=expFullName AREA=aux.write NAME="test_generate_exps" EXT="exp" OPT=aux
  generate/new EXP/S IF expFullName
  assert/text="^reg.main.name: EXP/S exists " expFullName FEXISTS
  if expFullName FEXISTS then
    !!!assert/text="^reg.main.name: EXP/S = MASTER " expFullName FEQ/B expMaster
    if /NOERASE isFalse then
      erase expFullName
    endif
  endif
  
return

!******************************************************************************!
! test "JARS" function to create Web Start jar file for option tree
procedure test_jars

  if ^{env.NMROOT} EQS "classpath:" then
    warn "SKIPPING ^reg.main.name skipping GENERATE JARS when running from jar. Would need opt tree to be outside of this jar."
    return
  endif
  ! SIMPLE CHECKS ON THE SYS JAR FILE ==========================================
  FILE NAME sysJar (^{env.nmroot},jars) "nxm-sys.jar"
  if sysJar FEXISTS then
    assert/text="^reg.main.name: SYS jar contains Shell.class" "jar:^{sysJar}!/nxm/sys/lib/Shell.class{FG=RAW}" FEXISTS
    assert/text="^reg.main.name: SYS jar contains world.shp"  "jar:^{sysJar}!/nxm/sys/dat/world.shp"          FEXISTS
  else
    warn "^reg.main.name: Skipping JARS #1 tests, ^{sysJar} not found. Run 'nm make jars sys' and re-run test."
  endif

  ! TEST A NORMAL USER-DEFINED OPTION TREE =====================================
  ! define test option tree (mytestopt1)
  FILE NAME rootOptDir (^{env.nmroot},nxm,sys,test,nmopts) "" ""
  res optname "mytestopt1"
  option ^optname  ^rootOptDir

  FNAME writeDir AREA=^aux.write OPT=AUX
  FILE NAME writeDir1 (^{writeDir},test_generate1_^{env.pid})
  if writeDir1 ndexists then
    new java.io.File(writeDir1) dirFile
    invoke retval dirFile.mkdirs()
    assert/text="^reg.main.name: Created temp dir ^writeDir1" retval isTrue
    remove dirFile
  endif

  ! cleanup any existing jar files before testing
  res optJar       "^{writeDir1}nxm-^{optname}.jar"
  res optOtherJar1 "^{writeDir1}UPPERCASE.jar"
  res optOtherJar2 "^{writeDir1}TestClassPath.jar"
  erase/warn=n optJar optOtherJar1 optOtherJar2

  if optJar FEXISTS then
    ! 2010-07-16 NTN TODO: something is fishy under Windows (i.e resource is NOT getting cleaned up somewhere)? (2014-5-28: cannot delete while open?)
    WARN "^reg.main.name: Skipping JARS #2 tests since we cannot cleanup existing ^{optJar}"
  else
    ! test JAR file generation for mytestopt1 option tree to write AUX
    generate "JARS" ^optname "^writeDir1" /skip="JARNATIVE|COPYJARS" /notest /nodocs

    ! test that jar file was created for option tree
    assert/text="^reg.main.name: nxm-^{optname}.jar created" optJar FEXISTS
    ! test that commands.cnf for option tree was added to jar file
    assert/text="^reg.main.name: nxm-^{optname}.jar contains commands.cnf" "jar:^{optJar}!/nxm/^optname/cfg/commands.cnf" FEXISTS
    ! test that option tree's build.props can override the jnlp.file_filter property from SYS/cfg/build.props
    assert/text="^reg.main.name: ^{optname}'s build.props, jar has testpathprim.java" "jar:^{optJar}!/nxm/^optname/prim/testpathprim.java" FEXISTS
    ! test /SKIP= switch for BUG 2215
    set inNeXtOpt TEST("^{reg.shell.class}",eqs,"class nxm.sys.libxm.XmShell")
    if inNeXtOpt isFALSE then
      FILES/LIST=nativeJarFiles "nxm-^{optname}-native*" "jar" "^writeDir1"
      assert/text="^reg.main.name: native OS jar not created with /skip=JARNATIVE" nativeJarFiles eqs ""
    else
      info "^reg.main.name: Skipping native OS jar not created with /skip=JARNATIVE check in NeXtOpt"
    endif
    assert/text="^reg.main.name: copy and sign jar file #1 skipped with /skip=COPYJARS" optOtherJar1 NFEXISTS
    assert/text="^reg.main.name: copy and sign jar file #2 skipped with /skip=COPYJARS" optOtherJar2 NFEXISTS
    ! since 3.6.0: using DISABLEUSECACHES file qualifier to workaround Java resource leak when file does not exists in jar file
    assert/text="^reg.main.name: files under ^{optname}/test dir not in jar with /notest" &
                          "jar:^{optJar}!/nxm/^optname/test/test_bug2747.mm{DISABLEUSECACHES=true}"  NFEXISTS
    assert/text="^reg.main.name: files under ^{optname}/docs dir not in jar with /nodocs" &
                          "jar:^{optJar}!/nxm/^optname/docs/test_bug2747.txt{DISABLEUSECACHES=true}" NFEXISTS
    ! clean up
    erase/warn=n optOtherJar1 optOtherJar2
    erase/warn=y ^optJar
    assert/text="^reg.main.name: able to remove generated jar: ^{optJar}" optJar NFEXISTS
    invoke ,, nxm.sys.lib.FileUtil.recursiveDelete(writeDir1)
  endif

  ! === begin test for BUG 2803 allow custom keystore (since 3.5.0) ===
  FILE NAME writeDir2 (^{writeDir},test_generate2_^{env.pid})
  FILE NAME keystorefn writeDir2 "testkeystore.jks"
  FILE NAME jarfn      writeDir2 "nxm-^{optname}.jar"
  if writeDir2 ndexists then
    new java.io.File(writeDir2) dirFile
    invoke retval dirFile.mkdirs()
    assert/text="^reg.main.name: Created temp dir ^writeDir2" retval isTrue
    remove dirFile
  endif

  import "JAVAHOME" javahome
  if javahome ndexists then import "JAVA_HOME" javahome
  file name keytool_cmd   (^javahome,bin) "keytool"
  file name jarsigner_cmd (^javahome,bin) "jarsigner"
  if env.osname eqss "Windows" then
    set keytool_cmd ^{keytool_cmd}.exe
    set jarsigner_cmd ^{jarsigner_cmd}.exe
  endif
  if keytool_cmd nfexists then
    WARN "^reg.main.name: Skipping JARS with custom keystore, cannot find keytool at ^keytool_cmd"
  else
    ! create a custom keystore for testing
    ! jarsigning issue - if the keystore is PKCS12, the storepass and keypass must be the same. Since 3.8.1
    os ^{keytool_cmd} -genkeypair -keyalg DSA -keysize 2048 -validity 365 -dname CN=TestCustomKeyStore,OU=NeXtMidas,O=NeXtMidas,L=Chantilly,ST=VA,C=US &
                      -alias testKeyAlias -keystore ^{keystorefn} -storetype PKCS12 -storepass ilovejava -keypass ilovejava
    assert/text="^reg.main.name: created test keystore at ^{keystorefn}" keystorefn fexists
    ! test JAR file generation and signing for mytestopt1 option tree to writeDir2 using custom keystore
    set keystoreCfg {KEYSTOREPASS="ilovejava",KEYALIAS="testKeyAlias",KEYPASS="ilovejava"}
    set keystoreCfg.KEYSTOREFILE keystorefn
    ! since 3.5.1, can pass additional jarsigner options to GENERATE
    set moreJarsignerOptions "-verbose"
    info "Numerous WARNINGS below about '...this jar is not timestamped...' are EXPECTED" 
    generate "JARS" ^optname "^writeDir2" keystoreCfg /signoptions=moreJarsignerOptions /skip="JARNATIVE|COPYJARS" /notest /nodocs
    assert/text="^reg.main.name: created jar signed with custom keystore at ^jarfn" jarfn fexists

    if jarsigner_cmd nfexists then
      WARN "^reg.main.name: Skipping verification of JAR signing with custom keystore, cannot find jarsigner at ^jarsigner_cmd"
    else
      ! validate that jar is signed correctly
      os/stdout=myout ^{jarsigner_cmd} -verify -keystore ^{keystorefn} ^{jarfn}
      invoke trimout myout.trim()
      assert/text="^reg.main.name: Verify nxm-^{optname}.jar is signed with custom keystore" "jar verified." SUBS trimout
    endif

    ! Clean up
    erase/warn=n jarfn keystorefn
    invoke ,, nxm.sys.lib.FileUtil.recursiveDelete(writeDir2)
  endif
  ! === end test for BUG 2803 (since 3.5.0, then updated to config table in 3.5.1) ==
  ! cleanup - undefine MYTESTOPT1 option tree
  option/delete ^optname

  ! TEST A DEPRECATED USER-DEFINED OPTION TREE WITH BACK-LINK ==================
  if (ENV.OSNAME NEQS "Linux") then
    INFO "^reg.main.name: Skipping JARS #3 tests for option tree with back-link since we are not on Linux."
  else
    ! Create back-link
    FILE NAME rootOptDir (^{env.nmroot},nxm,sys,test,nmopts,backlinktestopt) "" ""
    FILE NAME linkName   (^{rootOptDir},nxm,backlinktestopt) "" ""

    invoke lenLinkTarget rootOptDir.lastIndexOf("/")
    invoke lenLinkName   linkName.lastIndexOf("/")
    invoke linkTarget    rootOptDir.substring(0,lenLinkTarget)
    invoke linkName      linkName.substring(0,lenLinkName)
    OS ln -s ^linkTarget ^linkName

    ! define test option tree (mytestopt3)
    res optname3 "backlinktestopt"
    option ^optname3  ^rootOptDir
    FNAME writeDir AREA=^aux.write OPT=AUX
    file name optJar3 writeDir "nxm-^{optname3}.jar"

    if optJar3 FEXISTS then
      WARN "^reg.main.name: Skipping JARS #3 test since we cannot cleanup existing ^{optJar3}"
    else
      ! test JAR file generation for option tree to write AUX -- we intentionally
      ! use /ffilt="-*.txt" to duplicate an issue seen with the ICE option tree
      ! and the NXM snapshot from 8 Oct 2012 when creating native JARs.
      generate "JARS" ^optname3 "^writeDir" /ffilt="-*.txt" /skip=JARNATIVE|COPYJARS

      ! test that jar file was created for option tree
      assert/text="^reg.main.name: nxm-^{optname3}.jar created" optJar3 FEXISTS
      ! test that commands.cnf for option tree was added to jar file
      assert/text="^reg.main.name: nxm-^{optname3}.jar contains commands.cnf" "jar:^{optJar3}!/nxm/^{optname3}/cfg/commands.cnf" FEXISTS

      erase/warn=n optJar3
    endif
    ! Remove the back-link
    OS unlink ^linkName
    option/delete ^optname3
  endif

  ! OTHER TESTS ================================================================
  ! test case for BUG 2324 generate JARS should terminate destination path
  res dirNoTerminator writedir.substring(0,writedir.length-1)
  FILE NAME dspJarFile ^writeDir nxm-dsp.jar
  generate "JARS" DSP dirNoTerminator /skip=JARNATIVE|COPYJARS
  assert/text="^reg.main.name: nxm-dsp.jar created in dest without path terminator" dspJarFile FEXISTS
  
  !test BUG 2999 SIGN jar without opt should NOT return Null Pointer Exception
  generate "SIGN" dspJarFile
  assert/text="^reg.main.name: nxm-dsp.jar is now signed using 'generate SIGN'." dspJarFile FEXISTS
 
  ! test JarFile.signJarFile() with option = null
  new nxm.sys.lib.FileName( ^{writeDir}nxm-dsp.jar) jfile
  set Z:debug true
  set myopt null
  FILE NAME sysKeystoreFname (^{env.nmroot},nxm,sys,cfg) keystore
  ! result keystoreCfg {KEYSTOREFILE="^{env.nmroot}nxm/sys/cfg/keystore", KEYSTOREPASS="nmsign", KEYALIAS="nmsign"}
  result keystoreCfg {KEYSTOREPASS="nmsign", KEYALIAS="nmsign"}
  result keystoreCfg.KEYSTOREFILE  sysKeystoreFname
  new nxm.sys.lib.JarFile() jarFile
  invoke ,, jarFile.signJarFile(this.M, jfile, myopt, keystoreCfg, myopt, debug)
  assert/text="^reg.main.name: nxm-dsp.jar is now signed using JarFile.signJarFile()." dspJarFile FEXISTS
  if jarsigner_cmd nfexists then
    WARN "^reg.main.name: Skipping verification of JAR signing with keystore and opt=null, cannot find jarsigner at ^jarsigner_cmd"
  else
    ! validate that jar is signed correctly
    os/stdout=myout ^{jarsigner_cmd} -verify -keystore ^sysKeystoreFname ^{dspJarFile}
    assert/text="^reg.main.name: Verify ^{dspJarFile} is signed with keystore" "jar verified." SUBS myout
  endif
  
  erase/warn=n dspJarFile
return ! end test_jars


!******************************************************************************!
procedure test_jnlp
  set jnlpName "test_generate"
  fname LABEL=jnlpFullName AREA=aux.write NAME="^jnlpName" EXT="jnlp" OPT=aux
  fname LABEL=jnlpMaster AREA=TEST NAME="jnlp_master" EXT="jnlp" OPT=SYS
  fname LABEL=jnlpDir AREA=aux.write NAME="" EXT="" OPT=aux
  generate jnlp jnlpName DSP jnlpDir "http://nextmidas.com/nxmxxx/jars"

  assert/text="^reg.main.name: JNLP exists " jnlpFullName FEXISTS
  if jnlpFullName FEXISTS then
! JC4: Test fails on windows... can not do a FEQ/B on a text file because line
!      terminators don't match. Stupid Windows.
    if env.ostype EQS "UNIX" then
      assert/text="^reg.main.name: JNLP = MASTER " jnlpFullName FEQ/B jnlpMaster
    else
      WARNING "^reg.main.name: TBD make JNLP comparison work for WINDOWS &
                and others"
    endif
    erase jnlpFullName
  endif
return

!******************************************************************************!
procedure test_oper
  warning "^reg.main.name: no test for OPER function"
return

!******************************************************************************!
procedure test_sign
  info "^reg.main.name: test for SIGN function in test_jars"
return

!******************************************************************************!
! Test making a jar for an option tree with an upper-case jar filename (BUG 2212)
procedure test_jars_uppercase
  
  if ^{env.NMROOT} EQS "classpath:" then
    warn "SKIPPING ^reg.main.name skipping GENERATE JARS uppercase when running from jar. Would need opt tree to be outside of this jar."
    return
  endif
  FILE NAME rootOptDir (^{env.nmroot},nxm,sys,test,nmopts) "" ""
  option mytestopt1  ^rootOptDir
  FNAME writeDir AREA=^aux.write OPT=AUX

  generate jars mytestopt1 "^writeDir" /skip="JARSTANDARD|JARNATIVE"
  ! the above cmd should copy jar files from <MYTESTOPT1>/jars (specificially UPPERCASE.jar) to ^writeDir
  assert/text="^reg.main.name: MYTESTOPT1/jars/UPPERCASE.jar file copied to Write AUX" "UPPERCASE.jar" fexists
  assert/text="^reg.main.name: MYTESTOPT1/jars/TestClassPath.jar file copied to Write AUX" "TestClassPath.jar" fexists

  option/delete mytestopt1
  ERASE/warn=n  "UPPERCASE.jar" "TestClassPath.jar"
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
