Coverage for src/bluetooth_sig/gatt/characteristics/utils/data_validator.py: 100%
44 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
1"""Data validation and integrity checking utilities."""
3from __future__ import annotations
5from enum import IntEnum
7from ...constants import (
8 ABSOLUTE_ZERO_CELSIUS,
9 EXTENDED_PERCENTAGE_MAX,
10 MAX_CONCENTRATION_PPM,
11 MAX_POWER_WATTS,
12 MAX_TEMPERATURE_CELSIUS,
13 PERCENTAGE_MAX,
14 PERCENTAGE_MIN,
15)
16from ...exceptions import DataValidationError, EnumValueError, ValueRangeError
19class DataValidator:
20 """Utility class for data validation and integrity checking."""
22 @staticmethod
23 def validate_data_length(data: bytearray, expected_min: int, expected_max: int | None = None) -> None:
24 """Validate data length against expected range."""
25 length = len(data)
26 if length < expected_min:
27 raise DataValidationError("data", data, f"at least {expected_min} bytes")
28 if expected_max is not None and length > expected_max:
29 raise DataValidationError("data_length", length, f"at most {expected_max} bytes")
31 @staticmethod
32 def validate_range(value: int | float, min_val: int | float, max_val: int | float) -> None:
33 """Validate that a value is within the specified range."""
34 if not min_val <= value <= max_val:
35 raise ValueRangeError("value", value, min_val, max_val)
37 @staticmethod
38 def validate_enum_value(value: int, enum_class: type[IntEnum]) -> None:
39 """Validate that a value is a valid member of an IntEnum."""
40 try:
41 enum_class(value)
42 except ValueError as e:
43 valid_values = [member.value for member in enum_class]
44 raise EnumValueError(enum_class.__name__, value, enum_class, valid_values) from e
46 @staticmethod
47 def validate_concentration_range(value: float, max_ppm: float = MAX_CONCENTRATION_PPM) -> None:
48 """Validate concentration value is in acceptable range."""
49 if value < PERCENTAGE_MIN:
50 raise ValueRangeError("concentration", value, 0, max_ppm)
51 if value > max_ppm:
52 raise ValueRangeError("concentration", value, 0, max_ppm)
54 @staticmethod
55 def validate_temperature_range(
56 value: float,
57 min_celsius: float = ABSOLUTE_ZERO_CELSIUS,
58 max_celsius: float = MAX_TEMPERATURE_CELSIUS,
59 ) -> None:
60 """Validate temperature is in physically reasonable range."""
61 if value < min_celsius:
62 raise ValueRangeError("temperature", value, min_celsius, max_celsius)
63 if value > max_celsius:
64 raise ValueRangeError("temperature", value, min_celsius, max_celsius)
66 @staticmethod
67 def validate_percentage(value: int | float, allow_over_100: bool = False) -> None:
68 """Validate percentage value (0-100% or 0-200% for some characteristics)."""
69 max_value = EXTENDED_PERCENTAGE_MAX if allow_over_100 else PERCENTAGE_MAX
70 if value < PERCENTAGE_MIN or value > max_value:
71 raise ValueRangeError("percentage", value, 0, max_value)
73 @staticmethod
74 def validate_power_range(value: int | float, max_watts: float = MAX_POWER_WATTS) -> None:
75 """Validate power measurement range."""
76 if value < 0 or value > max_watts:
77 raise ValueRangeError("power", value, 0, max_watts)