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