# Commands covered:  file
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1994 The Regents of the University of California.
# Copyright (c) 1994 Sun Microsystems, Inc.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# @(#) file.test 1.25 94/12/17 16:19:56

if {[string compare test [info procs test]] == 1} then {source defs}

# rootname and ext

test file-1.1 {rootname and extension options} {file ext abc.def} .def
test file-1.2 {rootname and extension options} {file ro abc.def} abc
test file-1.3 {rootname and extension options} {file extension a/b/c.d} .d
test file-1.4 {rootname and extension options} {file rootname a/b/c.d} a/b/c
test file-1.5 {rootname and extension options} {file extension a/b.c/d} {}
test file-1.6 {rootname and extension options} {file rootname a/b.c/d} a/b.c/d
set num 7
foreach outer { {} a .a a. a.a } {
  foreach inner { {} a .a a. a.a } {
    set thing [format %s/%s $outer $inner]
    test file-1.$num {rootname and extension options} {
	format %s%s [file rootname $thing] [file ext $thing]
    } $thing
    set num [expr $num+1]
  }
}

# dirname and tail

test file-2.1 {dirname and tail options} {file dirname .def} .
test file-2.2 {dirname and tail options} {file tail abc.def} abc.def
test file-2.3 {dirname and tail options} {file d a/b/c.d} a/b
test file-2.4 {dirname and tail options} {file ta a/b/c.d} c.d
test file-2.5 {dirname and tail options} {file dirname a/b.c/d} a/b.c
test file-2.6 {dirname and tail options} {file tail a/b.c/d} d
set num 7
foreach outer { a .a a. a.a } {
  foreach inner { {} a .a a. a.a } {
    set thing [format %s/%s $outer $inner]
    test file-2.$num {dirname and tail options} {
	format %s/%s [file dirname $thing] [file tail $thing]
    } $thing
    set num [expr $num+1]
  }
}

# exists
 
catch {exec chmod 777 dir.file}
catch {exec rm -f dir.file/gorp.file}
catch {exec rm -f gorp.file}
catch {exec rmdir dir.file}
catch {exec rm -f link.file}
test file-3.1 {exists option} {file exists gorp.file} 0
test file-3.2 {exists option} {file exists dir.file/gorp.file} 0
exec cat > gorp.file << abcde
exec mkdir dir.file
exec cat > dir.file/gorp.file << 12345
test file-3.3 {exists option} {file exists gorp.file} 1
test file-3.4 {exists option} {file exi dir.file/gorp.file} 1

# The test below has to be done in /tmp rather than the current
# directory in order to guarantee (?) a local file system:  some
# NFS file systems won't do the stuff below correctly.

catch {exec rm /tmp/tcl.foo.dir/file}
catch {exec rmdir /tmp/tcl.foo.dir}
exec mkdir /tmp/tcl.foo.dir
exec cat > /tmp/tcl.foo.dir/file << 12345
exec chmod 000 /tmp/tcl.foo.dir
if {$user != "root"} {
    test file-3.5 {exists option} {file exists /tmp/tcl.foo.dir/file} 0
}
exec chmod 775 /tmp/tcl.foo.dir
exec rm /tmp/tcl.foo.dir/file
exec rmdir /tmp/tcl.foo.dir

# executable

exec chmod 000 dir.file
if {$user != "root"} {
    test file-4.1 {executable option} {file executable gorp.file} 0
}
exec chmod 775 gorp.file
test file-4.2 {executable option} {file exe gorp.file} 1

# isdirectory

test file-5.1 {isdirectory option} {file isdirectory gorp.file} 0
test file-5.2 {isdirectory option} {file isd dir.file} 1

# isfile

test file-6.1 {isfile option} {file isfile gorp.file} 1
test file-6.2 {isfile option} {file isfile dir.file} 0

# isowned

test file-7.1 {owned option} {file owned gorp.file} 1
if {$user != "root"} {
    test file-7.2 {owned option} {file owned /} 0
}

# readable

exec chmod 444 gorp.file
test file-8.1 {readable option} {file readable gorp.file} 1
exec chmod 333 gorp.file
if {$user != "root"} {
    test file-8.2 {readable option} {file reada gorp.file} 0
}

# writable

exec chmod 555 gorp.file
if {$user != "root"} {
    test file-9.1 {writable option} {file writable gorp.file} 0
}
exec chmod 222 gorp.file
test file-9.2 {writable option} {file w gorp.file} 1

# stat

exec cat > gorp.file << "Test string"
exec chmod 765 gorp.file
test file-10.1 {stat option} {
    catch {unset stat}
    file stat gorp.file stat
    lsort [array names stat]
} {atime ctime dev gid ino mode mtime nlink size type uid}
test file-10.2 {stat option} {
    catch {unset stat}
    file stat gorp.file stat
    list $stat(nlink) $stat(size) [expr $stat(mode)&0777] $stat(type)
} {1 11 501 file}
test file-10.3 {stat option} {
    string tolower [list [catch {file stat _bogus_ stat} msg] \
	    $msg $errorCode]
} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
test file-10.4 {stat option} {
    list [catch {file stat _bogus_} msg] $msg $errorCode
} {1 {wrong # args: should be "file stat name varName"} NONE}
test file-10.5 {stat option} {
    list [catch {file stat _bogus_ a b} msg] $msg $errorCode
} {1 {wrong # args: should be "file stat name varName"} NONE}
test file-10.6 {stat option} {
    catch {unset x}
    set x 44
    list [catch {file stat gorp.file x} msg] $msg $errorCode
} {1 {can't set "x(dev)": variable isn't array} NONE}
catch {unset stat}

# mtime, and size (I've given up trying to find a test for "atime":  there
# seem to be too many quirks in the way file systems handle this to come
# up with a reproducible test).

test file-11.1 {mtime and atime and size options} {
    catch {unset stat}
    file stat gorp.file stat
    list [expr {[file mtime gorp.file] == $stat(mtime)}] \
	    [expr {[file atime gorp.file] == $stat(atime)}] \
	    [file size gorp.file]
} {1 1 11}
test file-11.2 {mtime option} {
    set old [file mtime gorp.file]
    exec sleep 2
    set f [open gorp.file w]
    puts $f "More text"
    close $f
    set new [file mtime gorp.file]
    expr {($new > $old) && ($new <= ($old+5))}
} {1}
test file-11.3 {size option} {
    set oldsize [file size gorp.file]
    set f [open gorp.file a]
    puts $f "More text"
    close $f
    expr {[file size gorp.file] - $oldsize}
} {10}
test file-11.4 {errors in atime option} {
    list [catch {file atime _bogus_ x} msg] $msg $errorCode
} {1 {wrong # args: should be "file atime name"} NONE}
test file-11.5 {errors in atime option} {
    string tolower [list [catch {file atime _bogus_} msg] \
	    $msg $errorCode]
} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
test file-11.6 {errors in mtime option} {
    list [catch {file mtime _bogus_ x} msg] $msg $errorCode
} {1 {wrong # args: should be "file mtime name"} NONE}
test file-11.7 {errors in mtime option} {
    string tolower [list [catch {file mtime _bogus_} msg] $msg \
	    $errorCode]
} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
test file-11.8 {errors in size option} {
    list [catch {file size _bogus_ x} msg] $msg $errorCode
} {1 {wrong # args: should be "file size name"} NONE}
test file-11.9 {errors in size option} {
    string tolower [list [catch {file size _bogus_} msg] $msg \
	    $errorCode]
} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}

# type

test file-12.1 {type option} {
    file type dir.file
} directory
test file-12.2 {type option} {
    file type gorp.file
} file
if $doNonPortableTests {
    exec ln -s a/b/c link.file
    test file-12.3 {type option} {
	file type link.file
    } link
    exec rm link.file
}
test file-12.4 {errors in type option} {
    list [catch {file type a b} msg] $msg $errorCode
} {1 {wrong # args: should be "file type name"} NONE}
test file-12.5 {errors in type option} {
    string tolower [list [catch {file type _bogus_} msg] $msg $errorCode]
} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}

# lstat and readlink:  don't run these tests everywhere, since not all
# sites will have symbolic links

if $doNonPortableTests {
    exec ln -s gorp.file link.file
    test file-13.1 {lstat option} {
	catch {unset stat}
	file lstat link.file stat
	lsort [array names stat]
    } {atime ctime dev gid ino mode mtime nlink size type uid}
    test file-13.1 {lstat option} {
	catch {unset stat}
	file lstat link.file stat
	list $stat(nlink) [expr $stat(mode)&0777] $stat(type)
    } {1 511 link}
    test file-13.3 {errors in lstat option} {
	string tolower [list [catch {file lstat _bogus_ stat} msg] \
		$msg $errorCode]
    } {1 {couldn't lstat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
    test file-13.4 {errors in lstat option} {
	list [catch {file lstat _bogus_} msg] $msg $errorCode
    } {1 {wrong # args: should be "file lstat name varName"} NONE}
    test file-13.5 {errors in lstat option} {
	list [catch {file lstat _bogus_ a b} msg] $msg $errorCode
    } {1 {wrong # args: should be "file lstat name varName"} NONE}
    test file-13.6 {errors in lstat option} {
	catch {unset x}
	set x 44
	list [catch {file lstat gorp.file x} msg] $msg $errorCode
    } {1 {can't set "x(dev)": variable isn't array} NONE}
    catch {unset stat}

    test file-14.1 {readlink option} {
	file readlink link.file
    } gorp.file
    test file-14.2 {errors in readlink option} {
	list [catch {file readlink a b} msg] $msg $errorCode
    } {1 {wrong # args: should be "file readlink name"} NONE}
    test file-14.3 {errors in readlink option} {
	list [catch {file readlink _bogus_} msg] [string tolower $msg] \
		[string tolower $errorCode]
    } {1 {couldn't readlink "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}

    exec rm link.file
}

# Error conditions

test file-15.1 {error conditions} {
    list [catch file msg] $msg
} {1 {wrong # args: should be "file option name ?arg ...?"}}
test file-15.2 {error conditions} {
    list [catch {file x} msg] $msg
} {1 {wrong # args: should be "file option name ?arg ...?"}}
test file-15.3 {error conditions} {
    list [catch {file exists x too} msg] $msg
} {1 {wrong # args: should be "file exists name"}}
test file-15.4 {error conditions} {
    list [catch {file gorp x} msg] $msg
} {1 {bad option "gorp": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
test file-15.5 {error conditions} {
    list [catch {file ex x} msg] $msg
} {1 {bad option "ex": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
test file-15.6 {error conditions} {
    list [catch {file is x} msg] $msg
} {1 {bad option "is": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
test file-15.7 {error conditions} {
    list [catch {file read x} msg] $msg
} {1 {bad option "read": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
test file-15.8 {error conditions} {
    list [catch {file s x} msg] $msg
} {1 {bad option "s": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
test file-15.9 {error conditions} {
    list [catch {file t x} msg] $msg
} {1 {bad option "t": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
test file-15.10 {error conditions} {
    list [catch {file rootname ~woohgy} msg] $msg
} {1 {user "woohgy" doesn't exist}}

exec chmod 777 dir.file
exec rm dir.file/gorp.file gorp.file
exec rmdir dir.file
