-
Notifications
You must be signed in to change notification settings - Fork 94
Expand file tree
/
Copy pathtest_code_mappings.py
More file actions
162 lines (126 loc) · 6.09 KB
/
Copy pathtest_code_mappings.py
File metadata and controls
162 lines (126 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
"""Tests for code mappings.
These tests exercise the custom enum methods using arbitrary enum values.
"""
import logging
import pytest
from roborock import HomeDataProduct, RoborockCategory
from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP, YXCleanType
from roborock.data.code_mappings import completed_warnings
from roborock.data.dyad.dyad_code_mappings import DyadError
from roborock.data.v1.v1_code_mappings import (
RoborockErrorCode,
RoborockFinishReason,
RoborockStateCode,
)
def test_from_code() -> None:
"""Test from_code method."""
assert B01_Q10_DP.START_CLEAN == B01_Q10_DP.from_code(201)
assert B01_Q10_DP.PAUSE == B01_Q10_DP.from_code(204)
assert B01_Q10_DP.STOP == B01_Q10_DP.from_code(206)
def test_invalid_from_code() -> None:
"""Test invalid from_code method."""
with pytest.raises(ValueError, match="999999 is not a valid code for B01_Q10_DP"):
B01_Q10_DP.from_code(999999)
def test_invalid_from_code_optional() -> None:
"""Test invalid from_code_optional method."""
assert B01_Q10_DP.from_code_optional(999999) is None
def test_from_code_optional_does_not_warn(caplog: pytest.LogCaptureFixture) -> None:
"""from_code_optional must silently return None for unknown codes.
Regression test: ss07 hardware pushes data points this library does not model
(e.g. DPs 112 and 113); resolving them via the optional lookup must not emit
the "not a valid code" warning that the strict ``from_code`` logs.
"""
completed_warnings.discard("112 is not a valid code for B01_Q10_DP")
completed_warnings.discard("113 is not a valid code for B01_Q10_DP")
with caplog.at_level(logging.WARNING):
assert B01_Q10_DP.from_code_optional(112) is None
assert B01_Q10_DP.from_code_optional(113) is None
assert "not a valid code" not in caplog.text
def test_from_code_still_warns(caplog: pytest.LogCaptureFixture) -> None:
"""The strict from_code keeps logging and raising on unknown codes."""
completed_warnings.discard("87654 is not a valid code for B01_Q10_DP")
with caplog.at_level(logging.WARNING), pytest.raises(ValueError, match="not a valid code"):
B01_Q10_DP.from_code(87654)
assert "87654 is not a valid code for B01_Q10_DP" in caplog.text
def test_from_name() -> None:
"""Test from_name method."""
assert B01_Q10_DP.START_CLEAN == B01_Q10_DP.from_name("START_CLEAN")
assert B01_Q10_DP.PAUSE == B01_Q10_DP.from_name("pause")
assert B01_Q10_DP.STOP == B01_Q10_DP.from_name("Stop")
def test_invalid_from_name() -> None:
"""Test invalid from_name method."""
with pytest.raises(ValueError, match="INVALID_NAME is not a valid name for B01_Q10_DP"):
B01_Q10_DP.from_name("INVALID_NAME")
def test_from_value() -> None:
"""Test from_value method."""
assert B01_Q10_DP.START_CLEAN == B01_Q10_DP.from_value("dpStartClean")
assert B01_Q10_DP.PAUSE == B01_Q10_DP.from_value("dpPause")
assert B01_Q10_DP.STOP == B01_Q10_DP.from_value("dpStop")
def test_invalid_from_value() -> None:
"""Test invalid from_value method."""
with pytest.raises(ValueError, match="invalid_value is not a valid value for B01_Q10_DP"):
B01_Q10_DP.from_value("invalid_value")
@pytest.mark.parametrize(
"input, expected",
[
("START_CLEAN", B01_Q10_DP.START_CLEAN),
("start_clean", B01_Q10_DP.START_CLEAN),
("dpStartClean", B01_Q10_DP.START_CLEAN),
(201, B01_Q10_DP.START_CLEAN),
("PAUSE", B01_Q10_DP.PAUSE),
("pause", B01_Q10_DP.PAUSE),
("dpPause", B01_Q10_DP.PAUSE),
(204, B01_Q10_DP.PAUSE),
("STOP", B01_Q10_DP.STOP),
("stop", B01_Q10_DP.STOP),
("dpStop", B01_Q10_DP.STOP),
(206, B01_Q10_DP.STOP),
("invalid_value", None),
(999999, None),
],
)
def test_from_any_optional(input: str | int, expected: B01_Q10_DP | None) -> None:
"""Test from_any_optional method."""
assert B01_Q10_DP.from_any_optional(input) == expected
def test_homedata_product_unknown_category():
"""Test that HomeDataProduct can handle unknown categories."""
data = {
"id": "unknown_cat_id",
"name": "Unknown Device",
"model": "roborock.vacuum.a87",
"category": "roborock.random.category",
"schema": [],
}
product = HomeDataProduct.from_dict(data)
assert product.id == "unknown_cat_id"
assert product.category == RoborockCategory.UNKNOWN
@pytest.mark.parametrize(
("readable_value", "expected_clean_type"),
[
("vac_and_mop", YXCleanType.VAC_AND_MOP),
("vacuum", YXCleanType.VACUUM),
("mop", YXCleanType.MOP),
("customized", YXCleanType.CUSTOMIZED),
],
)
def test_yx_clean_type_from_value_readable_values(readable_value: str, expected_clean_type: YXCleanType) -> None:
"""Test YXCleanType accepts canonical readable values."""
assert YXCleanType.from_value(readable_value) is expected_clean_type
assert expected_clean_type.value == readable_value
def test_yx_clean_type_from_code_customized() -> None:
"""Test YXCleanType accepts custom mode code used by Q10 status updates."""
assert YXCleanType.from_code(4) is YXCleanType.CUSTOMIZED
def test_roborock_enum_display_names_group_duplicate_protocol_codes() -> None:
"""Duplicate protocol meanings keep raw codes but expose one user-facing name."""
assert RoborockStateCode(25) is RoborockStateCode.washing_the_mop_2
assert RoborockStateCode(25).value == 25
assert RoborockStateCode(25).display_name == "washing_the_mop"
assert RoborockStateCode.keys().count("washing_the_mop") == 1
assert "washing_the_mop_2" not in RoborockStateCode.keys()
assert RoborockErrorCode(45).display_name == "mopping_roller_1"
assert RoborockErrorCode.keys().count("mopping_roller_1") == 1
assert "mopping_roller_2" not in RoborockErrorCode.keys()
assert RoborockFinishReason(56).display_name == "finished_cleaning"
assert "finished_cleaning_4" not in RoborockFinishReason.keys()
assert DyadError(20008).display_name == "battery_temperature_protection"
assert "battery_temperature_protection_2" not in DyadError.keys()