1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepUse this module to get and run all tk tests.
3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTkinter tests should live in a package inside the directory where this file
5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeplives, like test_tkinter.
6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepExtensions also should live in packages following the same rule as above.
7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport os
10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport sys
11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport unittest
12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport importlib
13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport test.test_support
14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepthis_dir_path = os.path.abspath(os.path.dirname(__file__))
16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_tk_unavailable = None
18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef check_tk_availability():
20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Check that Tk is installed and available."""
21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    global _tk_unavailable
22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if _tk_unavailable is None:
24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        _tk_unavailable = False
25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if sys.platform == 'darwin':
26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # The Aqua Tk implementations on OS X can abort the process if
27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # being called in an environment where a window server connection
28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # cannot be made, for instance when invoked by a buildbot or ssh
29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # process not running under the same user id as the current console
30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # user.  To avoid that, raise an exception if the window manager
31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # connection is not available.
32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            from ctypes import cdll, c_int, pointer, Structure
33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            from ctypes.util import find_library
34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if app_services.CGMainDisplayID() == 0:
38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                _tk_unavailable = "cannot run without OS X window manager"
39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            else:
40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                class ProcessSerialNumber(Structure):
41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    _fields_ = [("highLongOfPSN", c_int),
42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                ("lowLongOfPSN", c_int)]
43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                psn = ProcessSerialNumber()
44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                psn_p = pointer(psn)
45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if (  (app_services.GetCurrentProcess(psn_p) < 0) or
46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                      (app_services.SetFrontProcess(psn_p) < 0) ):
47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    _tk_unavailable = "cannot run without OS X gui process"
48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:   # not OS X
49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            import Tkinter
50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            try:
51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                Tkinter.Button()
52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            except Tkinter.TclError as msg:
53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                # assuming tk is not available
54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                _tk_unavailable = "tk not available: %s" % msg
55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if _tk_unavailable:
57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raise unittest.SkipTest(_tk_unavailable)
58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return
59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef is_package(path):
61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    for name in os.listdir(path):
62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if name in ('__init__.py', '__init__.pyc', '__init.pyo'):
63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return True
64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return False
65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef get_tests_modules(basepath=this_dir_path, gui=True, packages=None):
67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """This will import and yield modules whose names start with test_
68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    and are inside packages found in the path starting at basepath.
69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    If packages is specified it should contain package names that want
71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    their tests colleted.
72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """
73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    py_ext = '.py'
74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    for dirpath, dirnames, filenames in os.walk(basepath):
76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for dirname in list(dirnames):
77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if dirname[0] == '.':
78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                dirnames.remove(dirname)
79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if is_package(dirpath) and filenames:
81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pkg_name = dirpath[len(basepath) + len(os.sep):].replace('/', '.')
82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if packages and pkg_name not in packages:
83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                continue
84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            filenames = filter(
86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    lambda x: x.startswith('test_') and x.endswith(py_ext),
87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    filenames)
88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            for name in filenames:
90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                try:
91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    yield importlib.import_module(
92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            ".%s" % name[:-len(py_ext)], pkg_name)
93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                except test.test_support.ResourceDenied:
94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    if gui:
95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        raise
96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef get_tests(text=True, gui=True, packages=None):
98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Yield all the tests in the modules found by get_tests_modules.
99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    If nogui is True, only tests that do not require a GUI will be
101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    returned."""
102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    attrs = []
103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if text:
104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        attrs.append('tests_nogui')
105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    if gui:
106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        attrs.append('tests_gui')
107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    for module in get_tests_modules(gui=gui, packages=packages):
108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for attr in attrs:
109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            for test in getattr(module, attr, ()):
110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                yield test
111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepif __name__ == "__main__":
113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    test.test_support.use_resources = ['gui']
114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    test.test_support.run_unittest(*get_tests())
115