1# This file contains tests for the pkg_mkIndex command.
2# Note that the tests are limited to Tcl scripts only, there are no shared
3# libraries against which to test.
4#
5# Sourcing this file into Tcl runs the tests and generates output for
6# errors.  No output means no errors were found.
7#
8# Copyright (c) 1998-1999 by Scriptics Corporation.
9# All rights reserved.
10
11package require tcltest 2
12namespace import ::tcltest::*
13
14set fullPkgPath [makeDirectory pkg]
15
16
17namespace eval pkgtest {
18    # Namespace for procs we can discard
19}
20
21# pkgtest::parseArgs --
22#
23#  Parse an argument list.
24#
25# Arguments:
26#  <flags>	(optional) arguments starting with a dash are collected
27#		as options to pkg_mkIndex and passed to pkg_mkIndex.
28#  dirPath	the directory to index
29#  pattern0	pattern to index
30#  ...		pattern to index
31#  patternN	pattern to index
32#
33# Results:
34#  Returns a three element list:
35#    0: the options
36#    1: the directory to index
37#    2: the patterns list
38
39proc pkgtest::parseArgs { args } {
40    set options ""
41
42    set argc [llength $args]
43    for {set iarg 0} {$iarg < $argc} {incr iarg} {
44	set a [lindex $args $iarg]
45	if {[regexp {^-} $a]} {
46	    lappend options $a
47	    if {$a eq "-load"} {
48		incr iarg
49		lappend options [lindex $args $iarg]
50	    }
51	} else {
52	    break
53	}
54    }
55
56    set dirPath [lindex $args $iarg]
57    incr iarg
58    set patternList [lrange $args $iarg end]
59
60    return [list $options $dirPath $patternList]
61}
62
63# pkgtest::parseIndex --
64#
65#  Loads a pkgIndex.tcl file, records all the calls to "package ifneeded".
66#
67# Arguments:
68#  filePath	path to the pkgIndex.tcl file.
69#
70# Results:
71#  Returns a list, in "array set/get" format, where the keys are the package
72#  name and version (in the form "$name:$version"), and the values the rest
73#  of the command line.
74
75proc pkgtest::parseIndex { filePath } {
76    # create a slave interpreter, where we override "package ifneeded"
77
78    set slave [interp create]
79    if {[catch {
80	$slave eval {
81	    rename package package_original
82	    proc package { args } {
83		if {[lindex $args 0] eq "ifneeded"} {
84		    set pkg [lindex $args 1]
85		    set ver [lindex $args 2]
86		    set ::PKGS($pkg:$ver) [lindex $args 3]
87		} else {
88		    return [package_original {*}$args]
89		}
90	    }
91	    array set ::PKGS {}
92	}
93
94	set dir [file dirname $filePath]
95	$slave eval {set curdir [pwd]}
96	$slave eval [list cd $dir]
97	$slave eval [list set dir $dir]
98	$slave eval [list source [file tail $filePath]]
99	$slave eval {cd $curdir}
100
101	# Create the list in sorted order, so that we don't get spurious
102	# errors because the order has changed.
103
104	array set P {}
105	foreach {k v} [$slave eval {array get ::PKGS}] {
106	    set P($k) $v
107	}
108
109	set PKGS ""
110	foreach k [lsort [array names P]] {
111	    lappend PKGS $k $P($k)
112	}
113    } err opts]} {
114	set ei [dict get $opts -errorinfo]
115	set ec [dict get $opts -errorcode]
116
117	catch {interp delete $slave}
118
119	error $ei $ec
120    }
121
122    interp delete $slave
123
124    return $PKGS
125}
126
127# pkgtest::createIndex --
128#
129#  Runs pkg_mkIndex for the given directory and set of patterns.
130#  This procedure deletes any pkgIndex.tcl file in the target directory,
131#  then runs pkg_mkIndex.
132#
133# Arguments:
134#  <flags>	(optional) arguments starting with a dash are collected
135#		as options to pkg_mkIndex and passed to pkg_mkIndex.
136#  dirPath	the directory to index
137#  pattern0	pattern to index
138#  ...		pattern to index
139#  patternN	pattern to index
140#
141# Results:
142#  Returns a two element list:
143#    0: 1 if the procedure encountered an error, 0 otherwise.
144#    1: the error result if element 0 was 1
145
146proc pkgtest::createIndex { args } {
147    set parsed [parseArgs {*}$args]
148    set options [lindex $parsed 0]
149    set dirPath [lindex $parsed 1]
150    set patternList [lindex $parsed 2]
151
152    file mkdir $dirPath
153
154    if {[catch {
155	file delete [file join $dirPath pkgIndex.tcl]
156	pkg_mkIndex {*}$options $dirPath {*}$patternList
157    } err]} {
158	return [list 1 $err]
159    }
160
161    return [list 0 {}]
162}
163
164# makePkgList --
165#
166#  Takes the output of a pkgtest::parseIndex call, filters it and returns a
167#  cleaned up list of packages and their actions.
168#
169# Arguments:
170#  inList	output from a pkgtest::parseIndex.
171#
172# Results:
173#  Returns a list of two element lists:
174#    0: the name:version
175#    1: a list describing the package.
176#	For tclPkgSetup packages it consists of:
177#	 0: the keyword tclPkgSetup
178#	 1: the first file to source, with its exported procedures
179#	 2: the second file ...
180#	 N: the N-1st file ...
181
182proc makePkgList { inList } {
183    set pkgList ""
184
185    foreach {k v} $inList {
186	switch [lindex $v 0] {
187	    tclPkgSetup {
188		set l tclPkgSetup
189		foreach s [lindex $v 4] {
190		    lappend l $s
191		}
192	    }
193
194	    source {
195		set l $v
196	    }
197
198	    default {
199		error "can't handle $k $v"
200	    }
201	}
202
203	lappend pkgList [list $k $l]
204    }
205
206    return $pkgList
207}
208
209# pkgtest::runIndex --
210#
211#  Runs pkg_mkIndex, parses the generated index file.
212#
213# Arguments:
214#  <flags>	(optional) arguments starting with a dash are collected
215#		as options to pkg_mkIndex and passed to pkg_mkIndex.
216#  dirPath	the directory to index
217#  pattern0	pattern to index
218#  ...		pattern to index
219#  patternN	pattern to index
220#
221# Results:
222#  Returns a two element list:
223#    0: 1 if the procedure encountered an error, 0 otherwise.
224#    1: if no error, this is the parsed generated index file, in the format
225#	returned by pkgtest::parseIndex.
226#	If error, this is the error result.
227
228proc pkgtest::runCreatedIndex {rv args} {
229    if {[lindex $rv 0] == 0} {
230	set parsed [parseArgs {*}$args]
231	set dirPath [lindex $parsed 1]
232	set idxFile [file join $dirPath pkgIndex.tcl]
233
234	if {[catch {
235	    set result [list 0 [makePkgList [parseIndex $idxFile]]]
236	} err]} {
237	    set result [list 1 $err]
238	}
239	file delete $idxFile
240    } else {
241	set result $rv
242    }
243
244    return $result
245}
246proc pkgtest::runIndex { args } {
247    set rv [createIndex {*}$args]
248    return [runCreatedIndex $rv {*}$args]
249}
250
251# If there is no match to the patterns, make sure the directory hasn't
252# changed on us
253
254test pkgMkIndex-1.1 {nothing matches pattern - current dir is the same} {
255    list [pkgtest::runIndex -lazy $fullPkgPath nomatch.tcl] [pwd]
256} [list {1 {no files matched glob pattern "nomatch.tcl"}} [pwd]]
257
258makeFile {
259#  This is a simple package, just to check basic functionality.
260package provide simple 1.0
261namespace eval simple {
262    namespace export lower upper
263}
264proc simple::lower { stg } {
265    return [string tolower $stg]
266}
267proc simple::upper { stg } {
268    return [string toupper $stg]
269}
270} [file join pkg simple.tcl]
271
272test pkgMkIndex-2.1 {simple package} {
273    pkgtest::runIndex -lazy $fullPkgPath simple.tcl
274} {0 {{simple:1.0 {tclPkgSetup {simple.tcl source {::simple::lower ::simple::upper}}}}}}
275
276test pkgMkIndex-2.2 {simple package - use -direct} {
277    pkgtest::runIndex -direct $fullPkgPath simple.tcl
278} "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}"
279
280test pkgMkIndex-2.3 {simple package - direct loading is default} {
281    pkgtest::runIndex $fullPkgPath simple.tcl
282} "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}"
283
284test pkgMkIndex-2.4 {simple package - use -verbose} -body {
285    pkgtest::runIndex -verbose $fullPkgPath simple.tcl
286} -result "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}" \
287    -errorOutput {successful sourcing of simple.tcl
288packages provided were {simple 1.0}
289processed simple.tcl
290}
291
292removeFile [file join pkg simple.tcl]
293
294makeFile {
295#  Contains global symbols, used to check that they don't have a leading ::
296package provide global 1.0
297proc global_lower { stg } {
298    return [string tolower $stg]
299}
300proc global_upper { stg } {
301    return [string toupper $stg]
302}
303} [file join pkg global.tcl]
304
305test pkgMkIndex-3.1 {simple package with global symbols} {
306    pkgtest::runIndex -lazy $fullPkgPath global.tcl
307} {0 {{global:1.0 {tclPkgSetup {global.tcl source {global_lower global_upper}}}}}}
308
309removeFile [file join pkg global.tcl]
310
311makeFile {
312#  This package is required by pkg1.
313#  This package is split into two files, to test packages that are split
314#  over multiple files.
315package provide pkg2 1.0
316namespace eval pkg2 {
317    namespace export p2-1
318}
319proc pkg2::p2-1 { num } {
320    return [expr $num * 2]
321}
322} [file join pkg pkg2_a.tcl]
323
324makeFile {
325#  This package is required by pkg1.
326#  This package is split into two files, to test packages that are split
327#  over multiple files.
328package provide pkg2 1.0
329namespace eval pkg2 {
330    namespace export p2-2
331}
332proc pkg2::p2-2 { num } {
333    return [expr $num * 3]
334}
335} [file join pkg pkg2_b.tcl]
336
337test pkgMkIndex-4.1 {split package} {
338    pkgtest::runIndex -lazy $fullPkgPath pkg2_a.tcl pkg2_b.tcl
339} {0 {{pkg2:1.0 {tclPkgSetup {pkg2_a.tcl source ::pkg2::p2-1} {pkg2_b.tcl source ::pkg2::p2-2}}}}}
340
341test pkgMkIndex-4.2 {split package - direct loading} {
342    pkgtest::runIndex -direct $fullPkgPath pkg2_a.tcl pkg2_b.tcl
343} "0 {{pkg2:1.0 {[list source [file join $fullPkgPath pkg2_a.tcl]]
344[list source [file join $fullPkgPath pkg2_b.tcl]]}}}"
345
346# Add the direct1 directory to auto_path, so that the direct1 package
347# can be found.
348set direct1 [makeDirectory direct1]
349lappend auto_path $direct1
350makeFile {
351#  This is referenced by pkgIndex.tcl as a -direct script.
352package provide direct1 1.0
353namespace eval direct1 {
354    namespace export pd1 pd2
355}
356proc direct1::pd1 { stg } {
357    return [string tolower $stg]
358}
359proc direct1::pd2 { stg } {
360    return [string toupper $stg]
361}
362} [file join direct1 direct1.tcl]
363pkg_mkIndex -direct $direct1 direct1.tcl
364
365makeFile {
366#  Does a package require of direct1, whose pkgIndex.tcl entry
367#  is created above with option -direct.  This tests that pkg_mkIndex
368#  can handle code that is sourced in pkgIndex.tcl files.
369package require direct1
370package provide std 1.0
371namespace eval std {
372    namespace export p1 p2
373}
374proc std::p1 { stg } {
375    return [string tolower $stg]
376}
377proc std::p2 { stg } {
378    return [string toupper $stg]
379}
380} [file join pkg std.tcl]
381
382test pkgMkIndex-5.1 {requires -direct package} {
383    pkgtest::runIndex -lazy $fullPkgPath std.tcl
384} {0 {{std:1.0 {tclPkgSetup {std.tcl source {::std::p1 ::std::p2}}}}}}
385
386removeFile [file join direct1 direct1.tcl]
387file delete [file join $direct1 pkgIndex.tcl]
388removeDirectory direct1
389removeFile [file join pkg std.tcl]
390
391makeFile {
392#  This package requires pkg3, but it does
393#  not use any of pkg3's procs in the code that is executed by the file
394#  (i.e. references to pkg3's procs are in the proc bodies only).
395package require pkg3 1.0
396package provide pkg1 1.0
397namespace eval pkg1 {
398    namespace export p1-1 p1-2
399}
400proc pkg1::p1-1 { num } {
401    return [pkg3::p3-1 $num]
402}
403proc pkg1::p1-2 { num } {
404    return [pkg3::p3-2 $num]
405}
406} [file join pkg pkg1.tcl]
407
408makeFile {
409package provide pkg3 1.0
410namespace eval pkg3 {
411    namespace export p3-1 p3-2
412}
413proc pkg3::p3-1 { num } {
414    return {[expr $num * 2]}
415}
416proc pkg3::p3-2 { num } {
417    return {[expr $num * 3]}
418}
419} [file join pkg pkg3.tcl]
420
421test pkgMkIndex-6.1 {pkg1 requires pkg3} {
422    pkgtest::runIndex -lazy $fullPkgPath pkg1.tcl pkg3.tcl
423} {0 {{pkg1:1.0 {tclPkgSetup {pkg1.tcl source {::pkg1::p1-1 ::pkg1::p1-2}}}} {pkg3:1.0 {tclPkgSetup {pkg3.tcl source {::pkg3::p3-1 ::pkg3::p3-2}}}}}}
424
425test pkgMkIndex-6.2 {pkg1 requires pkg3 - use -direct} {
426    pkgtest::runIndex -direct $fullPkgPath pkg1.tcl pkg3.tcl
427} "0 {{pkg1:1.0 {[list source [file join $fullPkgPath pkg1.tcl]]}} {pkg3:1.0 {[list source [file join $fullPkgPath pkg3.tcl]]}}}"
428
429removeFile [file join pkg pkg1.tcl]
430
431makeFile {
432#  This package requires pkg3, and it calls
433#  a pkg3 proc in the code that is executed by the file
434package require pkg3 1.0
435package provide pkg4 1.0
436namespace eval pkg4 {
437    namespace export p4-1 p4-2
438    variable m2 [pkg3::p3-1 10]
439}
440proc pkg4::p4-1 { num } {
441    variable m2
442    return [expr {$m2 * $num}]
443}
444proc pkg4::p4-2 { num } {
445    return [pkg3::p3-2 $num]
446}
447} [file join pkg pkg4.tcl]
448
449test pkgMkIndex-7.1 {pkg4 uses pkg3} {
450    pkgtest::runIndex -lazy $fullPkgPath pkg4.tcl pkg3.tcl
451} {0 {{pkg3:1.0 {tclPkgSetup {pkg3.tcl source {::pkg3::p3-1 ::pkg3::p3-2}}}} {pkg4:1.0 {tclPkgSetup {pkg4.tcl source {::pkg4::p4-1 ::pkg4::p4-2}}}}}}
452
453test pkgMkIndex-7.2 {pkg4 uses pkg3 - use -direct} {
454    pkgtest::runIndex -direct $fullPkgPath pkg4.tcl pkg3.tcl
455} "0 {{pkg3:1.0 {[list source [file join $fullPkgPath pkg3.tcl]]}} {pkg4:1.0 {[list source [file join $fullPkgPath pkg4.tcl]]}}}"
456
457removeFile [file join pkg pkg4.tcl]
458removeFile [file join pkg pkg3.tcl]
459
460makeFile {
461#  This package requires pkg2, and it calls
462#  a pkg2 proc in the code that is executed by the file.
463#  Pkg2 is a split package.
464package require pkg2 1.0
465package provide pkg5 1.0
466namespace eval pkg5 {
467    namespace export p5-1 p5-2
468    variable m2 [pkg2::p2-1 10]
469    variable m3 [pkg2::p2-2 10]
470}
471proc pkg5::p5-1 { num } {
472    variable m2
473    return [expr {$m2 * $num}]
474}
475proc pkg5::p5-2 { num } {
476    variable m2
477    return [expr {$m2 * $num}]
478}
479} [file join pkg pkg5.tcl]
480
481test pkgMkIndex-8.1 {pkg5 uses pkg2} {
482    pkgtest::runIndex -lazy $fullPkgPath pkg5.tcl pkg2_a.tcl pkg2_b.tcl
483} {0 {{pkg2:1.0 {tclPkgSetup {pkg2_a.tcl source ::pkg2::p2-1} {pkg2_b.tcl source ::pkg2::p2-2}}} {pkg5:1.0 {tclPkgSetup {pkg5.tcl source {::pkg5::p5-1 ::pkg5::p5-2}}}}}}
484
485test pkgMkIndex-8.2 {pkg5 uses pkg2 - use -direct} {
486    pkgtest::runIndex -direct $fullPkgPath pkg5.tcl pkg2_a.tcl pkg2_b.tcl
487} "0 {{pkg2:1.0 {[list source [file join $fullPkgPath pkg2_a.tcl]]
488[list source [file join $fullPkgPath pkg2_b.tcl]]}} {pkg5:1.0 {[list source [file join $fullPkgPath pkg5.tcl]]}}}"
489
490removeFile [file join pkg pkg5.tcl]
491removeFile [file join pkg pkg2_a.tcl]
492removeFile [file join pkg pkg2_b.tcl]
493
494makeFile {
495#  This package requires circ2, and circ2
496#  requires circ3, which in turn requires circ1.
497#  In case of cirularities, pkg_mkIndex should give up when it gets stuck.
498package require circ2 1.0
499package provide circ1 1.0
500namespace eval circ1 {
501    namespace export c1-1 c1-2 c1-3 c1-4
502}
503proc circ1::c1-1 { num } {
504    return [circ2::c2-1 $num]
505}
506proc circ1::c1-2 { num } {
507    return [circ2::c2-2 $num]
508}
509proc circ1::c1-3 {} {
510    return 10
511}
512proc circ1::c1-4 {} {
513    return 20
514}
515} [file join pkg circ1.tcl]
516
517makeFile {
518#  This package is required by circ1, and
519#  requires circ3. Circ3, in turn, requires circ1 to give us a circularity.
520package require circ3 1.0
521package provide circ2 1.0
522namespace eval circ2 {
523    namespace export c2-1 c2-2
524}
525proc circ2::c2-1 { num } {
526    return [expr $num * [circ3::c3-1]]
527}
528proc circ2::c2-2 { num } {
529    return [expr $num * [circ3::c3-2]]
530}
531} [file join pkg circ2.tcl]
532
533makeFile {
534#  This package is required by circ2, and in
535#  turn requires circ1. This closes the circularity.
536package require circ1 1.0
537package provide circ3 1.0
538namespace eval circ3 {
539    namespace export c3-1 c3-4
540}
541proc circ3::c3-1 {} {
542    return [circ1::c1-3]
543}
544proc circ3::c3-2 {} {
545    return [circ1::c1-4]
546}
547} [file join pkg circ3.tcl]
548
549test pkgMkIndex-9.1 {circular packages} {
550    pkgtest::runIndex -lazy $fullPkgPath circ1.tcl circ2.tcl circ3.tcl
551} {0 {{circ1:1.0 {tclPkgSetup {circ1.tcl source {::circ1::c1-1 ::circ1::c1-2 ::circ1::c1-3 ::circ1::c1-4}}}} {circ2:1.0 {tclPkgSetup {circ2.tcl source {::circ2::c2-1 ::circ2::c2-2}}}} {circ3:1.0 {tclPkgSetup {circ3.tcl source ::circ3::c3-1}}}}}
552
553removeFile [file join pkg circ1.tcl]
554removeFile [file join pkg circ2.tcl]
555removeFile [file join pkg circ3.tcl]
556
557# Some tests require the existence of one of the DLLs in the dltest directory
558set x [file join [file dirname [info nameofexecutable]] dltest \
559	pkga[info sharedlibextension]]
560set dll "[file tail $x]Required"
561testConstraint $dll [file exists $x]
562
563if {[testConstraint $dll]} {
564    makeFile {
565#  This package provides Pkga, which is also provided by a DLL.
566package provide Pkga 1.0
567proc pkga_neq { x } {
568    return [expr {! [pkgq_eq $x]}]
569}
570} [file join pkg pkga.tcl]
571    file copy -force $x $fullPkgPath
572}
573testConstraint exec [llength [info commands ::exec]]
574
575test pkgMkIndex-10.1 {package in DLL and script} [list exec $dll] {
576    # Do all [load]ing of shared libraries in another process, so
577    # we can delete the file and not get stuck because we're holding
578    # a reference to it.
579    set cmd [list pkg_mkIndex -lazy $fullPkgPath [file tail $x] pkga.tcl]
580    exec [interpreter] << $cmd
581    pkgtest::runCreatedIndex {0 {}} -lazy $fullPkgPath pkga[info sharedlibextension] pkga.tcl
582} "0 {{Pkga:1.0 {tclPkgSetup {pkga[info sharedlibextension] load {pkga_eq pkga_quote}} {pkga.tcl source pkga_neq}}}}"
583test pkgMkIndex-10.2 {package in DLL hidden by -load} [list exec $dll] {
584    # Do all [load]ing of shared libraries in another process, so
585    # we can delete the file and not get stuck because we're holding
586    # a reference to it.
587    #
588    # This test depends on context from prior test, so repeat it.
589    set script "[list pkg_mkIndex -lazy $fullPkgPath [file tail $x] pkga.tcl]\n"
590    append script \
591	    "[list pkg_mkIndex -lazy -load Pkg* $fullPkgPath [file tail $x]]"
592    exec [interpreter] << $script
593    pkgtest::runCreatedIndex {0 {}} -lazy -load Pkg* -- $fullPkgPath pkga[info sharedlibextension]
594} {0 {}}
595
596if {[testConstraint $dll]} {
597    file delete -force [file join $fullPkgPath [file tail $x]]
598    removeFile [file join pkg pkga.tcl]
599}
600
601# Tolerate "namespace import" at the global scope
602
603makeFile {
604package provide fubar 1.0
605namespace eval ::fubar:: {
606    #
607    # export only public functions.
608    #
609    namespace export {[a-z]*}
610}
611proc ::fubar::foo {bar} {
612    puts "$bar"
613    return true
614}
615namespace import ::fubar::foo
616} [file join pkg import.tcl]
617
618test pkgMkIndex-11.1 {conflicting namespace imports} {
619    pkgtest::runIndex -lazy $fullPkgPath import.tcl
620} {0 {{fubar:1.0 {tclPkgSetup {import.tcl source ::fubar::foo}}}}}
621
622removeFile [file join pkg import.tcl]
623
624# Verify that the auto load list generated is correct even when there
625# is a proc name conflict between two namespaces (ie, ::foo::baz and
626# ::bar::baz)
627
628makeFile {
629package provide football 1.0
630namespace eval ::pro:: {
631    #
632    # export only public functions.
633    #
634    namespace export {[a-z]*}
635}
636namespace eval ::college:: {
637    #
638    # export only public functions.
639    #
640    namespace export {[a-z]*}
641}
642proc ::pro::team {} {
643    puts "go packers!"
644    return true
645}
646proc ::college::team {} {
647    puts "go badgers!"
648    return true
649}
650} [file join pkg samename.tcl]
651
652test pkgMkIndex-12.1 {same name procs in different namespace} {
653    pkgtest::runIndex -lazy $fullPkgPath samename.tcl
654} {0 {{football:1.0 {tclPkgSetup {samename.tcl source {::college::team ::pro::team}}}}}}
655
656removeFile [file join pkg samename.tcl]
657
658# Proc names with embedded spaces are properly listed (ie, correct number of
659# braces) in result
660makeFile {
661package provide spacename 1.0
662proc {a b} {} {}
663proc {c d} {} {}
664} [file join pkg spacename.tcl]
665
666test pkgMkIndex-13.1 {proc names with embedded spaces} {
667    pkgtest::runIndex -lazy $fullPkgPath spacename.tcl
668} {0 {{spacename:1.0 {tclPkgSetup {spacename.tcl source {{a b} {c d}}}}}}}
669
670removeFile [file join pkg spacename.tcl]
671
672# Test the tcl::Pkg::CompareExtension helper function
673test pkgMkIndex-14.1 {tcl::Pkg::CompareExtension} {unix} {
674    tcl::Pkg::CompareExtension foo.so .so
675} 1
676test pkgMkIndex-14.2 {tcl::Pkg::CompareExtension} {unix} {
677    tcl::Pkg::CompareExtension foo.so.bar .so
678} 0
679test pkgMkIndex-14.3 {tcl::Pkg::CompareExtension} {unix} {
680    tcl::Pkg::CompareExtension foo.so.1 .so
681} 1
682test pkgMkIndex-14.4 {tcl::Pkg::CompareExtension} {unix} {
683    tcl::Pkg::CompareExtension foo.so.1.2 .so
684} 1
685test pkgMkIndex-14.5 {tcl::Pkg::CompareExtension} {unix} {
686    tcl::Pkg::CompareExtension foo .so
687} 0
688test pkgMkIndex-14.6 {tcl::Pkg::CompareExtension} {unix} {
689    tcl::Pkg::CompareExtension foo.so.1.2.bar .so
690} 0
691
692# cleanup
693
694removeDirectory pkg
695
696namespace delete pkgtest
697::tcltest::cleanupTests
698return
699
700