diff --git a/packages/google-crc32c/.coveragerc b/packages/google-crc32c/.coveragerc index ab4a10fdea4b..35f44c901a9b 100644 --- a/packages/google-crc32c/.coveragerc +++ b/packages/google-crc32c/.coveragerc @@ -17,12 +17,18 @@ # Generated by synthtool. DO NOT EDIT! [run] branch = True +source = + src/google_crc32c omit = google/__init__.py google/cloud/__init__.py + # Windows-only DLL bootstrap logic (not executed on Linux/macOS) + src/google_crc32c/__config__.py + # Uncompiled C extension wrapper (exercised in wheel check session, not pure-Python unit tests) + src/google_crc32c/cext.py [report] -fail_under = 0 +fail_under = 100 show_missing = True exclude_lines = # Re-enable the standard pragma @@ -37,3 +43,7 @@ omit = */core/*.py */site-packages/*.py google/cloud/__init__.py + # Windows-only DLL bootstrap logic (not executed on Linux/macOS) + src/google_crc32c/__config__.py + # Uncompiled C extension wrapper (exercised in wheel check session, not pure-Python unit tests) + src/google_crc32c/cext.py diff --git a/packages/google-crc32c/noxfile.py b/packages/google-crc32c/noxfile.py index 3c238ff62f8f..bf0c56e740c4 100644 --- a/packages/google-crc32c/noxfile.py +++ b/packages/google-crc32c/noxfile.py @@ -40,6 +40,7 @@ "blacken", "format", "lint_setup_py", + "cover", "mypy", "prerelease_deps", "core_deps_from_source", @@ -66,11 +67,13 @@ def build_libcrc32c(session): @nox.session(python=UNIT_TEST_PYTHON_VERSIONS) def check(session): - session.install("pytest") + session.install("pytest", "pytest-cov") session.install("--no-index", f"--find-links={HERE}/wheels", "google-crc32c") # Run py.test against the unit tests. - session.run("py.test", "tests") + session.run( + "pytest", "--cov=google_crc32c", "--cov=tests", "tests", *session.posargs + ) session.run("python", f"{HERE}/scripts/check_crc32c_extension.py", *session.posargs) @@ -174,9 +177,9 @@ def lint_setup_py(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def prerelease_deps(session): """Run all tests with prerelease versions of dependencies installed.""" - # TODO(https://github.com/googleapis/google-cloud-python/issues/16014): - # Add prerelease deps tests - session.skip("prerelease deps tests are not yet supported") + session.skip( + "prerelease_deps session is not applicable as google-crc32c has no runtime dependencies" + ) @nox.session(python=DEFAULT_PYTHON_VERSION) @@ -184,15 +187,30 @@ def core_deps_from_source(session): """Run all tests with core dependencies installed from source rather than pulling the dependencies from PyPI. """ - # TODO(https://github.com/googleapis/google-cloud-python/issues/16014): - # Add core deps from source tests - session.skip("Core deps from source tests are not yet supported") + session.skip( + "core_deps_from_source session is not applicable as google-crc32c has no core dependencies" + ) -@nox.session(python=ALL_PYTHON) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS) def unit(session): """Run all unit tests.""" - session.skip("Unit tests are not supported") + session.env["CRC32C_PURE_PYTHON"] = "1" + session.env["PYTHONPATH"] = "src" + session.install("pytest", "pytest-cov") + session.run("pytest", "--cov=src/google_crc32c", "tests", *session.posargs) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def cover(session): + """Run the final coverage report. + + This outputs the coverage report aggregating coverage from the unit + test runs (not system test runs), and then erases coverage data. + """ + session.install("coverage", "pytest-cov") + session.run("coverage", "report", "--show-missing", "--fail-under=100") + session.run("coverage", "erase") @nox.session(python="3.10") diff --git a/packages/google-crc32c/src/google_crc32c/__init__.py b/packages/google-crc32c/src/google_crc32c/__init__.py index bba10d5c4b1c..0acf5476ba2f 100644 --- a/packages/google-crc32c/src/google_crc32c/__init__.py +++ b/packages/google-crc32c/src/google_crc32c/__init__.py @@ -20,11 +20,12 @@ "please configure a c build environment and compile the extension" ) -# Default to C exstension Implementation, falling back to pure python. +# Default to C extension implementation, falling back to pure Python. try: - from google_crc32c import cext as impl + # Pure-Python unit test sessions test python.py; cext is tested during wheel checks. + from google_crc32c import cext as impl # pragma: NO COVER - implementation = "c" + implementation = "c" # pragma: NO COVER except ImportError: from google_crc32c import python as impl # type: ignore diff --git a/packages/google-crc32c/src/google_crc32c/cext.py b/packages/google-crc32c/src/google_crc32c/cext.py index 53e58f6321f1..ec22abec5c1c 100644 --- a/packages/google-crc32c/src/google_crc32c/cext.py +++ b/packages/google-crc32c/src/google_crc32c/cext.py @@ -17,8 +17,8 @@ import google_crc32c.__config__ # noqa: F401 from google_crc32c._checksum import CommonChecksum from google_crc32c._crc32c import ( # type: ignore - extend, # type: ignore - value, # type: ignore + extend, + value, ) diff --git a/packages/google-crc32c/tests/test___init__.py b/packages/google-crc32c/tests/test___init__.py index 68bed918ffa4..8d108ac91657 100644 --- a/packages/google-crc32c/tests/test___init__.py +++ b/packages/google-crc32c/tests/test___init__.py @@ -206,10 +206,13 @@ def _crc32c(request): return python elif request.param == "cext": - from google_crc32c import cext + try: + from google_crc32c import cext - return cext - else: + return cext # pragma: NO COVER + except ImportError: # pragma: NO COVER + pytest.skip("C extension not compiled") # pragma: NO COVER + else: # pragma: NO COVER raise ValueError("invalid internal test config") @@ -225,6 +228,17 @@ def test_ctor_explicit(_crc32c): helper = google_crc32c.Checksum(chunk) assert helper._crc == google_crc32c.value(chunk) + @staticmethod + def test_update_array(): + import array + + from google_crc32c import python + + chunk = array.array("B", b"DEADBEEF") + helper = python.Checksum() + helper.update(chunk) + assert helper._crc == python.value(b"DEADBEEF") + @staticmethod def test_update(_crc32c): chunk = b"DEADBEEF" @@ -287,3 +301,18 @@ def test_consume_stream(_crc32c, chunksize): assert found == expected for call in stream.read.call_args_list: assert call == mock.call(chunksize) + + +def test_common_checksum(): + from google_crc32c._checksum import CommonChecksum + + class DummyChecksum(CommonChecksum): + __slots__ = ("_crc",) + + checksum = DummyChecksum() + assert checksum._crc == 0 + with pytest.raises(NotImplementedError): + checksum.update(b"data") + + with pytest.raises(NotImplementedError): + DummyChecksum(b"foo")