1# 2# filescan.test 3# 4# Tests for the scancontext and scanfile commands. 5#--------------------------------------------------------------------------- 6# Copyright 1992-1999 Karl Lehenbauer and Mark Diekhans. 7# 8# Permission to use, copy, modify, and distribute this software and its 9# documentation for any purpose and without fee is hereby granted, provided 10# that the above copyright notice appear in all copies. Karl Lehenbauer and 11# Mark Diekhans make no representations about the suitability of this 12# software for any purpose. It is provided "as is" without express or 13# implied warranty. 14#------------------------------------------------------------------------------ 15# $Id: filescan.test,v 1.2 2002/04/02 02:29:43 hobbs Exp $ 16#------------------------------------------------------------------------------ 17# 18 19if {[cequal [info procs Test] {}]} { 20 source [file join [file dirname [info script]] testlib.tcl] 21} 22 23# Increment a name. This takes a name and "adds one" to it, that is advancing 24# each digit lexically through "0"..."9" -> "A"-"Z" -> "a"..."z". When one 25# digit wraps, the next one is advanced. Optional arg forces upper case only 26# if true and start with all upper case or digits. 27 28proc IncrName {Name args} { 29 set Upper [expr {([llength $args] == 1) && [lindex $args 0]}] 30 set Last [expr [clength $Name]-1] 31 set Begin [csubstr $Name 0 $Last] 32 set Digit [cindex $Name $Last] 33 set Recurse 0 34 case $Digit in { 35 {9} {set Digit A} 36 {Z} {if {$Upper} {set Recurse 1} else {set Digit a}} 37 {z} {set Recurse 1} 38 default {set Digit [ctype char [expr [ctype ord $Digit]+1]]} 39 } 40 if {$Recurse} { 41 if {$Last == 0} then { 42 return 0 ;# Wrap around 43 } else { 44 return "[IncrName $Begin]0" 45 } 46 } 47 return "$Begin$Digit" 48} 49 50# Proc to generate record that can be validated. The record has 51# grows quite large to test the dynamic buffering in the file I/O. 52 53proc GenScanRec {key lineNum} { 54 set extra [replicate :@@@@@@@@: $lineNum] 55 return "$key This is a test record ($extra) index is $key" 56} 57 58# Proc to validate a matched record. 59 60proc ValMatch {scanInfo id} { 61 global testFH matchInfo 62 63 Test filescan-${id}.1 {filescan tests} { 64 list line $matchInfo(line) 65 } 0 [list line [GenScanRec [keylget scanInfo key] \ 66 [keylget scanInfo linenum]]] 67 68 Test filescan-${id}.2 {filescan tests} { 69 list offset $matchInfo(offset) 70 } 0 [list offset [keylget scanInfo offset]] 71 72 if 0 { 73 Test filescan-${id}.2.1 {filescan tests} { 74 list bytesread $matchInfo(bytesread) 75 } 0 [list bytesread [keylget scanInfo bytesread]] 76 } 77 78 Test filescan-${id}.3 {filescan tests} { 79 list linenum $matchInfo(linenum) 80 } 0 [list linenum [keylget scanInfo linenum]] 81 82 Test filescan-${id}.4 {filescan tests} { 83 list handle $matchInfo(handle) 84 } 0 [list handle $testFH] 85 86 global matchCnt 87 incr matchCnt([keylget scanInfo matchType]) 88} 89 90global matchInfo matchCnt chkMatchCnt testFH 91 92foreach i {0 1 2 3 df} { 93 set chkMatchCnt($i) 0 94} 95set scanList {} 96set maxRec 200 97 98# Build a test file and a list of records to scan for. Each element in the 99# list will have the following info: 100# {key fileOffset fileLineNumber matchType} 101# Also build a file to diff against for the -copyfile option. 102 103TestRemove TEST.TMP TEST2.TMP TESTCHK.TMP 104 105set testFH [open TEST.TMP w] 106set testChkFH [open TESTCHK.TMP w] 107 108set key FatHeadAAAA 109set bytesRead 0 110for {set cnt 0} {$cnt < $maxRec} {incr cnt} { 111 set rec [GenScanRec $key [expr $cnt+1]] 112 incr bytesRead [expr [clength $rec] + 1] 113 if {($cnt % 10) == 0} { 114 set matchType [random 4] 115 incr chkMatchCnt($matchType) 116 set scanInfo {} 117 keylset scanInfo key $key 118 keylset scanInfo offset [tell $testFH] 119 keylset scanInfo bytesread $bytesRead 120 keylset scanInfo linenum [expr $cnt+1] 121 keylset scanInfo matchType $matchType 122 if {[random 2]} { 123 set scanList [concat $scanList [list $scanInfo]] 124 } else { 125 set scanList [concat [list $scanInfo] $scanList] 126 } 127 } else { 128 incr chkMatchCnt(df) 129 puts $testChkFH $rec 130 } 131 if {$cnt == [expr $maxRec/2]} { 132 set midKey $key 133 } 134 puts $testFH $rec 135 set key [IncrName $key 1] ;# Upper case only 136} 137 138close $testFH 139close $testChkFH 140 141# Build up the scan context. 142 143set testCH [scancontext create] 144 145foreach scanInfo $scanList { 146 set key [keylget scanInfo key] 147 set matchType [keylget scanInfo matchType] 148 set cmd "global matchInfo; ValMatch [list $scanInfo] 1.1" 149 case $matchType in { 150 {0} {scanmatch -nocase $testCH [string toupper $key] $cmd} 151 {1} {scanmatch $testCH ^$key $cmd} 152 {2} {scanmatch $testCH $key\$ $cmd} 153 {3} {scanmatch $testCH $key $cmd} 154 } 155} 156 157scanmatch $testCH { 158 global matchCnt testFH matchInfo 159 160 incr matchCnt(df) 161 162 Test filescan-1.2 {filescan tests} { 163 set matchInfo(handle) 164 } 0 $testFH 165} 166 167proc ValScan id { 168 global matchInfo matchCnt chkMatchCnt testFH 169 170 Test filescan-${id}.1 {filescan tests} { 171 set matchCnt(0) 172 } 0 [set chkMatchCnt(0)] 173 174 Test filescan-${id}.2 {filescan tests} { 175 set matchCnt(1) 176 } 0 [set chkMatchCnt(1)] 177 178 Test filescan-${id}.3 {filescan tests} { 179 set matchCnt(2) 180 } 0 [set chkMatchCnt(2)] 181 182 Test filescan-${id}.4 {filescan tests} { 183 set matchCnt(3) 184 } 0 [set chkMatchCnt(3)] 185 186 Test filescan-${id}.5 {filescan tests} { 187 set matchCnt(df) 188 } 0 [set chkMatchCnt(df)] 189} 190 191foreach i {0 1 2 3 df} { 192 set matchCnt($i) 0 193} 194set testFH [open TEST.TMP r] 195scanfile $testCH $testFH 196close $testFH 197ValScan 1.3 198 199foreach i {0 1 2 3 df} { 200 set matchCnt($i) 0 201} 202set testFH [open TEST.TMP r] 203set test2FH [open TEST2.TMP w] 204scanfile -copyfile $test2FH $testCH $testFH 205close $testFH 206close $test2FH 207ValScan 1.4 208 209Test filescan-1.5 {filescan tests} { 210 set fh [open TESTCHK.TMP] 211 set TESTCHK [read $fh] 212 close $fh 213 set fh [open TEST2.TMP] 214 set TEST2 [read $fh] 215 close $fh 216 cequal $TESTCHK $TEST2 217} 0 1 218catch {unset TESTCHK} 219catch {unset TEST2} 220 221scancontext delete $testCH 222 223# Test return and continue from within match commands 224 225set testFH [open TEST.TMP r] 226 227set testCH [scancontext create] 228seek $testFH 0 229global matchCnt 230set matchCnt(0) 0 231 232scanmatch $testCH $midKey { 233 global matchCnt 234 incr matchCnt(0) 235 continue; 236} 237 238scanmatch $testCH ^$midKey { 239 error "This should not ever get executed 2.1" 240} 241 242scanmatch $testCH [IncrName $midKey] { 243 return "FudPucker" 244} 245 246Test filescan-2.2 {filescan tests} { 247 scanfile $testCH $testFH 248} 0 "FudPucker" 249 250scancontext delete $testCH 251 252# Test argument checking and error handling. 253 254Test filescan-3.1 {filescan tests} { 255 scancontext foomuch 256} 1 {invalid argument, expected one of: "create", "delete", or "copyfile"} 257 258Test filescan-3.2 {filescan tests} { 259 scanmatch $testCH 260} 1 {wrong # args: scanmatch ?-nocase? contexthandle ?regexp? command} 261 262Test filescan-3.3 {filescan tests} { 263 scanmatch 264} 1 {wrong # args: scanmatch ?-nocase? contexthandle ?regexp? command} 265 266Test filescan-3.4 {filescan tests} { 267 scanfile 268} 1 {wrong # args: scanfile ?-copyfile filehandle? contexthandle filehandle} 269 270Test filescan-3.5 {filescan tests} { 271 set testCH [scancontext create] 272 scanfile $testCH $testFH 273} 1 {no patterns in current scan context} 274 275Test filescan-3.6 {filescan tests} { 276 scancontext copyfile 277} 1 {wrong # args: scancontext copyfile contexthandle ?filehandle?} 278 279Test filescan-3.7 {filescan tests} { 280 scancontext copyfile $testCH x y 281} 1 {wrong # args: scancontext copyfile contexthandle ?filehandle?} 282 283 284catch {scancontext delete $testCH} 285 286close $testFH 287 288# 289# Test subMatch handling. 290# 291 292set testFH [open TEST.TMP w] 293loop idx 0 10 { 294 puts $testFH "AAx[replicate xx $idx]xBBc[replicate cc $idx]cDD" 295} 296close $testFH 297 298# Procedure to verify submatches. Works for upper or lower case. 299 300proc ChkSubMatch {id matchInfoVar} { 301 upvar $matchInfoVar matchInfo 302 303 set idx [expr $matchInfo(linenum) - 1] 304 305 set end0 [expr 3+($idx * 2)] 306 Test filescan-$id.0.$idx {filescan tests} { 307 set matchInfo(submatch0) 308 } 0 "x[replicate xx $idx]x" 309 Test filescan-$id.1.$idx {filescan tests} { 310 set matchInfo(subindex0) 311 } 0 "2 $end0" 312 313 set start1 [expr $end0+3] 314 set end1 [expr $start1+($idx*2)+1] 315 Test filescan-$id.2.$idx {filescan tests} { 316 set matchInfo(submatch1) 317 } 0 "c[replicate cc $idx]c" 318 Test filescan-$id.3.$idx {filescan tests} { 319 set matchInfo(subindex1) 320 } 0 "$start1 $end1" 321 322 Test filescan-$id.4.$idx {filescan tests} { 323 list [info exists matchInfo(submatch2)] \ 324 [info exists matchInfo(subindex2)] 325 } 0 {0 0} 326} 327 328set testFH [open TEST.TMP r] 329 330set testCH [scancontext create] 331scanmatch $testCH {A*(x*)B*(c*)DD} { 332 ChkSubMatch 4 matchInfo 333} 334 335scanmatch -nocase $testCH {Aa(x*)B(C*)Dd} { 336 ChkSubMatch 5 matchInfo 337} 338 339scanfile $testCH $testFH 340 341scancontext delete $testCH 342close $testFH 343 344# 345# Test optional match patterns. 346# 347set testFH [open TEST.TMP w] 348puts $testFH {ABCD : efgh 123435} 349puts $testFH {HIJK : efgh 123435} 350puts $testFH {ABCD : efgh X123435} 351puts $testFH {HIJK : efgh X123435} 352close $testFH 353 354set testCH [scancontext create] 355scanmatch $testCH {([H-Z]+)? : ([a-z]+) (X)?([0-9]+)} { 356 set thisLine {} 357 for {set idx 0} {$idx < 50} {incr idx} { 358 if {!([info exists matchInfo(submatch$idx)] || 359 [info exists matchInfo(subindex$idx)])} continue 360 361 set this [list $idx] 362 lappend this [info exists matchInfo(submatch$idx)] 363 lappend this [info exists matchInfo(subindex$idx)] 364 if [info exists matchInfo(submatch$idx)] { 365 lappend this $matchInfo(submatch$idx) 366 } 367 if [info exists matchInfo(subindex$idx)] { 368 lappend this $matchInfo(subindex$idx) 369 } 370 lappend thisLine $this 371 } 372 lappend matches $thisLine 373 catch {unset this} 374 unset thisLine 375} 376 377set testFH [open TEST.TMP r] 378Test filescan-6.1 {filescan tests} { 379 set matches {} 380 scanfile $testCH $testFH 381 set matches 382} 0 [list \ 383 [list {0 1 1 {} {-1 -1}} \ 384 {1 1 1 efgh {7 10}} \ 385 {2 1 1 {} {-1 -1}} \ 386 {3 1 1 123435 {12 17}}] \ 387 [list {0 1 1 HIJK {0 3}} \ 388 {1 1 1 efgh {7 10}} \ 389 {2 1 1 {} {-1 -1}} \ 390 {3 1 1 123435 {12 17}}] \ 391 [list {0 1 1 {} {-1 -1}} \ 392 {1 1 1 efgh {7 10}} \ 393 {2 1 1 X {12 12}} \ 394 {3 1 1 123435 {13 18}}] \ 395 [list {0 1 1 HIJK {0 3}} \ 396 {1 1 1 efgh {7 10}} \ 397 {2 1 1 X {12 12}} \ 398 {3 1 1 123435 {13 18}}]] 399close $testFH 400scancontext delete $testCH 401 402set testCH [scancontext create] 403 404Test filescan-7.1 {filescan tests} { 405 scanmatch $testCH {a[} {} 406} 1 {couldn't compile regular expression pattern: brackets [] not balanced} 407 408# 409# Test the copy file manipulation by sorting a file of numbered lines into two 410# files of odd and even. 411# 412 413set testFH [open TEST.TMP w] 414loop cnt 0 101 { 415 puts $testFH "Line $cnt" 416 puts $testFH "Match me" 417} 418close $testFH 419set testFH [open TEST.TMP r] 420 421set testChkFH [open TESTCHK.TMP w] 422set testChk2FH [open TESTCHK2.TMP w] 423 424set testCH [scancontext create] 425scancontext copyfile $testCH $testChkFH 426 427Test filescan-8.1 {filescan tests} { 428 scancontext copyfile $testCH 429} 0 $testChkFH 430 431scanmatch $testCH {^Match me$} { 432 if [cequal [scancontext copyfile $matchInfo(context)] $testChkFH] { 433 scancontext copyfile $matchInfo(context) $testChk2FH 434 } elseif [cequal [scancontext copyfile $matchInfo(context)] $testChk2FH] { 435 scancontext copyfile $matchInfo(context) $testChkFH 436 } else { 437 Test filescan-8.2 {filescan tests} { 438 scancontext copyfile $matchInfo(context) 439 } 0 "should have been $testChkFH or $testChk2FH" 440 } 441} 442 443scanfile $testCH $testFH 444 445close $testFH 446close $testChkFH 447close $testChk2FH 448scancontext delete $testCH 449 450set testChkFH [open TESTCHK.TMP r] 451set testChk2FH [open TESTCHK2.TMP r] 452loop cnt 0 101 2 { 453 Test filescan-8.3 {filescan tests} { 454 gets $testChkFH 455 } 0 "Line $cnt" 456} 457 458loop cnt 1 101 2 { 459 Test filescan-8.4 {filescan tests} { 460 gets $testChk2FH 461 } 0 "Line $cnt" 462} 463 464close $testChkFH 465close $testChk2FH 466 467# 468# Test for the problem De Clarke found with Boyer-Moore. 469# 470 471Test 9.1 {filescan tests} { 472 set testFH [open TEST.TMP w] 473 puts $testFH \ 474 {Sun Dec 01 14:56:08 1996 mask1a.ps kelson bigdog.ucolick.org 1} 475 close $testFH 476 477 set linesMatched {} 478 set testCH [scancontext create] 479 scanmatch $testCH {[A-z] Dec [0-9]* [0123456789:]* 1996 } { 480 lappend linesMatched $matchInfo(line) 481 } 482 set testFH [open TEST.TMP] 483 scanfile $testCH $testFH 484 close $testFH 485 set linesMatched 486} 0 {{Sun Dec 01 14:56:08 1996 mask1a.ps kelson bigdog.ucolick.org 1}} 487 488# 489# Test some regexps that have caused probelms in the past. 490# 491Test 9.2 {filescan tests} { 492 set ch [scancontext create] 493 scanmatch -nocase $ch {^[a-z]} {echo foo} 494 scancontext delete $ch 495} 0 {} 496 497Test 9.3 {filescan tests} { 498 # Tuende Kriegl <tuende.kriegl@mch.sni.de> says this 499 # panics on NT but not unix! 500 set ch [scancontext create] 501 scanmatch $ch {([^(]*).'([^']*).*%OpText %(.*)} {echo foo} 502 scancontext delete $ch 503} 0 {} 504 505Test 9.1 {filescan tests} { 506 set testFH [open TEST.TMP w] 507 puts $testFH "foo\nbar" 508 close $testFH 509 510 set linesMatched {} 511 set testCH [scancontext create] 512 scanmatch $testCH {foo|bar} { 513 lappend linesMatched $matchInfo(line) 514 } 515 set testFH [open TEST.TMP] 516 scanfile $testCH $testFH 517 close $testFH 518 set linesMatched 519} 0 {foo bar} 520 521TestRemove TEST.TMP TEST2.TMP TESTCHK.TMP TESTCHK2.TMP 522 523rename GenScanRec {} 524rename ValMatch {} 525rename ValScan {} 526rename ChkSubMatch {} 527 528unset matchCnt chkMatchCnt matchInfo testFH test2FH testChkFH testChk2FH 529 530 531