diff --git a/Tests/test_file_blp.py b/Tests/test_file_blp.py index 0afac6534..5ad81094e 100644 --- a/Tests/test_file_blp.py +++ b/Tests/test_file_blp.py @@ -2,7 +2,12 @@ from __future__ import annotations from pathlib import Path +import struct import pytest +from unittest.mock import Mock, patch +from PIL.BlpImagePlugin import _BLPBaseDecoder +from PIL.BlpImagePlugin import BLP1Decoder + from PIL import Image @@ -15,28 +20,11 @@ from .helper import ( def test_load_blp1() -> None: - # Test when _blp_compression is Format.JPEG with Image.open("Tests/images/blp/blp1_jpeg.blp") as im: assert_image_equal_tofile(im, "Tests/images/blp/blp1_jpeg.png") - # Test when _blp_compression is 1 and _blp_encoding is 4 or 5 - with Image.open("Tests/images/blp/blp1_encoding4.blp") as im: + with Image.open("Tests/images/blp/blp1_jpeg2.blp") as im: im.load() - with Image.open("Tests/images/blp/blp1_encoding5.blp") as im: - im.load() - - # Test when _blp_compression is 1 but _blp_encoding is not 4 or 5 - with pytest.raises(BLPFormatError): - with Image.open("Tests/images/blp/blp1_invalid_encoding.blp") as im: - im.load() - - # Test when _blp_compression is not 1 or Format.JPEG - with pytest.raises(BLPFormatError): - with Image.open("Tests/images/blp/blp1_invalid_compression.blp") as im: - im.load() - - - def test_load_blp2_raw() -> None: with Image.open("Tests/images/blp/blp2_raw.blp") as im: @@ -92,3 +80,21 @@ def test_crashes(test_file: str) -> None: with Image.open(f) as im: with pytest.raises(OSError): im.load() + +def test_decode(): + # Create a mock instance of BLP1Decoder with 'RGB' as the mode + decoder = BLP1Decoder('RGB') + + # Mock the _read_blp_header and _load methods to simulate normal execution + with patch.object(decoder, '_read_blp_header', return_value=None), \ + patch.object(decoder, '_load', return_value=None): + # Call the decode method and verify that it returns (-1, 0) + assert decoder.decode(b'') == (-1, 0) + + # Mock the _read_blp_header and _load methods to raise a struct.error + with patch.object(decoder, '_read_blp_header', side_effect=struct.error), \ + patch.object(decoder, '_load', side_effect=struct.error): + + # Call the decode method and verify that it raises an OSError with the expected message + with pytest.raises(OSError, match="Truncated BLP file"): + decoder.decode(b'') diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index 258e02b8f..53d149e61 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -3,6 +3,9 @@ from __future__ import annotations import io from pathlib import Path +import unittest +from unittest.mock import patch, MagicMock + import pytest from PIL import EpsImagePlugin, Image, UnidentifiedImageError, features @@ -443,3 +446,40 @@ def test_invalid_data_after_eof() -> None: with Image.open(img_bytes) as img: assert img.mode == "RGB" + +# class TestHasGhostscript(unittest.TestCase): +# @patch('PIL.EpsImagePlugin.shutil.which') +# @patch('PIL.EpsImagePlugin.sys.platform', 'win32') +# def test_windows_with_ghostscript(self, mock_which): +# # Simulate each binary being found in turn +# for binary in ("gswin32c", "gswin64c", "gs"): +# with self.subTest(binary=binary): +# EpsImagePlugin.gs_binary = None # Reset global state +# mock_which.side_effect = lambda x: x if x == binary else None +# self.assertTrue(EpsImagePlugin.has_ghostscript()) +# self.assertEqual(EpsImagePlugin.gs_windows_binary, binary) +# +# @patch('PIL.EpsImagePlugin.shutil.which', return_value=None) +# @patch('PIL.EpsImagePlugin.sys.platform', 'win32') +# def test_windows_without_ghostscript(self, mock_which): +# EpsImagePlugin.gs_binary = None # Reset global state +# self.assertFalse(EpsImagePlugin.has_ghostscript()) +# self.assertFalse(EpsImagePlugin.gs_windows_binary) +# +# @patch('PIL.EpsImagePlugin.subprocess.check_call') +# @patch('PIL.EpsImagePlugin.sys.platform', 'linux') +# def test_non_windows_with_ghostscript(self, mock_check_call): +# EpsImagePlugin.gs_binary = None # Reset global state +# mock_check_call.return_value = 0 # Simulate successful call +# self.assertTrue(EpsImagePlugin.has_ghostscript()) +# self.assertEqual(EpsImagePlugin.gs_binary, "gs") +# +# @patch('PIL.EpsImagePlugin.subprocess.check_call', side_effect=OSError) +# @patch('PIL.EpsImagePlugin.sys.platform', 'linux') +# def test_non_windows_without_ghostscript(self, mock_check_call): +# EpsImagePlugin.gs_binary = None # Reset global state +# self.assertFalse(EpsImagePlugin.has_ghostscript()) +# self.assertFalse(EpsImagePlugin.gs_binary) +# +# if __name__ == '__main__': +# unittest.main() diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 97efd32f2..d0c2335ae 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -2,6 +2,9 @@ from __future__ import annotations import warnings +import unittest +from unittest.mock import patch, MagicMock + import pytest from PIL import FliImagePlugin, Image, ImageFile diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 6c6e17a76..bd3593626 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -2,11 +2,12 @@ from __future__ import annotations import io import os +import struct import warnings from pathlib import Path import pytest - +from unittest.mock import Mock, patch from PIL import IcnsImagePlugin, Image, _binary from .helper import assert_image_equal, assert_image_similar_tofile, skip_unless_feature @@ -154,3 +155,22 @@ def test_icns_decompression_bomb() -> None: ) as im: with pytest.raises(Image.DecompressionBombError): im.load() + +def test_read_32t(): + # Create a mock instance of a file-like object + fobj = io.BytesIO() + + # Mock the file object to simulate normal execution + fobj.write(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') + fobj.seek(0) + start_length = (0, 12) + size = (1, 1, 1) + result = IcnsImagePlugin.read_32t(fobj, start_length, size) + assert isinstance(result, dict) + + # Simulate an exception + fobj = io.BytesIO() + fobj.write(b'\x01\x00\x00\x00') + fobj.seek(0) + with pytest.raises(SyntaxError, match="Unknown signature, expecting 0x00000000"): + IcnsImagePlugin.read_32t(fobj, start_length, size) diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 1863c20a9..75153bb42 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -4,6 +4,7 @@ from io import BytesIO from typing import Any import pytest +from io import BytesIO from PIL import ( BmpImagePlugin, diff --git a/conftest.py b/conftest.py index 57a5a80db..ed12317a5 100644 --- a/conftest.py +++ b/conftest.py @@ -8,43 +8,43 @@ from PIL import PdfParser pytest_plugins = ["Tests.helper"] -def calculate_coverage(test_name): - 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) -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 +# def calculate_coverage(test_name): +# 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) +# 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") +# +# diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 959e1d066..eff856c24 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -27,6 +27,8 @@ import re import subprocess import sys import tempfile +import shutil + from typing import IO from . import Image, ImageFile