1#
2# winPipe.test --
3#
4# This file contains a collection of tests for tclWinPipe.c
5#
6# Sourcing this file into Tcl runs the tests and generates output for errors.
7# No output (except for one message) means no errors were found.
8#
9# Copyright © 1996 Sun Microsystems, Inc.
10# Copyright © 1998-1999 Scriptics Corporation.
11#
12# See the file "license.terms" for information on usage and redistribution of
13# this file, and for a DISCLAIMER OF ALL WARRANTIES.
14
15if {"::tcltest" ni [namespace children]} {
16    package require tcltest 2.5
17    namespace import -force ::tcltest::*
18}
19unset -nocomplain path
20
21catch {
22    ::tcltest::loadTestedCommands
23    package require -exact tcl::test [info patchlevel]
24    set ::tcltestlib [info loaded {} Tcltest]
25}
26
27set org_pwd [pwd]
28set bindir [file join $org_pwd [file dirname [info nameofexecutable]]]
29set cat32 [file join $bindir cat32.exe]
30
31testConstraint notWine [expr {![info exists ::env(CI_USING_WINE)]}]
32
33
34# several test-cases here expect current directory == [temporaryDirectory]:
35cd [temporaryDirectory]
36
37testConstraint exec         [llength [info commands exec]]
38testConstraint cat32        [file exists $cat32]
39testConstraint AllocConsole [catch {puts console1 ""}]
40testConstraint RealConsole  [expr {![testConstraint AllocConsole]}]
41testConstraint testexcept   [llength [info commands testexcept]]
42testConstraint slowTest     0
43
44
45set big bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n
46append big $big
47append big $big
48append big $big
49append big $big
50append big $big
51append big $big
52
53set path(little) [makeFile {} little]
54set f [open $path(little) w]
55puts -nonewline $f "little"
56close $f
57
58set path(big) [makeFile {} big]
59set f [open $path(big) w]
60puts -nonewline $f $big
61close $f
62
63proc contents {file} {
64    set f [open $file r]
65    set r [read $f]
66    close $f
67    set r
68}
69
70set path(more) [makeFile {
71    while {[eof stdin] == 0} {
72	puts -nonewline [read stdin]
73    }
74} more]
75
76set path(stdout) [makeFile {} stdout]
77set path(stderr) [makeFile {} stderr]
78
79test winpipe-1.1 {32 bit comprehensive tests: from little file} {win exec cat32} {
80    exec $cat32 < $path(little) > $path(stdout) 2> $path(stderr)
81    list [contents $path(stdout)] [contents $path(stderr)]
82} {little stderr32}
83test winpipe-1.2 {32 bit comprehensive tests: from big file} {win exec cat32} {
84    exec $cat32 < $path(big) > $path(stdout) 2> $path(stderr)
85    list [contents $path(stdout)] [contents $path(stderr)]
86} "{$big} stderr32"
87test winpipe-1.3 {32 bit comprehensive tests: a little from pipe} {win exec cat32} {
88    exec [interpreter] $path(more) < $path(little) | $cat32 > $path(stdout) 2> $path(stderr)
89    list [contents $path(stdout)] [contents $path(stderr)]
90} {little stderr32}
91test winpipe-1.4 {32 bit comprehensive tests: a lot from pipe} {win exec cat32} {
92    exec [interpreter] $path(more) < $path(big) | $cat32 > $path(stdout) 2> $path(stderr)
93    list [contents $path(stdout)] [contents $path(stderr)]
94} "{$big} stderr32"
95test winpipe-1.6 {32 bit comprehensive tests: from console} \
96	{win cat32 AllocConsole} {
97    # would block waiting for human input
98} {}
99test winpipe-1.7 {32 bit comprehensive tests: from NUL} {win exec cat32} {
100    exec $cat32 < nul > $path(stdout) 2> $path(stderr)
101    list [contents $path(stdout)] [contents $path(stderr)]
102} {{} stderr32}
103test winpipe-1.8 {32 bit comprehensive tests: from socket} {win cat32} {
104    # doesn't work
105} {}
106test winpipe-1.9 {32 bit comprehensive tests: from nowhere} \
107	{win exec cat32 RealConsole} {
108    exec $cat32 > $path(stdout) 2> $path(stderr)
109    list [contents $path(stdout)] [contents $path(stderr)]
110} {{} stderr32}
111test winpipe-1.10 {32 bit comprehensive tests: from file handle} \
112	{win exec cat32} {
113    set f [open $path(little) r]
114    exec $cat32 <@$f > $path(stdout) 2> $path(stderr)
115    close $f
116    list [contents $path(stdout)] [contents $path(stderr)]
117} {little stderr32}
118test winpipe-1.11 {32 bit comprehensive tests: read from application} \
119	{win exec cat32} {
120    set f [open "|[list $cat32] < [list $path(little)]" r]
121    gets $f line
122    catch {close $f} msg
123    list $line $msg
124} {little stderr32}
125test winpipe-1.12 {32 bit comprehensive tests: a little to file} \
126	{win exec cat32} {
127    exec $cat32 < $path(little) > $path(stdout) 2> $path(stderr)
128    list [contents $path(stdout)] [contents $path(stderr)]
129} {little stderr32}
130test winpipe-1.13 {32 bit comprehensive tests: a lot to file} \
131	{win exec cat32} {
132    exec $cat32 < $path(big) > $path(stdout) 2> $path(stderr)
133    list [contents $path(stdout)] [contents $path(stderr)]
134} "{$big} stderr32"
135test winpipe-1.14 {32 bit comprehensive tests: a little to pipe} \
136	{win exec stdio cat32} {
137    exec $cat32 < $path(little) | [interpreter] $path(more) > $path(stdout) 2> $path(stderr)
138    list [contents $path(stdout)] [contents $path(stderr)]
139} {little stderr32}
140test winpipe-1.15 {32 bit comprehensive tests: a lot to pipe} \
141	{win exec stdio cat32} {
142    exec $cat32 < $path(big) | [interpreter] $path(more) > $path(stdout) 2> $path(stderr)
143    list [contents $path(stdout)] [contents $path(stderr)]
144} "{$big} stderr32"
145test winpipe-1.16 {32 bit comprehensive tests: to console} {win exec cat32} {
146    catch {exec $cat32 << "You should see this\n" >@stdout} msg
147    set msg
148} stderr32
149test winpipe-1.17 {32 bit comprehensive tests: to NUL} {win exec cat32} {
150    # some apps hang when sending a large amount to NUL.  $cat32 isn't one.
151    catch {exec $cat32 < $path(big) > nul} msg
152    set msg
153} stderr32
154test winpipe-1.18 {32 bit comprehensive tests: to nowhere} \
155	{win exec cat32 RealConsole} {
156    exec $cat32 < $path(big) >&@stdout
157} {}
158test winpipe-1.19 {32 bit comprehensive tests: to file handle} {win exec cat32} {
159    set f1 [open $path(stdout) w]
160    set f2 [open $path(stderr) w]
161    exec $cat32 < $path(little) >@$f1 2>@$f2
162    close $f1
163    close $f2
164    list [contents $path(stdout)] [contents $path(stderr)]
165} {little stderr32}
166test winpipe-1.20 {32 bit comprehensive tests: write to application} \
167	{win exec cat32} {
168    set f [open |[list $cat32 >$path(stdout)] w]
169    puts -nonewline $f "foo"
170    catch {close $f} msg
171    list [contents $path(stdout)] $msg
172} {foo stderr32}
173test winpipe-1.21 {32 bit comprehensive tests: read/write application} \
174	{win exec cat32} {
175    set f [open "|[list $cat32]" r+]
176    puts $f $big
177    puts $f \x1A
178    flush $f
179    set r [read $f 64]
180    catch {close $f}
181    set r
182} "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
183
184test winpipe-4.1 {Tcl_WaitPid} {win exec cat32} {
185    proc readResults {f} {
186	global x result
187	if { [eof $f] } {
188	    close $f
189	    set x 1
190	} else {
191	    set line [read $f ]
192	    set result "$result$line"
193	}
194    }
195    set f [open "|[list $cat32] < $path(big) 2> $path(stderr)" r]
196    fconfigure $f  -buffering none -blocking 0
197    fileevent $f readable "readResults $f"
198    set x 0
199    set result ""
200    vwait x
201    list $result $x [contents $path(stderr)]
202} "{$big} 1 stderr32"
203test winpipe-4.2 {Tcl_WaitPid: return of exception codes, SIGFPE} {win exec testexcept notWine} {
204    set f [open "|[list [interpreter]]" w+]
205    set pid [pid $f]
206    puts $f "load $::tcltestlib Tcltest"
207    puts $f "testexcept float_underflow"
208    set status [catch {close $f}]
209    list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2]
210} {1 1 SIGFPE}
211test winpipe-4.3 {Tcl_WaitPid: return of exception codes, SIGSEGV} {win exec testexcept notWine} {
212    set f [open "|[list [interpreter]]" w+]
213    set pid [pid $f]
214    puts $f "load $::tcltestlib Tcltest"
215    puts $f "testexcept access_violation"
216    set status [catch {close $f}]
217    list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2]
218} {1 1 SIGSEGV}
219test winpipe-4.4 {Tcl_WaitPid: return of exception codes, SIGILL} {win exec testexcept notWine} {
220    set f [open "|[list [interpreter]]" w+]
221    set pid [pid $f]
222    puts $f "load $::tcltestlib Tcltest"
223    puts $f "testexcept illegal_instruction"
224    set status [catch {close $f}]
225    list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2]
226} {1 1 SIGILL}
227test winpipe-4.5 {Tcl_WaitPid: return of exception codes, SIGINT} {win exec testexcept notWine} {
228    set f [open "|[list [interpreter]]" w+]
229    set pid [pid $f]
230    puts $f "load $::tcltestlib Tcltest"
231    puts $f "testexcept ctrl+c"
232    set status [catch {close $f}]
233    list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2]
234} {1 1 SIGINT}
235
236set path(nothing) [makeFile {} nothing]
237close [open $path(nothing) w]
238
239catch {set env_tmp $env(TMP)}
240catch {set env_temp $env(TEMP)}
241
242set env(TMP) c:/
243set env(TEMP) c:/
244
245test winpipe-5.1 {TclpCreateTempFile: cleanup temp files} {win exec} {
246    set x {}
247    set existing [glob -nocomplain c:/tcl*.tmp]
248    exec [interpreter] < $path(nothing)
249    foreach p [glob -nocomplain c:/tcl*.tmp] {
250	if {$p ni $existing} {
251	    lappend x $p
252	}
253    }
254    set x
255} {}
256test winpipe-5.2 {TclpCreateTempFile: TMP and TEMP not defined} {win exec} {
257    set tmp $env(TMP)
258    set temp $env(TEMP)
259    unset env(TMP)
260    unset env(TEMP)
261    exec [interpreter] < $path(nothing)
262    set env(TMP) $tmp
263    set env(TEMP) $temp
264    set x {}
265} {}
266test winpipe-5.3 {TclpCreateTempFile: TMP specifies non-existent directory} \
267	{win exec } {
268    set tmp $env(TMP)
269    set env(TMP) snarky
270    exec [interpreter] < $path(nothing)
271    set env(TMP) $tmp
272    set x {}
273} {}
274test winpipe-5.4 {TclpCreateTempFile: TEMP specifies non-existent directory} \
275	{win exec} {
276    set tmp $env(TMP)
277    set temp $env(TEMP)
278    unset env(TMP)
279    set env(TEMP) snarky
280    exec [interpreter] < $path(nothing)
281    set env(TMP) $tmp
282    set env(TEMP) $temp
283    set x {}
284} {}
285
286test winpipe-6.1 {PipeSetupProc & PipeCheckProc: read threads} \
287	{win exec cat32} {
288    set f [open "|[list $cat32]" r+]
289    fconfigure $f -blocking 0
290    fileevent $f writable { set x writable }
291    set x {}
292    vwait x
293    fileevent $f writable {}
294    fileevent $f readable { lappend x readable }
295    after 100 { lappend x timeout }
296    vwait x
297    puts $f foobar
298    flush $f
299    vwait x
300    lappend x [read $f]
301    after 100 { lappend x timeout }
302    vwait x
303    fconfigure $f -blocking 1
304    lappend x [catch {close $f} msg] $msg
305} {writable timeout readable {foobar
306} timeout 1 stderr32}
307test winpipe-6.2 {PipeSetupProc & PipeCheckProc: write threads} \
308	{win exec cat32} {
309    set f [open "|[list $cat32]" r+]
310    fconfigure $f -blocking 0
311    fileevent $f writable { set x writable }
312    set x {}
313    vwait x
314    puts -nonewline $f $big$big$big$big
315    flush $f
316    after 100 { lappend x timeout }
317    vwait x
318    lappend x [catch {close $f} msg] $msg
319} {writable timeout 0 {}}
320
321proc _testExecArgs {single args} {
322    variable path
323    if {![info exists path(echoArgs.tcl)] || ![file exists $path(echoArgs.tcl)]} {
324	set path(echoArgs.tcl) [makeFile {
325	    puts "[list [file tail $argv0] {*}$argv]"
326	} echoArgs.tcl]
327    }
328    if {![info exists path(echoArgs.bat)] || ![file exists $path(echoArgs.bat)]} {
329	set path(echoArgs.bat) [makeFile "@[file native [interpreter]] $path(echoArgs.tcl) %*" "echoArgs.bat"]
330    }
331    set cmds [list [list [interpreter] $path(echoArgs.tcl)]]
332    if {!($single & 2)} {
333	lappend cmds [list $path(echoArgs.bat)]
334    } else {
335	if {![info exists path(echoArgs2.bat)] || ![file exists $path(echoArgs2.bat)]} {
336	    set path(echoArgs2.bat) [makeFile \
337		"@[file native [interpreter]] $path(echoArgs.tcl) %*" \
338		"echo(Cmd)Test Args & Batch.bat" [makeDirectory test(Dir)Check]]
339	}
340	lappend cmds [list $path(echoArgs2.bat)]
341    }
342    set broken {}
343    foreach args $args {
344	if {$single & 1} {
345	    # enclose single test-arg between 1st/3rd to be sure nothing is truncated
346	    # (e. g. to cover unexpected trim by nts-zero case, and args don't recombined):
347	    set args [list "1st" $args "3rd"]
348	}
349	set args [list {*}$args]; # normalized canonical list
350	foreach cmd $cmds {
351	    set e [linsert $args 0 [file tail $path(echoArgs.tcl)]]
352	    tcltest::DebugPuts 4 "  ## test exec [file extension [lindex $cmd 0]] ($cmd) for\n  ##   $args"
353	    if {[catch {
354		exec {*}$cmd {*}$args
355	    } r]} {
356		set r "ERROR: $r"
357	    }
358	    if {$r ne $e} {
359		append broken "\[ERROR\]: exec [file extension [lindex $cmd 0]] on $args\n  -- result:\n$r\n  -- expected:\n$e\n"
360	    }
361	    if {$single & 8} {
362		# if test exe only:
363		break
364	    }
365	}
366    }
367    return $broken
368}
369
370### validate the raw output of BuildCommandLine().
371###
372test winpipe-7.1 {BuildCommandLine: null arguments} {win exec} {
373    exec $env(COMSPEC) /c echo foo "" bar
374} {foo "" bar}
375test winpipe-7.2 {BuildCommandLine: null arguments} {win exec} {
376    exec $env(COMSPEC) /c echo foo {} bar
377} {foo "" bar}
378test winpipe-7.3 {BuildCommandLine: dbl quote quoting #1} {win exec} {
379    exec $env(COMSPEC) /c echo foo "\"" bar
380} {foo \" bar}
381test winpipe-7.4 {BuildCommandLine: dbl quote quoting #2} {win exec} {
382    exec $env(COMSPEC) /c echo foo {""} bar
383} {foo \"\" bar}
384test winpipe-7.5 {BuildCommandLine: dbl quote quoting #3} {win exec} {
385    exec $env(COMSPEC) /c echo foo "\" " bar
386} {foo "\" " bar}
387test winpipe-7.6 {BuildCommandLine: dbl quote quoting #4} {win exec} {
388    exec $env(COMSPEC) /c echo foo {a="b"} bar
389} {foo a=\"b\" bar}
390test winpipe-7.7 {BuildCommandLine: dbl quote quoting #5} {win exec} {
391    exec $env(COMSPEC) /c echo foo {a = "b"} bar
392} {foo "a = \"b\"" bar}
393test winpipe-7.8 {BuildCommandLine: dbl quote quoting #6} {win exec} {
394    exec $env(COMSPEC) /c echo {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} "he \" llo"
395} {\"hello\" \"\"hello\"\" \"\"\"hello\"\"\" \"\\\"hello\\\"\" "he llo" "he \" llo"}
396test winpipe-7.9 {BuildCommandLine: N backslashes followed a quote rule #1} {win exec} {
397    exec $env(COMSPEC) /c echo foo \\ bar
398} {foo \ bar}
399test winpipe-7.10 {BuildCommandLine: N backslashes followed a quote rule #2} {win exec} {
400    exec $env(COMSPEC) /c echo foo \\\\ bar
401} {foo \\ bar}
402test winpipe-7.11 {BuildCommandLine: N backslashes followed a quote rule #3} {win exec} {
403    exec $env(COMSPEC) /c echo foo \\\ \\ bar
404} {foo "\ \\" bar}
405test winpipe-7.12 {BuildCommandLine: N backslashes followed a quote rule #4} {win exec} {
406    exec $env(COMSPEC) /c echo foo \\\ \\\\ bar
407} {foo "\ \\\\" bar}
408test winpipe-7.13 {BuildCommandLine: N backslashes followed a quote rule #5} {win exec} {
409    exec $env(COMSPEC) /c echo foo \\\ \\\\\\ bar
410} {foo "\ \\\\\\" bar}
411test winpipe-7.14 {BuildCommandLine: N backslashes followed a quote rule #6} {win exec} {
412    exec $env(COMSPEC) /c echo foo \\\ \\\" bar
413} {foo "\ \\\"" bar}
414test winpipe-7.15 {BuildCommandLine: N backslashes followed a quote rule #7} {win exec} {
415    exec $env(COMSPEC) /c echo foo \\\ \\\\\" bar
416} {foo "\ \\\\\"" bar}
417test winpipe-7.16 {BuildCommandLine: N backslashes followed a quote rule #8} {win exec} {
418    exec $env(COMSPEC) /c echo foo \\\ \\\\\\\" bar
419} {foo "\ \\\\\\\"" bar}
420test winpipe-7.17 {BuildCommandLine: special chars #4} {win exec} {
421    exec $env(COMSPEC) /c echo foo \{ bar
422} "foo \{ bar"
423test winpipe-7.18 {BuildCommandLine: special chars #5} {win exec} {
424    exec $env(COMSPEC) /c echo foo \} bar
425} "foo \} bar"
426
427set injectList {
428    {test"whoami}     {test""whoami}
429    {test"""whoami}   {test""""whoami}
430
431    "test\"whoami\\"     "test\"\"whoami\\"
432    "test\"\"\"whoami\\" "test\"\"\"\"whoami\\"
433
434    {test\\&\\test}    {test"\\&\\test}
435    {"test\\&\\test}   {"test"\\&\\"test"}
436    {test\\"&"\\test}  {test"\\"&"\\test}
437    {"test\\"&"\\test} {"test"\\"&"\\"test"}
438
439    {test\"&whoami}    {test"\"&whoami}
440    {test""\"&whoami}  {test"""\"&whoami}
441    {test\"\&whoami}   {test"\"\&whoami}
442    {test""\"\&whoami} {test"""\"\&whoami}
443
444    {test&whoami}    {test|whoami}
445    {"test&whoami}   {"test|whoami}
446    {test"&whoami}   {test"|whoami}
447    {"test"&whoami}  {"test"|whoami}
448    {""test"&whoami} {""test"|whoami}
449
450    {test&echo "}    {test|echo "}
451    {"test&echo "}   {"test|echo "}
452    {test"&echo "}   {test"|echo "}
453    {"test"&echo "}  {"test"|echo "}
454    {""test"&echo "} {""test"|echo "}
455
456    {test&echo ""}    {test|echo ""}
457    {"test&echo ""}   {"test|echo ""}
458    {test"&echo ""}   {test"|echo ""}
459    {"test"&echo ""}  {"test"|echo ""}
460    {""test"&echo ""} {""test"|echo ""}
461
462    {test>whoami}    {test<whoami}
463    {"test>whoami}   {"test<whoami}
464    {test">whoami}   {test"<whoami}
465    {"test">whoami}  {"test"<whoami}
466    {""test">whoami} {""test"<whoami}
467    {test(whoami)}   {test(whoami)}
468    {test"(whoami)}  {test"(whoami)}
469    {test^whoami}    {test^^echo ^^^}
470    {test"^whoami}   {test"^^echo ^^^}
471    {test"^echo ^^^"} {test""^echo" ^^^"}
472
473    {test%USERDOMAIN%\%USERNAME%}
474    {test" %USERDOMAIN%\%USERNAME%}
475    {test%USERDOMAIN%\\%USERNAME%}
476    {test" %USERDOMAIN%\\%USERNAME%}
477    {test%USERDOMAIN%&%USERNAME%}
478    {test" %USERDOMAIN%&%USERNAME%}
479    {test%USERDOMAIN%\&\%USERNAME%}
480    {test" %USERDOMAIN%\&\%USERNAME%}
481
482    {test%USERDOMAIN%\&\test}
483    {test" %USERDOMAIN%\&\test}
484    {test%USERDOMAIN%\\&\\test}
485    {test" %USERDOMAIN%\\&\\test}
486
487    {test%USERDOMAIN%\&\"test}
488    {test" %USERDOMAIN%\&\"test}
489    {test%USERDOMAIN%\\&\\"test}
490    {test" %USERDOMAIN%\\&\\"test}
491}
492
493### validate the pass-thru from BuildCommandLine() to the crt's parse_cmdline().
494###
495test winpipe-8.1 {BuildCommandLine/parse_cmdline pass-thru: dumped arguments are equal original} \
496-constraints {win exec} -body {
497    _testExecArgs 0 \
498	[list foo "" bar] \
499	[list foo {} bar] \
500	[list foo "\"" bar] \
501	[list foo {""} bar] \
502	[list foo "\" " bar] \
503	[list foo {a="b"} bar] \
504	[list foo {a = "b"} bar] \
505	[list {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo}] \
506	[list foo \\ bar] \
507	[list foo \\\\ bar] \
508	[list foo \\\ \\ bar] \
509	[list foo \\\ \\\\ bar] \
510	[list foo \\\ \\\\\\ bar] \
511	[list foo \\\ \\\" bar] \
512	[list foo \\\ \\\\\" bar] \
513	[list foo \\\ \\\\\\\" bar] \
514	[list foo \{ bar] \
515	[list foo \} bar] \
516	[list foo * makefile.?c bar]
517} -result {}
518
519test winpipe-8.2 {BuildCommandLine/parse_cmdline pass-thru: check injection on special meta-chars (particular)} \
520-constraints {win exec slowTest} -body {
521    _testExecArgs 1 {*}$injectList
522} -result {}
523
524test winpipe-8.3 {BuildCommandLine/parse_cmdline pass-thru: check injection on special meta-chars (jointly)} \
525-constraints {win exec notWine} -body {
526    _testExecArgs 0 \
527	[list START     {*}$injectList END] \
528	[list "START\"" {*}$injectList END] \
529	[list START     {*}$injectList "\"END"] \
530	[list "START\"" {*}$injectList "\"END"]
531} -result {}
532
533test winpipe-8.4 {BuildCommandLine/parse_cmdline pass-thru: check injection on special meta-chars (command/jointly args)} \
534-constraints {win exec notWine} -body {
535    _testExecArgs 2 \
536	[list START     {*}$injectList END] \
537	[list "START\"" {*}$injectList END] \
538	[list START     {*}$injectList "\"END"] \
539	[list "START\"" {*}$injectList "\"END"]
540} -result {}
541
542test winpipe-8.5 {BuildCommandLine/parse_cmdline pass-thru: check injection on special meta-chars (random mix)} \
543-constraints {win exec notWine} -body {
544    set lst {}
545    set maps {
546	{\&|^<>!()%}
547	{\&|^<>!()% }
548	{"\&|^<>!()%}
549	{"\&|^<>!()% }
550	{"""""\\\\\&|^<>!()%}
551	{"""""\\\\\&|^<>!()% }
552    }
553    set i 0
554    time {
555	set args {[incr i].}
556	time {
557	    set map [lindex $maps [expr {int(rand()*[llength $maps])}]]
558	    # be sure arg has some prefix (avoid special handling, like |& etc)
559	    set a {x}
560	    while {[string length $a] < 50} {
561		append a [string index $map [expr {int(rand()*[string length $map])}]]
562	    }
563	    lappend args $a
564	} 20
565	lappend lst $args
566    } 10
567    _testExecArgs 0 {*}$lst
568} -result {} -cleanup {
569    unset -nocomplain lst args a map maps
570}
571
572set injectList {
573    "test\"\nwhoami"     "test\"\"\nwhoami"
574    "test\"\"\"\nwhoami" "test\"\"\"\"\nwhoami"
575    "test;\n&echo \""    "\"test;\n&echo \""
576    "test\";\n&echo \""  "\"test\";\n&echo \""
577    "\"\"test\";\n&echo \""
578}
579
580test winpipe-8.6 {BuildCommandLine/parse_cmdline pass-thru: check new-line quoted in args} \
581-constraints {win exec} -body {
582    # test exe only, because currently there is no proper way to escape a new-line char resp.
583    # to supply a new-line to the batch-files within arguments (command line is truncated).
584    _testExecArgs 8 \
585	[list START     {*}$injectList END] \
586	[list "START\"" {*}$injectList END] \
587	[list START     {*}$injectList "\"END"] \
588	[list "START\"" {*}$injectList "\"END"]
589} -result {}
590
591test winpipe-8.7 {BuildCommandLine/parse_cmdline pass-thru: check new-line quoted in args (batch)} \
592-constraints {win exec knownBug} -body {
593    # this will fail if executed batch-file, because currently there is no proper way to escape a new-line char.
594    _testExecArgs 0 $injectList
595} -result {}
596
597
598rename _testExecArgs {}
599
600# restore old values for env(TMP) and env(TEMP)
601
602if {[catch {set env(TMP) $env_tmp}]} {
603    unset env(TMP)
604}
605if {[catch {set env(TEMP) $env_temp}]} {
606    unset env(TEMP)
607}
608
609# cleanup
610removeFile little
611removeFile big
612removeFile more
613removeFile stdout
614removeFile stderr
615removeFile nothing
616if {[info exists path(echoArgs.tcl)]} { removeFile echoArgs.tcl }
617if {[info exists path(echoArgs.bat)]} { removeFile echoArgs.bat }
618if {[info exists path(echoArgs2.bat)]} { removeDirectory test(Dir)Check }
619::tcltest::cleanupTests
620# back to original directory:
621cd $org_pwd; unset org_pwd
622return
623
624# Local Variables:
625# mode: tcl
626# End:
627