-
-
Notifications
You must be signed in to change notification settings - Fork 37.8k
Improve parametrization for unit conversion tests #84808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
aef18ba
33cdb0d
1bd83af
5d4272d
a481e59
addf12c
e1136d4
b3487f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| """Test Home Assistant eneergy utility functions.""" | ||
| import inspect | ||
|
|
||
| import pytest | ||
|
|
||
| from homeassistant.const import ( | ||
|
|
@@ -16,6 +18,7 @@ | |
| UnitOfVolumetricFlux, | ||
| ) | ||
| from homeassistant.exceptions import HomeAssistantError | ||
| from homeassistant.util import unit_conversion | ||
| from homeassistant.util.unit_conversion import ( | ||
| BaseUnitConverter, | ||
| DataRateConverter, | ||
|
|
@@ -32,59 +35,31 @@ | |
| ) | ||
|
|
||
| INVALID_SYMBOL = "bob" | ||
| _CONVERTERS: list[type[BaseUnitConverter]] = [ | ||
| obj | ||
| for _, obj in inspect.getmembers(unit_conversion) | ||
| if inspect.isclass(obj) | ||
| and issubclass(obj, BaseUnitConverter) | ||
| and obj != BaseUnitConverter | ||
| ] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another possibility is to make this list explicit, and then add a unit test to ensure that the explicit list contains all converters.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sometimes I wonder if we should use the Hypothesis library in HA for cases like these. |
||
|
|
||
|
|
||
| def _get_valid_unit(converter: type[BaseUnitConverter]) -> str: | ||
| """Get a valid unit from the converter, different from the normalized unit.""" | ||
| return next( | ||
| filter( | ||
|
MartinHjelmare marked this conversation as resolved.
Outdated
|
||
| lambda v: v != converter.NORMALIZED_UNIT, | ||
| sorted(converter.VALID_UNITS), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filtering and then sorting, means you need to sort fewer items, than sorting and then filtering. |
||
| ) | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "converter,valid_unit", | ||
| [ | ||
| (DataRateConverter, UnitOfDataRate.GIBIBYTES_PER_SECOND), | ||
| (DistanceConverter, UnitOfLength.KILOMETERS), | ||
| (DistanceConverter, UnitOfLength.METERS), | ||
| (DistanceConverter, UnitOfLength.CENTIMETERS), | ||
| (DistanceConverter, UnitOfLength.MILLIMETERS), | ||
| (DistanceConverter, UnitOfLength.MILES), | ||
| (DistanceConverter, UnitOfLength.YARDS), | ||
| (DistanceConverter, UnitOfLength.FEET), | ||
| (DistanceConverter, UnitOfLength.INCHES), | ||
| (ElectricCurrentConverter, UnitOfElectricCurrent.AMPERE), | ||
| (ElectricCurrentConverter, UnitOfElectricCurrent.MILLIAMPERE), | ||
| (EnergyConverter, UnitOfEnergy.WATT_HOUR), | ||
| (EnergyConverter, UnitOfEnergy.KILO_WATT_HOUR), | ||
| (EnergyConverter, UnitOfEnergy.MEGA_WATT_HOUR), | ||
| (EnergyConverter, UnitOfEnergy.GIGA_JOULE), | ||
| (InformationConverter, UnitOfInformation.GIGABYTES), | ||
| (MassConverter, UnitOfMass.GRAMS), | ||
| (MassConverter, UnitOfMass.KILOGRAMS), | ||
| (MassConverter, UnitOfMass.MICROGRAMS), | ||
| (MassConverter, UnitOfMass.MILLIGRAMS), | ||
| (MassConverter, UnitOfMass.OUNCES), | ||
| (MassConverter, UnitOfMass.POUNDS), | ||
| (PowerConverter, UnitOfPower.WATT), | ||
| (PowerConverter, UnitOfPower.KILO_WATT), | ||
| (PressureConverter, UnitOfPressure.PA), | ||
| (PressureConverter, UnitOfPressure.HPA), | ||
| (PressureConverter, UnitOfPressure.MBAR), | ||
| (PressureConverter, UnitOfPressure.INHG), | ||
| (PressureConverter, UnitOfPressure.KPA), | ||
| (PressureConverter, UnitOfPressure.CBAR), | ||
| (PressureConverter, UnitOfPressure.MMHG), | ||
| (PressureConverter, UnitOfPressure.PSI), | ||
| (SpeedConverter, UnitOfVolumetricFlux.INCHES_PER_DAY), | ||
| (SpeedConverter, UnitOfVolumetricFlux.INCHES_PER_HOUR), | ||
| (SpeedConverter, UnitOfVolumetricFlux.MILLIMETERS_PER_DAY), | ||
| (SpeedConverter, UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR), | ||
| (SpeedConverter, UnitOfSpeed.FEET_PER_SECOND), | ||
| (SpeedConverter, UnitOfSpeed.KILOMETERS_PER_HOUR), | ||
| (SpeedConverter, UnitOfSpeed.KNOTS), | ||
| (SpeedConverter, UnitOfSpeed.METERS_PER_SECOND), | ||
| (SpeedConverter, UnitOfSpeed.MILES_PER_HOUR), | ||
| (TemperatureConverter, UnitOfTemperature.CELSIUS), | ||
| (TemperatureConverter, UnitOfTemperature.FAHRENHEIT), | ||
| (TemperatureConverter, UnitOfTemperature.KELVIN), | ||
| (VolumeConverter, UnitOfVolume.LITERS), | ||
| (VolumeConverter, UnitOfVolume.MILLILITERS), | ||
| (VolumeConverter, UnitOfVolume.GALLONS), | ||
| (VolumeConverter, UnitOfVolume.FLUID_OUNCES), | ||
| (converter, valid_unit) | ||
| for converter in _CONVERTERS | ||
| for valid_unit in sorted(converter.VALID_UNITS) | ||
| ], | ||
| ) | ||
| def test_convert_same_unit(converter: type[BaseUnitConverter], valid_unit: str) -> None: | ||
|
|
@@ -94,21 +69,7 @@ def test_convert_same_unit(converter: type[BaseUnitConverter], valid_unit: str) | |
|
|
||
| @pytest.mark.parametrize( | ||
| "converter,valid_unit", | ||
| [ | ||
| (DataRateConverter, UnitOfDataRate.GIBIBYTES_PER_SECOND), | ||
| (DistanceConverter, UnitOfLength.KILOMETERS), | ||
| (ElectricCurrentConverter, UnitOfElectricCurrent.AMPERE), | ||
| (EnergyConverter, UnitOfEnergy.KILO_WATT_HOUR), | ||
| (InformationConverter, UnitOfInformation.GIBIBYTES), | ||
| (MassConverter, UnitOfMass.GRAMS), | ||
| (PowerConverter, UnitOfPower.WATT), | ||
| (PressureConverter, UnitOfPressure.PA), | ||
| (SpeedConverter, UnitOfSpeed.KILOMETERS_PER_HOUR), | ||
| (TemperatureConverter, UnitOfTemperature.CELSIUS), | ||
| (TemperatureConverter, UnitOfTemperature.FAHRENHEIT), | ||
| (TemperatureConverter, UnitOfTemperature.KELVIN), | ||
| (VolumeConverter, UnitOfVolume.LITERS), | ||
| ], | ||
| [(converter, _get_valid_unit(converter)) for converter in _CONVERTERS], | ||
| ) | ||
| def test_convert_invalid_unit( | ||
| converter: type[BaseUnitConverter], valid_unit: str | ||
|
|
@@ -124,24 +85,8 @@ def test_convert_invalid_unit( | |
| @pytest.mark.parametrize( | ||
| "converter,from_unit,to_unit", | ||
| [ | ||
| ( | ||
| DataRateConverter, | ||
| UnitOfDataRate.BYTES_PER_SECOND, | ||
| UnitOfDataRate.BITS_PER_SECOND, | ||
| ), | ||
| (DistanceConverter, UnitOfLength.KILOMETERS, UnitOfLength.METERS), | ||
| (EnergyConverter, UnitOfEnergy.WATT_HOUR, UnitOfEnergy.KILO_WATT_HOUR), | ||
| ( | ||
| InformationConverter, | ||
| UnitOfInformation.GIBIBYTES, | ||
| UnitOfInformation.GIGABYTES, | ||
| ), | ||
| (MassConverter, UnitOfMass.GRAMS, UnitOfMass.KILOGRAMS), | ||
| (PowerConverter, UnitOfPower.WATT, UnitOfPower.KILO_WATT), | ||
| (PressureConverter, UnitOfPressure.HPA, UnitOfPressure.INHG), | ||
| (SpeedConverter, UnitOfSpeed.KILOMETERS_PER_HOUR, UnitOfSpeed.MILES_PER_HOUR), | ||
| (TemperatureConverter, UnitOfTemperature.CELSIUS, UnitOfTemperature.FAHRENHEIT), | ||
| (VolumeConverter, UnitOfVolume.GALLONS, UnitOfVolume.LITERS), | ||
| (converter, converter.NORMALIZED_UNIT, _get_valid_unit(converter)) | ||
| for converter in _CONVERTERS | ||
| ], | ||
| ) | ||
| def test_convert_nonnumeric_value( | ||
|
|
@@ -153,55 +98,17 @@ def test_convert_nonnumeric_value( | |
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "converter,from_unit,to_unit,expected", | ||
| "converter,from_unit,to_unit", | ||
| [ | ||
| ( | ||
| DataRateConverter, | ||
| UnitOfDataRate.BITS_PER_SECOND, | ||
| UnitOfDataRate.BYTES_PER_SECOND, | ||
| 8, | ||
| ), | ||
| (DistanceConverter, UnitOfLength.KILOMETERS, UnitOfLength.METERS, 1 / 1000), | ||
| ( | ||
| ElectricCurrentConverter, | ||
| UnitOfElectricCurrent.AMPERE, | ||
| UnitOfElectricCurrent.MILLIAMPERE, | ||
| 1 / 1000, | ||
| ), | ||
| (EnergyConverter, UnitOfEnergy.WATT_HOUR, UnitOfEnergy.KILO_WATT_HOUR, 1000), | ||
| (InformationConverter, UnitOfInformation.BITS, UnitOfInformation.BYTES, 8), | ||
| (PowerConverter, UnitOfPower.WATT, UnitOfPower.KILO_WATT, 1000), | ||
| ( | ||
| PressureConverter, | ||
| UnitOfPressure.HPA, | ||
| UnitOfPressure.INHG, | ||
| pytest.approx(33.86389), | ||
| ), | ||
| ( | ||
| SpeedConverter, | ||
| UnitOfSpeed.KILOMETERS_PER_HOUR, | ||
| UnitOfSpeed.MILES_PER_HOUR, | ||
| pytest.approx(1.609343), | ||
| ), | ||
| ( | ||
| TemperatureConverter, | ||
| UnitOfTemperature.CELSIUS, | ||
| UnitOfTemperature.FAHRENHEIT, | ||
| 1 / 1.8, | ||
| ), | ||
| ( | ||
| VolumeConverter, | ||
| UnitOfVolume.GALLONS, | ||
| UnitOfVolume.LITERS, | ||
| pytest.approx(0.264172), | ||
| ), | ||
| (converter, converter.NORMALIZED_UNIT, _get_valid_unit(converter)) | ||
| for converter in _CONVERTERS | ||
| ], | ||
| ) | ||
| def test_get_unit_ratio( | ||
| converter: type[BaseUnitConverter], from_unit: str, to_unit: str, expected: float | ||
| converter: type[BaseUnitConverter], from_unit: str, to_unit: str | ||
| ) -> None: | ||
| """Test unit ratio.""" | ||
| assert converter.get_unit_ratio(from_unit, to_unit) == expected | ||
| assert converter.get_unit_ratio(from_unit, to_unit) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nice that we don't need to update this container, but it's not very readable what the contents is besides the type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think it might be better to add a test to ensure all converters are tested instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MartinHjelmare I've opened #86271 as an alternative.
I think it is better to keep the generated list just for comparing against the manual list and not for actually running the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good!