From d023c02904f4e3d2857afd07d75d5e5432e39090 Mon Sep 17 00:00:00 2001 From: dutcu Date: Wed, 19 Jun 2024 20:41:47 +0200 Subject: [PATCH 1/2] conftest coverage tool fix (only works for single func) --- Tests/test_image.py | 3 --- Tests/test_image_merge.py | 7 ++++++- conftest.py | 40 +++++++++++++++++++++++++++++++++++++++ coveragetool.py | 22 --------------------- src/PIL/Image.py | 17 +++++++++-------- 5 files changed, 55 insertions(+), 34 deletions(-) delete mode 100644 coveragetool.py diff --git a/Tests/test_image.py b/Tests/test_image.py index c1065d463..cd056d205 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1087,6 +1087,3 @@ class TestRegistry: def test_encode_registry_fail(self) -> None: with pytest.raises(OSError): Image._getencoder("RGB", "DoesNotExist", ("args",), extra=("extra",)) - - - diff --git a/Tests/test_image_merge.py b/Tests/test_image_merge.py index 40e198623..21b8a1bfd 100644 --- a/Tests/test_image_merge.py +++ b/Tests/test_image_merge.py @@ -2,6 +2,11 @@ import pytest from PIL import Image +def calculate_branch_coverage(): + b = Image.Branches + print("Branches covered:", sum(b.values())) + + def test_merge_wrong_number_of_bands(): R = Image.new('L', (100, 100), color=255) G = Image.new('L', (100, 100), color=128) @@ -22,4 +27,4 @@ def test_merge_size_mismatch(): with pytest.raises(ValueError, match="size mismatch"): Image.merge('RGB', [R, G, B]) - + diff --git a/conftest.py b/conftest.py index 5fda4f477..9fb8731fb 100644 --- a/conftest.py +++ b/conftest.py @@ -1,3 +1,43 @@ from __future__ import annotations +import pytest +import sys + +from PIL import Image pytest_plugins = ["Tests.helper"] + + +def calculate_coverage(test_name): + branch = Image.branches + branches = Image.branches + num_branches = len(branches) + branch_covered = {key: value for key, value in branches.items() if value is True} + sum_branches = len(branch_covered) + coverage = (sum_branches/num_branches) * 100 + print(f"\nBranches covered: {sum_branches}") + print(f"\nTotal branches: {num_branches}") + print("\nBRANCH COVERAGE:", coverage, "%\n") + return coverage + + + +@pytest.hookimpl(tryfirst=True) +def pytest_runtest_protocol(item, nextitem): + global test_name + + last_arg = sys.argv[-1] + + test_name = last_arg.split('/')[-1].split('::')[-1] + + test_name = test_name.rstrip('.py') + + return None + +@pytest.hookimpl(tryfirst=True) +def pytest_sessionfinish(session, exitstatus): + global test_name + + coverage = calculate_coverage(test_name) + print("\nBRANCH COVERAGE for", test_name, ":", coverage, "%\n") + + \ No newline at end of file diff --git a/coveragetool.py b/coveragetool.py deleted file mode 100644 index 60b74e26e..000000000 --- a/coveragetool.py +++ /dev/null @@ -1,22 +0,0 @@ -from PIL import Image -from PIL.Image import branches - -# Define a function to calculate and print branch coverage - - -def calculate_branch_coverage(): - num_branches = len(branches) - branch_covered = {key: value for key, value in branches.items() if value is True} - sum_branches = len(branch_covered) - coverage = (sum_branches/num_branches) * 100 - print(f"Branches covered: {sum_branches}") - print(f"Total branches: {num_branches}") - print("\nBRANCH COVERAGE:", coverage, "%\n") - -R = Image.new('L', (100, 100), color=255) -G = Image.new('L', (100, 100), color=128) -B = Image.new('L', (100, 100), color=0) -merged_image = Image.merge('RGB', (R, G, B)) -merged_image.save('merged_image.png') - -calculate_branch_coverage() diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 947deeb78..315b65851 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -75,14 +75,6 @@ class DecompressionBombWarning(RuntimeWarning): class DecompressionBombError(Exception): pass -branches = { - "1": False, - "2": False, - "3": False, - "4": False, - "5": False, -} - # Limit to around a quarter gigabyte for a 24-bit (3 bpp) image MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3) @@ -545,6 +537,14 @@ class Image: self.pyaccess = None self._exif = None + branches = { + "1": False, + "2": False, + "3": False, + "4": False, + "5": False, + } + @property def width(self) -> int: return self.size[0] @@ -594,6 +594,7 @@ class Image: self._close_fp() self.fp = None + def close(self) -> None: """ Closes the file pointer, if possible. From 27c7ac4dadf950418e21883ef7f9b9a209a7b481 Mon Sep 17 00:00:00 2001 From: dutcu Date: Wed, 19 Jun 2024 21:22:31 +0200 Subject: [PATCH 2/2] conftest coverage tool fix and pdfparser function coverage --- conftest.py | 28 ++++++++++++++++++---------- src/PIL/Image.py | 15 +++++++-------- src/PIL/PdfParser.py | 12 ++++++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/conftest.py b/conftest.py index 9fb8731fb..ff3fe1d2c 100644 --- a/conftest.py +++ b/conftest.py @@ -3,22 +3,30 @@ import pytest import sys from PIL import Image +from PIL import PdfParser pytest_plugins = ["Tests.helper"] def calculate_coverage(test_name): - branch = Image.branches - branches = Image.branches - num_branches = len(branches) - branch_covered = {key: value for key, value in branches.items() if value is True} - sum_branches = len(branch_covered) - coverage = (sum_branches/num_branches) * 100 - print(f"\nBranches covered: {sum_branches}") - print(f"\nTotal branches: {num_branches}") - print("\nBRANCH COVERAGE:", coverage, "%\n") - return coverage + all_branches = { + "branches1": Image.branches, + "branches2": PdfParser.XrefTable.branches, + # Add more + } + for name, branches in all_branches.items(): + num_branches = len(branches) + branch_covered = {key: value for key, value in branches.items() if value is True} + sum_branches = len(branch_covered) + coverage = (sum_branches / num_branches) * 100 + + print(f"\n{name} - Branches covered: {sum_branches}") + print(f"{name} - Total branches: {num_branches}") + print(f"{name} - BRANCH COVERAGE: {coverage}%\n") + + + return all_branches["branches1"] @pytest.hookimpl(tryfirst=True) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 315b65851..98f9ed981 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -67,6 +67,13 @@ except ImportError: logger = logging.getLogger(__name__) +branches = { + "1": False, + "2": False, + "3": False, + "4": False, + "5": False, + } class DecompressionBombWarning(RuntimeWarning): pass @@ -537,14 +544,6 @@ class Image: self.pyaccess = None self._exif = None - branches = { - "1": False, - "2": False, - "3": False, - "4": False, - "5": False, - } - @property def width(self) -> int: return self.size[0] diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index 93d677e89..11649f1c2 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -112,6 +112,14 @@ class IndirectObjectDef(IndirectReference): class XrefTable: + + branches = { + "1": False, + "2": False, + "3": False, + "4": False, + } + def __init__(self): self.existing_entries = {} # object ID => (offset, generation) self.new_entries = {} # object ID => (offset, generation) @@ -134,15 +142,19 @@ class XrefTable: def __delitem__(self, key): if key in self.new_entries: + XrefTable.branches["1"] = True generation = self.new_entries[key][1] + 1 del self.new_entries[key] self.deleted_entries[key] = generation elif key in self.existing_entries: + XrefTable.branches["2"] = True generation = self.existing_entries[key][1] + 1 self.deleted_entries[key] = generation elif key in self.deleted_entries: + XrefTable.branches["3"] = True generation = self.deleted_entries[key] else: + XrefTable.branches["4"] = True msg = f"object ID {key} cannot be deleted because it doesn't exist" raise IndexError(msg)