diff --git a/terracotta/server/fields.py b/terracotta/server/fields.py index defbd08b..af758299 100644 --- a/terracotta/server/fields.py +++ b/terracotta/server/fields.py @@ -27,11 +27,8 @@ def _deserialize( def validate_stretch_range(data: Any) -> None: - if isinstance(data, str) and data.startswith("p"): + if isinstance(data, str): if not re.match("^p\\d+$", data): raise ValidationError("Percentile format is `p`") - else: - try: - float(data) - except ValueError: - raise ValidationError("Must be a number") + elif not isinstance(data, (int, float)): + raise ValidationError("Must be a number or string like `p`") diff --git a/tests/handlers/test_rgb.py b/tests/handlers/test_rgb.py index 07a59eee..358c4f85 100644 --- a/tests/handlers/test_rgb.py +++ b/tests/handlers/test_rgb.py @@ -3,6 +3,8 @@ import pytest +from terracotta import exceptions + def test_rgb_handler(use_testdb, raster_file, raster_file_xyz): import terracotta @@ -184,6 +186,35 @@ def test_rgb_percentile_stretch(use_testdb, testdb, raster_file_xyz): assert np.all(valid_img[valid_data > stretch_range[1]] == 255) +@pytest.mark.parametrize( + "stretch_range_params", + [ + ["s2", "p98", "Invalid scale value"], + ["pp2", "p98", "Invalid percentile value"], + ["p", "p98", "Invalid percentile value"], + ["2", "p8", "Invalid scale value"], + [{}, "p98", "Invalid scale value"], + ["p-2", "p98", "Invalid percentile, out of range"], + ["p2", "p298", "Invalid percentile, out of range"], + ], +) +def test_rgb_invalid_percentiles(use_testdb, raster_file_xyz, stretch_range_params): + from terracotta.handlers import rgb + + ds_keys = ["val21", "x", "val22"] + bands = ["val22", "val23", "val24"] + + stretch_range = stretch_range_params[:2] + with pytest.raises(exceptions.InvalidArgumentsError) as err: + rgb.rgb( + ds_keys[:2], + bands, + raster_file_xyz, + stretch_ranges=[stretch_range] * 3, + ) + assert stretch_range_params[2] in str(err.value) + + def test_rgb_preview(use_testdb): import terracotta from terracotta.handlers import rgb diff --git a/tests/handlers/test_singleband.py b/tests/handlers/test_singleband.py index 09dbf51f..7029737a 100644 --- a/tests/handlers/test_singleband.py +++ b/tests/handlers/test_singleband.py @@ -3,6 +3,8 @@ import pytest +from terracotta import exceptions + @pytest.mark.parametrize("resampling_method", ["nearest", "linear", "cubic", "average"]) def test_singleband_handler(use_testdb, raster_file_xyz, resampling_method): @@ -196,3 +198,30 @@ def test_singleband_stretch_percentile(use_testdb, testdb, raster_file_xyz): assert np.all(valid_img[stretch_range_mask] >= 1) assert np.all(valid_img[stretch_range_mask] <= 255) assert np.all(valid_img[valid_data > stretch_range[1]] == 255) + + +@pytest.mark.parametrize( + "stretch_range_params", + [ + ["s2", "p98", "Invalid scale value"], + ["pp2", "p98", "Invalid percentile value"], + ["p", "p98", "Invalid percentile value"], + ["2", "p8", "Invalid scale value"], + [{}, "p98", "Invalid scale value"], + ["p-2", "p98", "Invalid percentile, out of range"], + ["p2", "p298", "Invalid percentile, out of range"], + ], +) +def test_rgb_invalid_percentiles(use_testdb, stretch_range_params): + from terracotta.handlers import singleband + + ds_keys = ["val21", "x", "val22"] + + stretch_range = stretch_range_params[:2] + + with pytest.raises(exceptions.InvalidArgumentsError) as err: + singleband.singleband( + ds_keys, + stretch_range=stretch_range, + ) + assert stretch_range_params[2] in str(err.value) diff --git a/tests/server/test_flask_api.py b/tests/server/test_flask_api.py index e153c2f0..21a107ff 100644 --- a/tests/server/test_flask_api.py +++ b/tests/server/test_flask_api.py @@ -3,6 +3,7 @@ import urllib.parse from PIL import Image +import marshmallow import numpy as np import pytest @@ -562,3 +563,27 @@ def test_get_spec(client): rv = client.get("/apidoc") assert rv.status_code == 200 assert b"Terracotta" in rv.data + + +@pytest.mark.parametrize( + "stretch_range_params", + [ + ['["s2", "p98"]', "Percentile format is"], + ['["pp2", "p98"]', "Percentile format is"], + ['["p", "p98"]', "Percentile format is"], + ['["2", "p98"]', "Percentile format is"], + ['["[]", "p98"]', "Percentile format is"], + ], +) +def test_get_rgb_invalid_stretch_percentile( + debug_client, use_testdb, raster_file_xyz, stretch_range_params +): + + x, y, z = raster_file_xyz + stretch_range = stretch_range_params[0] + with pytest.raises(marshmallow.ValidationError) as ve: + debug_client.get( + f"/rgb/val21/x/{z}/{x}/{y}.png?r=val22&g=val23&b=val24&" + f"r_range={stretch_range}&b_range={stretch_range}&g_range={stretch_range}" + ) + assert stretch_range_params[1] in str(ve.value)