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