Changeset 2077 for trunk/tester/testtree.tcl
- Timestamp:
- Feb 1, 2011, 5:37:45 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tester/testtree.tcl
r2068 r2077 33 33 inherit itk::Widget 34 34 35 itk_option define -selectcommand selectCommand SelectCommand ""36 itk_option define -testdir testDir TestDir ""37 itk_option define -toolxml toolXml ToolXml ""38 39 35 constructor {args} { #defined later } 40 36 destructor { #defined later } 41 37 42 public method getTest {args} 43 public method refresh {args} 44 45 protected method getData {id} 46 protected method getLeaves {{id 0}} 47 protected method getSelected {} 48 protected method populate {args} 49 protected method runSelected {} 50 protected method runTest {id} 51 protected method setData {id data} 52 protected method updateLabel {} 53 38 public method add {args} 39 public method clear {} 40 public method curselection {} 41 42 protected method _getLeaves {{id 0}} 43 protected method _getTest {id} 44 protected method _refresh {args} 45 46 # add support for a spinning icon 47 proc spinner {op} 48 49 private common spinner 50 set spinner(frames) 8 51 set spinner(current) 0 52 set spinner(pending) "" 53 set spinner(uses) 0 54 55 for {set n 0} {$n < $spinner(frames)} {incr n} { 56 set spinner(frame$n) [Rappture::icon circle-ball[expr {$n+1}]] 57 } 58 set spinner(image) [image create photo -width [image width $spinner(frame0)] -height [image height $spinner(frame0)]] 54 59 } 55 60 … … 66 71 -xscrollmode auto -yscrollmode auto 67 72 } 73 pack $itk_component(scrollbars) -expand yes -fill both 74 68 75 itk_component add treeview { 69 76 blt::treeview $itk_component(scrollbars).treeview -separator | \ 70 -autocreate true -selectmode multiple 77 -autocreate true -selectmode multiple \ 78 -icons [list [Rappture::icon folder] [Rappture::icon folder2]] \ 79 -activeicons "" 71 80 } { 72 81 keep -foreground -font -cursor 73 } 74 $itk_component(treeview) column insert 0 result -width 75 82 keep -selectcommand 83 } 84 $itk_component(treeview) column insert 0 result -title "Result" 75 85 $itk_component(treeview) column insert end test -hide yes 86 $itk_component(treeview) column configure treeView -justify left -title "Test Case" 76 87 $itk_component(scrollbars) contents $itk_component(treeview) 77 88 … … 79 90 frame $itk_interior.bottomBar 80 91 } 81 pack $itk_component(bottomBar) -fill x -side bottom 92 pack $itk_component(bottomBar) -fill x -side bottom -pady {8 0} 93 94 itk_component add selLabel { 95 label $itk_component(bottomBar).selLabel -anchor w -text "Select:" 96 } 97 pack $itk_component(selLabel) -side left 82 98 83 99 itk_component add bSelectAll { 84 button $itk_component(bottomBar).bSelectAll -text " Select all" \100 button $itk_component(bottomBar).bSelectAll -text "All" \ 85 101 -command "$itk_component(treeview) selection set 0 end" 86 102 } … … 88 104 89 105 itk_component add bSelectNone { 90 button $itk_component(bottomBar).bSelectNone -text " Select none" \106 button $itk_component(bottomBar).bSelectNone -text "None" \ 91 107 -command "$itk_component(treeview) selection clearall" 92 108 } 93 109 pack $itk_component(bSelectNone) -side left 94 110 95 itk_component add bRun {96 button $itk_component(bottomBar).bRun -text "Run" -state disabled \97 -command [itcl::code $this runSelected]98 }99 pack $itk_component(bRun) -side right100 101 itk_component add lSelected {102 label $itk_component(bottomBar).lSelected -text "0 tests selected"103 }104 pack $itk_component(lSelected) -side right -padx 5105 106 # TODO: Fix black empty space when columns are shrunk107 108 pack $itk_component(scrollbars) -side left -expand yes -fill both109 111 110 112 eval itk_initialize $args 111 112 if {$itk_option(-testdir) == ""} {113 error "no -testdir configuration option given."114 }115 if {$itk_option(-toolxml) == ""} {116 error "no -toolxml configuration option given."117 }118 119 113 } 120 114 … … 123 117 # ---------------------------------------------------------------------- 124 118 itcl::body Rappture::Tester::TestTree::destructor {} { 125 foreach id [getLeaves] { 126 itcl::delete object [getTest $id] 127 } 128 } 129 130 # ---------------------------------------------------------------------- 131 # CONFIGURATION OPTION: -testdir 132 # 133 # Location of the directory containing a set of test xml files. 134 # Repopulate the tree if -testdir option is changed, but only if 135 # -toolxml has already been defined. 136 # ---------------------------------------------------------------------- 137 itcl::configbody Rappture::Tester::TestTree::testdir { 138 if {[file isdirectory $itk_option(-testdir)]} { 139 if {$itk_option(-toolxml) != ""} { 140 populate 141 } 142 } else { 143 error "Test directory \"$itk_option(-testdir)\" does not exist" 144 } 145 } 146 147 # ---------------------------------------------------------------------- 148 # CONFIGURATION OPTION: -toolxml 149 # 150 # Location of the tool.xml for the tool being tested. Repopulate the 151 # tree if -toolxml is changed, but only if -testdir has already been 152 # defined. 153 # ---------------------------------------------------------------------- 154 itcl::configbody Rappture::Tester::TestTree::toolxml { 155 if {[file exists $itk_option(-toolxml)]} { 156 if {$itk_option(-testdir) != ""} { 157 populate 158 } 159 } else { 160 error "Tool \"$itk_option(-testdir)\" does not exist" 161 } 162 } 163 164 # ---------------------------------------------------------------------- 165 # CONFIGURATION OPTION: -selectcommand 166 # 167 # Forward the TestTree's selectcommand to the treeview, but tack on the 168 # updateLabel method to keep the label refreshed when selection is 169 # changed 170 # ---------------------------------------------------------------------- 171 itcl::configbody Rappture::Tester::TestTree::selectcommand { 172 $itk_component(treeview) configure -selectcommand \ 173 "[itcl::code $this updateLabel]; $itk_option(-selectcommand)" 174 } 175 176 # ---------------------------------------------------------------------- 177 # USAGE getTest ?id? 119 clear 120 } 121 122 # ---------------------------------------------------------------------- 123 # USAGE: add ?<testObj> <testObj> ...? 124 # 125 # Adds one or more Test objects to the tree shown in this viewer. 126 # Once added, these objects become property of this widget and 127 # are destroyed when the widget is cleared or deleted. 128 # ---------------------------------------------------------------------- 129 itcl::body Rappture::Tester::TestTree::add {args} { 130 set icon [Rappture::icon testcase] 131 132 foreach obj $args { 133 if {[catch {$obj isa Rappture::Tester::Test} valid] || !$valid} { 134 error "bad value \"$obj\": should be Test object" 135 } 136 137 # add each Test object into the tree 138 set testpath [$obj getTestInfo test.label] 139 set n [$itk_component(treeview) insert end $testpath \ 140 -data [list test $obj] -icons [list $icon $icon]] 141 142 # tag this node so we can find it easily later 143 $itk_component(treeview) tag add $obj $n 144 145 # monitor state changes on the object 146 $obj configure -notifycommand [itcl::code $this _refresh] 147 } 148 } 149 150 # ---------------------------------------------------------------------- 151 # USAGE: clear 152 # 153 # Clears the contents of the tree so that it's completely empty. 154 # All Test objects stored internally are destroyed. 155 # ---------------------------------------------------------------------- 156 itcl::body Rappture::Tester::TestTree::clear {} { 157 foreach id [_getLeaves] { 158 itcl::delete object [_getTest $id] 159 } 160 $itk_component(treeview) delete 0 161 } 162 163 # ---------------------------------------------------------------------- 164 # USAGE: curselection 165 # 166 # Returns a list ids for all currently selected tests (leaf nodes) and 167 # the child tests of any currently selected branch nodes. Tests can 168 # only be leaf nodes in the tree (the ids in the returned list will 169 # correspond to leaf nodes only). 170 # ---------------------------------------------------------------------- 171 itcl::body Rappture::Tester::TestTree::curselection {} { 172 set rlist "" 173 foreach id [$itk_component(treeview) curselection] { 174 foreach node [_getLeaves $id] { 175 catch {unset data} 176 array set data [$itk_component(treeview) entry cget $node -data] 177 178 if {[lsearch -exact $rlist $data(test)] < 0} { 179 lappend rlist $data(test) 180 } 181 } 182 } 183 return $rlist 184 } 185 186 # ---------------------------------------------------------------------- 187 # USAGE _getTest <nodeId> 178 188 # 179 189 # Returns the test object associated with a given treeview node id. If … … 182 192 # branch node. 183 193 # ---------------------------------------------------------------------- 184 itcl::body Rappture::Tester::TestTree::getTest {args} { 185 if {[llength $args] == 0} { 186 set id [$itk_component(treeview) index focus] 187 } elseif {[llength $args] == 1} { 188 set id [lindex $args 0] 189 } else { 190 error "wrong # args: should be getTest ?id?" 191 } 192 array set darray [getData $id] 193 if {[lsearch -exact [getLeaves] $id] == -1} { 194 itcl::body Rappture::Tester::TestTree::_getTest {id} { 195 if {[lsearch -exact [_getLeaves] $id] < 0} { 194 196 # Return empty string if branch node selected 195 197 return "" 196 198 } 199 array set darray [$itk_component(treeview) entry cget $id -data] 197 200 return $darray(test) 198 201 } 199 202 200 203 # ---------------------------------------------------------------------- 201 # USAGE: refresh ?id? 202 # 203 # Refreshes the result column and any other information which may be 204 # added later for the given tree node id. Mainly needed to update the 205 # result from Fail to Pass after regoldenizing a test. If no id is 206 # given, refresh all tests and search the test directory again to check 207 # for new tests. 208 # ---------------------------------------------------------------------- 209 itcl::body Rappture::Tester::TestTree::refresh {args} { 210 if {[llength $args] == 0} { 211 foreach id [getLeaves] { 212 refresh $id 213 } 214 populate -noclear 215 } elseif {[llength $args] == 1} { 216 set id [lindex $args 0] 217 if {[lsearch -exact [getLeaves] $id] == -1} { 218 error "given id $id is not a leaf node." 219 } 220 set test [getTest $id] 221 setData $id [list result [$test getResult] test $test] 222 } else { 223 error "wrong # args: should be refresh ?id?" 224 } 225 } 226 227 # ---------------------------------------------------------------------- 228 # USAGE: getData <id> 229 # 230 # Returns a list of key-value pairs representing the column data stored 231 # at the tree node with the given id. 232 # ---------------------------------------------------------------------- 233 itcl::body Rappture::Tester::TestTree::getData {id} { 234 return [$itk_component(treeview) entry cget $id -data] 235 } 236 237 # ---------------------------------------------------------------------- 238 # USAGE: getLeaves ?id? 204 # USAGE: _refresh ?<testObj> <testObj> ...? 205 # 206 # Invoked whenever the state of a <testObj> changes. Finds the 207 # corresponding entry in the tree and updates the "Result" column 208 # to show the new status. 209 # ---------------------------------------------------------------------- 210 itcl::body Rappture::Tester::TestTree::_refresh {args} { 211 foreach obj $args { 212 set n [$itk_component(treeview) index $obj] 213 if {$n ne ""} { 214 catch {unset data} 215 array set data [$itk_component(treeview) entry cget $n -data] 216 217 # getting rid of a spinner? then drop it 218 if {[info exists data(result)] 219 && $data(result) == "@$spinner(image)"} { 220 spinner drop 221 } 222 223 # plug in the new icon 224 switch -- [$obj getResult] { 225 Pass { set data(result) "@[Rappture::icon pass16]" } 226 Fail { set data(result) "@[Rappture::icon fail16]" } 227 Waiting { set data(result) "@[Rappture::icon wait]" } 228 Running { set data(result) "@[spinner use]" } 229 default { set data(result) "" } 230 } 231 puts "ICON: $data(result)" 232 $itk_component(treeview) entry configure $n -data [array get data] 233 } 234 } 235 } 236 237 # ---------------------------------------------------------------------- 238 # USAGE: _getLeaves ?id? 239 239 # 240 240 # Returns a list of ids for all tests contained in the tree. If an … … 243 243 # id. Tests can only be leaf nodes. 244 244 # ---------------------------------------------------------------------- 245 itcl::body Rappture::Tester::TestTree:: getLeaves {{id 0}} {245 itcl::body Rappture::Tester::TestTree::_getLeaves {{id 0}} { 246 246 set clist [$itk_component(treeview) entry children $id] 247 247 if {$clist == "" && $id == 0} { … … 254 254 set tests [list] 255 255 foreach child $clist { 256 set tests [concat $tests [ getLeaves $child]]256 set tests [concat $tests [_getLeaves $child]] 257 257 } 258 258 return $tests … … 260 260 261 261 # ---------------------------------------------------------------------- 262 # USAGE: getSelected 263 # 264 # Returns a list ids for all currently selected tests (leaf nodes) and 265 # the child tests of any currently selected branch nodes. Tests can 266 # only be leaf nodes in the tree (the ids in the returned list will 267 # correspond to leaf nodes only). 268 # ---------------------------------------------------------------------- 269 itcl::body Rappture::Tester::TestTree::getSelected {} { 270 set selection [$itk_component(treeview) curselection] 271 set selectedTests [list] 272 foreach id $selection { 273 foreach node [getLeaves $id] { 274 if {[lsearch -exact $selectedTests $node] == -1} { 275 lappend selectedTests $node 276 } 277 } 278 } 279 return $selectedTests 280 } 281 282 # ---------------------------------------------------------------------- 283 # USAGE: populate ?-noclear? 284 # 285 # Used internally to insert nodes into the treeview for each test xml 286 # found in the test directory. Skips any xml files that do not contain 287 # information at path test.label. Relies on the autocreate treeview 288 # option so that branch nodes need not be explicitly created. Deletes 289 # any existing contents unless -noclear is given as an argument. 290 # ---------------------------------------------------------------------- 291 itcl::body Rappture::Tester::TestTree::populate {args} { 292 if {[lsearch $args -noclear] == -1} { 293 foreach id [getLeaves] { 294 itcl::delete object [getTest $id] 295 } 296 $itk_component(treeview) delete 0 297 $itk_component(treeview) selection clearall 298 } 299 # TODO: add an appropriate icon 300 set icon [Rappture::icon molvis-3dorth] 301 # TODO: Descend through subdirectories inside testdir? 302 foreach testxml [glob -nocomplain -directory $itk_option(-testdir) *.xml] { 303 set lib [Rappture::library $testxml] 304 set testpath [$lib get test.label] 305 if {$testpath != "" && \ 306 [$itk_component(treeview) find -full $testpath] == ""} { 307 set test [Rappture::Tester::Test ::#auto \ 308 $itk_option(-toolxml) $testxml] 309 $itk_component(treeview) insert end $testpath -data \ 310 [list test $test] -icons "$icon $icon" \ 311 -activeicons "$icon $icon" 312 } 313 } 314 $itk_component(treeview) open -recurse root 315 # TODO: Fix width of main treeview column 316 updateLabel 317 } 318 319 # ---------------------------------------------------------------------- 320 # USAGE: runSelected 321 # 322 # Invoked by the run button to run all currently selected tests. 323 # After completion, call selectcommand to re-select the newly completed 324 # focused node. 325 # ---------------------------------------------------------------------- 326 itcl::body Rappture::Tester::TestTree::runSelected {} { 327 foreach id [$this getSelected] { 328 runTest $id 329 } 330 # Try calling selectcommand with the -refresh option. If selectcommand 331 # does not accept this argument, then call it with no arguments. 332 if {[catch {eval $itk_option(-selectcommand) -refresh}]} { 333 eval $itk_option(-selectcommand) 334 } 335 } 336 337 # ---------------------------------------------------------------------- 338 # USAGE: runTest id 339 # 340 # Runs the test located at the tree node with the given id. The id 341 # must be a leaf node, because tests may not be located at branch nodes. 342 # ---------------------------------------------------------------------- 343 itcl::body Rappture::Tester::TestTree::runTest {id} { 344 if {[lsearch -exact [getLeaves] $id] == -1} { 345 error "given id $id is not a leaf node" 346 } 347 set test [getTest $id] 348 setData $id [list result Running test $test] 349 $test run 350 setData $id [list result [$test getResult] test $test] 351 } 352 353 # ---------------------------------------------------------------------- 354 # USAGE: setData <id> <data> 355 # 356 # Accepts a node id and a list of key-value pairs. Stored the list as 357 # column data associated with the tree node with the given id. 358 # ---------------------------------------------------------------------- 359 itcl::body Rappture::Tester::TestTree::setData {id data} { 360 $itk_component(treeview) entry configure $id -data $data 361 } 362 363 # ---------------------------------------------------------------------- 364 # USAGE: updateLabel 365 # 366 # Used internally to update the label which indicates how many tests 367 # are currently selected. Also disables the run button if no tests are 368 # selected. 369 # ---------------------------------------------------------------------- 370 itcl::body Rappture::Tester::TestTree::updateLabel {} { 371 set n [llength [getSelected]] 372 if {$n == 1} { 373 $itk_component(lSelected) configure -text "1 test selected" 374 } else { 375 $itk_component(lSelected) configure -text "$n tests selected" 376 } 377 378 if {$n > 0} { 379 $itk_component(bRun) configure -state normal 380 } else { 381 $itk_component(bRun) configure -state disabled 382 } 383 } 384 262 # USAGE: spinner use|drop|next 263 # 264 # Used to update the spinner icon that represents running test cases. 265 # The "use" option returns the spinner icon and starts the animation, 266 # if it isn't already running. The "drop" operation lets go of the 267 # spinner. If nobody is using it, the animation stops. The "next" 268 # option is used internally to change the animation to the next frame. 269 # ---------------------------------------------------------------------- 270 itcl::body Rappture::Tester::TestTree::spinner {op} { 271 switch -- $op { 272 use { 273 if {$spinner(pending) == ""} { 274 set spinner(current) 0 275 set spinner(pending) [after 100 Rappture::Tester::TestTree::spinner next] 276 } 277 incr spinner(uses) 278 return $spinner(image) 279 } 280 drop { 281 if {[incr spinner(uses) -1] <= 0} { 282 after cancel $spinner(pending) 283 set spinner(pending) "" 284 set spinner(uses) 0 285 } 286 } 287 next { 288 set n $spinner(current) 289 $spinner(image) copy $spinner(frame$n) 290 291 # go to the next frame 292 if {[incr spinner(current)] >= $spinner(frames)} { 293 set spinner(current) 0 294 } 295 296 # update again after a short delay 297 set spinner(pending) [after 100 Rappture::Tester::TestTree::spinner next] 298 } 299 default { 300 error "bad option \"$op\": should be use, drop, next" 301 } 302 } 303 }
Note: See TracChangeset
for help on using the changeset viewer.