import pytest import dpg_gauges as dpgg from dpg_gauges.exceptions import GaugeConfigError, GaugeNotFoundError, GaugeValueError from dpg_gauges.gauges import AnalogGaugeConfig, DigitalGaugeConfig from dpg_gauges.scales import ( clamp_value, clamped_threshold, fill_fraction, format_gauge_value, generate_ticks, normalize_value, value_to_angle, ) def test_public_api_exports_required_names() -> None: required = { "configure", "GaugeTheme", "GaugeStyle", "AnimationConfig", "SmoothingConfig", "ThresholdBand", "GaugeMarker", "StatusState", "GaugeValue", "GaugeStats", "analog_gauge", "digital_gauge", "bar_gauge", "level_gauge", "status_light", "segmented_gauge", "compass_gauge", "thermometer_gauge", "battery_gauge", "multi_value_gauge", "gauge_panel", "gauge_grid", "set_value", "get_value", "update_gauge", "configure_gauge", "set_thresholds", "set_markers", "set_show", "delete_gauge", "get_gauge_debug_state", } assert required.issubset(set(dpgg.__all__)) for name in required: assert hasattr(dpgg, name) def test_dataclass_construction_and_context_stub() -> None: threshold = dpgg.ThresholdBand(10, 20, (255, 0, 0, 255), "hot") marker = dpgg.GaugeMarker(50, (0, 255, 0), thickness=1.5) config = AnalogGaugeConfig( label="RPM", min_value=0, max_value=8000, thresholds=[threshold], markers=[marker], animation=True, smoothing=False, ) assert config.thresholds == (threshold,) assert config.markers == (marker,) assert config.animation == dpgg.AnimationConfig(enabled=True) assert config.smoothing == dpgg.SmoothingConfig(enabled=False) with dpgg.digital_gauge(label="Speed", value=12.3) as digital: assert isinstance(digital, DigitalGaugeConfig) assert digital.label == "Speed" def test_clamp_normalize_angle_and_fill_math() -> None: assert clamp_value(150, 0, 100) == 100 assert normalize_value(25, 0, 100) == 0.25 assert fill_fraction(-10, 0, 100) == 0 assert value_to_angle(50, 0, 100, 225, -45) == 90 with pytest.raises(GaugeValueError): clamp_value(float("nan"), 0, 100) def test_tick_generation_and_formatting() -> None: assert generate_ticks(0, 100, 5) == [0, 25, 50, 75, 100] assert format_gauge_value(12.345, precision=1, unit="V") == "12.3 V" assert format_gauge_value(float("inf"), precision=1) == "--" with pytest.raises(GaugeConfigError): generate_ticks(0, 100, 1) def test_threshold_validation_and_clamping() -> None: threshold = dpgg.ThresholdBand(-10, 120, (255, 128, 0, 255)) assert clamped_threshold(threshold, 0, 100) == (0, 100) with pytest.raises(GaugeConfigError): dpgg.ThresholdBand(20, 10, (255, 0, 0)) with pytest.raises(GaugeConfigError): AnalogGaugeConfig(min_value=100, max_value=0) def test_runtime_stubs_import_without_dpg_context() -> None: dpgg.configure(debug=True) with pytest.raises(GaugeNotFoundError): dpgg.set_value("missing", 1) with pytest.raises(GaugeNotFoundError): dpgg.get_gauge_debug_state("missing")