From c712d3104d7b96195e4930350ca834d15e7995a4 Mon Sep 17 00:00:00 2001 From: Valyrian-Code Date: Wed, 3 Jun 2026 11:33:10 +0530 Subject: [PATCH 1/2] grass.jupyter: add tests for utils helpers get_rendering_size and get_map_name_from_d_command in grass.jupyter.utils had no direct test coverage. Both are pure, deterministic, and free of rendering or optional mapping dependencies. Add a pytest module covering get_rendering_size across all aspect-ratio branches and get_map_name_from_d_command across its default, per-command special-case, missing, and non-string inputs. --- .../jupyter/tests/grass_jupyter_utils_test.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 python/grass/jupyter/tests/grass_jupyter_utils_test.py diff --git a/python/grass/jupyter/tests/grass_jupyter_utils_test.py b/python/grass/jupyter/tests/grass_jupyter_utils_test.py new file mode 100644 index 00000000000..a937219d02b --- /dev/null +++ b/python/grass/jupyter/tests/grass_jupyter_utils_test.py @@ -0,0 +1,63 @@ +"""Tests of pure helper functions in grass.jupyter.utils""" + +import pytest + +from grass.jupyter.utils import get_map_name_from_d_command, get_rendering_size + + +@pytest.mark.parametrize( + ("region", "width", "height", "expected"), + [ + # Both dimensions given: returned unchanged, the region is ignored. + ({"n": 10, "s": 0, "e": 10, "w": 0}, 800, 600, (800, 600)), + # Only width given: height follows the region aspect ratio. + ({"n": 200, "s": 0, "e": 400, "w": 0}, 800, None, (800, 400)), + # Only height given: width follows the region aspect ratio. + ({"n": 200, "s": 0, "e": 400, "w": 0}, None, 300, (600, 300)), + # Neither given, taller-than-wide region: the default height is used. + ({"n": 400, "s": 0, "e": 200, "w": 0}, None, None, (200, 400)), + # Neither given, wider-than-tall region: the default width is used. + ({"n": 200, "s": 0, "e": 400, "w": 0}, None, None, (600, 300)), + ], +) +def test_get_rendering_size(region, width, height, expected): + assert get_rendering_size(region, width, height) == expected + + +def test_get_rendering_size_custom_defaults(): + """Custom defaults: default_width sizes a wide region, default_height a tall one. + + Only one default applies per call; the other dimension is derived from the + region aspect ratio. + """ + wide = {"n": 100, "s": 0, "e": 400, "w": 0} + tall = {"n": 400, "s": 0, "e": 100, "w": 0} + assert get_rendering_size( + wide, None, None, default_width=500, default_height=400 + ) == (500, 125) + assert get_rendering_size( + tall, None, None, default_width=500, default_height=400 + ) == (100, 400) + + +@pytest.mark.parametrize( + ("module", "kwargs", "expected"), + [ + ("d.rast", {"map": "elevation"}, "elevation"), + ("d.vect", {"map": "roads"}, "roads"), + # Commands whose primary raster is not named "map". + ("d.his", {"hue": "hue_map"}, "hue_map"), + ("d.legend", {"raster": "elevation"}, "elevation"), + ("d.rgb", {"red": "red_map"}, "red_map"), + ("d.shade", {"shade": "relief"}, "relief"), + # Expected parameter absent: empty string, not an error. + ("d.rast", {}, ""), + ], +) +def test_get_map_name_from_d_command(module, kwargs, expected): + assert get_map_name_from_d_command(module, **kwargs) == expected + + +def test_get_map_name_from_d_command_non_string_returns_none(): + """A non-string value yields None rather than the raw object.""" + assert get_map_name_from_d_command("d.rast", map=123) is None From b2d28fc51dde1cb822a82de4dd16c653987f759f Mon Sep 17 00:00:00 2001 From: Valyrian-Code Date: Fri, 5 Jun 2026 19:44:58 +0530 Subject: [PATCH 2/2] grass.jupyter: add edge-case tests for utils helpers Following review: add get_map_name_from_d_command cases for map=None and for multiple maps passed to d.rgb (only the primary red map is returned), and get_rendering_size cases documenting round()'s half-to-even behavior (2.5 -> 2, 3.5 -> 4). --- .../jupyter/tests/grass_jupyter_utils_test.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/python/grass/jupyter/tests/grass_jupyter_utils_test.py b/python/grass/jupyter/tests/grass_jupyter_utils_test.py index a937219d02b..1d1232efdee 100644 --- a/python/grass/jupyter/tests/grass_jupyter_utils_test.py +++ b/python/grass/jupyter/tests/grass_jupyter_utils_test.py @@ -18,6 +18,10 @@ ({"n": 400, "s": 0, "e": 200, "w": 0}, None, None, (200, 400)), # Neither given, wider-than-tall region: the default width is used. ({"n": 200, "s": 0, "e": 400, "w": 0}, None, None, (600, 300)), + # round() is half-to-even (banker's rounding): 5 * 1 / 2 = 2.5 -> 2. + ({"n": 1, "s": 0, "e": 2, "w": 0}, 5, None, (5, 2)), + # ...and 7 * 1 / 2 = 3.5 -> 4. + ({"n": 1, "s": 0, "e": 2, "w": 0}, 7, None, (7, 4)), ], ) def test_get_rendering_size(region, width, height, expected): @@ -49,6 +53,12 @@ def test_get_rendering_size_custom_defaults(): ("d.his", {"hue": "hue_map"}, "hue_map"), ("d.legend", {"raster": "elevation"}, "elevation"), ("d.rgb", {"red": "red_map"}, "red_map"), + # d.rgb takes several maps; only the primary (red) is returned. + ( + "d.rgb", + {"red": "red_map", "blue": "blue_map", "green": "green_map"}, + "red_map", + ), ("d.shade", {"shade": "relief"}, "relief"), # Expected parameter absent: empty string, not an error. ("d.rast", {}, ""), @@ -58,6 +68,7 @@ def test_get_map_name_from_d_command(module, kwargs, expected): assert get_map_name_from_d_command(module, **kwargs) == expected -def test_get_map_name_from_d_command_non_string_returns_none(): - """A non-string value yields None rather than the raw object.""" - assert get_map_name_from_d_command("d.rast", map=123) is None +@pytest.mark.parametrize("value", [123, None]) +def test_get_map_name_from_d_command_non_string_returns_none(value): + """A non-string value (including None) yields None rather than the raw object.""" + assert get_map_name_from_d_command("d.rast", map=value) is None