123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- import getopt
- import os
- import re
- import sys
- import traceback
- import unittest
-
- try:
- this_file = __file__
- except NameError:
- this_file = sys.argv[0]
-
- win32com_src_dir = os.path.abspath(os.path.join(this_file, "../.."))
-
- import win32com
-
- # We'd prefer the win32com namespace to be the parent of __file__ - ie, our source-tree,
- # rather than the version installed - otherwise every .py change needs a full install to
- # test!
- # We can't patch win32comext as most of them have a .pyd in their root :(
- # This clearly ins't ideal or perfect :)
- win32com.__path__[0] = win32com_src_dir
-
- import pythoncom
- import win32com.client
- from win32com.test.util import (
- CapturingFunctionTestCase,
- CheckClean,
- RegisterPythonServer,
- ShellTestCase,
- TestCase,
- TestLoader,
- TestRunner,
- )
-
- verbosity = 1 # default unittest verbosity.
-
-
- def GenerateAndRunOldStyle():
- from . import GenTestScripts
-
- GenTestScripts.GenerateAll()
- try:
- pass #
- finally:
- GenTestScripts.CleanAll()
-
-
- def CleanGenerated():
- import shutil
-
- import win32com
-
- if os.path.isdir(win32com.__gen_path__):
- if verbosity > 1:
- print("Deleting files from %s" % (win32com.__gen_path__))
- shutil.rmtree(win32com.__gen_path__)
- import win32com.client.gencache
-
- win32com.client.gencache.__init__() # Reset
-
-
- def RemoveRefCountOutput(data):
- while 1:
- last_line_pos = data.rfind("\n")
- if not re.match("\[\d+ refs\]", data[last_line_pos + 1 :]):
- break
- if last_line_pos < 0:
- # All the output
- return ""
- data = data[:last_line_pos]
-
- return data
-
-
- def ExecuteSilentlyIfOK(cmd, testcase):
- f = os.popen(cmd)
- data = f.read().strip()
- rc = f.close()
- if rc:
- print(data)
- testcase.fail("Executing '%s' failed (%d)" % (cmd, rc))
- # for "_d" builds, strip the '[xxx refs]' line
- return RemoveRefCountOutput(data)
-
-
- class PyCOMTest(TestCase):
- no_leak_tests = True # done by the test itself
-
- def testit(self):
- # Check that the item is registered, so we get the correct
- # 'skipped' behaviour (and recorded as such) rather than either
- # error or silence due to non-registration.
- RegisterPythonServer(
- os.path.join(
- os.path.dirname(__file__), "..", "servers", "test_pycomtest.py"
- ),
- "Python.Test.PyCOMTest",
- )
-
- # Execute testPyComTest in its own process so it can play
- # with the Python thread state
- fname = os.path.join(os.path.dirname(this_file), "testPyComTest.py")
- cmd = '%s "%s" -q 2>&1' % (sys.executable, fname)
- data = ExecuteSilentlyIfOK(cmd, self)
-
-
- class PippoTest(TestCase):
- def testit(self):
- # Check we are registered before spawning the process.
- from win32com.test import pippo_server
-
- RegisterPythonServer(pippo_server.__file__, "Python.Test.Pippo")
-
- python = sys.executable
- fname = os.path.join(os.path.dirname(this_file), "testPippo.py")
- cmd = '%s "%s" 2>&1' % (python, fname)
- ExecuteSilentlyIfOK(cmd, self)
-
-
- # This is a list of "win32com.test.???" module names, optionally with a
- # function in that module if the module isn't unitest based...
- unittest_modules = [
- # Level 1 tests - fast and few dependencies - good for CI!
- """testIterators testvbscript_regexp testStorage
- testStreams testWMI policySemantics testShell testROT
- testxslt testCollections
- errorSemantics.test testArrays
- testClipboard
- testConversionErrors
- """.split(),
- # Level 2 tests - wants our demo COM objects registered.
- # (these are strange; on github CI they get further than expected when
- # our objects are not installed, so fail to quietly fail with "can't
- # register" like they do locally. So really just a nod to CI)
- """
- testAXScript testDictionary testServers testvb testMarshal
- """.split(),
- # Level 3 tests - Requires Office or other non-free stuff.
- """testMSOffice.TestAll testMSOfficeEvents.test testAccess.test
- testExplorer.TestAll testExchange.test
- """.split(),
- # Level 4 tests - we try and run `makepy` over every typelib installed!
- """testmakepy.TestAll
- """.split(),
- ]
-
- # A list of other unittest modules we use - these are fully qualified module
- # names and the module is assumed to be unittest based.
- unittest_other_modules = [
- # Level 1 tests.
- """win32com.directsound.test.ds_test
- """.split(),
- # Level 2 tests.
- [],
- # Level 3 tests.
- [],
- # Level 4 tests.
- [],
- ]
-
-
- output_checked_programs = [
- # Level 1 tests.
- [],
- # Level 2 tests.
- [
- ("cscript.exe /nologo //E:vbscript testInterp.vbs", "VBScript test worked OK"),
- (
- "cscript.exe /nologo //E:vbscript testDictionary.vbs",
- "VBScript has successfully tested Python.Dictionary",
- ),
- ],
- # Level 3 tests
- [],
- # Level 4 tests.
- [],
- ]
-
- custom_test_cases = [
- # Level 1 tests.
- [],
- # Level 2 tests.
- [
- PyCOMTest,
- PippoTest,
- ],
- # Level 3 tests
- [],
- # Level 4 tests.
- [],
- ]
-
-
- def get_test_mod_and_func(test_name, import_failures):
- if test_name.find(".") > 0:
- mod_name, func_name = test_name.split(".")
- else:
- mod_name = test_name
- func_name = None
- fq_mod_name = "win32com.test." + mod_name
- try:
- __import__(fq_mod_name)
- mod = sys.modules[fq_mod_name]
- except:
- import_failures.append((mod_name, sys.exc_info()[:2]))
- return None, None
- func = None if func_name is None else getattr(mod, func_name)
- return mod, func
-
-
- # Return a test suite all loaded with the tests we want to run
- def make_test_suite(test_level=1):
- suite = unittest.TestSuite()
- import_failures = []
- loader = TestLoader()
- for i in range(testLevel):
- for mod_name in unittest_modules[i]:
- mod, func = get_test_mod_and_func(mod_name, import_failures)
- if mod is None:
- raise Exception("no such module '{}'".format(mod_name))
- if func is not None:
- test = CapturingFunctionTestCase(func, description=mod_name)
- else:
- if hasattr(mod, "suite"):
- test = mod.suite()
- else:
- test = loader.loadTestsFromModule(mod)
- assert test.countTestCases() > 0, "No tests loaded from %r" % mod
- suite.addTest(test)
- for cmd, output in output_checked_programs[i]:
- suite.addTest(ShellTestCase(cmd, output))
-
- for test_class in custom_test_cases[i]:
- suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(test_class))
- # other "normal" unittest modules.
- for i in range(testLevel):
- for mod_name in unittest_other_modules[i]:
- try:
- __import__(mod_name)
- except:
- import_failures.append((mod_name, sys.exc_info()[:2]))
- continue
-
- mod = sys.modules[mod_name]
- if hasattr(mod, "suite"):
- test = mod.suite()
- else:
- test = loader.loadTestsFromModule(mod)
- assert test.countTestCases() > 0, "No tests loaded from %r" % mod
- suite.addTest(test)
-
- return suite, import_failures
-
-
- def usage(why):
- print(why)
- print()
- print("win32com test suite")
- print("usage: testall [-v] test_level")
- print(" where test_level is an integer 1-3. Level 1 tests are quick,")
- print(" level 2 tests invoke Word, IE etc, level 3 take ages!")
- sys.exit(1)
-
-
- if __name__ == "__main__":
- try:
- opts, args = getopt.getopt(sys.argv[1:], "v")
- except getopt.error as why:
- usage(why)
- for opt, val in opts:
- if opt == "-v":
- verbosity += 1
- testLevel = 2 # default to quick test with local objects
- test_names = []
- for arg in args:
- try:
- testLevel = int(arg)
- if testLevel < 0 or testLevel > 4:
- raise ValueError("Only levels 1-4 are supported")
- except ValueError:
- test_names.append(arg)
- if test_names:
- usage("Test names are not supported yet")
- CleanGenerated()
-
- suite, import_failures = make_test_suite(testLevel)
- if verbosity:
- if hasattr(sys, "gettotalrefcount"):
- print("This is a debug build - memory leak tests will also be run.")
- print("These tests may take *many* minutes to run - be patient!")
- print("(running from python.exe will avoid these leak tests)")
- print(
- "Executing level %d tests - %d test cases will be run"
- % (testLevel, suite.countTestCases())
- )
- if verbosity == 1 and suite.countTestCases() < 70:
- # A little row of markers so the dots show how close to finished
- print("|" * suite.countTestCases())
- testRunner = TestRunner(verbosity=verbosity)
- testResult = testRunner.run(suite)
- if import_failures:
- testResult.stream.writeln(
- "*** The following test modules could not be imported ***"
- )
- for mod_name, (exc_type, exc_val) in import_failures:
- desc = "\n".join(traceback.format_exception_only(exc_type, exc_val))
- testResult.stream.write("%s: %s" % (mod_name, desc))
- testResult.stream.writeln(
- "*** %d test(s) could not be run ***" % len(import_failures)
- )
-
- # re-print unit-test error here so it is noticed
- if not testResult.wasSuccessful():
- print("*" * 20, "- unittest tests FAILED")
-
- CheckClean()
- pythoncom.CoUninitialize()
- CleanGenerated()
- if not testResult.wasSuccessful():
- sys.exit(1)
|