###############################################################################
#
# package.eagle --
#
# Extensible Adaptable Generalized Logic Engine (Eagle)
#
# Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: $
#
###############################################################################

source [file join [file normalize [file dirname [info script]]] prologue.eagle]

###############################################################################

#
# NOTE: This test cannot be run if the test log file has been disabled as it
#       needs to scan the log file to determine if the tests actually ran.
#
runTest {test garuda-1.1 {Eagle Package for Tcl (Garuda) via Tcl} -setup {
  proc findStringInFile { fileName string } {
    try {
      set data [readFile $fileName]

      #
      # NOTE: Check for the string in the entire log file and return
      #       non-zero if found.
      #
      return [string last $string $data]
    } finally {
      #
      # NOTE: We do not want to hold all the log file data in memory;
      #       therefore, do our very best to remove it now.
      #
      unset -nocomplain -purge -- data; debug collect
    }
  }

  unset -nocomplain stdErr stdOut exitCode script sentryIndex test_sentry
} -body {
  #
  # NOTE: This is the test sentry string to look for in the log file.  It
  #       must be placed into the log file by the test file being run
  #       (i.e. "tcl-load.eagle").
  #
  set test_sentry " running Tcl integration tests."

  tputs $test_channel [appendArgs "---- log file size is " \
      [file size $test_log] " before test\n"]

  set sentryIndex(old) [findStringInFile $test_log $test_sentry]

  tputs $test_channel [appendArgs \
      "---- sentry string at position " $sentryIndex(old) \
      " before test\n"]

  #
  # NOTE: Prevent superfluous object disposal related diagnostic messages from
  #       interfering with the testing itself.
  #
  set script(pre) { \
    set env(DefaultQuiet) true \
  }

  #
  # HACK: Chain the entire Garuda test suite (in native Tcl) to this one.
  #
  testExec $test_tclsh \
      [list -exitcode exitCode -stdout stdOut -stderr stdErr] \
      [appendArgs \" [file join $base_path Native Package Tests all.tcl] \
      \"] -configuration [appendArgs \" [getTestConfiguration] \"] \
      -suffix [appendArgs \" [getTestSuffix] \"] -exitOnComplete true \
      -preTest [appendArgs \" $script(pre) \"] \
      -logFile [appendArgs \" [getTestLog] \"]

  tputs $test_channel [appendArgs "---- log file size is " \
      [file size $test_log] " after test\n"]

  set sentryIndex(new) [findStringInFile $test_log $test_sentry]

  tputs $test_channel [appendArgs \
      "---- sentry string at position " $sentryIndex(new) \
      " after test\n"]

  #
  # NOTE: If the sentry string position has not changed then the package
  #       probably failed to load and we need to record why.  Also, we
  #       need to dump the captured standard output if we fail to find
  #       our sentry string at all.
  #
  if {$sentryIndex(new) == -1 || \
      $sentryIndex(new) == $sentryIndex(old)} then {
    if {[info exists stdOut] && [string length $stdOut] > 0} then {
      tputs $test_channel "---- dumping \"stdout\" to log file...\n"

      tlog "---- BEGIN STDOUT OUTPUT\n"
      tlog $stdOut
      tlog "\n---- END STDOUT OUTPUT\n"
    }
  }

  #
  # HACK: Always dump the captured standard error output because it may
  #       contain useful information even when the test succeeds.
  #
  if {[info exists stdErr] && [string length $stdErr] > 0} then {
    tputs $test_channel "---- dumping \"stderr\" to log file...\n"

    tlog "---- BEGIN STDERR OUTPUT\n"
    tlog $stdErr
    tlog "\n---- END STDERR OUTPUT\n"
  }

  set exitCode
} -cleanup {
  catch {info previouspid true}

  #
  # NOTE: We captured all the output from the child process (which could
  #       be quite large); therefore, attempt to recover the memory now.
  #
  unset -nocomplain -purge -- stdErr stdOut; debug collect
  unset -nocomplain exitCode script sentryIndex test_sentry

  rename findStringInFile ""
} -constraints {eagle dotNet windows logFile tclShell compile.WINDOWS\
compile.NATIVE compile.TCL compile.NATIVE_PACKAGE testExec file_Garuda.dll\
file_pkgAll.tcl} -result {Success}}

###############################################################################

runTest {test garuda-1.2 {Eagle Package for Tcl (Garuda) via Eagle} -setup {
  proc findStringInFile { fileName string } {
    try {
      set data [readFile $fileName]

      #
      # NOTE: Check for the string in the entire log file and return
      #       non-zero if found.
      #
      return [string last $string $data]
    } finally {
      #
      # NOTE: We do not want to hold all the log file data in memory;
      #       therefore, do our very best to remove it now.
      #
      unset -nocomplain -purge -- data; debug collect
    }
  }

  unset -nocomplain stdErr stdOut exitCode script sentryIndex test_sentry
} -body {
  #
  # NOTE: This is the test sentry string to look for in the log file.  It
  #       must be placed into the log file by the test file being run
  #       (i.e. "tcl-load.eagle").
  #
  set test_sentry " running Tcl integration tests."

  tputs $test_channel [appendArgs "---- log file size is " \
      [file size $test_log] " before test\n"]

  set sentryIndex(old) [findStringInFile $test_log $test_sentry]

  tputs $test_channel [appendArgs \
      "---- sentry string at position " $sentryIndex(old) \
      " before test\n"]

  #
  # HACK: Prior to running the test file, we need to make sure that the Tcl
  #       is loaded into the Eagle interpreter and that the Garuda package is
  #       loaded into the master Tcl interpreter.
  #
  # BUGFIX: Make sure that the specified directory is the *FIRST* one that
  #         gets searched for the package being tested; otherwise, we may
  #         end up loading and testing the wrong package binary.
  #
  set script(pre) { \
    set env(DefaultQuiet) true; \
    tcl load; tcl eval [tcl master] [list proc lprepend { varName args } { \
      if {[llength $args] > 0} then { \
        upvar 1 $varName list; \
        set list [eval linsert [list $list] 0 $args] \
      } \
    }]; \
    tcl eval [tcl master] \
        [list lprepend auto_path [file dirname [getGarudaDll]]]; \
    tcl set [tcl master] test_flags(-configuration) \
        [getTestConfiguration]; \
    tcl set [tcl master] test_flags(-suffix) [getTestSuffix]; \
    tcl eval [tcl master] [list namespace eval ::Garuda { \
      set verbose true; set logCommand tclLog \
    }]; \
    tcl eval [tcl master] package require Garuda \
  }

  #
  # HACK: After running the test file, we need to verify number of tests that
  #       passed against the hard-coded value(s) in this script.  The exact
  #       number of tests required to pass is non-trivial to calculate and
  #       will vary based on several factors, including but not limited to:
  #
  #       1.  Whether or not Tk is available (i.e. there is currently 1 test
  #           that requires Tk).
  #
  #       2.  Whether or not Tcl 8.6 is available (i.e. there are currently 2
  #           tests that require Tcl 8.6 or higher).
  #
  #       3.  Whether or not the "interactive", "userInteraction", and/or
  #           "isolated" test constraints have been set manually (i.e. we do
  #           not set them).
  #
  #       4.  Whether or not Eagle has been compiled with the requirement that
  #           the Tcl library is thread-safe.
  #
  #       5.  Whether or not Eagle has been compiled with the isolated Tcl
  #           worker thread feature enabled (i.e. the "TclThread" class).
  #
  #       6.  Whether or not Eagle has been compiled with the dedicated test
  #           code included (i.e. the Eagle._Tests.Default class).
  #
  #       Also, the hard-coded value(s) must be kept in sync if the number of
  #       tests in "tcl-load.eagle" changes OR if the constraints in the
  #       "tcl-load.eagle" file change such that a different number of tests
  #       may be skipped.
  #
  set script(post) { \
    set b(1) [haveConstraint tclReadyOrLibrary86]; \
    set b(2) [haveConstraint tk]; \
    set b(3) [haveConstraint tkPackage]; \
    set b(4) [haveConstraint interactive]; \
    set b(5) [haveConstraint userInteraction]; \
    set b(6) [haveConstraint isolated]; \
    set b(7) [haveConstraint compile.TCL_THREADED]; \
    set b(8) [haveConstraint compile.TCL_THREADS]; \
    set b(9) [haveConstraint compile.TEST]; \
    set c(1) [expr {10 + \
        ($b(1) && $b(2) && $b(3) ? 1 : 0) + ($b(4) && $b(5) ? 1 : 0) + \
        ($b(6) ? 2 : 0) + ($b(7) && $b(8) ? 1 : 0) + \
        ($b(1) && $b(7) && $b(8) ? 1 : 0) + ($b(9) ? 1 : 0)}]; \
    if {$eagle_tests(Passed) == $c(1)} then { \
      tputs $test_channel [appendArgs \
          [subst {---- test 'Passed' count match\n}]] \
    } else { \
      tputs $test_channel [appendArgs \
          [subst {---- test 'Passed' count mismatch, must be $c(1)\n}]]; \
      set exitCode Failure \
    } \
  }

  execTestShell [list -exitcode exitCode -stdout stdOut -stderr stdErr] \
      -file [appendArgs \" [file join $test_path tcl-load.eagle] \"] \
      -configuration [appendArgs \" [getTestConfiguration] \"] \
      -suffix [appendArgs \" [getTestSuffix] \"] \
      -preTest [appendArgs \" $script(pre) \"] \
      -postTest [appendArgs \" $script(post) \"] \
      -exitOnComplete true -logFile [appendArgs \" [getTestLog] \"] \
      -no [appendArgs \" "logFileName 1" \"]

  tputs $test_channel [appendArgs "---- log file size is " \
      [file size $test_log] " after test\n"]

  set sentryIndex(new) [findStringInFile $test_log $test_sentry]

  tputs $test_channel [appendArgs \
      "---- sentry string at position " $sentryIndex(new) \
      " after test\n"]

  #
  # NOTE: If the sentry string position has not changed then the package
  #       probably failed to load and we need to record why.  Also, we
  #       need to dump the captured standard output if we fail to find
  #       our sentry string at all.
  #
  if {$sentryIndex(new) == -1 || \
      $sentryIndex(new) == $sentryIndex(old)} then {
    if {[info exists stdOut] && [string length $stdOut] > 0} then {
      tputs $test_channel "---- dumping \"stdout\" to log file...\n"

      tlog "---- BEGIN STDOUT OUTPUT\n"
      tlog $stdOut
      tlog "\n---- END STDOUT OUTPUT\n"
    }
  }

  #
  # HACK: Always dump the captured standard error output because it may
  #       contain useful information even when the test succeeds.
  #
  if {[info exists stdErr] && [string length $stdErr] > 0} then {
    tputs $test_channel "---- dumping \"stderr\" to log file...\n"

    tlog "---- BEGIN STDERR OUTPUT\n"
    tlog $stdErr
    tlog "\n---- END STDERR OUTPUT\n"
  }

  set exitCode
} -cleanup {
  catch {info previouspid true}

  #
  # NOTE: We captured all the output from the child process (which could
  #       be quite large); therefore, attempt to recover the memory now.
  #
  unset -nocomplain -purge -- stdErr stdOut; debug collect
  unset -nocomplain exitCode script sentryIndex test_sentry

  rename findStringInFile ""
} -constraints \
{eagle dotNet windows logFile tclLibrary compile.WINDOWS compile.NATIVE\
compile.TCL compile.NATIVE_PACKAGE testExec file_Garuda.dll} -result {Success}}

###############################################################################

runTest {test package-1.1 {package info sub-command} -body {
  package info Eagle.Library
} -constraints {eagle} -match regexp -result [appendArgs "^kind Package id " \
"\[0-9A-Fa-f\]{8}-\[0-9A-Fa-f\]{4}-\[0-9A-Fa-f\]{4}-\[0-9A-Fa-f\]{4}-" \
"\[0-9A-Fa-f\]{12} name Eagle\\.Library description \\{\\} indexFileName\
[string map [list \\ \\\\ . \\. \{ \\\{ \} \\\}] [list [file nativename [file \
join $tcl_library pkgIndex.eagle]]]] provideFileName [string map [list \\ \\\\\
. \\. \{ \\\{ \} \\\}] [list [file nativename [file join $tcl_library \
init.eagle]]]] flags None loaded [string map [list . \\.] [info engine \
PatchLevel]] ifNeeded \\{1\\.0 \\{[string map [list \\ \\\\ . \\. \{ \\\{ \} \
\\\}] [package ifneeded Eagle.Library 1.0]]\\}\\}\$"]}

###############################################################################

source [file join [file normalize [file dirname [info script]]] epilogue.eagle]
