| 1 | # Functions used by widget tests. |
| 2 | |
| 3 | import imp |
| 4 | import os |
| 5 | import re |
| 6 | import string |
| 7 | import sys |
| 8 | import traceback |
| 9 | import types |
| 10 | import Tkinter |
| 11 | import _tkinter |
| 12 | |
| 13 | if Tkinter.TkVersion >= 8.4: |
| 14 | refcountafterdestroy = 7 |
| 15 | else: |
| 16 | refcountafterdestroy = 6 |
| 17 | |
| 18 | script_name = imp.find_module(__name__)[1] |
| 19 | if not os.path.isabs(script_name): |
| 20 | script_name = os.path.join(os.getcwd(), script_name) |
| 21 | |
| 22 | while 1: |
| 23 | script_dir = os.path.dirname(script_name) |
| 24 | if not os.path.islink(script_name): |
| 25 | break |
| 26 | script_name = os.path.join(script_dir, os.readlink(script_name)) |
| 27 | script_dir = os.path.join(os.getcwd(), script_dir) |
| 28 | script_dir = os.path.normpath(script_dir) |
| 29 | |
| 30 | # Add the '../../..' directory to the path. |
| 31 | package_dir = os.path.dirname(script_dir) |
| 32 | package_dir = os.path.dirname(package_dir) |
| 33 | package_dir = os.path.dirname(package_dir) |
| 34 | sys.path[:0] = [package_dir] |
| 35 | |
| 36 | import Pmw |
| 37 | # Need to import TestVersion, rather than do its work here, since |
| 38 | # __name__ will be known there. |
| 39 | import TestVersion |
| 40 | |
| 41 | # Set this to 1 to generate tracebacks on exceptions, rather than |
| 42 | # catching them and continuing with the tests. |
| 43 | # This is useful for debugging the test scripts. |
| 44 | dont_even_try = 0 |
| 45 | |
| 46 | _delay = 1 |
| 47 | _verbose = 0 |
| 48 | _printTraceback = 0 |
| 49 | _initialised = 0 |
| 50 | |
| 51 | ############################################################################## |
| 52 | # Public functions: |
| 53 | |
| 54 | rand = 12345 |
| 55 | def random(): |
| 56 | global rand |
| 57 | rand = (rand * 125) % 2796203 |
| 58 | return rand |
| 59 | |
| 60 | def initialise(): |
| 61 | global _initialised, font, flagup, earthris, emptyimage, \ |
| 62 | stringvar, floatvar, root, reliefs |
| 63 | if not _initialised: |
| 64 | root = Tkinter.Tk(className = 'PmwTest') |
| 65 | root.withdraw() |
| 66 | if os.name == 'nt': |
| 67 | size = 16 |
| 68 | else: |
| 69 | size = 12 |
| 70 | Pmw.initialise(root, size = size, fontScheme = 'pmw2') |
| 71 | font = {} |
| 72 | font['small'] = '6x13' |
| 73 | font['large'] = '10x20' |
| 74 | font['variable'] = '-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*' |
| 75 | flagup = Tkinter.BitmapImage(file = 'flagup.bmp') |
| 76 | earthris = Tkinter.PhotoImage(file = 'earthris.gif') |
| 77 | emptyimage = Tkinter.PhotoImage() |
| 78 | stringvar = Tkinter.StringVar() |
| 79 | stringvar.set('this is some text') |
| 80 | floatvar = Tkinter.DoubleVar() |
| 81 | floatvar.set(50.0) |
| 82 | if haveBlt(): |
| 83 | global vectorSize, vector_x, vector_y |
| 84 | vector_x = Pmw.Blt.Vector() |
| 85 | vector_y = [] |
| 86 | for y in range(3): |
| 87 | vector_y.append(Pmw.Blt.Vector()) |
| 88 | vectorSize = 50 |
| 89 | for index in range(vectorSize): |
| 90 | vector_x.append(index) |
| 91 | vector_y[0].append(random() % 100) |
| 92 | vector_y[1].append(random() % 200) |
| 93 | vector_y[2].append(random() % 100 + 300) |
| 94 | |
| 95 | # "solid" relief type was added to 8.0 |
| 96 | if Tkinter.TkVersion >= 8.0: |
| 97 | reliefs = 'flat, groove, raised, ridge, solid, or sunken' |
| 98 | else: |
| 99 | reliefs = 'flat, groove, raised, ridge, or sunken' |
| 100 | |
| 101 | _initialised = 1 |
| 102 | |
| 103 | def haveBlt(): |
| 104 | return Pmw.Blt.haveblt(root) |
| 105 | |
| 106 | def bell(): |
| 107 | root.bell() |
| 108 | |
| 109 | def setdelay(newdelay): |
| 110 | global _delay |
| 111 | _delay = newdelay |
| 112 | |
| 113 | def setverbose(newverbose): |
| 114 | global _verbose |
| 115 | _verbose = newverbose |
| 116 | |
| 117 | def printtraceback(newprintTraceback = 1): |
| 118 | global _printTraceback |
| 119 | _printTraceback = newprintTraceback |
| 120 | |
| 121 | def num_options(widget): |
| 122 | return len(widget.configure()) |
| 123 | |
| 124 | def callback(): |
| 125 | return 1 |
| 126 | |
| 127 | def callback1(dummy): |
| 128 | # Callback taking 1 argument |
| 129 | return dummy |
| 130 | |
| 131 | def callback2(dummy1, dummy2): |
| 132 | # Callback taking 2 arguments |
| 133 | return (dummy1, dummy2) |
| 134 | |
| 135 | def callbackN(*args): |
| 136 | # Callback taking zero or more arguments |
| 137 | return args |
| 138 | |
| 139 | def actioncallback(): |
| 140 | w = currentWidget() |
| 141 | w.action('button press') |
| 142 | |
| 143 | def currentWidget(): |
| 144 | return _currentWidget |
| 145 | |
| 146 | def delay(): |
| 147 | return _delay |
| 148 | |
| 149 | def set_geom(width, height): |
| 150 | _currentToplevel.geometry(str(width) + 'x' + str(height)) |
| 151 | |
| 152 | def runTests(allTestData): |
| 153 | root.after(_delay, _runTest, None, None, allTestData, 0, -1, -1) |
| 154 | root.mainloop() |
| 155 | |
| 156 | _pattern = None |
| 157 | |
| 158 | ############################################################################## |
| 159 | # Private functions: |
| 160 | |
| 161 | def _print_results(result, expected, description): |
| 162 | if type(expected) == types.ClassType: |
| 163 | if hasattr(result, '__class__'): |
| 164 | ok = (result.__class__ == expected) |
| 165 | else: |
| 166 | ok = 0 |
| 167 | else: |
| 168 | ok = (result == expected) |
| 169 | |
| 170 | # Megawidgets return a value of the correct type. Tk widgets |
| 171 | # always return a string, so convert the string and check again. |
| 172 | if not ok: |
| 173 | if type(expected) == types.InstanceType: |
| 174 | if result == str(expected) and ( |
| 175 | expected is earthris or expected is stringvar or |
| 176 | expected is floatvar or expected is flagup): |
| 177 | ok = 1 |
| 178 | elif hasattr(_tkinter, 'Tcl_Obj') and \ |
| 179 | type(result) == _tkinter.Tcl_Obj: |
| 180 | ok = (str(stringvar) == result.string) |
| 181 | elif type(expected) == types.IntType: |
| 182 | if type(result) is types.StringType: |
| 183 | try: |
| 184 | ok = (string.atoi(result) == expected) |
| 185 | except ValueError: |
| 186 | pass |
| 187 | elif hasattr(_tkinter, 'Tcl_Obj') and \ |
| 188 | type(result) == _tkinter.Tcl_Obj: |
| 189 | ok = (string.atoi(str(result)) == expected) |
| 190 | elif type(expected) == types.FloatType: |
| 191 | if type(result) is types.StringType: |
| 192 | try: |
| 193 | ok = (string.atof(result) == expected) |
| 194 | except ValueError: |
| 195 | pass |
| 196 | elif expected == callback: |
| 197 | ok = re.search('^[0-9]*callback$', str(result)) is not None |
| 198 | elif expected == callback1: |
| 199 | ok = re.search('^[0-9]*callback1$', str(result)) is not None |
| 200 | elif expected == callback2: |
| 201 | ok = re.search('^[0-9]*callback2$', str(result)) is not None |
| 202 | elif expected == actioncallback: |
| 203 | ok = re.search('^[0-9]*actioncallback$',str(result)) is not None |
| 204 | |
| 205 | if not ok or _verbose > 0: |
| 206 | print '====', description |
| 207 | if not ok or _verbose > 1: |
| 208 | print '==== result was:' |
| 209 | print result, type(result) |
| 210 | if ok: |
| 211 | if _verbose > 1: |
| 212 | print '++++ PASSED' |
| 213 | else: |
| 214 | print '---- result should have been:' |
| 215 | print expected, type(expected) |
| 216 | if _printTraceback: |
| 217 | traceback.print_exc() |
| 218 | print '---- FAILED' |
| 219 | print |
| 220 | |
| 221 | def _destroyToplevel(top, title): |
| 222 | if _verbose > 0: |
| 223 | print '==== destruction of Toplevel for', title |
| 224 | top.destroy() |
| 225 | |
| 226 | def _Toplevel(title): |
| 227 | if _verbose > 0: |
| 228 | print '==== construction of Toplevel for', title |
| 229 | top = Tkinter.Toplevel() |
| 230 | top.geometry('+100+100') |
| 231 | top.title(title) |
| 232 | return top |
| 233 | |
| 234 | def _constructor(isWidget, top, classCmd, kw): |
| 235 | if _verbose > 0: |
| 236 | print '====', classCmd.__name__, 'construction' |
| 237 | if isWidget: |
| 238 | if dont_even_try: |
| 239 | w = apply(classCmd, (top,), kw) |
| 240 | else: |
| 241 | try: |
| 242 | w = apply(classCmd, (top,), kw) |
| 243 | except: |
| 244 | print 'Could not construct', classCmd.__name__ |
| 245 | traceback.print_exc() |
| 246 | print 'Can not continue' |
| 247 | print 'Bye' |
| 248 | return None |
| 249 | |
| 250 | isMegaWidget = hasattr(classCmd, 'defineoptions') |
| 251 | # Check the option types: |
| 252 | options = w.configure() |
| 253 | option_list = options.keys() |
| 254 | option_list.sort() |
| 255 | for option in option_list: |
| 256 | # Some of the options (like bd, bg and fg) have only two parts |
| 257 | # and are just abbreviations. Only check 'real' options. |
| 258 | if len(options[option]) == 5: |
| 259 | initoption = isMegaWidget and w.isinitoption(option) |
| 260 | if dont_even_try: |
| 261 | value = w.cget(option) |
| 262 | if option not in ('class', 'container') and not initoption: |
| 263 | apply(w.configure, (), {option : value}) |
| 264 | newvalue = w.cget(option) |
| 265 | if newvalue != value: |
| 266 | print '====', classCmd.__name__, 'widget', \ |
| 267 | '\'' + option + '\'', 'option' |
| 268 | print '---- setting option returns different value' |
| 269 | print '==== new value was:' |
| 270 | print newvalue, type(newvalue) |
| 271 | print '---- set value was:' |
| 272 | print value, type(value) |
| 273 | print '---- FAILED' |
| 274 | print |
| 275 | else: |
| 276 | try: |
| 277 | value = w.cget(option) |
| 278 | if option not in ('class', 'container') and not initoption: |
| 279 | try: |
| 280 | apply(w.configure, (), {option : value}) |
| 281 | newvalue = w.cget(option) |
| 282 | if hasattr(_tkinter, 'Tcl_Obj') and \ |
| 283 | ( |
| 284 | (type(newvalue) == _tkinter.Tcl_Obj |
| 285 | and str(newvalue) != str(value)) |
| 286 | or |
| 287 | (type(newvalue) != _tkinter.Tcl_Obj |
| 288 | and newvalue != value) |
| 289 | ) or \ |
| 290 | ( |
| 291 | not hasattr(_tkinter, 'Tcl_Obj') and |
| 292 | newvalue != value |
| 293 | ): |
| 294 | print '====', classCmd.__name__, 'widget', \ |
| 295 | '\'' + option + '\'', 'option' |
| 296 | print '---- setting option returns different value' |
| 297 | print '==== new value was:' |
| 298 | print `newvalue`, type(newvalue) |
| 299 | print '---- set value was:' |
| 300 | print `value`, type(value) |
| 301 | print '---- FAILED' |
| 302 | print |
| 303 | except: |
| 304 | print '====', classCmd.__name__, 'widget', \ |
| 305 | '\'' + option + '\'', 'option' |
| 306 | print '---- could not set option' |
| 307 | print '---- FAILED' |
| 308 | print |
| 309 | except KeyError: |
| 310 | print '====', classCmd.__name__, 'widget', \ |
| 311 | '\'' + option + '\'', 'option' |
| 312 | print '---- unknown option' |
| 313 | print '---- FAILED' |
| 314 | print |
| 315 | |
| 316 | if hasattr(classCmd, 'geometry'): |
| 317 | w.geometry('+100+100') |
| 318 | w.title(classCmd.__name__) |
| 319 | else: |
| 320 | w = apply(classCmd, (), kw) |
| 321 | return w |
| 322 | |
| 323 | def _destructor(widget, isWidget): |
| 324 | if _verbose > 0: |
| 325 | print '====', widget.__class__.__name__, 'destruction' |
| 326 | if isWidget: |
| 327 | if dont_even_try: |
| 328 | widget.destroy() |
| 329 | else: |
| 330 | try: |
| 331 | widget.destroy() |
| 332 | ref = sys.getrefcount(widget) |
| 333 | if ref != refcountafterdestroy: |
| 334 | print '====', widget.__class__.__name__, 'destructor' |
| 335 | print '---- refcount', ref, 'not zero after destruction' |
| 336 | print '---- FAILED' |
| 337 | print |
| 338 | except: |
| 339 | print 'Could not destroy', widget.__class__.__name__ |
| 340 | traceback.print_exc() |
| 341 | print 'Can not continue' |
| 342 | print 'Bye' |
| 343 | return None |
| 344 | return 1 |
| 345 | |
| 346 | # Structure of allTestData: |
| 347 | # ( |
| 348 | # ( |
| 349 | # 'ButtonBox', |
| 350 | # ( |
| 351 | # ( |
| 352 | # Pmw.ButtonBox, |
| 353 | # {}, |
| 354 | # ( |
| 355 | # (c.pack, ()), |
| 356 | # (c.pack, ()), |
| 357 | # (c.pack, ()), |
| 358 | # ... |
| 359 | # ) |
| 360 | # ), |
| 361 | # ( |
| 362 | # Pmw.ButtonBox, |
| 363 | # {}, |
| 364 | # ( |
| 365 | # (c.pack, ()), |
| 366 | # (c.pack, ()), |
| 367 | # (c.pack, ()), |
| 368 | # ... |
| 369 | # ) |
| 370 | # ), |
| 371 | # ... |
| 372 | # ) |
| 373 | # ), |
| 374 | # ( |
| 375 | # 'ButtonBox', |
| 376 | # ( |
| 377 | # ( |
| 378 | # Pmw.ButtonBox, |
| 379 | # {}, |
| 380 | # ( |
| 381 | # (c.pack, ()), |
| 382 | # (c.pack, ()), |
| 383 | # (c.pack, ()), |
| 384 | # ... |
| 385 | # ) |
| 386 | # ), |
| 387 | # ( |
| 388 | # Pmw.ButtonBox, |
| 389 | # {}, |
| 390 | # ( |
| 391 | # (c.pack, ()), |
| 392 | # (c.pack, ()), |
| 393 | # (c.pack, ()), |
| 394 | # ... |
| 395 | # ) |
| 396 | # ), |
| 397 | # ... |
| 398 | # ) |
| 399 | # ), |
| 400 | # ... |
| 401 | # ) |
| 402 | |
| 403 | def _runTest(top, w, allTestData, index0, index1, index2): |
| 404 | if index0 >= len(allTestData): |
| 405 | root.quit() |
| 406 | return |
| 407 | classCmd, fileTests = allTestData[index0] |
| 408 | if classCmd == Tkinter.Menu: |
| 409 | isToplevel = 1 |
| 410 | else: |
| 411 | isToplevel = hasattr(classCmd, 'userdeletefunc') |
| 412 | isWidget = hasattr(classCmd, 'cget') |
| 413 | title = classCmd.__name__ |
| 414 | |
| 415 | if index1 == -1: |
| 416 | if isToplevel: |
| 417 | top = None |
| 418 | else: |
| 419 | top = _Toplevel(title) |
| 420 | global _currentToplevel |
| 421 | _currentToplevel = top |
| 422 | index1 = 0 |
| 423 | elif index1 >= len(fileTests): |
| 424 | if not isToplevel: |
| 425 | _destroyToplevel(top, title) |
| 426 | index1 = -1 |
| 427 | index0 = index0 + 1 |
| 428 | else: |
| 429 | methodTests, kw = fileTests[index1] |
| 430 | if index2 == -1: |
| 431 | w = _constructor(isWidget, top, classCmd, kw) |
| 432 | if w is None: |
| 433 | root.quit() |
| 434 | return |
| 435 | global _currentWidget |
| 436 | _currentWidget = w |
| 437 | index2 = 0 |
| 438 | elif index2 >= len(methodTests): |
| 439 | if _destructor(w, isWidget) is None: |
| 440 | root.quit() |
| 441 | return |
| 442 | index2 = -1 |
| 443 | index1 = index1 + 1 |
| 444 | else: |
| 445 | methodTestData = methodTests[index2] |
| 446 | if type(methodTestData[0]) == types.StringType: |
| 447 | _configureTest(w, methodTestData) |
| 448 | else: |
| 449 | _methodTest(w, methodTestData) |
| 450 | index2 = index2 + 1 |
| 451 | root.update() |
| 452 | root.after(_delay, _runTest, top, w, allTestData, index0, index1, index2) |
| 453 | |
| 454 | def _configureTest(w, testData): |
| 455 | option = testData[0] |
| 456 | value = testData[1] |
| 457 | if dont_even_try: |
| 458 | apply(w.configure, (), {option: value}) |
| 459 | result = w.cget(option) |
| 460 | else: |
| 461 | try: |
| 462 | apply(w.configure, (), {option: value}) |
| 463 | result = w.cget(option) |
| 464 | except: |
| 465 | result = _getErrorValue() |
| 466 | if len(testData) > 2: |
| 467 | expected = testData[2] |
| 468 | else: |
| 469 | expected = value |
| 470 | _print_results(result, expected, \ |
| 471 | w.__class__.__name__ + ' option ' + str(testData)) |
| 472 | |
| 473 | def _getErrorValue(): |
| 474 | exc_type, exc_value, exc_traceback = sys.exc_info() |
| 475 | if type(exc_type) == types.ClassType: |
| 476 | # Handle python 1.5 class exceptions. |
| 477 | exc_type = exc_type.__name__ |
| 478 | if type(exc_value) == types.StringType: |
| 479 | return exc_type + ': ' + exc_value |
| 480 | else: |
| 481 | exc_value_str = str(exc_value) |
| 482 | if exc_value_str[:1] == "'" and exc_value_str[-1:] == "'": |
| 483 | exc_value_str = exc_value_str[1:-1] |
| 484 | return exc_type + ': ' + exc_value_str |
| 485 | |
| 486 | def _methodTest(w, testData): |
| 487 | func = testData[0] |
| 488 | args = testData[1] |
| 489 | kw = {} |
| 490 | expected = None |
| 491 | if len(testData) == 3: |
| 492 | if type(testData[2]) == types.DictionaryType: |
| 493 | kw = testData[2] |
| 494 | else: |
| 495 | expected = testData[2] |
| 496 | elif len(testData) > 3: |
| 497 | kw = testData[2] |
| 498 | expected = testData[3] |
| 499 | if type(args) != types.TupleType: |
| 500 | args = (args,) |
| 501 | if func is num_options: |
| 502 | args = (w,) + args |
| 503 | origArgs = args |
| 504 | if type(func) == types.MethodType and func.im_self is None: |
| 505 | args = (w,) + args |
| 506 | if dont_even_try: |
| 507 | result = apply(func, args, kw) |
| 508 | else: |
| 509 | try: |
| 510 | result = apply(func, args, kw) |
| 511 | except: |
| 512 | result = _getErrorValue() |
| 513 | if hasattr(func, 'im_func'): |
| 514 | name = w.__class__.__name__ + ' method ' + \ |
| 515 | func.im_func.func_code.co_name |
| 516 | else: |
| 517 | name = 'function ' + func.__name__ |
| 518 | name = name + ' ' + str(origArgs) |
| 519 | if kw: |
| 520 | name = name + ' ' + str(kw) |
| 521 | _print_results(result, expected, name) |