summaryrefslogtreecommitdiff
path: root/pixpat-python/tests/test_basic.py
diff options
context:
space:
mode:
Diffstat (limited to 'pixpat-python/tests/test_basic.py')
-rw-r--r--pixpat-python/tests/test_basic.py539
1 files changed, 0 insertions, 539 deletions
diff --git a/pixpat-python/tests/test_basic.py b/pixpat-python/tests/test_basic.py
deleted file mode 100644
index 2ed8bb7..0000000
--- a/pixpat-python/tests/test_basic.py
+++ /dev/null
@@ -1,539 +0,0 @@
-"""Smoke tests for the pixpat Python bindings."""
-
-import pytest
-
-import pixpat
-
-
-def test_supported_formats_nonempty():
- formats = pixpat.supported_formats()
- assert isinstance(formats, list)
- assert len(formats) > 0
- assert all(isinstance(f, str) for f in formats)
- assert 'XRGB8888' in formats
- assert 'NV12' in formats
-
-
-def test_is_supported():
- assert pixpat.is_supported('XRGB8888')
- assert pixpat.is_supported('NV12')
- assert not pixpat.is_supported('NOT_A_REAL_FORMAT')
-
-
-def test_draw_pattern_xrgb8888():
- w, h = 64, 32
- stride = w * 4
- data = bytearray(stride * h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'smpte')
- assert any(b != 0 for b in data)
-
-
-def test_draw_pattern_unknown_pattern_raises():
- data = bytearray(64 * 32 * 4)
- buf = pixpat.Buffer([data], 'XRGB8888', 64, 32, [64 * 4])
- with pytest.raises(ValueError):
- pixpat.draw_pattern(buf, 'bogus')
-
-
-def test_draw_pattern_unknown_format_raises():
- data = bytearray(64 * 32 * 4)
- buf = pixpat.Buffer([data], 'NOT_A_REAL_FORMAT', 64, 32, [64 * 4])
- with pytest.raises(pixpat.PixpatError):
- pixpat.draw_pattern(buf)
-
-
-def test_draw_pattern_readonly_buffer_raises():
- data = bytes(64 * 32 * 4)
- buf = pixpat.Buffer([data], 'XRGB8888', 64, 32, [64 * 4])
- with pytest.raises((TypeError, BufferError)):
- pixpat.draw_pattern(buf)
-
-
-def _alloc_xrgb(w, h):
- stride = w * 4
- return bytearray(stride * h), stride
-
-
-def _first_pixel_bgr(data):
- # BGR888-style byte order: pixpat XRGB8888 stores B at byte 0,
- # G at byte 1, R at byte 2, X at byte 3. See
- # README "Format names and byte order".
- return data[0], data[1], data[2]
-
-
-def test_draw_pattern_plain_red_str_params():
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'plain', params='color=ff0000')
- b, g, r = _first_pixel_bgr(data)
- assert (b, g, r) == (0, 0, 0xFF)
-
-
-def test_draw_pattern_plain_red_dict_params():
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'plain', params={'color': 'ff0000'})
- b, g, r = _first_pixel_bgr(data)
- assert (b, g, r) == (0, 0, 0xFF)
-
-
-def test_draw_pattern_plain_alpha_passes_through_to_argb():
- w, h = 16, 8
- stride = w * 4
- data = bytearray(stride * h)
- buf = pixpat.Buffer([data], 'ARGB8888', w, h, [stride])
- # 8-char form is alpha-first: AARRGGBB.
- pixpat.draw_pattern(buf, 'plain', params={'color': '80112233'})
- # ARGB8888 byte order (LSB-first): B, G, R, A
- assert (data[0], data[1], data[2], data[3]) == (0x33, 0x22, 0x11, 0x80)
-
-
-def test_draw_pattern_plain_accepts_0x_prefix():
- w, h = 16, 8
- stride = w * 4
- data = bytearray(stride * h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'plain', params={'color': '0xff0000'})
- assert (data[0], data[1], data[2]) == (0, 0, 0xFF)
-
-
-def test_draw_pattern_plain_16bpc_rgb():
- """16-bpc form: 12 hex chars, RRRRGGGGBBBB. ABGR16161616 names
- A-B-G-R MSB-first in a 64-bit word; stored little-endian, the
- bytes are R lo, R hi, G lo, G hi, B lo, B hi, A lo, A hi."""
- w, h = 4, 2
- stride = w * 8
- data = bytearray(stride * h)
- buf = pixpat.Buffer([data], 'ABGR16161616', w, h, [stride])
- pixpat.draw_pattern(buf, 'plain', params={'color': '0xfedc00000000'})
- # R=0xFEDC, G=0x0000, B=0x0000, A=0xFFFF (default opaque).
- pix = bytes(data[:8])
- assert pix == b'\xdc\xfe\x00\x00\x00\x00\xff\xff'
-
-
-def test_draw_pattern_plain_16bpc_argb():
- w, h = 4, 2
- stride = w * 8
- data = bytearray(stride * h)
- buf = pixpat.Buffer([data], 'ABGR16161616', w, h, [stride])
- # 16-char form is alpha-first: AAAARRRRGGGGBBBB.
- pixpat.draw_pattern(buf, 'plain', params={'color': '0x80007f000000ffff'})
- pix = bytes(data[:8])
- # R=0x7F00, G=0x0000, B=0xFFFF, A=0x8000.
- assert pix == b'\x00\x7f\x00\x00\xff\xff\x00\x80'
-
-
-def test_draw_pattern_plain_missing_color_raises():
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- with pytest.raises(pixpat.PixpatError):
- pixpat.draw_pattern(buf, 'plain')
- with pytest.raises(pixpat.PixpatError):
- pixpat.draw_pattern(buf, 'plain', params='')
-
-
-def test_draw_pattern_plain_malformed_color_raises():
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- for bad in ('color=zzzzzz', 'color=abc', 'color=', 'color=1234567'):
- with pytest.raises(pixpat.PixpatError):
- pixpat.draw_pattern(buf, 'plain', params=bad)
-
-
-def test_draw_pattern_malformed_params_string_raises():
- """Top-level params parse failure (not pattern-specific)."""
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- for bad in ('foo,bar', '=ff0000', ',color=ff0000'):
- with pytest.raises(pixpat.PixpatError):
- pixpat.draw_pattern(buf, 'plain', params=bad)
-
-
-def test_draw_pattern_dict_params_with_separators_rejected_by_python():
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- with pytest.raises(ValueError):
- pixpat.draw_pattern(buf, 'plain', params={'color': 'ff,00,00'})
- with pytest.raises(ValueError):
- pixpat.draw_pattern(buf, 'plain', params={'col=or': 'ff0000'})
-
-
-def test_draw_pattern_unknown_params_keys_ignored():
- """Patterns silently ignore keys they don't read; unknown keys
- alongside the recognised one still let the call succeed."""
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'plain', params={'color': 'ff0000', 'unknown_key': '42'})
- b, g, r = _first_pixel_bgr(data)
- assert (b, g, r) == (0, 0, 0xFF)
-
-
-def test_draw_pattern_params_ignored_by_kmstest():
- """Patterns that don't read params accept arbitrary params strings."""
- w, h = 32, 16
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'kmstest', params={'whatever': 'foo'})
- assert any(b != 0 for b in data)
-
-
-def _xrgb_pixel_at(data, stride, x, y):
- off = y * stride + x * 4
- return data[off], data[off + 1], data[off + 2] # B, G, R
-
-
-@pytest.mark.parametrize(
- 'pattern,extra',
- [
- ('hramp', {}),
- ('vramp', {}),
- ('dramp', {}),
- ('zoneplate', {}),
- ('checker', {}),
- ('checker', {'params': 'cell=1'}),
- ('checker', {'params': {'cell': '32'}}),
- ],
-)
-def test_draw_pattern_phase3_smoke(pattern, extra):
- w, h = 64, 32
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, pattern, **extra)
- assert any(b != 0 for b in data)
-
-
-def test_draw_pattern_checker_default_cell_first_pixel_white():
- w, h = 64, 32
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'checker')
- # (0,0) is in the first cell -> white.
- assert _xrgb_pixel_at(data, stride, 0, 0) == (0xFF, 0xFF, 0xFF)
- # Default cell=8: (8,0) is the next cell horizontally -> black.
- assert _xrgb_pixel_at(data, stride, 8, 0) == (0, 0, 0)
-
-
-def test_draw_pattern_checker_cell1_alternates():
- w, h = 16, 8
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'checker', params={'cell': '1'})
- p00 = _xrgb_pixel_at(data, stride, 0, 0)
- p10 = _xrgb_pixel_at(data, stride, 1, 0)
- p01 = _xrgb_pixel_at(data, stride, 0, 1)
- p11 = _xrgb_pixel_at(data, stride, 1, 1)
- assert p00 != p10
- assert p00 != p01
- assert p00 == p11 # diagonal repeats
-
-
-@pytest.mark.parametrize('cell', ['0', '-1', 'oops', '1.5'])
-def test_draw_pattern_checker_invalid_cell_raises(cell):
- w, h = 16, 8
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- with pytest.raises(pixpat.PixpatError):
- pixpat.draw_pattern(buf, 'checker', params={'cell': cell})
-
-
-def test_draw_pattern_hramp_stripes():
- """hramp: 4 horizontal stripes (R, G, B, gray), each ramping along x.
- The right edge (x=W-1) hits 0xFF in the active channel(s)."""
- w, h = 32, 16 # h=16 → stripes at rows [0,3], [4,7], [8,11], [12,15]
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'hramp')
- assert _xrgb_pixel_at(data, stride, w - 1, 0) == (0, 0, 0xFF) # R
- assert _xrgb_pixel_at(data, stride, w - 1, 4) == (0, 0xFF, 0) # G
- assert _xrgb_pixel_at(data, stride, w - 1, 8) == (0xFF, 0, 0) # B
- assert _xrgb_pixel_at(data, stride, w - 1, h - 1) == (0xFF, 0xFF, 0xFF) # gray
- # Left edge is the 0 end of every ramp.
- for y in (0, 4, 8, 12):
- assert _xrgb_pixel_at(data, stride, 0, y) == (0, 0, 0)
-
-
-def test_draw_pattern_vramp_columns():
- """vramp: 4 vertical columns (R, G, B, gray), each ramping along y."""
- w, h = 16, 32
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'vramp')
- # Bottom row hits max in the active channel(s).
- assert _xrgb_pixel_at(data, stride, 0, h - 1) == (0, 0, 0xFF) # R
- assert _xrgb_pixel_at(data, stride, 4, h - 1) == (0, 0xFF, 0) # G
- assert _xrgb_pixel_at(data, stride, 8, h - 1) == (0xFF, 0, 0) # B
- assert _xrgb_pixel_at(data, stride, 12, h - 1) == (0xFF, 0xFF, 0xFF) # gray
- # Top row is the 0 end.
- for x in (0, 4, 8, 12):
- assert _xrgb_pixel_at(data, stride, x, 0) == (0, 0, 0)
- # Within a column, luma is monotonic.
- prev = -1
- for y in range(h):
- b, g, r = _xrgb_pixel_at(data, stride, 12, y) # gray column
- assert b == g == r
- assert b >= prev
- prev = b
-
-
-def test_draw_pattern_zoneplate_center_white():
- """Even sizes don't sample exactly at the center; pick odd dimensions
- so (W//2, H//2) is the center pixel where cos(0)=1 → white."""
- w, h = 65, 33
- data, stride = _alloc_xrgb(w, h)
- buf = pixpat.Buffer([data], 'XRGB8888', w, h, [stride])
- pixpat.draw_pattern(buf, 'zoneplate')
- b, g, r = _xrgb_pixel_at(data, stride, w // 2, h // 2)
- # Center pixel: phase=0, gray ≈ 1.0.
- assert b == g == r and b >= 0xFE
-
-
-def test_convert_roundtrip_xrgb8888():
- w, h = 64, 32
- src = bytearray(w * h * 4)
- mid = bytearray(w * h * 8)
- dst = bytearray(w * h * 4)
- pixpat.draw_pattern(pixpat.Buffer([src], 'XRGB8888', w, h, [w * 4]), 'smpte')
- pixpat.convert(
- pixpat.Buffer([mid], 'ABGR16161616', w, h, [w * 8]),
- pixpat.Buffer([src], 'XRGB8888', w, h, [w * 4]),
- )
- pixpat.convert(
- pixpat.Buffer([dst], 'XRGB8888', w, h, [w * 4]),
- pixpat.Buffer([mid], 'ABGR16161616', w, h, [w * 8]),
- )
- assert src == dst
-
-
-def test_convert_readonly_bytes_src():
- """Source planes may be read-only (bytes); the C library only reads src."""
- w, h = 64, 32
- src_writable = bytearray(w * h * 4)
- pixpat.draw_pattern(pixpat.Buffer([src_writable], 'XRGB8888', w, h, [w * 4]), 'smpte')
- src_readonly = bytes(src_writable)
- dst = bytearray(w * h * 8)
- pixpat.convert(
- pixpat.Buffer([dst], 'ABGR16161616', w, h, [w * 8]),
- pixpat.Buffer([src_readonly], 'XRGB8888', w, h, [w * 4]),
- )
- assert any(b != 0 for b in dst)
-
-
-def test_convert_dimension_mismatch_raises():
- w, h = 64, 32
- src = bytearray(w * h * 4)
- dst = bytearray((w * 2) * h * 8)
- with pytest.raises(ValueError, match='dimensions'):
- pixpat.convert(
- pixpat.Buffer([dst], 'ABGR16161616', w * 2, h, [w * 2 * 8]),
- pixpat.Buffer([src], 'XRGB8888', w, h, [w * 4]),
- )
-
-
-def test_draw_pattern_nv12_semi_planar():
- """Semi-planar NV12: separate Y and interleaved-UV planes."""
- w, h = 64, 32
- y = bytearray(w * h)
- uv = bytearray(w * (h // 2))
- pixpat.draw_pattern(pixpat.Buffer([y, uv], 'NV12', w, h, [w, w]), 'smpte')
- assert any(b != 0 for b in y)
- assert any(b != 0 for b in uv)
-
-
-def test_draw_pattern_yuv420_three_planes():
- """Fully planar YUV420: Y, U and V all at separate plane pointers."""
- w, h = 64, 32
- yp = bytearray(w * h)
- up = bytearray((w // 2) * (h // 2))
- vp = bytearray((w // 2) * (h // 2))
- pixpat.draw_pattern(
- pixpat.Buffer([yp, up, vp], 'YUV420', w, h, [w, w // 2, w // 2]),
- 'smpte',
- )
- assert any(b != 0 for b in yp)
- assert any(b != 0 for b in up)
- assert any(b != 0 for b in vp)
-
-
-def test_convert_xrgb_to_nv12_writes_both_planes():
- """Convert into a multi-plane destination must populate every plane."""
- w, h = 64, 32
- src = bytearray(w * h * 4)
- pixpat.draw_pattern(pixpat.Buffer([src], 'XRGB8888', w, h, [w * 4]), 'smpte')
- y = bytearray(w * h)
- uv = bytearray(w * (h // 2))
- pixpat.convert(
- pixpat.Buffer([y, uv], 'NV12', w, h, [w, w]),
- pixpat.Buffer([src], 'XRGB8888', w, h, [w * 4]),
- )
- assert any(b != 0 for b in y)
- assert any(b != 0 for b in uv)
-
-
-def test_convert_yuv420_src_three_planes():
- """Planar YUV is a supported convert source — the C library reads
- all three plane pointers, so make sure the binding wires them up."""
- w, h = 64, 32
- yp = bytearray(w * h)
- up = bytearray((w // 2) * (h // 2))
- vp = bytearray((w // 2) * (h // 2))
- pixpat.draw_pattern(
- pixpat.Buffer([yp, up, vp], 'YUV420', w, h, [w, w // 2, w // 2]),
- 'smpte',
- )
- dst = bytearray(w * h * 4)
- pixpat.convert(
- pixpat.Buffer([dst], 'XRGB8888', w, h, [w * 4]),
- pixpat.Buffer([yp, up, vp], 'YUV420', w, h, [w, w // 2, w // 2]),
- )
- assert any(b != 0 for b in dst)
-
-
-def test_convert_bayer_src():
- """Bayer formats are supported as a convert source (decoded by
- nearest-neighbor demosaic per the public header docstring)."""
- w, h = 64, 32
- src = bytearray(w * h)
- pixpat.draw_pattern(pixpat.Buffer([src], 'SRGGB8', w, h, [w]), 'smpte')
- dst = bytearray(w * h * 4)
- pixpat.convert(
- pixpat.Buffer([dst], 'XRGB8888', w, h, [w * 4]),
- pixpat.Buffer([src], 'SRGGB8', w, h, [w]),
- )
- assert any(b != 0 for b in dst)
-
-
-def test_convert_roundtrip_yuyv():
- """YUYV (packed 4:2:2) — chroma is averaged on write and replicated on
- read, so the second leg must not change the buffer."""
- w, h = 64, 32
- src = bytearray(w * h * 2)
- mid = bytearray(w * h * 8)
- dst = bytearray(w * h * 2)
- pixpat.draw_pattern(pixpat.Buffer([src], 'YUYV', w, h, [w * 2]), 'smpte')
- pixpat.convert(
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- pixpat.Buffer([src], 'YUYV', w, h, [w * 2]),
- )
- pixpat.convert(
- pixpat.Buffer([dst], 'YUYV', w, h, [w * 2]),
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- )
- assert src == dst
-
-
-def test_convert_roundtrip_y8():
- """Y8 grayscale — chroma is discarded on write and synthesized on read,
- Y values themselves should roundtrip exactly."""
- w, h = 64, 32
- src = bytearray(w * h)
- mid = bytearray(w * h * 8)
- dst = bytearray(w * h)
- pixpat.draw_pattern(pixpat.Buffer([src], 'Y8', w, h, [w]), 'smpte')
- pixpat.convert(
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- pixpat.Buffer([src], 'Y8', w, h, [w]),
- )
- pixpat.convert(
- pixpat.Buffer([dst], 'Y8', w, h, [w]),
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- )
- assert src == dst
-
-
-def test_convert_roundtrip_nv12():
- """NV12 semi-planar 4:2:0 — chroma averaged into a 2x2 block on write,
- replicated on read; second leg is a no-op."""
- w, h = 64, 32
- y_src = bytearray(w * h)
- uv_src = bytearray(w * (h // 2))
- mid = bytearray(w * h * 8)
- y_dst = bytearray(w * h)
- uv_dst = bytearray(w * (h // 2))
- pixpat.draw_pattern(pixpat.Buffer([y_src, uv_src], 'NV12', w, h, [w, w]), 'smpte')
- pixpat.convert(
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- pixpat.Buffer([y_src, uv_src], 'NV12', w, h, [w, w]),
- )
- pixpat.convert(
- pixpat.Buffer([y_dst, uv_dst], 'NV12', w, h, [w, w]),
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- )
- assert y_src == y_dst
- assert uv_src == uv_dst
-
-
-def test_convert_roundtrip_xv15():
- """P030 semi-planar 4:2:0, 10 bits packed 3-per-32-bit. Width and height
- chosen so the Y plane fits 3 samples per word and chroma is on a 2x2 grid."""
- w, h = 96, 32 # multiples of 3 (Y group) and 2 (v_sub)
- y_words = (w // 3) * h
- uv_words = (w // 3 // 2) * (h // 2)
- y_src = bytearray(y_words * 4)
- uv_src = bytearray(uv_words * 8)
- mid = bytearray(w * h * 8)
- y_dst = bytearray(y_words * 4)
- uv_dst = bytearray(uv_words * 8)
- pixpat.draw_pattern(
- pixpat.Buffer([y_src, uv_src], 'P030', w, h, [(w // 3) * 4, (w // 3 // 2) * 8]),
- 'smpte',
- )
- pixpat.convert(
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- pixpat.Buffer([y_src, uv_src], 'P030', w, h, [(w // 3) * 4, (w // 3 // 2) * 8]),
- )
- pixpat.convert(
- pixpat.Buffer([y_dst, uv_dst], 'P030', w, h, [(w // 3) * 4, (w // 3 // 2) * 8]),
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- )
- assert y_src == y_dst
- assert uv_src == uv_dst
-
-
-def test_convert_roundtrip_x403():
- """T430 fully-planar 4:4:4 with 3-samples-per-32-bit packing on each
- plane; no chroma subsampling so first leg is already lossless."""
- w, h = 96, 32 # width must be a multiple of 3
- plane_words = (w // 3) * h
- y_src = bytearray(plane_words * 4)
- cb_src = bytearray(plane_words * 4)
- cr_src = bytearray(plane_words * 4)
- mid = bytearray(w * h * 8)
- y_dst = bytearray(plane_words * 4)
- cb_dst = bytearray(plane_words * 4)
- cr_dst = bytearray(plane_words * 4)
- strides = [(w // 3) * 4] * 3
- pixpat.draw_pattern(
- pixpat.Buffer([y_src, cb_src, cr_src], 'T430', w, h, strides),
- 'smpte',
- )
- pixpat.convert(
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- pixpat.Buffer([y_src, cb_src, cr_src], 'T430', w, h, strides),
- )
- pixpat.convert(
- pixpat.Buffer([y_dst, cb_dst, cr_dst], 'T430', w, h, strides),
- pixpat.Buffer([mid], 'AVUY16161616', w, h, [w * 8]),
- )
- assert y_src == y_dst
- assert cb_src == cb_dst
- assert cr_src == cr_dst
-
-
-def test_strides_length_mismatch_multi_plane_raises():
- """Strides count must match planes count — caught in Python before C."""
- w, h = 64, 32
- y = bytearray(w * h)
- uv = bytearray(w * (h // 2))
- with pytest.raises(ValueError, match='strides'):
- pixpat.draw_pattern(
- pixpat.Buffer([y, uv], 'NV12', w, h, [w]), # 1 stride, 2 planes
- 'smpte',
- )