From 95ac8a6c9d992e20488d0625120773412936657d Mon Sep 17 00:00:00 2001 From: Kevin James Date: Wed, 3 Nov 2021 15:36:35 -0700 Subject: [PATCH] tests: fix tests & linting --- .circleci/config.yml | 22 ++-- .pre-commit-config.yaml | 4 + coveralls/api.py | 5 +- coveralls/git.py | 16 +-- setup.py | 4 +- tests/api/configuration_test.py | 2 +- tests/api/wear_test.py | 56 ++++----- tests/cli_test.py | 4 +- tests/coverage_templates/bar_310.py | 13 -- tests/coverage_templates/foo.py | 8 -- .../bar.py => data/foo.py} | 10 +- tests/git_test.py | 3 +- tests/integration_test.py | 115 +++++++----------- tox.ini | 10 +- 14 files changed, 120 insertions(+), 152 deletions(-) delete mode 100644 tests/coverage_templates/bar_310.py delete mode 100644 tests/coverage_templates/foo.py rename tests/{coverage_templates/bar.py => data/foo.py} (50%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4811049a..b1d4bf7f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -49,7 +49,9 @@ workflows: lint: jobs: - linter/pre-commit: - python_version: 3.10.0 + # N.B. lowest common denominator, don't want to error on not using + # the latest syntax. + python_version: 3.6.15 test-cpython: jobs: @@ -63,35 +65,35 @@ workflows: tox_environment: py36 matrix: parameters: - cov_version: ['41', '5'] + cov_version: ['41', '5', '6'] - toxpy: name: test-py3.7-cov<> docker_image: '3.7' tox_environment: py37 matrix: parameters: - cov_version: ['41', '5'] + cov_version: ['41', '5', '6'] - toxpy: name: test-py3.8-cov<> docker_image: '3.8' tox_environment: py38 matrix: parameters: - cov_version: ['41', '5'] + cov_version: ['41', '5', '6'] - toxpy: name: test-py3.9-cov<> docker_image: '3.9' tox_environment: py39 matrix: parameters: - cov_version: ['41', '5'] + cov_version: ['41', '5', '6'] - toxpy: name: test-py3.10-cov<> docker_image: '3.10' tox_environment: py310 matrix: parameters: - cov_version: ['41', '5'] + cov_version: ['41', '5', '6'] test-pypy: jobs: @@ -100,4 +102,10 @@ workflows: matrix: parameters: cov_version: ['41', '5'] - docker_image: ['3-5', '3-6', '3-7'] + docker_image: ['3-5', '3-6'] + - toxpypy: + name: test-pypy3-7-cov<> + docker_image: '3-7' + matrix: + parameters: + cov_version: ['41', '5', '6'] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 471fdaec..f374daeb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,6 +28,7 @@ repos: - id: double-quote-string-fixer exclude: nonunicode/.* - id: name-tests-test + exclude: tests/data/.* - id: requirements-txt-fixer - repo: https://github.com/pycqa/pylint rev: v2.11.1 @@ -53,6 +54,9 @@ repos: - -d too-few-public-methods - -d ungrouped-imports # conflicts with reorder-python-imports - -d wrong-import-order # conflicts with reorder-python-imports + - -d consider-using-f-string # not py35 compatible + - -d unspecified-encoding # TODO: reevaluate + - -d disallowed-name # TODO: fix exclude: example/.* - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.1.10 diff --git a/coveralls/api.py b/coveralls/api.py index 64f73a9b..56616880 100644 --- a/coveralls/api.py +++ b/coveralls/api.py @@ -229,8 +229,9 @@ def load_config_from_environment(self): def load_config_from_file(self): try: - with open(os.path.join(os.getcwd(), - self.config_filename)) as config: + fname = os.path.join(os.getcwd(), self.config_filename) + + with open(fname) as config: try: import yaml # pylint: disable=import-outside-toplevel self.config.update(yaml.safe_load(config)) diff --git a/coveralls/git.py b/coveralls/git.py index b0efa9de..895405ae 100644 --- a/coveralls/git.py +++ b/coveralls/git.py @@ -9,16 +9,16 @@ def run_command(*args): - cmd = subprocess.Popen(list(args), stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = cmd.communicate() + with subprocess.Popen(list(args), stdout=subprocess.PIPE, + stderr=subprocess.PIPE) as cmd: + stdout, stderr = cmd.communicate() - if cmd.returncode != 0: - raise CoverallsException( - 'command return code {}, STDOUT: "{}"\nSTDERR: "{}"'.format( - cmd.returncode, stdout, stderr)) + if cmd.returncode != 0: + raise CoverallsException( + 'command return code {}, STDOUT: "{}"\nSTDERR: "{}"'.format( + cmd.returncode, stdout, stderr)) - return stdout.decode().strip() + return stdout.decode().strip() def gitlog(fmt): diff --git a/setup.py b/setup.py index 2f0d7a06..2858f294 100644 --- a/setup.py +++ b/setup.py @@ -6,9 +6,9 @@ VERSION_FILE = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'coveralls', 'version.py') -DESCRIPTION = open('README.rst').read() +with open('README.rst') as f: + DESCRIPTION = f.read() -VERSION = None with open(VERSION_FILE) as f: VERSION = f.read().split()[2][1:-1] diff --git a/tests/api/configuration_test.py b/tests/api/configuration_test.py index 88125c23..9383fcc0 100644 --- a/tests/api/configuration_test.py +++ b/tests/api/configuration_test.py @@ -250,7 +250,7 @@ def test_service_name_from_env(self): assert cover.config['repo_token'] == 'a1b2c3d4' assert cover.config['service_name'] == 'bbb' assert cover.config['flag_name'] == 'cc' - assert cover.config['service_number'] == '1234' + assert cover.config['service_job_number'] == '1234' @mock.patch.object(Coveralls, 'config_filename', '.coveralls.mock') diff --git a/tests/api/wear_test.py b/tests/api/wear_test.py index b6435af1..d487cccc 100644 --- a/tests/api/wear_test.py +++ b/tests/api/wear_test.py @@ -33,46 +33,46 @@ def test_wet_run(self, mock_requests): assert result == EXPECTED def test_merge(self, _mock_requests): - coverage_file = tempfile.NamedTemporaryFile() - coverage_file.write( - b'{"source_files": [{"name": "foobar", "coverage": []}]}') - coverage_file.seek(0) + with tempfile.NamedTemporaryFile() as coverage_file: + coverage_file.write( + b'{"source_files": [{"name": "foobar", "coverage": []}]}') + coverage_file.seek(0) - api = coveralls.Coveralls(repo_token='xxx') - api.merge(coverage_file.name) - result = api.create_report() + api = coveralls.Coveralls(repo_token='xxx') + api.merge(coverage_file.name) + result = api.create_report() - source_files = json.loads(result)['source_files'] - assert source_files == [{'name': 'foobar', 'coverage': []}] + source_files = json.loads(result)['source_files'] + assert source_files == [{'name': 'foobar', 'coverage': []}] def test_merge_empty_data(self, _mock_requests): - coverage_file = tempfile.NamedTemporaryFile() - coverage_file.write(b'{}') - coverage_file.seek(0) + with tempfile.NamedTemporaryFile() as coverage_file: + coverage_file.write(b'{}') + coverage_file.seek(0) - api = coveralls.Coveralls(repo_token='xxx') - api.merge(coverage_file.name) - result = api.create_report() + api = coveralls.Coveralls(repo_token='xxx') + api.merge(coverage_file.name) + result = api.create_report() - source_files = json.loads(result)['source_files'] - assert source_files == [] + source_files = json.loads(result)['source_files'] + assert source_files == [] @mock.patch.object(log, 'warning') def test_merge_invalid_data(self, mock_logger, _mock_requests): - coverage_file = tempfile.NamedTemporaryFile() - coverage_file.write(b'{"random": "stuff"}') - coverage_file.seek(0) + with tempfile.NamedTemporaryFile() as coverage_file: + coverage_file.write(b'{"random": "stuff"}') + coverage_file.seek(0) - api = coveralls.Coveralls(repo_token='xxx') - api.merge(coverage_file.name) - result = api.create_report() + api = coveralls.Coveralls(repo_token='xxx') + api.merge(coverage_file.name) + result = api.create_report() - source_files = json.loads(result)['source_files'] - assert source_files == [] + source_files = json.loads(result)['source_files'] + assert source_files == [] - mock_logger.assert_called_once_with('No data to be merged; does the ' - 'json file contain "source_files" ' - 'data?') + mock_logger.assert_called_once_with( + 'No data to be merged; does the json file contain ' + '"source_files" data?') def test_dry_run(self, mock_requests): mock_requests.post.return_value.json.return_value = EXPECTED diff --git a/tests/cli_test.py b/tests/cli_test.py index 0242a3fc..45b8aa90 100644 --- a/tests/cli_test.py +++ b/tests/cli_test.py @@ -180,9 +180,9 @@ def test_save_report_to_file_no_token(mock_coveralls): @mock.patch.dict(os.environ, {'TRAVIS': 'True'}, clear=True) def test_submit(mock_submit): json_file = os.path.join(EXAMPLE_DIR, 'example.json') - json_string = open(json_file).read() coveralls.cli.main(argv=['--submit=' + json_file]) - mock_submit.assert_called_with(json_string) + with open(json_file) as f: + mock_submit.assert_called_with(f.read()) @mock.patch('coveralls.cli.Coveralls') diff --git a/tests/coverage_templates/bar_310.py b/tests/coverage_templates/bar_310.py deleted file mode 100644 index 9856022a..00000000 --- a/tests/coverage_templates/bar_310.py +++ /dev/null @@ -1,13 +0,0 @@ -def test_func(max_val): - for idx in range(0, max_val): - match idx: - case -1: - print("Miss 1", idx) - case 4: - print("Hit 1", idx) - case 6: - print("Hit 2", idx) - case 12: - print("Miss 2", idx) - case _: - print("Other", idx) diff --git a/tests/coverage_templates/foo.py b/tests/coverage_templates/foo.py deleted file mode 100644 index 8c21ef8b..00000000 --- a/tests/coverage_templates/foo.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys - -__all__ = ["test_func"] - -if sys.version_info[:2] >= (3, 10): - from bar_310 import test_func -else: - from bar import test_func diff --git a/tests/coverage_templates/bar.py b/tests/data/foo.py similarity index 50% rename from tests/coverage_templates/bar.py rename to tests/data/foo.py index 98167f3c..5098c2d4 100644 --- a/tests/coverage_templates/bar.py +++ b/tests/data/foo.py @@ -1,12 +1,12 @@ def test_func(max_val): for idx in range(0, max_val): if idx == -1: - print("Miss 1", idx) + print('Miss 1', idx) elif idx == 4: - print("Hit 1", idx) + print('Hit 1', idx) elif idx == 6: - print("Hit 2", idx) + print('Hit 2', idx) elif idx == 12: - print("Miss 2", idx) + print('Miss 2', idx) else: - print("Other", idx) + print('Other', idx) diff --git a/tests/git_test.py b/tests/git_test.py index 585ec5a9..cc7d99dc 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -22,7 +22,8 @@ def setUp(self): self.dir = tempfile.mkdtemp() os.chdir(self.dir) - open('README', 'a').close() + # TODO: switch to pathlib + open('README', 'a').close() # pylint: disable=consider-using-with subprocess.call(['git', 'init'], cwd=self.dir) subprocess.call(['git', 'config', 'user.name', diff --git a/tests/integration_test.py b/tests/integration_test.py index 79b8ebc9..39b08d49 100644 --- a/tests/integration_test.py +++ b/tests/integration_test.py @@ -1,91 +1,66 @@ import os +import subprocess +import sys import tempfile import unittest -from os.path import join as jp, dirname -from pprint import pprint -from subprocess import check_call from coveralls import Coveralls -COVERAGE_CONFIG = """ -[run] -branch = True -data_file = %s - -[paths] -source = %s - %s -""" COVERAGE_CODE_STANZA = """ import sys +sys.path.append('{}') -sys.path.append(%r) - -exec(''' import foo - -foo.test_func(%r) -''') +foo.test_func({:d}) """ -COVERAGE_TEMPLATE_PATH = jp(dirname(__file__), "coverage_templates") +COVERAGE_TEMPLATE_PATH = os.path.join(os.path.dirname(__file__), 'data') class IntegrationTest(unittest.TestCase): - @classmethod - def setUpClass(cls): - try: - cls.old_cwd = os.getcwd() - except FileNotFoundError: - cls.old_cwd = None - - @classmethod - def tearDownClass(cls): - if cls.old_cwd: - os.chdir(cls.old_cwd) - - def setUp(self): - self.temp_dir = tempfile.TemporaryDirectory() - os.chdir(self.temp_dir.name) - self.covrc = jp(self.temp_dir.name, ".coveragerc") - self.cov = jp(self.temp_dir.name, ".coverage") - self.test_file = jp(self.temp_dir.name, "test.py") - - def tearDown(self): - self.temp_dir.cleanup() - - def _test_harness(self, code): - with open(self.covrc, "wt") as f: - f.write(COVERAGE_CONFIG % (self.cov, COVERAGE_TEMPLATE_PATH, self.temp_dir)) - with open(self.test_file, "wt") as f: - f.write(code) - - check_call(["coverage", "run", "test.py"]) - - os.unlink(self.test_file) - - coverallz = Coveralls(repo_token="xxx", - config_file=self.covrc) - report = coverallz.create_data() - coverallz.create_report() # This is purely for coverage - - source_files = set(f["name"] for f in report["source_files"]) - self.assertNotIn(self.test_file, source_files) - self.assertIn(jp(COVERAGE_TEMPLATE_PATH, "foo.py"), source_files) - self.assertTrue(jp(COVERAGE_TEMPLATE_PATH, "bar.py") in source_files or - jp(COVERAGE_TEMPLATE_PATH, "bar_310.py") in source_files) - self.assertFalse(jp(COVERAGE_TEMPLATE_PATH, "bar.py") in source_files and - jp(COVERAGE_TEMPLATE_PATH, "bar_310.py") in source_files) - - def _test_number(self, num): - self._test_harness(COVERAGE_CODE_STANZA % (COVERAGE_TEMPLATE_PATH, num)) - + gitinfo = { + 'GIT_ID': 'asdf1234', + 'GIT_AUTHOR_NAME': 'Integration Tests', + 'GIT_AUTHOR_EMAIL': 'integration@test.com', + 'GIT_COMMITTER_NAME': 'Integration Tests', + 'GIT_COMMITTER_EMAIL': 'integration@test.com', + 'GIT_MESSAGE': 'Ran the integration tests', + } + + def _test_harness(self, num, hits): + with tempfile.TemporaryDirectory() as tempdir: + os.chdir(tempdir) + + test_file = os.path.join(tempdir, 'test.py') + with open(test_file, 'wt') as f: + f.write(COVERAGE_CODE_STANZA.format(COVERAGE_TEMPLATE_PATH, + num)) + + subprocess.check_call([sys.executable, '-m', 'coverage', 'run', + test_file]) + + coverallz = Coveralls(repo_token='xxx') + report = coverallz.create_data() + coverallz.create_report() # This is purely for coverage + + source_files = {f['name'] for f in report['source_files']} + print(source_files) + foo = os.path.join(COVERAGE_TEMPLATE_PATH, 'foo.py') + self.assertIn(foo, source_files) + + lines = next((f['coverage'] for f in report['source_files'] + if f['name'] == foo), None) + assert sum(int(bool(x)) for x in lines) == hits + + @unittest.mock.patch.dict(os.environ, gitinfo, clear=True) def test_5(self): - self._test_number(5) + self._test_harness(5, 8) + @unittest.mock.patch.dict(os.environ, gitinfo, clear=True) def test_7(self): - self._test_number(7) + self._test_harness(7, 9) + @unittest.mock.patch.dict(os.environ, gitinfo, clear=True) def test_11(self): - self._test_number(11) + self._test_harness(11, 9) diff --git a/tox.ini b/tox.ini index fafe8a1e..f5cedc4c 100644 --- a/tox.ini +++ b/tox.ini @@ -4,11 +4,11 @@ envlist = py35-cov41-{default,pyyaml},py{36,37,38,39,310,py3}-cov{41,5,6}-{defau [gh-actions] python = 3.5: py35 - 3.6: py36-cov5 - 3.7: py37-cov5 - 3.8: py38-cov5 - 3.9: py39-cov5 - 3.10: py310-cov5 + 3.6: py36-cov6 + 3.7: py37-cov6 + 3.8: py38-cov6 + 3.9: py39-cov6 + 3.10: py310-cov6 [testenv] passenv = *