Skip to content

Commit 9d279d8

Browse files
authored
fix: check for negative coordinates (#445)
* Add a test for tuples that have negative coordinates. Specifically, a negative width or height. Particularly, this seems like an easy case for a user to hit if somebody forgets that the PIL tuple style uses top, left, RIGHT, BOTTOM and not top, left, WIDTH, HEIGHT. Ask how I know. Test that we do handle that gracefully. * Ensure that grab regions are valid * Remove a now-obsolete test I thought I'd seen a test for for invalid regions somewhere before...
1 parent 032e587 commit 9d279d8

File tree

3 files changed

+32
-33
lines changed

3 files changed

+32
-33
lines changed

src/mss/base.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ def grab(self, monitor: Monitor | tuple[int, int, int, int], /) -> ScreenShot:
112112
"height": monitor[3] - monitor[1],
113113
}
114114

115+
if monitor["left"] < 0 or monitor["top"] < 0:
116+
msg = f"Region has negative coordinates: {monitor!r}"
117+
raise ScreenShotError(msg)
118+
if monitor["width"] <= 0 or monitor["height"] <= 0:
119+
msg = f"Region has zero or negative size: {monitor!r}"
120+
raise ScreenShotError(msg)
121+
115122
with lock:
116123
screenshot = self._grab_impl(monitor)
117124
if self.with_cursor and (cursor := self._cursor_impl()):

src/tests/test_gnu_linux.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -170,39 +170,6 @@ def test_unsupported_depth(backend: str) -> None:
170170
sct.grab(sct.monitors[1])
171171

172172

173-
def test_region_out_of_monitor_bounds(display: str, backend: str) -> None:
174-
monitor = {"left": -30, "top": 0, "width": WIDTH, "height": HEIGHT}
175-
176-
with mss.mss(display=display, backend=backend, with_cursor=True) as sct:
177-
# At one point, I had accidentally been reporting the resource ID as a CData object instead of the contained
178-
# int. This is to make sure I don't repeat that mistake. That said, change this error regex if needed to keep
179-
# up with formatting changes.
180-
expected_err_re = (
181-
r"(?is)"
182-
r"Error of failed request:\s+(8|BadMatch)\b"
183-
r".*Major opcode of failed request:\s+73\b"
184-
r".*Resource id in failed request:\s+[0-9]"
185-
r".*Serial number of failed request:\s+[0-9]"
186-
)
187-
188-
with pytest.raises(ScreenShotError, match=expected_err_re) as exc:
189-
sct.grab(monitor)
190-
191-
details = exc.value.details
192-
assert details
193-
assert isinstance(details, dict)
194-
if backend in {"xgetimage", "xshmgetimage"} and mss.linux.xcb.LIB.errors is None:
195-
pytest.xfail("Error strings in XCB backends are only available with the xcb-util-errors library.")
196-
assert isinstance(details["error"], str)
197-
198-
errstr = str(exc.value)
199-
assert "Match" in errstr # Xlib: "BadMatch"; XCB: "Match"
200-
assert "GetImage" in errstr # Xlib: "X_GetImage"; XCB: "GetImage"
201-
202-
if backend == "xlib":
203-
assert not mss.linux.xlib._ERROR
204-
205-
206173
def test__is_extension_enabled_unknown_name(display: str) -> None:
207174
with mss.mss(display=display, backend="xlib") as sct:
208175
assert isinstance(sct, mss.linux.xlib.MSS) # For Mypy

src/tests/test_implementation.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,31 @@ def test_grab_with_tuple(mss_impl: Callable[..., MSSBase]) -> None:
251251
assert im.rgb == im2.rgb
252252

253253

254+
def test_grab_with_invalid_tuple(mss_impl: Callable[..., MSSBase]) -> None:
255+
with mss_impl() as sct:
256+
# Remember that rect tuples are PIL-style: (left, top, right, bottom)
257+
258+
# Negative top
259+
negative_box = (100, -100, 500, 500)
260+
with pytest.raises(ScreenShotError):
261+
sct.grab(negative_box)
262+
263+
# Negative left
264+
negative_box = (-100, 100, 500, 500)
265+
with pytest.raises(ScreenShotError):
266+
sct.grab(negative_box)
267+
268+
# Negative width (but right > 0)
269+
negative_box = (100, 100, 50, 500)
270+
with pytest.raises(ScreenShotError):
271+
sct.grab(negative_box)
272+
273+
# Negative height (but bottom > 0)
274+
negative_box = (100, 100, 500, 50)
275+
with pytest.raises(ScreenShotError):
276+
sct.grab(negative_box)
277+
278+
254279
def test_grab_with_tuple_percents(mss_impl: Callable[..., MSSBase]) -> None:
255280
with mss_impl() as sct:
256281
monitor = sct.monitors[1]

0 commit comments

Comments
 (0)