Pillow/Tests/test_imagepath.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

228 lines
5.1 KiB
Python
Raw Permalink Normal View History

from __future__ import annotations
2024-01-20 14:23:03 +03:00
import array
2020-12-18 23:09:44 +03:00
import math
import struct
from collections.abc import Sequence
import pytest
from PIL import Image, ImagePath
2014-06-10 13:10:47 +04:00
def test_path() -> None:
2020-12-18 12:12:04 +03:00
p = ImagePath.Path(list(range(10)))
# sequence interface
assert len(p) == 5
assert p[0] == (0.0, 1.0)
assert p[-1] == (8.0, 9.0)
assert list(p[:1]) == [(0.0, 1.0)]
with pytest.raises(TypeError) as cm:
p["foo"]
assert str(cm.value) == "Path indices must be integers, not str"
assert list(p) == [(0.0, 1.0), (2.0, 3.0), (4.0, 5.0), (6.0, 7.0), (8.0, 9.0)]
# method sanity check
assert p.tolist() == [
(0.0, 1.0),
(2.0, 3.0),
(4.0, 5.0),
(6.0, 7.0),
(8.0, 9.0),
]
2023-05-05 11:25:05 +03:00
assert p.tolist(True) == [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
2020-12-18 12:12:04 +03:00
assert p.getbbox() == (0.0, 1.0, 8.0, 9.0)
assert p.compact(5) == 2
assert list(p) == [(0.0, 1.0), (4.0, 5.0), (8.0, 9.0)]
p.transform((1, 0, 1, 0, 1, 1))
assert list(p) == [(1.0, 2.0), (5.0, 6.0), (9.0, 10.0)]
2023-01-19 08:03:13 +03:00
@pytest.mark.parametrize(
"coords",
(
(0, 1),
[0, 1],
(0.0, 1.0),
[0.0, 1.0],
((0, 1),),
[(0, 1)],
((0.0, 1.0),),
[(0.0, 1.0)],
array.array("f", [0, 1]),
array.array("f", [0, 1]).tobytes(),
2023-01-19 08:03:13 +03:00
ImagePath.Path((0, 1)),
),
)
2024-02-20 07:41:20 +03:00
def test_path_constructors(
coords: Sequence[float] | array.array[float] | ImagePath.Path,
) -> None:
2023-01-19 08:03:13 +03:00
# Arrange / Act
p = ImagePath.Path(coords)
2020-12-18 12:12:04 +03:00
2023-01-19 08:03:13 +03:00
# Assert
2020-12-18 12:12:04 +03:00
assert list(p) == [(0.0, 1.0)]
2020-12-18 23:09:44 +03:00
2023-01-19 08:03:13 +03:00
@pytest.mark.parametrize(
"coords",
(
("a", "b"),
([0, 1],),
[[0, 1]],
([0.0, 1.0],),
[[0.0, 1.0]],
),
)
2024-02-17 07:00:38 +03:00
def test_invalid_path_constructors(
coords: tuple[str, str] | Sequence[Sequence[int]]
) -> None:
2023-01-19 08:03:13 +03:00
# Act
with pytest.raises(ValueError) as e:
2020-12-18 23:09:44 +03:00
ImagePath.Path(coords)
2023-01-19 08:03:13 +03:00
# Assert
assert str(e.value) == "incorrect coordinate type"
2020-12-18 23:09:44 +03:00
2023-01-19 08:03:13 +03:00
@pytest.mark.parametrize(
"coords",
(
(0,),
[0],
(0, 1, 2),
[0, 1, 2],
),
)
2024-02-17 07:00:38 +03:00
def test_path_odd_number_of_coordinates(coords: Sequence[int]) -> None:
2023-01-19 08:03:13 +03:00
# Act
2020-12-18 23:09:44 +03:00
with pytest.raises(ValueError) as e:
ImagePath.Path(coords)
2023-01-19 08:03:13 +03:00
# Assert
2020-12-18 23:09:44 +03:00
assert str(e.value) == "wrong number of coordinates"
@pytest.mark.parametrize(
"coords, expected",
[
([0, 1, 2, 3], (0.0, 1.0, 2.0, 3.0)),
([3, 2, 1, 0], (1.0, 0.0, 3.0, 2.0)),
2021-12-06 14:25:14 +03:00
(0, (0.0, 0.0, 0.0, 0.0)),
2021-12-06 14:24:19 +03:00
(1, (0.0, 0.0, 0.0, 0.0)),
2020-12-18 23:09:44 +03:00
],
)
2024-02-17 07:00:38 +03:00
def test_getbbox(
coords: int | list[int], expected: tuple[float, float, float, float]
) -> None:
2020-12-18 23:09:44 +03:00
# Arrange
p = ImagePath.Path(coords)
# Act / Assert
assert p.getbbox() == expected
def test_getbbox_no_args() -> None:
2020-12-18 23:09:44 +03:00
# Arrange
p = ImagePath.Path([0, 1, 2, 3])
# Act / Assert
with pytest.raises(TypeError):
p.getbbox(1)
@pytest.mark.parametrize(
"coords, expected",
[
(0, []),
(list(range(6)), [(0.0, 3.0), (4.0, 9.0), (8.0, 15.0)]),
],
)
2024-02-17 07:00:38 +03:00
def test_map(coords: int | list[int], expected: list[tuple[float, float]]) -> None:
2020-12-18 23:09:44 +03:00
# Arrange
p = ImagePath.Path(coords)
# Act
# Modifies the path in-place
p.map(lambda x, y: (x * 2, y * 3))
# Assert
assert list(p) == expected
def test_transform() -> None:
2020-12-18 23:09:44 +03:00
# Arrange
p = ImagePath.Path([0, 1, 2, 3])
theta = math.pi / 15
# Act
# Affine transform, in-place
p.transform(
(math.cos(theta), math.sin(theta), 20, -math.sin(theta), math.cos(theta), 20),
)
# Assert
assert p.tolist() == [
(20.20791169081776, 20.978147600733806),
(22.58003027392089, 22.518619420565898),
]
def test_transform_with_wrap() -> None:
2020-12-18 23:09:44 +03:00
# Arrange
p = ImagePath.Path([0, 1, 2, 3])
theta = math.pi / 15
# Act
# Affine transform, in-place, with wrap parameter
p.transform(
(math.cos(theta), math.sin(theta), 20, -math.sin(theta), math.cos(theta), 20),
1.0,
)
# Assert
assert p.tolist() == [
(0.20791169081775962, 20.978147600733806),
(0.5800302739208902, 22.518619420565898),
]
def test_overflow_segfault() -> None:
2020-12-18 12:12:04 +03:00
# Some Pythons fail getting the argument as an integer, and it falls
# through to the sequence. Seeing this on 32-bit Windows.
with pytest.raises((TypeError, MemoryError)):
# post patch, this fails with a memory error
2022-04-10 21:26:23 +03:00
x = Evil()
2020-12-18 12:12:04 +03:00
# This fails due to the invalid malloc above,
# and segfaults
for i in range(200000):
x[i] = b"0" * 16
2016-03-15 22:56:40 +03:00
def test_compact_within_map() -> None:
p = ImagePath.Path([0, 1])
def map_func(x: float, y: float) -> tuple[float, float]:
p.compact()
return 0, 0
with pytest.raises(ValueError):
p.map(map_func)
2022-04-10 21:26:23 +03:00
class Evil:
def __init__(self) -> None:
self.corrupt = Image.core.path(0x4000000000000000)
2016-03-15 22:56:40 +03:00
2024-02-20 07:41:20 +03:00
def __getitem__(self, i: int) -> bytes:
x = self.corrupt[i]
return struct.pack("dd", x[0], x[1])
2016-03-15 22:56:40 +03:00
2024-02-20 07:41:20 +03:00
def __setitem__(self, i: int, x: bytes) -> None:
self.corrupt[i] = struct.unpack("dd", x)