Merge remote-tracking branch 'origin/Sofija' into Sofija

This commit is contained in:
sofijazolotarev 2024-06-27 19:27:14 +02:00
commit 56cac18b23
13 changed files with 165 additions and 144 deletions

Binary file not shown.

View File

@ -1,64 +0,0 @@
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()

View File

@ -39,7 +39,6 @@ HAVE_PROFILE = os.path.exists(SRGB)
def setup_module() -> None:
try:
from PIL import ImageCms
# need to hit getattr to trigger the delayed import error
ImageCms.core.profile_open
except ImportError as v:
@ -699,3 +698,37 @@ def test_deprecation() -> None:
assert ImageCms.VERSION == "1.0.0 pil"
with pytest.warns(DeprecationWarning):
assert isinstance(ImageCms.FLAGS, dict)
def test_buildTransform_flags_non_integer():
with pytest.raises(ImageCms.PyCMSError):
ImageCms.buildTransform(
inputProfile="path/to/input/profile",
outputProfile="path/to/output/profile",
inMode="RGB",
outMode="CMYK",
renderingIntent=ImageCms.Intent.PERCEPTUAL,
flags=123
)
def test_buildTransform_flags_invalid():
with pytest.raises(ImageCms.PyCMSError):
ImageCms.buildTransform(
inputProfile="path/to/input/profile",
outputProfile="path/to/output/profile",
inMode="RGB",
outMode="CMYK",
renderingIntent=ImageCms.Intent.PERCEPTUAL,
flags=999999
)
def test_rendering_intent_non_integer():
with pytest.raises(ImageCms.PyCMSError) as exc_info:
ImageCms.buildTransform(
inputProfile="path/to/input/profile",
outputProfile="path/to/output/profile",
inMode="RGB",
outMode="CMYK",
renderingIntent="not an integer",
flags=0
)
assert str(exc_info.value) == "renderingIntent must be an integer between 0 and 3"

View File

@ -216,19 +216,44 @@ class MockPyDecoder(ImageFile.PyDecoder):
class MockPyEncoder(ImageFile.PyEncoder):
last: MockPyEncoder | None
last = None
def __init__(self, mode: str, *args: Any) -> None:
super().__init__(mode, *args)
self._pushes_fd = False
self.cleanup_called = False
MockPyEncoder.last = self
super().__init__(mode, *args)
def encode(self, buffer):
# Simulate encoding
if buffer is None:
raise NotImplementedError
return 1, 1, b""
def cleanup(self) -> None:
self.cleanup_called = True
def test_encode_to_file() -> None:
encoder = MockPyEncoder("RGBA")
with pytest.raises(NotImplementedError):
encoder.encode_to_file(None, None)
encoder._pushes_fd = True
with pytest.raises(NotImplementedError):
encoder.encode_to_file(None, None)
buffer = BytesIO(b"\x00" * 10)
encoder._pushes_fd = False
encoder.encode = lambda buffer: (1, 1, b"")
try:
encoder.encode_to_file(buffer, None)
except NotImplementedError:
pass
encoder.encode = lambda buffer: (_ for _ in ()).throw(NotImplementedError)
with pytest.raises(NotImplementedError):
encoder.encode_to_file(buffer, None)
xoff, yoff, xsize, ysize = 10, 20, 100, 100

View File

@ -1,25 +1,25 @@
from __future__ import annotations
import pytest
import tkinter as tk
from unittest import mock
from PIL import Image
from PIL import ImageTk
from unittest.mock import patch
from .helper import assert_image_equal, hopper
TK_MODES = ("1", "L", "P", "RGB", "RGBA")
try:
import tkinter as tk
from PIL import ImageTk
dir(ImageTk)
HAS_TK = True
except (OSError, ImportError):
# Skipped via pytestmark
HAS_TK = False
TK_MODES = ("1", "L", "P", "RGB", "RGBA")
pytestmark = pytest.mark.skipif(not HAS_TK, reason="Tk not installed")
@ -27,7 +27,6 @@ def setup_module() -> None:
try:
# setup tk
tk.Frame()
# root = tk.Tk()
except RuntimeError as v:
pytest.skip(f"RuntimeError: {v}")
except tk.TclError as v:
@ -102,3 +101,5 @@ def test_bitmapimage() -> None:
# reloaded = ImageTk.getimage(im_tk)
# assert_image_equal(reloaded, im)

View File

@ -1,26 +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):
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"]

View File

@ -6,25 +6,24 @@ from PIL import Image
from PIL import PdfParser
from PIL import SpiderImagePlugin
from PIL import MpegImagePlugin
from PIL import ImageCms
from PIL import McIdasImagePlugin
from PIL import BlpImagePlugin
from PIL import IcnsImagePlugin
from PIL import ImageFile
from PIL import ImageCms
pytest_plugins = ["Tests.helper"]
def calculate_coverage(test_name):
all_branches = {
"branches1": Image.branches,
"branches2": PdfParser.XrefTable.branches,
"branches3": SpiderImagePlugin.branches,
"branches4": MpegImagePlugin.BitStream.branches,
"branches5": ImageCms.ImageCmsProfile.branches,
"branches6": McIdasImagePlugin.McIdasImageFile.branches,
"branches7": BlpImagePlugin._BLPBaseDecoder.branches,
"branches8": IcnsImagePlugin.branches,
# Add more
"branches1": Image.branches, # duru
"branches2": PdfParser.XrefTable.branches, # duru
"branches3": SpiderImagePlugin.branches, # isidora
"branches4": MpegImagePlugin.BitStream.branches, # isidora
"branches5": ImageCms.branches, # deekshu
"branches6": ImageFile.PyEncoder.branches, # deekshu
"branches7": BlpImagePlugin._BLPBaseDecoder.branches, # sofija
"branches8": IcnsImagePlugin.branches, # sofija
}
for name, branches in all_branches.items():
@ -58,4 +57,3 @@ def pytest_sessionfinish(session, exitstatus):
coverage = calculate_coverage(test_name)
print("\nBRANCH COVERAGE for", test_name, ":", coverage, "%\n")

View File

@ -40,6 +40,7 @@ from typing import IO
from . import Image, ImageFile
class Format(IntEnum):
JPEG = 0
@ -276,22 +277,20 @@ class BlpImageFile(ImageFile.ImageFile):
class _BLPBaseDecoder(ImageFile.PyDecoder):
branches = {
"1": False,
"2": False,
}
_pulls_fd = True
def decode(self, buffer: bytes) -> tuple[int, int]:
branches = {
"1": False,
"2": False,
}
try:
branches["1"] = True;
_BLPBaseDecoder.branches["1"] = True
self._read_blp_header()
self._load()
except struct.error as e:
branches["2"] = True;
_BLPBaseDecoder.branches["2"] = True
msg = "Truncated BLP file"
raise OSError(msg) from e
return -1, 0

View File

@ -48,11 +48,11 @@ def read_32t(fobj, start_length, size):
fobj.seek(start)
sig = fobj.read(4)
if sig != b"\x00\x00\x00\x00":
branches["1"] = True;
branches["1"] = True
msg = "Unknown signature, expecting 0x00000000"
raise SyntaxError(msg)
else:
branches["2"] = True;
branches["2"] = True
return read_32(fobj, (start + 4, length - 4), size)

View File

@ -29,6 +29,15 @@ from . import Image, __version__
from ._deprecate import deprecate
from ._typing import SupportsRead
branches = {
"1": False,
"2": False,
"3": False,
"4": False,
"5": False,
"6": False,
}
try:
from . import _imagingcms as core
except ImportError as ex:
@ -237,17 +246,6 @@ _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,
@ -257,28 +255,21 @@ 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)
@ -582,22 +573,28 @@ def buildTransform(
"""
if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
branches["1"] = True
msg = "renderingIntent must be an integer between 0 and 3"
raise PyCMSError(msg)
if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
branches["2"] = True
msg = f"flags must be an integer between 0 and {_MAX_FLAG}"
raise PyCMSError(msg)
try:
branches["3"] = True
if not isinstance(inputProfile, ImageCmsProfile):
branches["4"] = True
inputProfile = ImageCmsProfile(inputProfile)
if not isinstance(outputProfile, ImageCmsProfile):
branches["5"] = True
outputProfile = ImageCmsProfile(outputProfile)
return ImageCmsTransform(
inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
)
except (OSError, TypeError, ValueError) as v:
branches["6"] = True
raise PyCMSError(v) from v

View File

@ -39,6 +39,7 @@ from . import Image
from ._deprecate import deprecate
from ._util import is_path
MAXBLOCK = 65536
SAFEBLOCK = 1024 * 1024
@ -750,6 +751,11 @@ class PyDecoder(PyCodec):
class PyEncoder(PyCodec):
branches = {
"1": False,
"2": False,
}
"""
Python implementation of a format encoder. Override this class and
add the decoding logic in the :meth:`encode` method.
@ -801,7 +807,9 @@ class PyEncoder(PyCodec):
"""
errcode = 0
while errcode == 0:
PyEncoder.branches["1"] = True
status, errcode, buf = self.encode(bufsize)
if status > 0:
PyEncoder.branches["2"] = True
fh.write(buf[status:])
return errcode

View File

@ -21,7 +21,6 @@ import struct
from . import Image, ImageFile
def _accept(prefix: bytes) -> bool:
return prefix[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"

25
src/PIL/test_ImageFile.py Normal file
View File

@ -0,0 +1,25 @@
from io import BytesIO
import pytest
from PIL import ImageFile
def test_encode_to_file_branches():
# Create a mock file object
mock_file = io.BytesIO()
# Create a PyEncoder instance
encoder = ImageFile.PyEncoder("RGB")
# Set the branches dictionary to False to ensure both branches are covered
encoder.branches = {"1": False, "2": False}
# Call the encode_to_file method
errcode = encoder.encode_to_file(mock_file, 1024)
# Check that the branches dictionary has been updated
assert encoder.branches["1"] is True
assert encoder.branches["2"] is True
# Check that the error code is 0, indicating successful encoding
assert errcode == 0
mock_file = BytesIO()