os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/tests/pkgMkIndex.test
Update contrib.
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.
5 # Sourcing this file into Tcl runs the tests and generates output for
6 # errors. No output means no errors were found.
8 # Copyright (c) 1998-1999 by Scriptics Corporation.
11 # RCS: @(#) $Id: pkgMkIndex.test,v 1.23.2.1 2003/07/24 08:23:39 rmax Exp $
13 if {[lsearch [namespace children] ::tcltest] == -1} {
14 package require tcltest 2
15 namespace import -force ::tcltest::*
18 set fullPkgPath [makeDirectory pkg]
21 namespace eval pkgtest {
22 # Namespace for procs we can discard
25 # pkgtest::parseArgs --
27 # Parse an argument list.
30 # <flags> (optional) arguments starting with a dash are collected
31 # as options to pkg_mkIndex and passed to pkg_mkIndex.
32 # dirPath the directory to index
33 # pattern0 pattern to index
34 # ... pattern to index
35 # patternN pattern to index
38 # Returns a three element list:
40 # 1: the directory to index
41 # 2: the patterns list
43 proc pkgtest::parseArgs { args } {
46 set argc [llength $args]
47 for {set iarg 0} {$iarg < $argc} {incr iarg} {
48 set a [lindex $args $iarg]
49 if {[regexp {^-} $a]} {
51 if {[string compare -load $a] == 0} {
53 lappend options [lindex $args $iarg]
60 set dirPath [lindex $args $iarg]
62 set patternList [lrange $args $iarg end]
64 return [list $options $dirPath $patternList]
67 # pkgtest::parseIndex --
69 # Loads a pkgIndex.tcl file, records all the calls to "package ifneeded".
72 # filePath path to the pkgIndex.tcl file.
75 # Returns a list, in "array set/get" format, where the keys are the package
76 # name and version (in the form "$name:$version"), and the values the rest
77 # of the command line.
79 proc pkgtest::parseIndex { filePath } {
80 # create a slave interpreter, where we override "package ifneeded"
82 set slave [interp create]
85 rename package package_original
86 proc package { args } {
87 if {[string compare [lindex $args 0] ifneeded] == 0} {
88 set pkg [lindex $args 1]
89 set ver [lindex $args 2]
90 set ::PKGS($pkg:$ver) [lindex $args 3]
92 return [eval package_original $args]
98 set dir [file dirname $filePath]
99 $slave eval {set curdir [pwd]}
100 $slave eval [list cd $dir]
101 $slave eval [list set dir $dir]
102 $slave eval [list source [file tail $filePath]]
103 $slave eval {cd $curdir}
105 # Create the list in sorted order, so that we don't get spurious
106 # errors because the order has changed.
109 foreach {k v} [$slave eval {array get ::PKGS}] {
114 foreach k [lsort [array names P]] {
115 lappend PKGS $k $P($k)
121 catch {interp delete $slave}
131 # pkgtest::createIndex --
133 # Runs pkg_mkIndex for the given directory and set of patterns.
134 # This procedure deletes any pkgIndex.tcl file in the target directory,
135 # then runs pkg_mkIndex.
138 # <flags> (optional) arguments starting with a dash are collected
139 # as options to pkg_mkIndex and passed to pkg_mkIndex.
140 # dirPath the directory to index
141 # pattern0 pattern to index
142 # ... pattern to index
143 # patternN pattern to index
146 # Returns a two element list:
147 # 0: 1 if the procedure encountered an error, 0 otherwise.
148 # 1: the error result if element 0 was 1
150 proc pkgtest::createIndex { args } {
151 set parsed [eval parseArgs $args]
152 set options [lindex $parsed 0]
153 set dirPath [lindex $parsed 1]
154 set patternList [lindex $parsed 2]
159 file delete [file join $dirPath pkgIndex.tcl]
160 eval pkg_mkIndex $options [list $dirPath] $patternList
170 # Takes the output of a pkgtest::parseIndex call, filters it and returns a
171 # cleaned up list of packages and their actions.
174 # inList output from a pkgtest::parseIndex.
177 # Returns a list of two element lists:
178 # 0: the name:version
179 # 1: a list describing the package.
180 # For tclPkgSetup packages it consists of:
181 # 0: the keyword tclPkgSetup
182 # 1: the first file to source, with its exported procedures
183 # 2: the second file ...
184 # N: the N-1st file ...
186 proc makePkgList { inList } {
189 foreach {k v} $inList {
190 switch [lindex $v 0] {
193 foreach s [lindex $v 4] {
203 error "can't handle $k $v"
207 lappend pkgList [list $k $l]
213 # pkgtest::runIndex --
215 # Runs pkg_mkIndex, parses the generated index file.
218 # <flags> (optional) arguments starting with a dash are collected
219 # as options to pkg_mkIndex and passed to pkg_mkIndex.
220 # dirPath the directory to index
221 # pattern0 pattern to index
222 # ... pattern to index
223 # patternN pattern to index
226 # Returns a two element list:
227 # 0: 1 if the procedure encountered an error, 0 otherwise.
228 # 1: if no error, this is the parsed generated index file, in the format
229 # returned by pkgtest::parseIndex.
230 # If error, this is the error result.
232 proc pkgtest::runCreatedIndex {rv args} {
233 if {[lindex $rv 0] == 0} {
234 set parsed [eval parseArgs $args]
235 set dirPath [lindex $parsed 1]
236 set idxFile [file join $dirPath pkgIndex.tcl]
239 set result [list 0 [makePkgList [parseIndex $idxFile]]]
241 set result [list 1 $err]
250 proc pkgtest::runIndex { args } {
251 set rv [eval createIndex $args]
252 return [eval [list runCreatedIndex $rv] $args]
255 # If there is no match to the patterns, make sure the directory hasn't
258 test pkgMkIndex-1.1 {nothing matches pattern - current dir is the same} {
259 list [pkgtest::runIndex -lazy $fullPkgPath nomatch.tcl] [pwd]
260 } [list {1 {no files matched glob pattern "nomatch.tcl"}} [pwd]]
263 # This is a simple package, just to check basic functionality.
264 package provide simple 1.0
265 namespace eval simple {
266 namespace export lower upper
268 proc simple::lower { stg } {
269 return [string tolower $stg]
271 proc simple::upper { stg } {
272 return [string toupper $stg]
274 } [file join pkg simple.tcl]
276 test pkgMkIndex-2.1 {simple package} {
277 pkgtest::runIndex -lazy $fullPkgPath simple.tcl
278 } {0 {{simple:1.0 {tclPkgSetup {simple.tcl source {::simple::lower ::simple::upper}}}}}}
280 test pkgMkIndex-2.2 {simple package - use -direct} {
281 pkgtest::runIndex -direct $fullPkgPath simple.tcl
282 } "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}"
284 test pkgMkIndex-2.3 {simple package - direct loading is default} {
285 pkgtest::runIndex $fullPkgPath simple.tcl
286 } "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}"
288 test pkgMkIndex-2.4 {simple package - use -verbose} -body {
289 pkgtest::runIndex -verbose $fullPkgPath simple.tcl
290 } -result "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}" \
291 -errorOutput {successful sourcing of simple.tcl
292 packages provided were {simple 1.0}
296 removeFile [file join pkg simple.tcl]
299 # Contains global symbols, used to check that they don't have a leading ::
300 package provide global 1.0
301 proc global_lower { stg } {
302 return [string tolower $stg]
304 proc global_upper { stg } {
305 return [string toupper $stg]
307 } [file join pkg global.tcl]
309 test pkgMkIndex-3.1 {simple package with global symbols} {
310 pkgtest::runIndex -lazy $fullPkgPath global.tcl
311 } {0 {{global:1.0 {tclPkgSetup {global.tcl source {global_lower global_upper}}}}}}
313 removeFile [file join pkg global.tcl]
316 # This package is required by pkg1.
317 # This package is split into two files, to test packages that are split
318 # over multiple files.
319 package provide pkg2 1.0
320 namespace eval pkg2 {
321 namespace export p2-1
323 proc pkg2::p2-1 { num } {
324 return [expr $num * 2]
326 } [file join pkg pkg2_a.tcl]
329 # This package is required by pkg1.
330 # This package is split into two files, to test packages that are split
331 # over multiple files.
332 package provide pkg2 1.0
333 namespace eval pkg2 {
334 namespace export p2-2
336 proc pkg2::p2-2 { num } {
337 return [expr $num * 3]
339 } [file join pkg pkg2_b.tcl]
341 test pkgMkIndex-4.1 {split package} {
342 pkgtest::runIndex -lazy $fullPkgPath pkg2_a.tcl pkg2_b.tcl
343 } {0 {{pkg2:1.0 {tclPkgSetup {pkg2_a.tcl source ::pkg2::p2-1} {pkg2_b.tcl source ::pkg2::p2-2}}}}}
345 test pkgMkIndex-4.2 {split package - direct loading} {
346 pkgtest::runIndex -direct $fullPkgPath pkg2_a.tcl pkg2_b.tcl
347 } "0 {{pkg2:1.0 {[list source [file join $fullPkgPath pkg2_a.tcl]]
348 [list source [file join $fullPkgPath pkg2_b.tcl]]}}}"
350 # Add the direct1 directory to auto_path, so that the direct1 package
352 set direct1 [makeDirectory direct1]
353 lappend auto_path $direct1
355 # This is referenced by pkgIndex.tcl as a -direct script.
356 package provide direct1 1.0
357 namespace eval direct1 {
358 namespace export pd1 pd2
360 proc direct1::pd1 { stg } {
361 return [string tolower $stg]
363 proc direct1::pd2 { stg } {
364 return [string toupper $stg]
366 } [file join direct1 direct1.tcl]
367 pkg_mkIndex -direct $direct1 direct1.tcl
370 # Does a package require of direct1, whose pkgIndex.tcl entry
371 # is created above with option -direct. This tests that pkg_mkIndex
372 # can handle code that is sourced in pkgIndex.tcl files.
373 package require direct1
374 package provide std 1.0
376 namespace export p1 p2
378 proc std::p1 { stg } {
379 return [string tolower $stg]
381 proc std::p2 { stg } {
382 return [string toupper $stg]
384 } [file join pkg std.tcl]
386 test pkgMkIndex-5.1 {requires -direct package} {
387 pkgtest::runIndex -lazy $fullPkgPath std.tcl
388 } {0 {{std:1.0 {tclPkgSetup {std.tcl source {::std::p1 ::std::p2}}}}}}
390 removeFile [file join direct1 direct1.tcl]
391 file delete [file join $direct1 pkgIndex.tcl]
392 removeDirectory direct1
393 removeFile [file join pkg std.tcl]
396 # This package requires pkg3, but it does
397 # not use any of pkg3's procs in the code that is executed by the file
398 # (i.e. references to pkg3's procs are in the proc bodies only).
399 package require pkg3 1.0
400 package provide pkg1 1.0
401 namespace eval pkg1 {
402 namespace export p1-1 p1-2
404 proc pkg1::p1-1 { num } {
405 return [pkg3::p3-1 $num]
407 proc pkg1::p1-2 { num } {
408 return [pkg3::p3-2 $num]
410 } [file join pkg pkg1.tcl]
413 package provide pkg3 1.0
414 namespace eval pkg3 {
415 namespace export p3-1 p3-2
417 proc pkg3::p3-1 { num } {
418 return {[expr $num * 2]}
420 proc pkg3::p3-2 { num } {
421 return {[expr $num * 3]}
423 } [file join pkg pkg3.tcl]
425 test pkgMkIndex-6.1 {pkg1 requires pkg3} {
426 pkgtest::runIndex -lazy $fullPkgPath pkg1.tcl pkg3.tcl
427 } {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}}}}}}
429 test pkgMkIndex-6.2 {pkg1 requires pkg3 - use -direct} {
430 pkgtest::runIndex -direct $fullPkgPath pkg1.tcl pkg3.tcl
431 } "0 {{pkg1:1.0 {[list source [file join $fullPkgPath pkg1.tcl]]}} {pkg3:1.0 {[list source [file join $fullPkgPath pkg3.tcl]]}}}"
433 removeFile [file join pkg pkg1.tcl]
436 # This package requires pkg3, and it calls
437 # a pkg3 proc in the code that is executed by the file
438 package require pkg3 1.0
439 package provide pkg4 1.0
440 namespace eval pkg4 {
441 namespace export p4-1 p4-2
442 variable m2 [pkg3::p3-1 10]
444 proc pkg4::p4-1 { num } {
446 return [expr {$m2 * $num}]
448 proc pkg4::p4-2 { num } {
449 return [pkg3::p3-2 $num]
451 } [file join pkg pkg4.tcl]
453 test pkgMkIndex-7.1 {pkg4 uses pkg3} {
454 pkgtest::runIndex -lazy $fullPkgPath pkg4.tcl pkg3.tcl
455 } {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}}}}}}
457 test pkgMkIndex-7.2 {pkg4 uses pkg3 - use -direct} {
458 pkgtest::runIndex -direct $fullPkgPath pkg4.tcl pkg3.tcl
459 } "0 {{pkg3:1.0 {[list source [file join $fullPkgPath pkg3.tcl]]}} {pkg4:1.0 {[list source [file join $fullPkgPath pkg4.tcl]]}}}"
461 removeFile [file join pkg pkg4.tcl]
462 removeFile [file join pkg pkg3.tcl]
465 # This package requires pkg2, and it calls
466 # a pkg2 proc in the code that is executed by the file.
467 # Pkg2 is a split package.
468 package require pkg2 1.0
469 package provide pkg5 1.0
470 namespace eval pkg5 {
471 namespace export p5-1 p5-2
472 variable m2 [pkg2::p2-1 10]
473 variable m3 [pkg2::p2-2 10]
475 proc pkg5::p5-1 { num } {
477 return [expr {$m2 * $num}]
479 proc pkg5::p5-2 { num } {
481 return [expr {$m2 * $num}]
483 } [file join pkg pkg5.tcl]
485 test pkgMkIndex-8.1 {pkg5 uses pkg2} {
486 pkgtest::runIndex -lazy $fullPkgPath pkg5.tcl pkg2_a.tcl pkg2_b.tcl
487 } {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}}}}}}
489 test pkgMkIndex-8.2 {pkg5 uses pkg2 - use -direct} {
490 pkgtest::runIndex -direct $fullPkgPath pkg5.tcl pkg2_a.tcl pkg2_b.tcl
491 } "0 {{pkg2:1.0 {[list source [file join $fullPkgPath pkg2_a.tcl]]
492 [list source [file join $fullPkgPath pkg2_b.tcl]]}} {pkg5:1.0 {[list source [file join $fullPkgPath pkg5.tcl]]}}}"
494 removeFile [file join pkg pkg5.tcl]
495 removeFile [file join pkg pkg2_a.tcl]
496 removeFile [file join pkg pkg2_b.tcl]
499 # This package requires circ2, and circ2
500 # requires circ3, which in turn requires circ1.
501 # In case of cirularities, pkg_mkIndex should give up when it gets stuck.
502 package require circ2 1.0
503 package provide circ1 1.0
504 namespace eval circ1 {
505 namespace export c1-1 c1-2 c1-3 c1-4
507 proc circ1::c1-1 { num } {
508 return [circ2::c2-1 $num]
510 proc circ1::c1-2 { num } {
511 return [circ2::c2-2 $num]
513 proc circ1::c1-3 {} {
516 proc circ1::c1-4 {} {
519 } [file join pkg circ1.tcl]
522 # This package is required by circ1, and
523 # requires circ3. Circ3, in turn, requires circ1 to give us a circularity.
524 package require circ3 1.0
525 package provide circ2 1.0
526 namespace eval circ2 {
527 namespace export c2-1 c2-2
529 proc circ2::c2-1 { num } {
530 return [expr $num * [circ3::c3-1]]
532 proc circ2::c2-2 { num } {
533 return [expr $num * [circ3::c3-2]]
535 } [file join pkg circ2.tcl]
538 # This package is required by circ2, and in
539 # turn requires circ1. This closes the circularity.
540 package require circ1 1.0
541 package provide circ3 1.0
542 namespace eval circ3 {
543 namespace export c3-1 c3-4
545 proc circ3::c3-1 {} {
548 proc circ3::c3-2 {} {
551 } [file join pkg circ3.tcl]
553 test pkgMkIndex-9.1 {circular packages} {
554 pkgtest::runIndex -lazy $fullPkgPath circ1.tcl circ2.tcl circ3.tcl
555 } {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}}}}}
557 removeFile [file join pkg circ1.tcl]
558 removeFile [file join pkg circ2.tcl]
559 removeFile [file join pkg circ3.tcl]
561 # Some tests require the existence of one of the DLLs in the dltest directory
562 set x [file join [file dirname [info nameofexecutable]] dltest \
563 pkga[info sharedlibextension]]
564 set dll "[file tail $x]Required"
565 ::tcltest::testConstraint $dll [file exists $x]
567 if {[testConstraint $dll]} {
569 # This package provides Pkga, which is also provided by a DLL.
570 package provide Pkga 1.0
571 proc pkga_neq { x } {
572 return [expr {! [pkgq_eq $x]}]
574 } [file join pkg pkga.tcl]
575 file copy -force $x $fullPkgPath
577 testConstraint exec [llength [info commands ::exec]]
579 test pkgMkIndex-10.1 {package in DLL and script} [list exec $dll] {
580 # Do all [load]ing of shared libraries in another process, so
581 # we can delete the file and not get stuck because we're holding
583 set cmd [list pkg_mkIndex -lazy $fullPkgPath [file tail $x] pkga.tcl]
584 exec [interpreter] << $cmd
585 pkgtest::runCreatedIndex {0 {}} -lazy $fullPkgPath pkga[info sharedlibextension] pkga.tcl
586 } "0 {{Pkga:1.0 {tclPkgSetup {pkga[info sharedlibextension] load {pkga_eq pkga_quote}} {pkga.tcl source pkga_neq}}}}"
587 test pkgMkIndex-10.2 {package in DLL hidden by -load} [list exec $dll] {
588 # Do all [load]ing of shared libraries in another process, so
589 # we can delete the file and not get stuck because we're holding
592 # This test depends on context from prior test, so repeat it.
593 set script "[list pkg_mkIndex -lazy $fullPkgPath [file tail $x] pkga.tcl]\n"
595 "[list pkg_mkIndex -lazy -load Pkg* $fullPkgPath [file tail $x]]"
596 exec [interpreter] << $script
597 pkgtest::runCreatedIndex {0 {}} -lazy -load Pkg* -- $fullPkgPath pkga[info sharedlibextension]
600 if {[testConstraint $dll]} {
601 file delete -force [file join $fullPkgPath [file tail $x]]
602 removeFile [file join pkg pkga.tcl]
605 # Tolerate "namespace import" at the global scope
608 package provide fubar 1.0
609 namespace eval ::fubar:: {
611 # export only public functions.
613 namespace export {[a-z]*}
615 proc ::fubar::foo {bar} {
619 namespace import ::fubar::foo
620 } [file join pkg import.tcl]
622 test pkgMkIndex-11.1 {conflicting namespace imports} {
623 pkgtest::runIndex -lazy $fullPkgPath import.tcl
624 } {0 {{fubar:1.0 {tclPkgSetup {import.tcl source ::fubar::foo}}}}}
626 removeFile [file join pkg import.tcl]
628 # Verify that the auto load list generated is correct even when there
629 # is a proc name conflict between two namespaces (ie, ::foo::baz and
633 package provide football 1.0
634 namespace eval ::pro:: {
636 # export only public functions.
638 namespace export {[a-z]*}
640 namespace eval ::college:: {
642 # export only public functions.
644 namespace export {[a-z]*}
646 proc ::pro::team {} {
650 proc ::college::team {} {
654 } [file join pkg samename.tcl]
656 test pkgMkIndex-12.1 {same name procs in different namespace} {
657 pkgtest::runIndex -lazy $fullPkgPath samename.tcl
658 } {0 {{football:1.0 {tclPkgSetup {samename.tcl source {::college::team ::pro::team}}}}}}
660 removeFile [file join pkg samename.tcl]
662 # Proc names with embedded spaces are properly listed (ie, correct number of
665 package provide spacename 1.0
668 } [file join pkg spacename.tcl]
670 test pkgMkIndex-13.1 {proc names with embedded spaces} {
671 pkgtest::runIndex -lazy $fullPkgPath spacename.tcl
672 } {0 {{spacename:1.0 {tclPkgSetup {spacename.tcl source {{a b} {c d}}}}}}}
674 removeFile [file join pkg spacename.tcl]
676 # Test the pkg_compareExtension helper function
677 test pkgMkIndex-14.1 {pkg_compareExtension} {unixOnly} {
678 pkg_compareExtension foo.so .so
680 test pkgMkIndex-14.2 {pkg_compareExtension} {unixOnly} {
681 pkg_compareExtension foo.so.bar .so
683 test pkgMkIndex-14.3 {pkg_compareExtension} {unixOnly} {
684 pkg_compareExtension foo.so.1 .so
686 test pkgMkIndex-14.4 {pkg_compareExtension} {unixOnly} {
687 pkg_compareExtension foo.so.1.2 .so
689 test pkgMkIndex-14.5 {pkg_compareExtension} {unixOnly} {
690 pkg_compareExtension foo .so
692 test pkgMkIndex-14.6 {pkg_compareExtension} {unixOnly} {
693 pkg_compareExtension foo.so.1.2.bar .so
700 namespace delete pkgtest
701 ::tcltest::cleanupTests