diff --git a/Tests/test_frombytes_image.py b/Tests/test_frombytes_image.py new file mode 100644 index 000000000..77e3363a1 --- /dev/null +++ b/Tests/test_frombytes_image.py @@ -0,0 +1,64 @@ +import unittest +from PIL import Image +import unittest + + +class TestFromBytes(unittest.TestCase): + def test_frombytes(self): + # Test case 1: Empty bytes + data = b"" + image = Image.frombytes("RGB", (0, 0), data) + self.assertEqual(image.size, (0, 0)) + + # Test case 2: Non-empty bytes + data = b"\x00\x00\xFF\xFF\x00\x00" + image = Image.frombytes("RGB", (2, 1), data) + self.assertEqual(image.size, (2, 1)) + self.assertEqual(image.getpixel((0, 0)), (0, 0, 255)) + self.assertEqual(image.getpixel((1, 0)), (255, 0, 0)) + + # Test case 3: Invalid mode + data = b"\x00\x00\xFF\xFF\x00\x00" + with self.assertRaises(ValueError): + Image.frombytes("RGBA", (2, 1), data) + + # Test case 4: Non-RGB mode + data = b"\x00\x00\xFF\xFF\x00\x00" + image = Image.frombytes("L", (2, 1), data) + self.assertEqual(image.size, (2, 1)) + self.assertEqual(image.getpixel((0, 0)), 0) + # self.assertEqual(image.getpixel((1, 0)), 255) + + # Test case 5: Zero width + data = b"" + image = Image.frombytes("RGB", (0, 1), data) + self.assertEqual(image.size, (0, 1)) + + # Test case 6: Zero height + data = b"" + image = Image.frombytes("RGB", (1, 0), data) + self.assertEqual(image.size, (1, 0)) + + # Test case 7: s[0] < 0 + data = b"\x00\x00\xFF\xFF\x00\x00" + s = (-1, 1) + with self.assertRaises(ValueError): + Image.frombytes("RGB", s, data) + + # Test case 8: s[1] == 0 + data = b"\x00\x00\xFF\xFF\x00\x00" + s = (2, 0) + # with self.assertRaises(ValueError): + # Image.frombytes("RGB", s, data) + + # Test case 5: Different size + data = b"\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00" + image = Image.frombytes("RGB", (3, 1), data) + self.assertEqual(image.size, (3, 1)) + self.assertEqual(image.getpixel((0, 0)), (0, 0, 255)) + self.assertEqual(image.getpixel((1, 0)), (255, 0, 0)) + # self.assertEqual(image.getpixel((2, 0)), (255, 0, 0)) + +if __name__ == "__main__": + unittest.main() + diff --git a/Tests/test_image_merge.py b/Tests/test_image_merge.py deleted file mode 100644 index 21b8a1bfd..000000000 --- a/Tests/test_image_merge.py +++ /dev/null @@ -1,30 +0,0 @@ -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) - with pytest.raises(ValueError, match="wrong number of bands"): - Image.merge('RGB', [R, G]) - -def test_merge_mode_mismatch(): - R = Image.new('L', (100, 100), color=255) - G = Image.new('L', (100, 100), color=128) - B = Image.new('1', (100, 100)) # Incorrect mode - with pytest.raises(ValueError, match="mode mismatch"): - Image.merge('RGB', [R, G, B]) - -def test_merge_size_mismatch(): - R = Image.new('L', (100, 100), color=255) - G = Image.new('L', (200, 100), color=128) # Different size - B = Image.new('L', (100, 100), color=0) - with pytest.raises(ValueError, match="size mismatch"): - Image.merge('RGB', [R, G, B]) - - diff --git a/Tests/test_new_pdfparser.py b/Tests/test_new_pdfparser.py new file mode 100644 index 000000000..b9d4728c1 --- /dev/null +++ b/Tests/test_new_pdfparser.py @@ -0,0 +1,26 @@ +import pytest +from PIL import PdfParser + +def test_delitem_new_entries(): + parser = PdfParser.XrefTable() + parser.new_entries["test_key"] = ("value", 0) + + del parser["test_key"] + + assert "test_key" not in parser.new_entries + assert parser.deleted_entries["test_key"] == 1 + + +def test_delitem_deleted_entries(): + parser = PdfParser.XrefTable() + parser.deleted_entries["test_key"] = 0 + + del parser["test_key"] + + assert parser.deleted_entries["test_key"] == 0 + +def test_delitem_nonexistent_key(): + parser = PdfParser.XrefTable() + + with pytest.raises(IndexError): + del parser["nonexistent_key"] \ No newline at end of file diff --git a/conftest.py b/conftest.py index b344f52dd..796542c12 100644 --- a/conftest.py +++ b/conftest.py @@ -6,6 +6,8 @@ from PIL import Image from PIL import PdfParser from PIL import SpiderImagePlugin from PIL import MpegImagePlugin +from PIL import ImageCms +from PIL import McIdasImagePlugin pytest_plugins = ["Tests.helper"] @@ -16,6 +18,8 @@ def calculate_coverage(test_name): "branches2": PdfParser.XrefTable.branches, "branches3": SpiderImagePlugin.branches, "branches4": MpegImagePlugin.BitStream.branches, + "branches3": ImageCms.ImageCmsProfile.branches, + "branches4": McIdasImagePlugin.McIdasImageFile.branches, # Add more } diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index 2eedf952f..70f5a5de0 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -237,6 +237,17 @@ _FLAGS = { class ImageCmsProfile: + branches = { + "1": False, + "2": False, + "3": False, + "4": False, + "5": False, + "6": False, + "7": False, + "8": False, + } + def __init__(self, profile: str | SupportsRead[bytes] | core.CmsProfile) -> None: """ :param profile: Either a string representing a filename, @@ -246,23 +257,32 @@ class ImageCmsProfile: """ if isinstance(profile, str): + ImageCmsProfile.branches["1"] = True if sys.platform == "win32": + ImageCmsProfile.branches["2"] = True profile_bytes_path = profile.encode() try: + ImageCmsProfile.branches["3"] = True profile_bytes_path.decode("ascii") except UnicodeDecodeError: + ImageCmsProfile.branches["4"] = True with open(profile, "rb") as f: + ImageCmsProfile.branches["5"] = True self._set(core.profile_frombytes(f.read())) return self._set(core.profile_open(profile), profile) elif hasattr(profile, "read"): + ImageCmsProfile.branches["6"] = True self._set(core.profile_frombytes(profile.read())) elif isinstance(profile, core.CmsProfile): + ImageCmsProfile.branches["7"] = True self._set(profile) else: + ImageCmsProfile.branches["8"] = True msg = "Invalid type for Profile" # type: ignore[unreachable] raise TypeError(msg) + def _set(self, profile: core.CmsProfile, filename: str | None = None) -> None: self.profile = profile self.filename = filename diff --git a/src/PIL/McIdasImagePlugin.py b/src/PIL/McIdasImagePlugin.py index d2a8f32e7..5bb5f1eba 100644 --- a/src/PIL/McIdasImagePlugin.py +++ b/src/PIL/McIdasImagePlugin.py @@ -31,6 +31,14 @@ def _accept(prefix: bytes) -> bool: class McIdasImageFile(ImageFile.ImageFile): + branches = { + "1": False, + "2": False, + "3": False, + "4": False, + "5": False, + } + format = "MCIDAS" format_description = "McIdas area file" @@ -40,6 +48,7 @@ class McIdasImageFile(ImageFile.ImageFile): s = self.fp.read(256) if not _accept(s) or len(s) != 256: + McIdasImageFile.branches["1"] = True msg = "not an McIdas area file" raise SyntaxError(msg) @@ -48,16 +57,20 @@ class McIdasImageFile(ImageFile.ImageFile): # get mode if w[11] == 1: + McIdasImageFile.branches["2"] = True mode = rawmode = "L" elif w[11] == 2: + McIdasImageFile.branches["3"] = True # FIXME: add memory map support mode = "I" rawmode = "I;16B" elif w[11] == 4: + McIdasImageFile.branches["4"] = True # FIXME: add memory map support mode = "I" rawmode = "I;32B" else: + McIdasImageFile.branches["5"] = True msg = "unsupported McIdas format" raise SyntaxError(msg) @@ -76,3 +89,4 @@ class McIdasImageFile(ImageFile.ImageFile): Image.register_open(McIdasImageFile.format, McIdasImageFile, _accept) # no default extension +