Add more tests

This commit is contained in:
Beto Dealmeida
2026-05-18 14:26:13 -04:00
parent 085b187f66
commit ef960073f8

View File

@@ -15,7 +15,8 @@
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from datetime import date, datetime, time
from typing import Any
from unittest.mock import MagicMock
import pandas as pd
@@ -40,6 +41,7 @@ from superset_core.semantic_layers.types import (
from superset_core.semantic_layers.view import SemanticViewFeature
from superset.semantic_layers.mapper import (
_coerce_scalar_filter_value,
_convert_query_object_filter,
_convert_time_grain,
_get_filters_from_extras,
@@ -2826,3 +2828,160 @@ def test_get_group_limit_filters_no_granularity(
# Should return None - no granularity means no time filters added
assert result is None
# ---------------------------------------------------------------------------
# _coerce_scalar_filter_value: per-dtype branches
# ---------------------------------------------------------------------------
def _dim(dtype: pa.DataType, name: str = "d") -> Dimension:
return Dimension(name, name, dtype, name, name.capitalize())
def test_coerce_none_returns_none() -> None:
assert _coerce_scalar_filter_value(None, _dim(pa.int64())) is None
def test_coerce_unsupported_dtype_passes_through() -> None:
# utf8 (and any dtype not branched in the function) returns the value as-is.
assert _coerce_scalar_filter_value("abc", _dim(pa.utf8())) == "abc"
@pytest.mark.parametrize(
"raw,expected",
[
(True, True),
(False, False),
("true", True),
("T", True),
(" 1 ", True),
("yes", True),
("Y", True),
("on", True),
("false", False),
("F", False),
("0", False),
("no", False),
("N", False),
("off", False),
],
)
def test_coerce_boolean(raw: Any, expected: bool) -> None:
assert _coerce_scalar_filter_value(raw, _dim(pa.bool_())) is expected
@pytest.mark.parametrize("raw", ["maybe", 1, 0.5])
def test_coerce_boolean_invalid_raises(raw: Any) -> None:
with pytest.raises(ValueError, match="Invalid boolean value"):
_coerce_scalar_filter_value(raw, _dim(pa.bool_()))
def test_coerce_integer_passthrough() -> None:
assert _coerce_scalar_filter_value(42, _dim(pa.int64())) == 42
def test_coerce_integer_rejects_bool() -> None:
# bool is a subclass of int; we explicitly reject it.
with pytest.raises(ValueError, match="Invalid integer value"):
_coerce_scalar_filter_value(True, _dim(pa.int64()))
def test_coerce_integer_rejects_other_types() -> None:
with pytest.raises(ValueError, match="Invalid integer value"):
_coerce_scalar_filter_value(1.5, _dim(pa.int64()))
@pytest.mark.parametrize(
"dtype",
[pa.float64(), pa.decimal128(10, 2)],
)
def test_coerce_floating_or_decimal(dtype: pa.DataType) -> None:
assert _coerce_scalar_filter_value(1, _dim(dtype)) == 1.0
assert _coerce_scalar_filter_value(1.5, _dim(dtype)) == 1.5
assert _coerce_scalar_filter_value(" 2.5 ", _dim(dtype)) == 2.5
def test_coerce_floating_rejects_bool() -> None:
with pytest.raises(ValueError, match="Invalid numeric value"):
_coerce_scalar_filter_value(True, _dim(pa.float64()))
def test_coerce_floating_invalid_string_raises() -> None:
with pytest.raises(ValueError, match="Invalid numeric value"):
_coerce_scalar_filter_value("not-a-number", _dim(pa.float64()))
def test_coerce_floating_rejects_other_types() -> None:
with pytest.raises(ValueError, match="Invalid numeric value"):
_coerce_scalar_filter_value([1.0], _dim(pa.float64()))
def test_coerce_date_from_datetime() -> None:
out = _coerce_scalar_filter_value(datetime(2025, 1, 2, 12, 0), _dim(pa.date32()))
assert out == date(2025, 1, 2)
def test_coerce_date_passthrough() -> None:
out = _coerce_scalar_filter_value(date(2025, 1, 2), _dim(pa.date32()))
assert out == date(2025, 1, 2)
def test_coerce_date_from_iso_string() -> None:
out = _coerce_scalar_filter_value(" 2025-01-02 ", _dim(pa.date32()))
assert out == date(2025, 1, 2)
def test_coerce_date_invalid_string_raises() -> None:
with pytest.raises(ValueError, match="Invalid date value"):
_coerce_scalar_filter_value("not-a-date", _dim(pa.date32()))
def test_coerce_date_rejects_other_types() -> None:
with pytest.raises(ValueError, match="Invalid date value"):
_coerce_scalar_filter_value(20250102, _dim(pa.date32()))
def test_coerce_timestamp_from_datetime_passthrough() -> None:
dt = datetime(2025, 1, 2, 3, 4, 5)
assert _coerce_scalar_filter_value(dt, _dim(pa.timestamp("us"))) is dt
def test_coerce_timestamp_from_date() -> None:
out = _coerce_scalar_filter_value(date(2025, 1, 2), _dim(pa.timestamp("us")))
assert out == datetime(2025, 1, 2, 0, 0)
def test_coerce_timestamp_from_iso_string_with_z() -> None:
out = _coerce_scalar_filter_value("2025-01-02T03:04:05Z", _dim(pa.timestamp("us")))
assert out == datetime.fromisoformat("2025-01-02T03:04:05+00:00")
def test_coerce_timestamp_invalid_string_raises() -> None:
with pytest.raises(ValueError, match="Invalid timestamp value"):
_coerce_scalar_filter_value("not-a-ts", _dim(pa.timestamp("us")))
def test_coerce_timestamp_rejects_other_types() -> None:
with pytest.raises(ValueError, match="Invalid timestamp value"):
_coerce_scalar_filter_value(1234567890, _dim(pa.timestamp("us")))
def test_coerce_time_passthrough() -> None:
out = _coerce_scalar_filter_value(time(3, 4, 5), _dim(pa.time64("us")))
assert out == time(3, 4, 5)
def test_coerce_time_from_iso_string() -> None:
out = _coerce_scalar_filter_value(" 03:04:05 ", _dim(pa.time64("us")))
assert out == time(3, 4, 5)
def test_coerce_time_invalid_string_raises() -> None:
with pytest.raises(ValueError, match="Invalid time value"):
_coerce_scalar_filter_value("not-a-time", _dim(pa.time64("us")))
def test_coerce_time_rejects_other_types() -> None:
with pytest.raises(ValueError, match="Invalid time value"):
_coerce_scalar_filter_value(123, _dim(pa.time64("us")))