| # Copyright 2014 Dirk Pranke. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import io |
| import json |
| import os |
| import sys |
| import textwrap |
| |
| |
| from typ import main |
| from typ import test_case |
| from typ import Host |
| from typ import VERSION |
| from typ.fakes import test_result_server_fake |
| |
| |
| is_python3 = bool(sys.version_info.major == 3) |
| |
| if is_python3: # pragma: python3 |
| # redefining built-in 'unicode' pylint: disable=W0622 |
| unicode = str |
| |
| d = textwrap.dedent |
| |
| |
| PASS_TEST_PY = """ |
| import unittest |
| class PassingTest(unittest.TestCase): |
| def test_pass(self): |
| pass |
| """ |
| |
| |
| PASS_TEST_FILES = {'pass_test.py': PASS_TEST_PY} |
| |
| |
| FAIL_TEST_PY = """ |
| import unittest |
| class FailingTest(unittest.TestCase): |
| def test_fail(self): |
| self.fail() |
| """ |
| |
| |
| FAIL_TEST_FILES = {'fail_test.py': FAIL_TEST_PY} |
| |
| |
| OUTPUT_TEST_PY = """ |
| import sys |
| import unittest |
| |
| class PassTest(unittest.TestCase): |
| def test_out(self): |
| sys.stdout.write("hello on stdout\\n") |
| sys.stdout.flush() |
| |
| def test_err(self): |
| sys.stderr.write("hello on stderr\\n") |
| |
| class FailTest(unittest.TestCase): |
| def test_out_err_fail(self): |
| sys.stdout.write("hello on stdout\\n") |
| sys.stdout.flush() |
| sys.stderr.write("hello on stderr\\n") |
| self.fail() |
| """ |
| |
| |
| OUTPUT_TEST_FILES = {'output_test.py': OUTPUT_TEST_PY} |
| |
| |
| SF_TEST_PY = """ |
| import sys |
| import unittest |
| |
| class SkipMethods(unittest.TestCase): |
| @unittest.skip('reason') |
| def test_reason(self): |
| self.fail() |
| |
| @unittest.skipIf(True, 'reason') |
| def test_skip_if_true(self): |
| self.fail() |
| |
| @unittest.skipIf(False, 'reason') |
| def test_skip_if_false(self): |
| self.fail() |
| |
| |
| class SkipSetup(unittest.TestCase): |
| def setUp(self): |
| self.skipTest('setup failed') |
| |
| def test_notrun(self): |
| self.fail() |
| |
| |
| @unittest.skip('skip class') |
| class SkipClass(unittest.TestCase): |
| def test_method(self): |
| self.fail() |
| |
| class SetupClass(unittest.TestCase): |
| @classmethod |
| def setUpClass(cls): |
| sys.stdout.write('in setupClass\\n') |
| sys.stdout.flush() |
| assert False, 'setupClass failed' |
| |
| def test_method1(self): |
| pass |
| |
| def test_method2(self): |
| pass |
| |
| class ExpectedFailures(unittest.TestCase): |
| @unittest.expectedFailure |
| def test_fail(self): |
| self.fail() |
| |
| @unittest.expectedFailure |
| def test_pass(self): |
| pass |
| """ |
| |
| |
| SF_TEST_FILES = {'sf_test.py': SF_TEST_PY} |
| |
| |
| LOAD_TEST_PY = """ |
| import unittest |
| def load_tests(_, _2, _3): |
| class BaseTest(unittest.TestCase): |
| pass |
| |
| def method_fail(self): |
| self.fail() |
| |
| def method_pass(self): |
| pass |
| |
| setattr(BaseTest, "test_fail", method_fail) |
| setattr(BaseTest, "test_pass", method_pass) |
| suite = unittest.TestSuite() |
| suite.addTest(BaseTest("test_fail")) |
| suite.addTest(BaseTest("test_pass")) |
| return suite |
| """ |
| |
| |
| LOAD_TEST_FILES = {'load_test.py': LOAD_TEST_PY} |
| |
| |
| path_to_main = os.path.join( |
| os.path.dirname(os.path.dirname(os.path.abspath(__file__))), |
| 'runner.py') |
| |
| |
| class TestCli(test_case.MainTestCase): |
| prog = [sys.executable, path_to_main] |
| files_to_ignore = ['*.pyc'] |
| |
| def test_bad_arg(self): |
| self.check(['--bad-arg'], ret=2, out='', |
| rerr='.*: error: unrecognized arguments: --bad-arg\n') |
| self.check(['-help'], ret=2, out='', |
| rerr=(".*: error: argument -h/--help: " |
| "ignored explicit argument 'elp'\n")) |
| |
| def test_bad_metadata(self): |
| self.check(['--metadata', 'foo'], ret=2, err='', |
| out='Error: malformed --metadata "foo"\n') |
| |
| def test_basic(self): |
| self.check([], files=PASS_TEST_FILES, |
| ret=0, |
| out=('[1/1] pass_test.PassingTest.test_pass passed\n' |
| '1 test run, 0 failures.\n'), err='') |
| |
| def test_coverage(self): |
| try: |
| import coverage # pylint: disable=W0612 |
| files = { |
| 'pass_test.py': PASS_TEST_PY, |
| 'fail_test.py': FAIL_TEST_PY, |
| } |
| self.check(['-c', 'pass_test'], files=files, ret=0, err='', |
| out=d("""\ |
| [1/1] pass_test.PassingTest.test_pass passed |
| 1 test run, 0 failures. |
| |
| Name Stmts Miss Cover |
| ------------------------------- |
| fail_test 4 4 0% |
| pass_test 4 0 100% |
| ------------------------------- |
| TOTAL 8 4 50% |
| """)) |
| except ImportError: # pragma: no cover |
| # We can never cover this line, since running coverage means |
| # that import will succeed. |
| self.check(['-c'], files=PASS_TEST_FILES, ret=1, |
| out='Error: coverage is not installed\n', err='') |
| |
| def test_debugger(self): |
| if sys.version_info.major == 3: # pragma: python3 |
| return |
| else: # pragma: python2 |
| _, out, _, _ = self.check(['-d'], stdin='quit()\n', |
| files=PASS_TEST_FILES, ret=0, err='') |
| self.assertIn('(Pdb) ', out) |
| |
| def test_dryrun(self): |
| self.check(['-n'], files=PASS_TEST_FILES, ret=0, err='', |
| out=d("""\ |
| [1/1] pass_test.PassingTest.test_pass passed |
| 1 test run, 0 failures. |
| """)) |
| |
| def test_error(self): |
| files = {'err_test.py': d("""\ |
| import unittest |
| class ErrTest(unittest.TestCase): |
| def test_err(self): |
| foo = bar |
| """)} |
| _, out, _, _ = self.check([''], files=files, ret=1, err='') |
| self.assertIn('[1/1] err_test.ErrTest.test_err failed unexpectedly', |
| out) |
| self.assertIn('1 test run, 1 failure', out) |
| |
| def test_fail(self): |
| _, out, _, _ = self.check([], files=FAIL_TEST_FILES, ret=1, err='') |
| self.assertIn('fail_test.FailingTest.test_fail failed unexpectedly', |
| out) |
| |
| def test_fail_then_pass(self): |
| files = {'fail_then_pass_test.py': d("""\ |
| import unittest |
| count = 0 |
| class FPTest(unittest.TestCase): |
| def test_count(self): |
| global count |
| count += 1 |
| if count == 1: |
| self.fail() |
| """)} |
| _, out, _, files = self.check(['--retry-limit', '3', |
| '--write-full-results-to', |
| 'full_results.json'], |
| files=files, ret=0, err='') |
| self.assertIn('Retrying failed tests (attempt #1 of 3)', out) |
| self.assertNotIn('Retrying failed tests (attempt #2 of 3)', out) |
| self.assertIn('1 test run, 0 failures.\n', out) |
| results = json.loads(files['full_results.json']) |
| self.assertEqual(results['tests'][ |
| 'fail_then_pass_test']['FPTest']['test_count']['actual'], |
| 'FAIL PASS') |
| |
| def test_failures_are_not_elided(self): |
| _, out, _, _ = self.check(['--terminal-width=20'], |
| files=FAIL_TEST_FILES, ret=1, err='') |
| self.assertIn('[1/1] fail_test.FailingTest.test_fail failed ' |
| 'unexpectedly:\n', out) |
| |
| def test_file_list(self): |
| files = PASS_TEST_FILES |
| self.check(['-f', '-'], files=files, stdin='pass_test\n', ret=0) |
| self.check(['-f', '-'], files=files, stdin='pass_test.PassingTest\n', |
| ret=0) |
| self.check(['-f', '-'], files=files, |
| stdin='pass_test.PassingTest.test_pass\n', |
| ret=0) |
| files = {'pass_test.py': PASS_TEST_PY, |
| 'test_list.txt': 'pass_test.PassingTest.test_pass\n'} |
| self.check(['-f', 'test_list.txt'], files=files, ret=0) |
| |
| def test_find(self): |
| files = PASS_TEST_FILES |
| self.check(['-l'], files=files, ret=0, |
| out='pass_test.PassingTest.test_pass\n') |
| self.check(['-l', 'pass_test'], files=files, ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| self.check(['-l', 'pass_test.py'], files=files, ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| self.check(['-l', './pass_test.py'], files=files, ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| self.check(['-l', '.'], files=files, ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| self.check(['-l', 'pass_test.PassingTest.test_pass'], files=files, |
| ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| self.check(['-l', '.'], files=files, ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| |
| def test_find_from_subdirs(self): |
| files = { |
| 'foo/__init__.py': '', |
| 'foo/pass_test.py': PASS_TEST_PY, |
| 'bar/__init__.py': '', |
| 'bar/tmp': '', |
| |
| } |
| self.check(['-l', '../foo/pass_test.py'], files=files, cwd='bar', |
| ret=0, err='', |
| out='foo.pass_test.PassingTest.test_pass\n') |
| self.check(['-l', 'foo'], files=files, cwd='bar', |
| ret=0, err='', |
| out='foo.pass_test.PassingTest.test_pass\n') |
| self.check(['-l', '--path', '../foo', 'pass_test'], |
| files=files, cwd='bar', ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| |
| def test_help(self): |
| self.check(['--help'], ret=0, rout='.*', err='') |
| |
| def test_import_failure_missing_file(self): |
| self.check(['-l', 'foo'], ret=1, err='', |
| rout='Failed to load "foo".*') |
| |
| def test_import_failure_missing_package(self): |
| files = {'foo.py': d("""\ |
| import unittest |
| import package_that_does_not_exist |
| |
| class ImportFailureTest(unittest.TestCase): |
| def test_case(self): |
| pass |
| """)} |
| self.check(['-l', 'foo.py'], files=files, ret=1, err='', |
| rout=('Failed to load "foo.py": No module named ' |
| '\'?package_that_does_not_exist\'?\n')) |
| |
| def test_import_failure_no_tests(self): |
| files = {'foo.py': 'import unittest'} |
| self.check(['-l', 'foo.bar'], files=files, ret=1, err='', |
| rout='Failed to load "foo.bar":.*') |
| |
| def test_import_failure_syntax_error(self): |
| files = {'syn_test.py': d("""\ |
| import unittest |
| |
| class SyntaxErrorTest(unittest.TestCase): |
| def test_syntax_error_in_test(self): |
| syntax error |
| """)} |
| _, out, _, _ = self.check([], files=files, ret=1, err='') |
| self.assertIn('Failed to import test module: syn_test', out) |
| self.assertIn((' syntax error\n' |
| ' ^\n' |
| 'SyntaxError: invalid syntax\n'), out) |
| |
| def test_interrupt(self): |
| files = {'interrupt_test.py': d("""\ |
| import unittest |
| class Foo(unittest.TestCase): |
| def test_interrupt(self): |
| raise KeyboardInterrupt() |
| """)} |
| self.check(['-j', '1'], files=files, ret=130, out='', |
| err='interrupted, exiting\n') |
| |
| def test_isolate(self): |
| self.check(['--isolate', '*test_pass*'], files=PASS_TEST_FILES, ret=0, |
| out=('[1/1] pass_test.PassingTest.test_pass passed\n' |
| '1 test run, 0 failures.\n'), err='') |
| |
| def test_load_tests_failure(self): |
| files = {'foo_test.py': d("""\ |
| import unittest |
| |
| def load_tests(_, _2, _3): |
| raise ValueError('this should fail') |
| """)} |
| self.check([], files=files, ret=1, err='', |
| out=('foo_test.load_tests() failed: this should fail\n')) |
| |
| def test_load_tests_single_worker(self): |
| files = LOAD_TEST_FILES |
| _, out, _, _ = self.check(['-j', '1', '-v'], files=files, ret=1, |
| err='') |
| self.assertIn('[1/2] load_test.BaseTest.test_fail failed', out) |
| self.assertIn('[2/2] load_test.BaseTest.test_pass passed', out) |
| self.assertIn('2 tests run, 1 failure.\n', out) |
| |
| def test_load_tests_multiple_workers(self): |
| _, out, _, _ = self.check([], files=LOAD_TEST_FILES, ret=1, err='') |
| |
| # The output for this test is nondeterministic since we may run |
| # two tests in parallel. So, we just test that some of the substrings |
| # we care about are present. |
| self.assertIn('test_pass passed', out) |
| self.assertIn('test_fail failed', out) |
| self.assertIn('2 tests run, 1 failure.\n', out) |
| |
| def test_missing_builder_name(self): |
| self.check(['--test-results-server', 'localhost'], ret=2, |
| out=('Error: --builder-name must be specified ' |
| 'along with --test-result-server\n' |
| 'Error: --master-name must be specified ' |
| 'along with --test-result-server\n' |
| 'Error: --test-type must be specified ' |
| 'along with --test-result-server\n'), err='') |
| |
| def test_ninja_status_env(self): |
| self.check(['-v', 'output_test.PassTest.test_out'], |
| files=OUTPUT_TEST_FILES, aenv={'NINJA_STATUS': 'ns: '}, |
| out=d("""\ |
| ns: output_test.PassTest.test_out passed |
| 1 test run, 0 failures. |
| """), err='') |
| |
| def test_output_for_failures(self): |
| _, out, _, _ = self.check(['output_test.FailTest'], |
| files=OUTPUT_TEST_FILES, |
| ret=1, err='') |
| self.assertIn('[1/1] output_test.FailTest.test_out_err_fail ' |
| 'failed unexpectedly:\n' |
| ' hello on stdout\n' |
| ' hello on stderr\n', out) |
| |
| def test_quiet(self): |
| self.check(['-q'], files=PASS_TEST_FILES, ret=0, err='', out='') |
| |
| def test_retry_limit(self): |
| _, out, _, _ = self.check(['--retry-limit', '2'], |
| files=FAIL_TEST_FILES, ret=1, err='') |
| self.assertIn('Retrying failed tests', out) |
| lines = out.splitlines() |
| self.assertEqual(len([l for l in lines |
| if 'test_fail failed unexpectedly:' in l]), |
| 3) |
| |
| def test_skip(self): |
| self.check(['--skip', '*test_fail*'], files=FAIL_TEST_FILES, ret=1, |
| out='No tests to run.\n', err='') |
| |
| files = {'fail_test.py': FAIL_TEST_PY, |
| 'pass_test.py': PASS_TEST_PY} |
| self.check(['-j', '1', '--skip', '*test_fail*'], files=files, ret=0, |
| out=('[1/2] fail_test.FailingTest.test_fail was skipped\n' |
| '[2/2] pass_test.PassingTest.test_pass passed\n' |
| '2 tests run, 0 failures.\n'), err='') |
| |
| # This tests that we print test_started updates for skipped tests |
| # properly. It also tests how overwriting works. |
| _, out, _, _ = self.check(['-j', '1', '--overwrite', '--skip', |
| '*test_fail*'], files=files, ret=0, |
| err='', universal_newlines=False) |
| |
| # We test this string separately and call out.strip() to |
| # avoid the trailing \r\n we get on windows, while keeping |
| # the \r's elsewhere in the string. |
| self.assertMultiLineEqual( |
| out.strip(), |
| ('[0/2] fail_test.FailingTest.test_fail\r' |
| ' \r' |
| '[1/2] fail_test.FailingTest.test_fail was skipped\r' |
| ' \r' |
| '[1/2] pass_test.PassingTest.test_pass\r' |
| ' \r' |
| '[2/2] pass_test.PassingTest.test_pass passed\r' |
| ' \r' |
| '2 tests run, 0 failures.')) |
| |
| def test_skips_and_failures(self): |
| _, out, _, _ = self.check(['-j', '1', '-v', '-v'], files=SF_TEST_FILES, |
| ret=1, err='') |
| |
| # We do a bunch of assertIn()'s to work around the non-portable |
| # tracebacks. |
| self.assertIn(('[1/9] sf_test.ExpectedFailures.test_fail failed:\n' |
| ' Traceback '), out) |
| self.assertIn(('[2/9] sf_test.ExpectedFailures.test_pass ' |
| 'passed unexpectedly'), out) |
| self.assertIn(('[3/9] sf_test.SetupClass.test_method1 ' |
| 'failed unexpectedly:\n' |
| ' in setupClass\n'), out) |
| self.assertIn(('[4/9] sf_test.SetupClass.test_method2 ' |
| 'failed unexpectedly:\n' |
| ' in setupClass\n'), out) |
| self.assertIn(('[5/9] sf_test.SkipClass.test_method was skipped:\n' |
| ' skip class\n'), out) |
| self.assertIn(('[6/9] sf_test.SkipMethods.test_reason was skipped:\n' |
| ' reason\n'), out) |
| self.assertIn(('[7/9] sf_test.SkipMethods.test_skip_if_false ' |
| 'failed unexpectedly:\n' |
| ' Traceback'), out) |
| self.assertIn(('[8/9] sf_test.SkipMethods.test_skip_if_true ' |
| 'was skipped:\n' |
| ' reason\n' |
| '[9/9] sf_test.SkipSetup.test_notrun was skipped:\n' |
| ' setup failed\n' |
| '9 tests run, 4 failures.\n'), out) |
| |
| def test_skip_and_all(self): |
| # --all should override --skip |
| self.check(['-l', '--skip', '*test_pass'], |
| files=PASS_TEST_FILES, ret=1, err='', |
| out='No tests to run.\n') |
| self.check(['-l', '--all', '--skip', '*test_pass'], |
| files=PASS_TEST_FILES, ret=0, err='', |
| out='pass_test.PassingTest.test_pass\n') |
| |
| def test_skip_decorators_and_all(self): |
| _, out, _, _ = self.check(['--all', '-j', '1', '-v', '-v'], |
| files=SF_TEST_FILES, ret=1, err='') |
| self.assertIn('sf_test.SkipClass.test_method failed', out) |
| self.assertIn('sf_test.SkipMethods.test_reason failed', out) |
| self.assertIn('sf_test.SkipMethods.test_skip_if_true failed', out) |
| self.assertIn('sf_test.SkipMethods.test_skip_if_false failed', out) |
| |
| # --all does not override explicit calls to skipTest(), only |
| # the decorators. |
| self.assertIn('sf_test.SkipSetup.test_notrun was skipped', out) |
| |
| def test_subdir(self): |
| files = { |
| 'foo/__init__.py': '', |
| 'foo/bar/__init__.py': '', |
| 'foo/bar/pass_test.py': PASS_TEST_PY |
| } |
| self.check(['foo/bar'], files=files, ret=0, err='', |
| out=d("""\ |
| [1/1] foo.bar.pass_test.PassingTest.test_pass passed |
| 1 test run, 0 failures. |
| """)) |
| |
| def test_timing(self): |
| self.check(['-t'], files=PASS_TEST_FILES, ret=0, err='', |
| rout=('\[1/1\] pass_test.PassingTest.test_pass passed ' |
| '\d+.\d+s\n' |
| '1 test run in \d+.\d+s, 0 failures.')) |
| |
| def test_test_results_server(self): |
| server = test_result_server_fake.start() |
| self.assertNotEqual(server, None, 'could not start fake server') |
| |
| try: |
| self.check(['--test-results-server', |
| '%s:%d' % server.server_address, |
| '--master-name', 'fake_master', |
| '--builder-name', 'fake_builder', |
| '--test-type', 'typ_tests', |
| '--metadata', 'foo=bar'], |
| files=PASS_TEST_FILES, ret=0, err='', |
| out=('[1/1] pass_test.PassingTest.test_pass passed\n' |
| '1 test run, 0 failures.\n')) |
| |
| finally: |
| posts = server.stop() |
| |
| self.assertEqual(len(posts), 1) |
| payload = posts[0][2].decode('utf8') |
| self.assertIn('"test_pass": {"expected": "PASS", "actual": "PASS"}', |
| payload) |
| self.assertTrue(payload.endswith('--\r\n')) |
| self.assertNotEqual(server.log.getvalue(), '') |
| |
| def test_test_results_server_error(self): |
| server = test_result_server_fake.start(code=500) |
| self.assertNotEqual(server, None, 'could not start fake server') |
| |
| try: |
| self.check(['--test-results-server', |
| '%s:%d' % server.server_address, |
| '--master-name', 'fake_master', |
| '--builder-name', 'fake_builder', |
| '--test-type', 'typ_tests', |
| '--metadata', 'foo=bar'], |
| files=PASS_TEST_FILES, ret=1, err='', |
| out=('[1/1] pass_test.PassingTest.test_pass passed\n' |
| '1 test run, 0 failures.\n' |
| 'Uploading the JSON results raised ' |
| '"HTTP Error 500: Internal Server Error"\n')) |
| |
| finally: |
| _ = server.stop() |
| |
| def test_test_results_server_not_running(self): |
| self.check(['--test-results-server', 'localhost:99999', |
| '--master-name', 'fake_master', |
| '--builder-name', 'fake_builder', |
| '--test-type', 'typ_tests', |
| '--metadata', 'foo=bar'], |
| files=PASS_TEST_FILES, ret=1, err='', |
| rout=('\[1/1\] pass_test.PassingTest.test_pass passed\n' |
| '1 test run, 0 failures.\n' |
| 'Uploading the JSON results raised .*\n')) |
| |
| def test_verbose(self): |
| self.check(['-vv', '-j', '1', 'output_test.PassTest'], |
| files=OUTPUT_TEST_FILES, ret=0, |
| out=d("""\ |
| [1/2] output_test.PassTest.test_err passed: |
| hello on stderr |
| [2/2] output_test.PassTest.test_out passed: |
| hello on stdout |
| 2 tests run, 0 failures. |
| """), err='') |
| |
| def test_version(self): |
| self.check('--version', ret=0, out=(VERSION + '\n')) |
| |
| def test_write_full_results_to(self): |
| _, _, _, files = self.check(['--write-full-results-to', |
| 'results.json'], files=PASS_TEST_FILES) |
| self.assertIn('results.json', files) |
| results = json.loads(files['results.json']) |
| self.assertEqual(results['interrupted'], False) |
| self.assertEqual(results['path_delimiter'], '.') |
| self.assertEqual(results['tests'], |
| {u'pass_test': { |
| u'PassingTest': { |
| u'test_pass': { |
| u'actual': u'PASS', |
| u'expected': u'PASS', |
| } |
| } |
| }}) |
| |
| def test_write_trace_to(self): |
| _, _, _, files = self.check(['--write-trace-to', 'trace.json'], |
| files=PASS_TEST_FILES) |
| self.assertIn('trace.json', files) |
| trace_obj = json.loads(files['trace.json']) |
| self.assertEqual(trace_obj['otherData'], {}) |
| self.assertEqual(len(trace_obj['traceEvents']), 5) |
| event = trace_obj['traceEvents'][0] |
| self.assertEqual(event['name'], 'pass_test.PassingTest.test_pass') |
| self.assertEqual(event['ph'], 'X') |
| self.assertEqual(event['tid'], 1) |
| self.assertEqual(event['args']['expected'], ['Pass']) |
| self.assertEqual(event['args']['actual'], 'Pass') |
| |
| |
| class TestMain(TestCli): |
| prog = [] |
| |
| def make_host(self): |
| return Host() |
| |
| def call(self, host, argv, stdin, env): |
| stdin = unicode(stdin) |
| host.stdin = io.StringIO(stdin) |
| if env: |
| host.getenv = env.get |
| host.capture_output() |
| orig_sys_path = sys.path[:] |
| orig_sys_modules = list(sys.modules.keys()) |
| |
| try: |
| ret = main(argv + ['-j', '1'], host) |
| finally: |
| out, err = host.restore_output() |
| modules_to_unload = [] |
| for k in sys.modules: |
| if k not in orig_sys_modules: |
| modules_to_unload.append(k) |
| for k in modules_to_unload: |
| del sys.modules[k] |
| sys.path = orig_sys_path |
| |
| return ret, out, err |
| |
| def test_debugger(self): |
| # TODO: this test seems to hang under coverage. |
| pass |