(root)/
Python-3.11.7/
Lib/
test/
test_trace.py
       1  import os
       2  from pickle import dump
       3  import sys
       4  from test.support import captured_stdout, requires_resource
       5  from test.support.os_helper import (TESTFN, rmtree, unlink)
       6  from test.support.script_helper import assert_python_ok, assert_python_failure
       7  import textwrap
       8  import unittest
       9  
      10  import trace
      11  from trace import Trace
      12  
      13  from test.tracedmodules import testmod
      14  
      15  ##
      16  ## See also test_sys_settrace.py, which contains tests that cover
      17  ## tracing of many more code blocks.
      18  ##
      19  
      20  #------------------------------- Utilities -----------------------------------#
      21  
      22  def fix_ext_py(filename):
      23      """Given a .pyc filename converts it to the appropriate .py"""
      24      if filename.endswith('.pyc'):
      25          filename = filename[:-1]
      26      return filename
      27  
      28  def my_file_and_modname():
      29      """The .py file and module name of this file (__file__)"""
      30      modname = os.path.splitext(os.path.basename(__file__))[0]
      31      return fix_ext_py(__file__), modname
      32  
      33  def get_firstlineno(func):
      34      return func.__code__.co_firstlineno
      35  
      36  #-------------------- Target functions for tracing ---------------------------#
      37  #
      38  # The relative line numbers of lines in these functions matter for verifying
      39  # tracing. Please modify the appropriate tests if you change one of the
      40  # functions. Absolute line numbers don't matter.
      41  #
      42  
      43  def traced_func_linear(x, y):
      44      a = x
      45      b = y
      46      c = a + b
      47      return c
      48  
      49  def traced_func_loop(x, y):
      50      c = x
      51      for i in range(5):
      52          c += y
      53      return c
      54  
      55  def traced_func_importing(x, y):
      56      return x + y + testmod.func(1)
      57  
      58  def traced_func_simple_caller(x):
      59      c = traced_func_linear(x, x)
      60      return c + x
      61  
      62  def traced_func_importing_caller(x):
      63      k = traced_func_simple_caller(x)
      64      k += traced_func_importing(k, x)
      65      return k
      66  
      67  def traced_func_generator(num):
      68      c = 5       # executed once
      69      for i in range(num):
      70          yield i + c
      71  
      72  def traced_func_calling_generator():
      73      k = 0
      74      for i in traced_func_generator(10):
      75          k += i
      76  
      77  def traced_doubler(num):
      78      return num * 2
      79  
      80  def traced_capturer(*args, **kwargs):
      81      return args, kwargs
      82  
      83  def traced_caller_list_comprehension():
      84      k = 10
      85      mylist = [traced_doubler(i) for i in range(k)]
      86      return mylist
      87  
      88  def traced_decorated_function():
      89      def decorator1(f):
      90          return f
      91      def decorator_fabric():
      92          def decorator2(f):
      93              return f
      94          return decorator2
      95      @decorator1
      96      @decorator_fabric()
      97      def func():
      98          pass
      99      func()
     100  
     101  
     102  class ESC[4;38;5;81mTracedClass(ESC[4;38;5;149mobject):
     103      def __init__(self, x):
     104          self.a = x
     105  
     106      def inst_method_linear(self, y):
     107          return self.a + y
     108  
     109      def inst_method_calling(self, x):
     110          c = self.inst_method_linear(x)
     111          return c + traced_func_linear(x, c)
     112  
     113      @classmethod
     114      def class_method_linear(cls, y):
     115          return y * 2
     116  
     117      @staticmethod
     118      def static_method_linear(y):
     119          return y * 2
     120  
     121  
     122  #------------------------------ Test cases -----------------------------------#
     123  
     124  
     125  class ESC[4;38;5;81mTestLineCounts(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     126      """White-box testing of line-counting, via runfunc"""
     127      def setUp(self):
     128          self.addCleanup(sys.settrace, sys.gettrace())
     129          self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
     130          self.my_py_filename = fix_ext_py(__file__)
     131  
     132      def test_traced_func_linear(self):
     133          result = self.tracer.runfunc(traced_func_linear, 2, 5)
     134          self.assertEqual(result, 7)
     135  
     136          # all lines are executed once
     137          expected = {}
     138          firstlineno = get_firstlineno(traced_func_linear)
     139          for i in range(1, 5):
     140              expected[(self.my_py_filename, firstlineno +  i)] = 1
     141  
     142          self.assertEqual(self.tracer.results().counts, expected)
     143  
     144      def test_traced_func_loop(self):
     145          self.tracer.runfunc(traced_func_loop, 2, 3)
     146  
     147          firstlineno = get_firstlineno(traced_func_loop)
     148          expected = {
     149              (self.my_py_filename, firstlineno + 1): 1,
     150              (self.my_py_filename, firstlineno + 2): 6,
     151              (self.my_py_filename, firstlineno + 3): 5,
     152              (self.my_py_filename, firstlineno + 4): 1,
     153          }
     154          self.assertEqual(self.tracer.results().counts, expected)
     155  
     156      def test_traced_func_importing(self):
     157          self.tracer.runfunc(traced_func_importing, 2, 5)
     158  
     159          firstlineno = get_firstlineno(traced_func_importing)
     160          expected = {
     161              (self.my_py_filename, firstlineno + 1): 1,
     162              (fix_ext_py(testmod.__file__), 2): 1,
     163              (fix_ext_py(testmod.__file__), 3): 1,
     164          }
     165  
     166          self.assertEqual(self.tracer.results().counts, expected)
     167  
     168      def test_trace_func_generator(self):
     169          self.tracer.runfunc(traced_func_calling_generator)
     170  
     171          firstlineno_calling = get_firstlineno(traced_func_calling_generator)
     172          firstlineno_gen = get_firstlineno(traced_func_generator)
     173          expected = {
     174              (self.my_py_filename, firstlineno_calling + 1): 1,
     175              (self.my_py_filename, firstlineno_calling + 2): 11,
     176              (self.my_py_filename, firstlineno_calling + 3): 10,
     177              (self.my_py_filename, firstlineno_gen + 1): 1,
     178              (self.my_py_filename, firstlineno_gen + 2): 11,
     179              (self.my_py_filename, firstlineno_gen + 3): 10,
     180          }
     181          self.assertEqual(self.tracer.results().counts, expected)
     182  
     183      def test_trace_list_comprehension(self):
     184          self.tracer.runfunc(traced_caller_list_comprehension)
     185  
     186          firstlineno_calling = get_firstlineno(traced_caller_list_comprehension)
     187          firstlineno_called = get_firstlineno(traced_doubler)
     188          expected = {
     189              (self.my_py_filename, firstlineno_calling + 1): 1,
     190              # List comprehensions work differently in 3.x, so the count
     191              # below changed compared to 2.x.
     192              (self.my_py_filename, firstlineno_calling + 2): 12,
     193              (self.my_py_filename, firstlineno_calling + 3): 1,
     194              (self.my_py_filename, firstlineno_called + 1): 10,
     195          }
     196          self.assertEqual(self.tracer.results().counts, expected)
     197  
     198      def test_traced_decorated_function(self):
     199          self.tracer.runfunc(traced_decorated_function)
     200  
     201          firstlineno = get_firstlineno(traced_decorated_function)
     202          expected = {
     203              (self.my_py_filename, firstlineno + 1): 1,
     204              (self.my_py_filename, firstlineno + 2): 1,
     205              (self.my_py_filename, firstlineno + 3): 1,
     206              (self.my_py_filename, firstlineno + 4): 1,
     207              (self.my_py_filename, firstlineno + 5): 1,
     208              (self.my_py_filename, firstlineno + 6): 1,
     209              (self.my_py_filename, firstlineno + 7): 2,
     210              (self.my_py_filename, firstlineno + 8): 2,
     211              (self.my_py_filename, firstlineno + 9): 2,
     212              (self.my_py_filename, firstlineno + 10): 1,
     213              (self.my_py_filename, firstlineno + 11): 1,
     214          }
     215          self.assertEqual(self.tracer.results().counts, expected)
     216  
     217      def test_linear_methods(self):
     218          # XXX todo: later add 'static_method_linear' and 'class_method_linear'
     219          # here, once issue1764286 is resolved
     220          #
     221          for methname in ['inst_method_linear',]:
     222              tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
     223              traced_obj = TracedClass(25)
     224              method = getattr(traced_obj, methname)
     225              tracer.runfunc(method, 20)
     226  
     227              firstlineno = get_firstlineno(method)
     228              expected = {
     229                  (self.my_py_filename, firstlineno + 1): 1,
     230              }
     231              self.assertEqual(tracer.results().counts, expected)
     232  
     233  
     234  class ESC[4;38;5;81mTestRunExecCounts(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     235      """A simple sanity test of line-counting, via runctx (exec)"""
     236      def setUp(self):
     237          self.my_py_filename = fix_ext_py(__file__)
     238          self.addCleanup(sys.settrace, sys.gettrace())
     239  
     240      def test_exec_counts(self):
     241          self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
     242          code = r'''traced_func_loop(2, 5)'''
     243          code = compile(code, __file__, 'exec')
     244          self.tracer.runctx(code, globals(), vars())
     245  
     246          firstlineno = get_firstlineno(traced_func_loop)
     247          expected = {
     248              (self.my_py_filename, firstlineno + 1): 1,
     249              (self.my_py_filename, firstlineno + 2): 6,
     250              (self.my_py_filename, firstlineno + 3): 5,
     251              (self.my_py_filename, firstlineno + 4): 1,
     252          }
     253  
     254          # When used through 'run', some other spurious counts are produced, like
     255          # the settrace of threading, which we ignore, just making sure that the
     256          # counts fo traced_func_loop were right.
     257          #
     258          for k in expected.keys():
     259              self.assertEqual(self.tracer.results().counts[k], expected[k])
     260  
     261  
     262  class ESC[4;38;5;81mTestFuncs(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     263      """White-box testing of funcs tracing"""
     264      def setUp(self):
     265          self.addCleanup(sys.settrace, sys.gettrace())
     266          self.tracer = Trace(count=0, trace=0, countfuncs=1)
     267          self.filemod = my_file_and_modname()
     268          self._saved_tracefunc = sys.gettrace()
     269  
     270      def tearDown(self):
     271          if self._saved_tracefunc is not None:
     272              sys.settrace(self._saved_tracefunc)
     273  
     274      def test_simple_caller(self):
     275          self.tracer.runfunc(traced_func_simple_caller, 1)
     276  
     277          expected = {
     278              self.filemod + ('traced_func_simple_caller',): 1,
     279              self.filemod + ('traced_func_linear',): 1,
     280          }
     281          self.assertEqual(self.tracer.results().calledfuncs, expected)
     282  
     283      def test_arg_errors(self):
     284          res = self.tracer.runfunc(traced_capturer, 1, 2, self=3, func=4)
     285          self.assertEqual(res, ((1, 2), {'self': 3, 'func': 4}))
     286          with self.assertRaises(TypeError):
     287              self.tracer.runfunc(func=traced_capturer, arg=1)
     288          with self.assertRaises(TypeError):
     289              self.tracer.runfunc()
     290  
     291      def test_loop_caller_importing(self):
     292          self.tracer.runfunc(traced_func_importing_caller, 1)
     293  
     294          expected = {
     295              self.filemod + ('traced_func_simple_caller',): 1,
     296              self.filemod + ('traced_func_linear',): 1,
     297              self.filemod + ('traced_func_importing_caller',): 1,
     298              self.filemod + ('traced_func_importing',): 1,
     299              (fix_ext_py(testmod.__file__), 'testmod', 'func'): 1,
     300          }
     301          self.assertEqual(self.tracer.results().calledfuncs, expected)
     302  
     303      @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
     304                       'pre-existing trace function throws off measurements')
     305      def test_inst_method_calling(self):
     306          obj = TracedClass(20)
     307          self.tracer.runfunc(obj.inst_method_calling, 1)
     308  
     309          expected = {
     310              self.filemod + ('TracedClass.inst_method_calling',): 1,
     311              self.filemod + ('TracedClass.inst_method_linear',): 1,
     312              self.filemod + ('traced_func_linear',): 1,
     313          }
     314          self.assertEqual(self.tracer.results().calledfuncs, expected)
     315  
     316      def test_traced_decorated_function(self):
     317          self.tracer.runfunc(traced_decorated_function)
     318  
     319          expected = {
     320              self.filemod + ('traced_decorated_function',): 1,
     321              self.filemod + ('decorator_fabric',): 1,
     322              self.filemod + ('decorator2',): 1,
     323              self.filemod + ('decorator1',): 1,
     324              self.filemod + ('func',): 1,
     325          }
     326          self.assertEqual(self.tracer.results().calledfuncs, expected)
     327  
     328  
     329  class ESC[4;38;5;81mTestCallers(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     330      """White-box testing of callers tracing"""
     331      def setUp(self):
     332          self.addCleanup(sys.settrace, sys.gettrace())
     333          self.tracer = Trace(count=0, trace=0, countcallers=1)
     334          self.filemod = my_file_and_modname()
     335  
     336      @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
     337                       'pre-existing trace function throws off measurements')
     338      def test_loop_caller_importing(self):
     339          self.tracer.runfunc(traced_func_importing_caller, 1)
     340  
     341          expected = {
     342              ((os.path.splitext(trace.__file__)[0] + '.py', 'trace', 'Trace.runfunc'),
     343                  (self.filemod + ('traced_func_importing_caller',))): 1,
     344              ((self.filemod + ('traced_func_simple_caller',)),
     345                  (self.filemod + ('traced_func_linear',))): 1,
     346              ((self.filemod + ('traced_func_importing_caller',)),
     347                  (self.filemod + ('traced_func_simple_caller',))): 1,
     348              ((self.filemod + ('traced_func_importing_caller',)),
     349                  (self.filemod + ('traced_func_importing',))): 1,
     350              ((self.filemod + ('traced_func_importing',)),
     351                  (fix_ext_py(testmod.__file__), 'testmod', 'func')): 1,
     352          }
     353          self.assertEqual(self.tracer.results().callers, expected)
     354  
     355  
     356  # Created separately for issue #3821
     357  class ESC[4;38;5;81mTestCoverage(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     358      def setUp(self):
     359          self.addCleanup(sys.settrace, sys.gettrace())
     360  
     361      def tearDown(self):
     362          rmtree(TESTFN)
     363          unlink(TESTFN)
     364  
     365      DEFAULT_SCRIPT = '''if True:
     366          import unittest
     367          from test.test_pprint import QueryTestCase
     368          loader = unittest.TestLoader()
     369          tests = loader.loadTestsFromTestCase(QueryTestCase)
     370          tests(unittest.TestResult())
     371          '''
     372      def _coverage(self, tracer, cmd=DEFAULT_SCRIPT):
     373          tracer.run(cmd)
     374          r = tracer.results()
     375          r.write_results(show_missing=True, summary=True, coverdir=TESTFN)
     376  
     377      @requires_resource('cpu')
     378      def test_coverage(self):
     379          tracer = trace.Trace(trace=0, count=1)
     380          with captured_stdout() as stdout:
     381              self._coverage(tracer)
     382          stdout = stdout.getvalue()
     383          self.assertIn("pprint.py", stdout)
     384          self.assertIn("case.py", stdout)   # from unittest
     385          files = os.listdir(TESTFN)
     386          self.assertIn("pprint.cover", files)
     387          self.assertIn("unittest.case.cover", files)
     388  
     389      def test_coverage_ignore(self):
     390          # Ignore all files, nothing should be traced nor printed
     391          libpath = os.path.normpath(os.path.dirname(os.path.dirname(__file__)))
     392          # sys.prefix does not work when running from a checkout
     393          tracer = trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,
     394                               libpath], trace=0, count=1)
     395          with captured_stdout() as stdout:
     396              self._coverage(tracer)
     397          if os.path.exists(TESTFN):
     398              files = os.listdir(TESTFN)
     399              self.assertEqual(files, ['_importlib.cover'])  # Ignore __import__
     400  
     401      def test_issue9936(self):
     402          tracer = trace.Trace(trace=0, count=1)
     403          modname = 'test.tracedmodules.testmod'
     404          # Ensure that the module is executed in import
     405          if modname in sys.modules:
     406              del sys.modules[modname]
     407          cmd = ("import test.tracedmodules.testmod as t;"
     408                 "t.func(0); t.func2();")
     409          with captured_stdout() as stdout:
     410              self._coverage(tracer, cmd)
     411          stdout.seek(0)
     412          stdout.readline()
     413          coverage = {}
     414          for line in stdout:
     415              lines, cov, module = line.split()[:3]
     416              coverage[module] = (int(lines), int(cov[:-1]))
     417          # XXX This is needed to run regrtest.py as a script
     418          modname = trace._fullmodname(sys.modules[modname].__file__)
     419          self.assertIn(modname, coverage)
     420          self.assertEqual(coverage[modname], (5, 100))
     421  
     422      def test_coverageresults_update(self):
     423          # Update empty CoverageResults with a non-empty infile.
     424          infile = TESTFN + '-infile'
     425          with open(infile, 'wb') as f:
     426              dump(({}, {}, {'caller': 1}), f, protocol=1)
     427          self.addCleanup(unlink, infile)
     428          results = trace.CoverageResults({}, {}, infile, {})
     429          self.assertEqual(results.callers, {'caller': 1})
     430  
     431  ### Tests that don't mess with sys.settrace and can be traced
     432  ### themselves TODO: Skip tests that do mess with sys.settrace when
     433  ### regrtest is invoked with -T option.
     434  class ESC[4;38;5;81mTest_Ignore(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     435      def test_ignored(self):
     436          jn = os.path.join
     437          ignore = trace._Ignore(['x', 'y.z'], [jn('foo', 'bar')])
     438          self.assertTrue(ignore.names('x.py', 'x'))
     439          self.assertFalse(ignore.names('xy.py', 'xy'))
     440          self.assertFalse(ignore.names('y.py', 'y'))
     441          self.assertTrue(ignore.names(jn('foo', 'bar', 'baz.py'), 'baz'))
     442          self.assertFalse(ignore.names(jn('bar', 'z.py'), 'z'))
     443          # Matched before.
     444          self.assertTrue(ignore.names(jn('bar', 'baz.py'), 'baz'))
     445  
     446  # Created for Issue 31908 -- CLI utility not writing cover files
     447  class ESC[4;38;5;81mTestCoverageCommandLineOutput(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     448  
     449      codefile = 'tmp.py'
     450      coverfile = 'tmp.cover'
     451  
     452      def setUp(self):
     453          with open(self.codefile, 'w', encoding='iso-8859-15') as f:
     454              f.write(textwrap.dedent('''\
     455                  # coding: iso-8859-15
     456                  x = 'spœm'
     457                  if []:
     458                      print('unreachable')
     459              '''))
     460  
     461      def tearDown(self):
     462          unlink(self.codefile)
     463          unlink(self.coverfile)
     464  
     465      def test_cover_files_written_no_highlight(self):
     466          # Test also that the cover file for the trace module is not created
     467          # (issue #34171).
     468          tracedir = os.path.dirname(os.path.abspath(trace.__file__))
     469          tracecoverpath = os.path.join(tracedir, 'trace.cover')
     470          unlink(tracecoverpath)
     471  
     472          argv = '-m trace --count'.split() + [self.codefile]
     473          status, stdout, stderr = assert_python_ok(*argv)
     474          self.assertEqual(stderr, b'')
     475          self.assertFalse(os.path.exists(tracecoverpath))
     476          self.assertTrue(os.path.exists(self.coverfile))
     477          with open(self.coverfile, encoding='iso-8859-15') as f:
     478              self.assertEqual(f.read(),
     479                  "       # coding: iso-8859-15\n"
     480                  "    1: x = 'spœm'\n"
     481                  "    1: if []:\n"
     482                  "           print('unreachable')\n"
     483              )
     484  
     485      def test_cover_files_written_with_highlight(self):
     486          argv = '-m trace --count --missing'.split() + [self.codefile]
     487          status, stdout, stderr = assert_python_ok(*argv)
     488          self.assertTrue(os.path.exists(self.coverfile))
     489          with open(self.coverfile, encoding='iso-8859-15') as f:
     490              self.assertEqual(f.read(), textwrap.dedent('''\
     491                         # coding: iso-8859-15
     492                      1: x = 'spœm'
     493                      1: if []:
     494                  >>>>>>     print('unreachable')
     495              '''))
     496  
     497  class ESC[4;38;5;81mTestCommandLine(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     498  
     499      def test_failures(self):
     500          _errors = (
     501              (b'progname is missing: required with the main options', '-l', '-T'),
     502              (b'cannot specify both --listfuncs and (--trace or --count)', '-lc'),
     503              (b'argument -R/--no-report: not allowed with argument -r/--report', '-rR'),
     504              (b'must specify one of --trace, --count, --report, --listfuncs, or --trackcalls', '-g'),
     505              (b'-r/--report requires -f/--file', '-r'),
     506              (b'--summary can only be used with --count or --report', '-sT'),
     507              (b'unrecognized arguments: -y', '-y'))
     508          for message, *args in _errors:
     509              *_, stderr = assert_python_failure('-m', 'trace', *args)
     510              self.assertIn(message, stderr)
     511  
     512      def test_listfuncs_flag_success(self):
     513          filename = TESTFN + '.py'
     514          modulename = os.path.basename(TESTFN)
     515          with open(filename, 'w', encoding='utf-8') as fd:
     516              self.addCleanup(unlink, filename)
     517              fd.write("a = 1\n")
     518              status, stdout, stderr = assert_python_ok('-m', 'trace', '-l', filename,
     519                                                        PYTHONIOENCODING='utf-8')
     520              self.assertIn(b'functions called:', stdout)
     521              expected = f'filename: {filename}, modulename: {modulename}, funcname: <module>'
     522              self.assertIn(expected.encode(), stdout)
     523  
     524      def test_sys_argv_list(self):
     525          with open(TESTFN, 'w', encoding='utf-8') as fd:
     526              self.addCleanup(unlink, TESTFN)
     527              fd.write("import sys\n")
     528              fd.write("print(type(sys.argv))\n")
     529  
     530          status, direct_stdout, stderr = assert_python_ok(TESTFN)
     531          status, trace_stdout, stderr = assert_python_ok('-m', 'trace', '-l', TESTFN,
     532                                                          PYTHONIOENCODING='utf-8')
     533          self.assertIn(direct_stdout.strip(), trace_stdout)
     534  
     535      def test_count_and_summary(self):
     536          filename = f'{TESTFN}.py'
     537          coverfilename = f'{TESTFN}.cover'
     538          modulename = os.path.basename(TESTFN)
     539          with open(filename, 'w', encoding='utf-8') as fd:
     540              self.addCleanup(unlink, filename)
     541              self.addCleanup(unlink, coverfilename)
     542              fd.write(textwrap.dedent("""\
     543                  x = 1
     544                  y = 2
     545  
     546                  def f():
     547                      return x + y
     548  
     549                  for i in range(10):
     550                      f()
     551              """))
     552          status, stdout, _ = assert_python_ok('-m', 'trace', '-cs', filename,
     553                                               PYTHONIOENCODING='utf-8')
     554          stdout = stdout.decode()
     555          self.assertEqual(status, 0)
     556          self.assertIn('lines   cov%   module   (path)', stdout)
     557          self.assertIn(f'6   100%   {modulename}   ({filename})', stdout)
     558  
     559      def test_run_as_module(self):
     560          assert_python_ok('-m', 'trace', '-l', '--module', 'timeit', '-n', '1')
     561          assert_python_failure('-m', 'trace', '-l', '--module', 'not_a_module_zzz')
     562  
     563  
     564  if __name__ == '__main__':
     565      unittest.main()