mirror of
https://github.com/python-pillow/Pillow.git
synced 2026-01-28 02:55:49 +03:00
Use monkeypatch (#9406)
Co-authored-by: Andrew Murray <radarhere@users.noreply.github.com>
This commit is contained in:
parent
6a5c588c5f
commit
29ff5fcb55
|
|
@ -119,36 +119,36 @@ def test_large_count(tmp_path: Path) -> None:
|
|||
_roundtrip(tmp_path, im)
|
||||
|
||||
|
||||
def _test_buffer_overflow(tmp_path: Path, im: Image.Image, size: int = 1024) -> None:
|
||||
_last = ImageFile.MAXBLOCK
|
||||
ImageFile.MAXBLOCK = size
|
||||
try:
|
||||
_roundtrip(tmp_path, im)
|
||||
finally:
|
||||
ImageFile.MAXBLOCK = _last
|
||||
def _test_buffer_overflow(
|
||||
tmp_path: Path, im: Image.Image, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setattr(ImageFile, "MAXBLOCK", 1024)
|
||||
_roundtrip(tmp_path, im)
|
||||
|
||||
|
||||
def test_break_in_count_overflow(tmp_path: Path) -> None:
|
||||
def test_break_in_count_overflow(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
im = Image.new("L", (256, 5))
|
||||
px = im.load()
|
||||
assert px is not None
|
||||
for y in range(4):
|
||||
for x in range(256):
|
||||
px[x, y] = x % 128
|
||||
_test_buffer_overflow(tmp_path, im)
|
||||
_test_buffer_overflow(tmp_path, im, monkeypatch)
|
||||
|
||||
|
||||
def test_break_one_in_loop(tmp_path: Path) -> None:
|
||||
def test_break_one_in_loop(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im = Image.new("L", (256, 5))
|
||||
px = im.load()
|
||||
assert px is not None
|
||||
for y in range(5):
|
||||
for x in range(256):
|
||||
px[x, y] = x % 128
|
||||
_test_buffer_overflow(tmp_path, im)
|
||||
_test_buffer_overflow(tmp_path, im, monkeypatch)
|
||||
|
||||
|
||||
def test_break_many_in_loop(tmp_path: Path) -> None:
|
||||
def test_break_many_in_loop(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im = Image.new("L", (256, 5))
|
||||
px = im.load()
|
||||
assert px is not None
|
||||
|
|
@ -157,10 +157,10 @@ def test_break_many_in_loop(tmp_path: Path) -> None:
|
|||
px[x, y] = x % 128
|
||||
for x in range(8):
|
||||
px[x, 4] = 16
|
||||
_test_buffer_overflow(tmp_path, im)
|
||||
_test_buffer_overflow(tmp_path, im, monkeypatch)
|
||||
|
||||
|
||||
def test_break_one_at_end(tmp_path: Path) -> None:
|
||||
def test_break_one_at_end(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im = Image.new("L", (256, 5))
|
||||
px = im.load()
|
||||
assert px is not None
|
||||
|
|
@ -168,10 +168,10 @@ def test_break_one_at_end(tmp_path: Path) -> None:
|
|||
for x in range(256):
|
||||
px[x, y] = x % 128
|
||||
px[0, 3] = 128 + 64
|
||||
_test_buffer_overflow(tmp_path, im)
|
||||
_test_buffer_overflow(tmp_path, im, monkeypatch)
|
||||
|
||||
|
||||
def test_break_many_at_end(tmp_path: Path) -> None:
|
||||
def test_break_many_at_end(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im = Image.new("L", (256, 5))
|
||||
px = im.load()
|
||||
assert px is not None
|
||||
|
|
@ -181,10 +181,10 @@ def test_break_many_at_end(tmp_path: Path) -> None:
|
|||
for x in range(4):
|
||||
px[x * 2, 3] = 128 + 64
|
||||
px[x + 256 - 4, 3] = 0
|
||||
_test_buffer_overflow(tmp_path, im)
|
||||
_test_buffer_overflow(tmp_path, im, monkeypatch)
|
||||
|
||||
|
||||
def test_break_padding(tmp_path: Path) -> None:
|
||||
def test_break_padding(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im = Image.new("L", (257, 5))
|
||||
px = im.load()
|
||||
assert px is not None
|
||||
|
|
@ -193,4 +193,4 @@ def test_break_padding(tmp_path: Path) -> None:
|
|||
px[x, y] = x % 128
|
||||
for x in range(5):
|
||||
px[x, 3] = 0
|
||||
_test_buffer_overflow(tmp_path, im)
|
||||
_test_buffer_overflow(tmp_path, im, monkeypatch)
|
||||
|
|
|
|||
|
|
@ -654,21 +654,17 @@ class TestFilePng:
|
|||
with pytest.raises(SyntaxError, match="Unknown compression method"):
|
||||
PngImagePlugin.PngImageFile("Tests/images/unknown_compression_method.png")
|
||||
|
||||
def test_padded_idat(self) -> None:
|
||||
def test_padded_idat(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
# This image has been manually hexedited
|
||||
# so that the IDAT chunk has padding at the end
|
||||
# Set MAXBLOCK to the length of the actual data
|
||||
# so that the decoder finishes reading before the chunk ends
|
||||
MAXBLOCK = ImageFile.MAXBLOCK
|
||||
ImageFile.MAXBLOCK = 45
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
monkeypatch.setattr(ImageFile, "MAXBLOCK", 45)
|
||||
monkeypatch.setattr(ImageFile, "LOAD_TRUNCATED_IMAGES", True)
|
||||
|
||||
with Image.open("Tests/images/padded_idat.png") as im:
|
||||
im.load()
|
||||
|
||||
ImageFile.MAXBLOCK = MAXBLOCK
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||
|
||||
assert_image_equal_tofile(im, "Tests/images/bw_gradient.png")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont, _util
|
||||
|
||||
from .helper import PillowLeakTestCase, features, skip_unless_feature
|
||||
|
|
@ -7,11 +9,7 @@ from .helper import PillowLeakTestCase, features, skip_unless_feature
|
|||
original_core = ImageFont.core
|
||||
|
||||
|
||||
class TestTTypeFontLeak(PillowLeakTestCase):
|
||||
# fails at iteration 3 in main
|
||||
iterations = 10
|
||||
mem_limit = 4096 # k
|
||||
|
||||
class TestFontLeak(PillowLeakTestCase):
|
||||
def _test_font(self, font: ImageFont.FreeTypeFont | ImageFont.ImageFont) -> None:
|
||||
im = Image.new("RGB", (255, 255), "white")
|
||||
draw = ImageDraw.ImageDraw(im)
|
||||
|
|
@ -21,23 +19,29 @@ class TestTTypeFontLeak(PillowLeakTestCase):
|
|||
)
|
||||
)
|
||||
|
||||
|
||||
class TestTTypeFontLeak(TestFontLeak):
|
||||
# fails at iteration 3 in main
|
||||
iterations = 10
|
||||
mem_limit = 4096 # k
|
||||
|
||||
@skip_unless_feature("freetype2")
|
||||
def test_leak(self) -> None:
|
||||
ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20)
|
||||
self._test_font(ttype)
|
||||
|
||||
|
||||
class TestDefaultFontLeak(TestTTypeFontLeak):
|
||||
class TestDefaultFontLeak(TestFontLeak):
|
||||
# fails at iteration 37 in main
|
||||
iterations = 100
|
||||
mem_limit = 1024 # k
|
||||
|
||||
def test_leak(self) -> None:
|
||||
def test_leak(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
if features.check_module("freetype2"):
|
||||
ImageFont.core = _util.DeferredError(ImportError("Disabled for testing"))
|
||||
try:
|
||||
default_font = ImageFont.load_default()
|
||||
finally:
|
||||
ImageFont.core = original_core
|
||||
|
||||
monkeypatch.setattr(
|
||||
ImageFont,
|
||||
"core",
|
||||
_util.DeferredError(ImportError("Disabled for testing")),
|
||||
)
|
||||
default_font = ImageFont.load_default()
|
||||
self._test_font(default_font)
|
||||
|
|
|
|||
|
|
@ -456,9 +456,11 @@ class TestImage:
|
|||
# Assert
|
||||
assert len(Image.ID) == id_length
|
||||
|
||||
def test_registered_extensions_uninitialized(self) -> None:
|
||||
def test_registered_extensions_uninitialized(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
# Arrange
|
||||
Image._initialized = 0
|
||||
monkeypatch.setattr(Image, "_initialized", 0)
|
||||
|
||||
# Act
|
||||
Image.registered_extensions()
|
||||
|
|
|
|||
|
|
@ -1485,21 +1485,15 @@ def test_stroke_multiline() -> None:
|
|||
|
||||
|
||||
@skip_unless_feature("freetype2")
|
||||
def test_setting_default_font() -> None:
|
||||
# Arrange
|
||||
def test_setting_default_font(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im = Image.new("RGB", (100, 250))
|
||||
draw = ImageDraw.Draw(im)
|
||||
assert isinstance(draw.getfont(), ImageFont.load_default().__class__)
|
||||
|
||||
draw = ImageDraw.Draw(im)
|
||||
font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)
|
||||
|
||||
# Act
|
||||
ImageDraw.ImageDraw.font = font
|
||||
|
||||
# Assert
|
||||
try:
|
||||
assert draw.getfont() == font
|
||||
finally:
|
||||
ImageDraw.ImageDraw.font = None
|
||||
assert isinstance(draw.getfont(), ImageFont.load_default().__class__)
|
||||
monkeypatch.setattr(ImageDraw.ImageDraw, "font", font)
|
||||
assert draw.getfont() == font
|
||||
|
||||
|
||||
def test_default_font_size() -> None:
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ SAFEBLOCK = ImageFile.SAFEBLOCK
|
|||
|
||||
|
||||
class TestImageFile:
|
||||
def test_parser(self) -> None:
|
||||
def test_parser(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def roundtrip(format: str) -> tuple[Image.Image, Image.Image]:
|
||||
im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST)
|
||||
if format in ("MSP", "XBM"):
|
||||
|
|
@ -55,12 +55,9 @@ class TestImageFile:
|
|||
assert_image_equal(*roundtrip("IM"))
|
||||
assert_image_equal(*roundtrip("MSP"))
|
||||
if features.check("zlib"):
|
||||
try:
|
||||
# force multiple blocks in PNG driver
|
||||
ImageFile.MAXBLOCK = 8192
|
||||
assert_image_equal(*roundtrip("PNG"))
|
||||
finally:
|
||||
ImageFile.MAXBLOCK = MAXBLOCK
|
||||
# force multiple blocks in PNG driver
|
||||
monkeypatch.setattr(ImageFile, "MAXBLOCK", 8192)
|
||||
assert_image_equal(*roundtrip("PNG"))
|
||||
assert_image_equal(*roundtrip("PPM"))
|
||||
assert_image_equal(*roundtrip("TIFF"))
|
||||
assert_image_equal(*roundtrip("XBM"))
|
||||
|
|
@ -120,14 +117,11 @@ class TestImageFile:
|
|||
assert (128, 128) == p.image.size
|
||||
|
||||
@skip_unless_feature("zlib")
|
||||
def test_safeblock(self) -> None:
|
||||
def test_safeblock(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
im1 = hopper()
|
||||
|
||||
try:
|
||||
ImageFile.SAFEBLOCK = 1
|
||||
im2 = fromstring(tostring(im1, "PNG"))
|
||||
finally:
|
||||
ImageFile.SAFEBLOCK = SAFEBLOCK
|
||||
monkeypatch.setattr(ImageFile, "SAFEBLOCK", 1)
|
||||
im2 = fromstring(tostring(im1, "PNG"))
|
||||
|
||||
assert_image_equal(im1, im2)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,20 +38,18 @@ def test_invalid_mode() -> None:
|
|||
font._load_pilfont_data(fp, im)
|
||||
|
||||
|
||||
def test_without_freetype() -> None:
|
||||
original_core = ImageFont.core
|
||||
def test_without_freetype(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
if features.check_module("freetype2"):
|
||||
ImageFont.core = _util.DeferredError(ImportError("Disabled for testing"))
|
||||
try:
|
||||
with pytest.raises(ImportError):
|
||||
ImageFont.truetype("Tests/fonts/FreeMono.ttf")
|
||||
monkeypatch.setattr(
|
||||
ImageFont, "core", _util.DeferredError(ImportError("Disabled for testing"))
|
||||
)
|
||||
with pytest.raises(ImportError):
|
||||
ImageFont.truetype("Tests/fonts/FreeMono.ttf")
|
||||
|
||||
assert isinstance(ImageFont.load_default(), ImageFont.ImageFont)
|
||||
assert isinstance(ImageFont.load_default(), ImageFont.ImageFont)
|
||||
|
||||
with pytest.raises(ImportError):
|
||||
ImageFont.load_default(size=14)
|
||||
finally:
|
||||
ImageFont.core = original_core
|
||||
with pytest.raises(ImportError):
|
||||
ImageFont.load_default(size=14)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("font", fonts)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import sys
|
|||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from PIL import Image, PSDraw
|
||||
|
||||
|
||||
|
|
@ -47,21 +49,16 @@ def test_draw_postscript(tmp_path: Path) -> None:
|
|||
assert os.path.getsize(tempfile) > 0
|
||||
|
||||
|
||||
def test_stdout() -> None:
|
||||
def test_stdout(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
# Temporarily redirect stdout
|
||||
old_stdout = sys.stdout
|
||||
|
||||
class MyStdOut:
|
||||
buffer = BytesIO()
|
||||
|
||||
mystdout = MyStdOut()
|
||||
|
||||
sys.stdout = mystdout
|
||||
monkeypatch.setattr(sys, "stdout", mystdout)
|
||||
|
||||
ps = PSDraw.PSDraw()
|
||||
_create_document(ps)
|
||||
|
||||
# Reset stdout
|
||||
sys.stdout = old_stdout
|
||||
|
||||
assert mystdout.buffer.getvalue() != b""
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user