###############################################################################
#
# file-io.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]

###############################################################################
# MONO: Due to a Mono bug, some tests are disabled on Mono.
#       See: https://bugzilla.novell.com/show_bug.cgi?id=473899
#       See: https://bugzilla.novell.com/show_bug.cgi?id=478489
###############################################################################

catch {unset x0}
append x0 \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F
append x0 \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F
append x0 \x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F
append x0 \x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F
append x0 \x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F
append x0 \x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F
append x0 \x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F
append x0 \x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F
append x0 \x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F
append x0 \x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F
append x0 \xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF
append x0 \xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF
append x0 \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF
append x0 \xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF
append x0 \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF
append x0 \xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF

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

catch {unset x1}
append x1 \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F
append x1 \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F
append x1 \x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F
append x1 \x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F
append x1 \x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F
append x1 \x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F
append x1 \x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F
append x1 \x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F
append x1 \x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F\x3F

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

catch {unset x2}
append x2 \u0100\u0302\u0504\u0706\u0908\u0B0A\u0D0C\u0F0E
append x2 \u1110\u1312\u1514\u1716\u1918\u1B1A\u1D1C\u1F1E
append x2 \u2120\u2322\u2524\u2726\u2928\u2B2A\u2D2C\u2F2E
append x2 \u3130\u3332\u3534\u3736\u3938\u3B3A\u3D3C\u3F3E
append x2 \u4140\u4342\u4544\u4746\u4948\u4B4A\u4D4C\u4F4E
append x2 \u5150\u5352\u5554\u5756\u5958\u5B5A\u5D5C\u5F5E
append x2 \u6160\u6362\u6564\u6766\u6968\u6B6A\u6D6C\u6F6E
append x2 \u7170\u7372\u7574\u7776\u7978\u7B7A\u7D7C\u7F7E
append x2 \u8180\u8382\u8584\u8786\u8988\u8B8A\u8D8C\u8F8E
append x2 \u9190\u9392\u9594\u9796\u9998\u9B9A\u9D9C\u9F9E
append x2 \uA1A0\uA3A2\uA5A4\uA7A6\uA9A8\uABAA\uADAC\uAFAE
append x2 \uB1B0\uB3B2\uB5B4\uB7B6\uB9B8\uBBBA\uBDBC\uBFBE
append x2 \uC1C0\uC3C2\uC5C4\uC7C6\uC9C8\uCBCA\uCDCC\uCFCE
append x2 \uD1D0\uD3D2\uD5D4\uD7D6\uD9D8\uDBDA\uDDDC\uDFDE
append x2 \uE1E0\uE3E2\uE5E4\uE7E6\uE9E8\uEBEA\uEDEC\uEFEE
append x2 \uF1F0\uF3F2\uF5F4\uF7F6\uF9F8\uFBFA\uFDFC\uFFFE

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

catch {unset x3}
append x3 \u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007
append x3 \u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F
append x3 \u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017
append x3 \u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F
append x3 \u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027
append x3 \u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F
append x3 \u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037
append x3 \u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F
append x3 \u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047
append x3 \u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F
append x3 \u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057
append x3 \u0058\u0059\u005A\u005B\u005C\u005D\u005E\u005F
append x3 \u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067
append x3 \u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F
append x3 \u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077
append x3 \u0078\u0079\u007A\u007B\u007C\u007D\u007E\u007F
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD
append x3 \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD

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

catch {unset x4}
append x4 \u0100\u0302\u0504\u0706\u0908\u0B0A\u0D0C\u0F0E
append x4 \u1110\u1312\u1514\u1716\u1918\u1B1A\u1D1C\u1F1E
append x4 \u2120\u2322\u2524\u2726\u2928\u2B2A\u2D2C\u2F2E
append x4 \u3130\u3332\u3534\u3736\u3938\u3B3A\u3D3C\u3F3E
append x4 \u4140\u4342\u4544\u4746\u4948\u4B4A\u4D4C\u4F4E
append x4 \u5150\u5352\u5554\u5756\u5958\u5B5A\u5D5C\u5F5E
append x4 \u6160\u6362\u6564\u6766\u6968\u6B6A\u6D6C\u6F6E
append x4 \u7170\u7372\u7574\u7776\u7978\u7B7A\u7D7C\u7F7E
append x4 \u8180\u8382\u8584\u8786\u8988\u8B8A\u8D8C\u8F8E
append x4 \u9190\u9392\u9594\u9796\u9998\u9B9A\u9D9C\u9F9E
append x4 \uA1A0\uA3A2\uA5A4\uA7A6\uA9A8\uABAA\uADAC\uAFAE
append x4 \uB1B0\uB3B2\uB5B4\uB7B6\uB9B8\uBBBA\uBDBC\uBFBE
append x4 \uC1C0\uC3C2\uC5C4\uC7C6\uC9C8\uCBCA\uCDCC\uCFCE
append x4 \uD1D0\uD3D2\uD5D4\uD7D6\uFFFD\uDBDA\uDDDC\uFFFD
append x4 \uE1E0\uE3E2\uE5E4\uE7E6\uE9E8\uEBEA\uEDEC\uEFEE
append x4 \uF1F0\uF3F2\uF5F4\uF7F6\uF9F8\uFBFA\uFDFC\uFFFE

###############################################################################
#
# NOTE: These encodings work for these tests in both Tcl and Eagle.
#
# fconfigure $fd -encoding iso8859-1
# fconfigure $fd -encoding binary
# fconfigure $fd -encoding identity
#
###############################################################################
#
# NOTE: These encodings work for these tests in Eagle only (they are not
#       present in Tcl).
#
# fconfigure $fd -encoding default
# fconfigure $fd -encoding null
# fconfigure $fd -encoding onebyte
#
###############################################################################
#
# NOTE: These encodings do not "work" for these tests in Eagle due to how the
#       underlying .NET encodings behave in the face of invalid code points.
#
# fconfigure $fd -encoding utf-8; # invalid code points become '\uFFFD'.
# fconfigure $fd -encoding ascii; # invalid code points become '\u3F'.
#
###############################################################################
#
# NOTE: This encoding does not "work" for these tests because it produces one
#       character for every two bytes, ignoring invalid code points (fake
#       UCS-2).
#
# fconfigure $fd -encoding twobyte; # bytes "\x00\x01" becomes '\u0100'.
#
###############################################################################

runTest {test fileIO-1.1 {binary file data, default encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {file_file.dat} -result {1}}

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

runTest {test fileIO-1.2 {binary file data, 'iso8859-1' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  set encoding [expr {[isMono] ? "iso-8859-1" : "iso8859-1"}]
  fconfigure $fd -encoding $encoding -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain encoding fd z
} -constraints {file_file.dat} -result {1}}

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

runTest {test fileIO-1.3 {binary file data, 'Binary' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding binary -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {file_file.dat} -result {1}}

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

runTest {test fileIO-1.4 {binary file data, 'Identity' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding identity -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {file_file.dat} -result {1}}

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

runTest {test fileIO-1.5 {binary file data, 'default' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding default -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {1}}

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

runTest {test fileIO-1.6 {binary file data, 'Null' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding null -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {1}}

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

runTest {test fileIO-1.7 {binary file data, 'OneByte' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding onebyte -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {1}}

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

runTest {test fileIO-1.8 {binary file data, 'TwoByte' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding twobyte -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x2 $z] == 0)}; # SEE NOTES ABOVE.
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {1}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid utf-8 code points and the
#       Encoding class in the .NET Framework does not.
#
runTest {test fileIO-1.9.1 {binary file data, 'utf-8' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding utf-8 -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {tcl file_file.dat} -result {1}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid utf-8 code points and the
#       Encoding class in the .NET Framework does not.
#
runTest {test fileIO-1.9.2 {binary file data, 'utf-8' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding utf-8 -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {0}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid utf-8 code points and the
#       Encoding class in the .NET Framework does not.
#
runTest {test fileIO-1.9.3 {binary file data, 'utf-8' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding utf-8 -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x3 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {1}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid ASCII code points and the
#       Encoding class in the .NET Framework does not.
#
runTest {test fileIO-1.10.1 {binary file data, 'ascii' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding ascii -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {tcl file_file.dat} -result {1}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid ASCII code points and the
#       Encoding class in the .NET Framework does not.
#
runTest {test fileIO-1.10.2 {binary file data, 'ascii' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding ascii -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x1 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle file_file.dat} -result {1}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid Unicode code points and
#       the Encoding class in the .NET Framework does not.
#
runTest {test fileIO-1.11.1 {binary file data, 'unicode' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding unicode -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x0 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {tcl file_file.dat} -result {1}}

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

#
# HACK: This test cannot have the same result in Tcl and Eagle because the Tcl
#       encoding subsystem appears to ignore invalid Unicode code points and
#       the Encoding class in the .NET Framework does not.
#
# HACK: *MONO* This test does not work on Mono due to bug #473899, which is
#       still present as of version 3.3.0.
#
runTest {test fileIO-1.11.2 {binary file data, 'unicode' encoding} -body {
  set fd [open [file join $test_data_path file.dat] RDONLY]
  fconfigure $fd -encoding unicode -translation binary
  set z [read $fd]
  close $fd
  expr {int([string compare $x4 $z] == 0)}
} -cleanup {
  catch {close $fd}
  unset -nocomplain fd z
} -constraints {eagle monoBug file_file.dat} -result {1}}

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

unset -nocomplain x0 x1 x2 x3 x4

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

#
# HACK: *MONO* This test does not work on Mono due to bug #478489, which is
#       still present as of version 3.3.0.
#
runTest {test fileIO-2.1.1 {file dirname} -body {
  list [file dirname .] [file dirname ..] [file dirname :C/] \
      [file dirname C:/] [file dirname C:\\] [file dirname C:\\foo] \
      [file dirname C:\\foo\\bar] [file dirname foo] [file dirname foo/bar] \
      [file dirname foo\\bar]
} -constraints {windows monoBug} -result {. . . C:/ C:/ C:/ C:/foo . foo foo}}

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

#
# HACK: *MONO* This test does not work on Mono due to bug #478489, which is
#       still present as of version 3.3.0.
#
runTest {test fileIO-2.1.2 {file dirname} -body {
  list [file dirname .] [file dirname ..] [file dirname :C/] \
      [file dirname /] [file dirname \\] [file dirname \\foo] \
      [file dirname \\foo\\bar] [file dirname foo] [file dirname foo/bar] \
      [file dirname foo\\bar]
} -constraints [fixConstraints {!windows monoBug}] -result \
{. . . / . . . . foo .}}

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

runTest {test fileIO-3.1.1 {file tail} -body {
  list [file tail C:/] [file tail C:\\] [file tail C:/foo] [file tail C:\\foo] \
      [file tail C:/foo/bar] [file tail C:\\foo\\bar]
} -constraints {windows} -result {{} {} foo foo bar bar}}

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

runTest {test fileIO-3.1.2 {file tail} -body {
  list [file tail /] [file tail \\] [file tail /foo] [file tail \\foo] \
      [file tail /foo/bar] [file tail \\foo\\bar]
} -constraints {!windows} -result \
{{} \\ foo {\foo} bar {\foo\bar}}}

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

runTest {test fileIO-4.1.1 {file normalize, trailing slashes} -body {
  list [file normalize $base_path] [file normalize [appendArgs $base_path /]] \
      [file normalize [appendArgs $base_path \\]]
} -constraints {windows} -result [list $base_path $base_path $base_path]}

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

runTest {test fileIO-4.1.2 {file normalize, trailing slashes} -body {
  list [file normalize $base_path] [file normalize [appendArgs $base_path /]] \
      [file normalize [appendArgs $base_path \\]]
} -constraints {!windows} -result [list $base_path $base_path [appendArgs \
$base_path \\]]}

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

runTest {test fileIO-4.2 {relativefilename direct ok} -body {
  package relativefilename [file join $tcl_library init.eagle]
} -constraints {eagle tcl_library_external} -result {init.eagle}}

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

runTest {test fileIO-4.3 {relativefilename nested ok} -body {
  package relativefilename [file join $tcl_library one two three.eagle]
} -constraints {eagle tcl_library_external} -result {one/two/three.eagle}}

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

runTest {test fileIO-4.4 {relativefilename direct error} -body {
  package relativefilename init.eagle
} -constraints {eagle} -returnCodes 1 -match regexp -result {^package index\
matching directory ".*?" not found$}}

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

runTest {test fileIO-4.5 {relativefilename direct mismatch error} -body {
  package relativefilename [file join [appendArgs $tcl_library 1] init.eagle]
} -constraints {eagle} -returnCodes 1 -match regexp -result {^package index\
matching directory ".*?" not found$}}

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

runTest {test fileIO-4.6 {relativefilename nested error} -body {
  package relativefilename [file join [file dirname $tcl_library] \
      one two three.eagle]
} -constraints {eagle} -returnCodes 1 -match regexp -result {^package index\
matching directory ".*?" not found$}}

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

runTest {test fileIO-4.7 {relativefilename nested mismatch error} -body {
  package relativefilename [file join [file dirname [appendArgs \
      $tcl_library 1]] one two three.eagle]
} -constraints {eagle} -returnCodes 1 -match regexp -result {^package index\
matching directory ".*?" not found$}}

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

runTest {test fileIO-4.8 {file readable/writable/executable success} -body {
  set fileName(1) [info script]

  set fileName(2) [file join $test_data_path [appendArgs \
      not-found [clock seconds] .txt]]

  list [expr {int([file readable $fileName(1)])}] \
       [expr {int([file writable $fileName(1)])}] \
       [expr {int([file executable $fileName(1)])}] \
       [expr {int([file readable $fileName(2)])}] \
       [expr {int([file writable $fileName(2)])}] \
       [expr {int([file executable $fileName(2)])}]
} -cleanup {
  unset -nocomplain fileName
} -match regexp -result {^1 (?:0|1) (?:0|1) 0 0 0$}}

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

runTest {test fileIO-4.9 {file readable/writable/executable failure} -body {
  set fileName(1) [file join $env(SystemDrive) pagefile.sys]

  list [expr {int([file readable $fileName(1)])}] \
       [expr {int([file writable $fileName(1)])}] \
       [expr {int([file executable $fileName(1)])}]
} -cleanup {
  unset -nocomplain fileName
} -constraints {windows} -result {0 0 0}}

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

runTest {test fileIO-5.1.1 {file normalize /} -body {
  file normalize /
} -constraints {windows monoBug} -result [string range [pwd] 0 2]}

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

runTest {test fileIO-5.1.2 {file normalize /} -body {
  file normalize /
} -constraints {!windows} -result {/}}

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

runTest {test fileIO-5.2.1 {file normalize .} -body {
  file normalize .
} -constraints {windows} -result [pwd]}

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

runTest {test fileIO-5.2.2 {file normalize .} -body {
  file normalize .
} -constraints {!windows} -result [pwd]}

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

runTest {test fileIO-5.3.1 {file normalize ""} -body {
  file normalize ""
} -constraints {windows} -result {}}

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

runTest {test fileIO-5.3.2 {file normalize ""} -body {
  file normalize ""
} -constraints {!windows} -result {}}

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

if {[info exists env(Eagle_HOME)]} then {
  set home $env(Eagle_HOME)
} elseif {[info exists env(HOME)]} then {
  set home $env(HOME)
} else {
  set home ""
}

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

if {[string length $home] > 0} then {
  runTest {test fileIO-5.4.1 {file normalize ~} -body {
    file normalize ~
  } -constraints {windows} -result [string map [list \\ /] $home]}

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

  runTest {test fileIO-5.4.2 {file normalize ~} -body {
    file normalize ~
  } -constraints {!windows} -result $home}
} else {
  tputs $test_channel "---- no HOME environment variable, tests skipped\n"
}

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

unset -nocomplain home

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

runTest {test fileIO-5.5 {file normalize with extra slashes} -body {
  file normalize C://does//not//exist
} -constraints {windows} -result {C:/does/not/exist}}

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

runTest {test fileIO-5.6 {file normalize with extra backslashes} -body {
  file normalize C:\\\\does\\\\not\\\\exist
} -constraints {windows} -result {C:/does/not/exist}}

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

if {[isEagle] && [haveConstraint tclShell]} then {
  #
  # NOTE: These tests were originally designed to be run from within the build
  #       directory itself.  If they are not being run from there now, issue a
  #       warning.
  #
  if {![haveConstraint quiet] && (![file exists BuildTasks] || \
      [lsearch -glob -inverse -- [list Debug* Release*] \
      [file tail [file dirname [pwd]]]] == -1)} then {
    tputs $test_channel [appendArgs \
        "==== WARNING: tests do not appear to be running from the build " \
        "directory and this may cause code coverage issues\n"]
  }

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

  set patterns [list \
      [list {} {} ~] [list {1 2 4 6 7 10} {knownIncompatibility} ""] \
      [list {} {} .] [list {3 5} {knownIncompatibility} ..] \
      [list {1 2 3 4 5 6 7 10} {knownIncompatibility} ...] [list {} {} *] \
      [list {} {} .*] [list {} {} *.*] [list {} {} *.*.*] \
      [list {} {} 0] [list {} {} B] [list {} {} b] \
      [list {} {} E] [list {} {} e] [list {} {} Z] \
      [list {} {} z] [list {} {} [appendArgs notfound [pid]]] \
      [list {} {} [appendArgs *notfound [pid] *]] \
      [list {} {} [appendArgs .notfound [pid]]] \
      [list {} {} [appendArgs ..notfound [pid]]] \
      [list {} {} "BuildTasks{,.not}"] [list {} {} "Ea*{.exe,.pdb}"] \
      [list {} {} "Ea*{,.exe,.pdb}"] [list {} {} "Ea*{.exe,.pdb,}"] \
      [list {} {} "Ea*{}"] [list {} {} "Ea*{Name}*e"] \
      [list {} {} "S*{.exe}"] [list {} {} "Eagle{.dll,.pdb}"] \
      [list {} {} "System.Data.SQLite{.exe}"]]

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

  for {set index(0) 0} {$index(0) < [llength $patterns]} {incr index(0)} {
    set indexes [lindex [lindex $patterns $index(0)] 0]
    set constraint [lindex [lindex $patterns $index(0)] 1]
    set pattern [lindex [lindex $patterns $index(0)] 2]

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

    set index(2) [expr {$index(0) + 1}]
    set index(1) 0; incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" only"] -body {
      string equal [lsort [glob -noerror $pattern]] [lsort \
          [evalWithTclShell [list glob -nocomplain $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}

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

    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -directory"] -body {
      string equal [lsort [glob -noerror -directory . $pattern]] [lsort \
          [evalWithTclShell [list glob -nocomplain -directory . $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}

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

    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -path"] -body {
      string equal [lsort [glob -noerror -path . $pattern]] [lsort \
          [evalWithTclShell [list glob -nocomplain -path . $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}

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

    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -directory and -tails"] -body {
      string equal [lsort [glob -noerror -directory . -tails $pattern]] \
          [lsort [evalWithTclShell [list glob -nocomplain -directory . \
          -tails $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}

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

    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -path and -tails"] -body {
      string equal [lsort [glob -noerror -path . -tails $pattern]] \
          [lsort [evalWithTclShell [list glob -nocomplain -path . \
          -tails $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}

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

    #
    # MONO: Due to a Mono bug, this test is disabled on Mono; however, not
    #       all patterns cause this test to fail there.  The patterns with
    #       indexes 10-17, 19, and 20 all fail as of Mono 3.2.3.
    #
    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -join (all)"] -body {
      string equal [lsort [glob -noerror -join $pattern *]] [lsort \
          [evalWithTclShell [list glob -nocomplain -join $pattern *]]]
    } -constraints [eval lappendArgs {eagle tclShell monoBug} \
        $thisConstraint] -result {True}}

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

    #
    # MONO: Due to a Mono bug, this test is disabled on Mono; however, not
    #       all patterns cause this test to fail there.  The patterns with
    #       indexes 10-17, 19, and 20 all fail as of Mono 3.2.3.
    #
    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -join (some)"] -body {
      string equal [lsort [glob -noerror -join $pattern E*]] [lsort \
          [evalWithTclShell [list glob -nocomplain -join $pattern E*]]]
    } -constraints [eval lappendArgs {eagle tclShell monoBug} \
        $thisConstraint] -result {True}}

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

    #
    # MONO: Due to a Mono bug, this test is disabled on Mono; however, not
    #       all patterns cause this test to fail there.  The patterns with
    #       indexes 10-17, 19, and 20 all fail as of Mono 3.2.3.
    #
    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -join (none)"] -body {
      string equal [lsort [glob -noerror -join $pattern ZZ]] [lsort \
          [evalWithTclShell [list glob -nocomplain -join $pattern ZZ]]]
    } -constraints [eval lappendArgs {eagle tclShell monoBug} \
        $thisConstraint] -result {True}}

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

    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -types {f}"] -body {
      string equal [lsort [glob -noerror -types {f} $pattern]] [lsort \
          [evalWithTclShell [list glob -nocomplain -types {f} $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}

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

    incr index(1)
    set thisConstraint [expr {$index(1) in $indexes ? $constraint : ""}]

    runTest {test [appendArgs glob-99. $index(2) . $index(1)] [appendArgs \
        "pattern \"" $pattern "\" with -types {d}"] -body {
      string equal [lsort [glob -noerror -types {d} $pattern]] [lsort \
          [evalWithTclShell [list glob -nocomplain -types {d} $pattern]]]
    } -constraints [eval lappendArgs {eagle tclShell} $thisConstraint] \
        -result {True}}
  }

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

  unset -nocomplain thisConstraint pattern constraint indexes index patterns
}

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

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