Skip to content

Commit 3fb864e

Browse files
committed
fix: add test coverage for a01 traits
1 parent 4c4051e commit 3fb864e

File tree

1 file changed

+227
-0
lines changed

1 file changed

+227
-0
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
from collections.abc import Generator
2+
from typing import Any
3+
from unittest.mock import AsyncMock, call, patch
4+
5+
import pytest
6+
7+
from roborock.devices.mqtt_channel import MqttChannel
8+
from roborock.devices.traits.a01 import DyadApi, ZeoApi
9+
from roborock.roborock_message import RoborockDyadDataProtocol, RoborockZeoProtocol
10+
11+
12+
@pytest.fixture(name="mock_channel")
13+
def mock_channel_fixture() -> AsyncMock:
14+
return AsyncMock(spec=MqttChannel)
15+
16+
17+
@pytest.fixture(name="mock_send")
18+
def mock_send_fixture(mock_channel) -> Generator[AsyncMock, None, None]:
19+
with patch("roborock.devices.traits.a01.send_decoded_command") as mock_send:
20+
yield mock_send
21+
22+
23+
async def test_dyad_api_query_values(mock_channel: AsyncMock, mock_send: AsyncMock):
24+
"""Test that DyadApi currently returns raw values without conversion."""
25+
api = DyadApi(mock_channel)
26+
27+
mock_send.return_value = {
28+
RoborockDyadDataProtocol.POWER: 1,
29+
RoborockDyadDataProtocol.STATUS: 6,
30+
RoborockDyadDataProtocol.WATER_LEVEL: 3,
31+
RoborockDyadDataProtocol.MESH_LEFT: 120,
32+
RoborockDyadDataProtocol.BRUSH_LEFT: 90,
33+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: 85,
34+
RoborockDyadDataProtocol.RECENT_RUN_TIME: "3,4,5",
35+
RoborockDyadDataProtocol.TOTAL_RUN_TIME: 123456,
36+
}
37+
result = await api.query_values(
38+
[
39+
RoborockDyadDataProtocol.POWER,
40+
RoborockDyadDataProtocol.STATUS,
41+
RoborockDyadDataProtocol.WATER_LEVEL,
42+
RoborockDyadDataProtocol.MESH_LEFT,
43+
RoborockDyadDataProtocol.BRUSH_LEFT,
44+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME,
45+
RoborockDyadDataProtocol.RECENT_RUN_TIME,
46+
RoborockDyadDataProtocol.TOTAL_RUN_TIME,
47+
]
48+
)
49+
assert result == {
50+
# Note: Bugs here, returning raw values
51+
RoborockDyadDataProtocol.POWER: 1,
52+
RoborockDyadDataProtocol.STATUS: 6,
53+
RoborockDyadDataProtocol.WATER_LEVEL: 3,
54+
RoborockDyadDataProtocol.MESH_LEFT: 120,
55+
RoborockDyadDataProtocol.BRUSH_LEFT: 90,
56+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: 85,
57+
RoborockDyadDataProtocol.RECENT_RUN_TIME: "3,4,5",
58+
RoborockDyadDataProtocol.TOTAL_RUN_TIME: 123456,
59+
}
60+
61+
# Note: Bug here, this is the wrong encoding for the query
62+
assert mock_send.call_args_list == [
63+
call(
64+
mock_channel,
65+
{
66+
RoborockDyadDataProtocol.ID_QUERY: [209, 201, 207, 214, 215, 227, 229, 230],
67+
},
68+
),
69+
]
70+
71+
72+
@pytest.mark.parametrize(
73+
("query", "response", "expected_result"),
74+
[
75+
(
76+
[RoborockDyadDataProtocol.STATUS],
77+
{
78+
7: 1,
79+
RoborockDyadDataProtocol.STATUS: 3,
80+
9999: -3,
81+
},
82+
{
83+
# Note: Bug here, should return enum value
84+
RoborockDyadDataProtocol.STATUS: 3,
85+
# Note: Bug here, unknown value should not be returned
86+
7: 1,
87+
9999: -3,
88+
},
89+
),
90+
(
91+
[RoborockDyadDataProtocol.SILENT_MODE_START_TIME],
92+
{
93+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: "invalid",
94+
},
95+
{
96+
# Note: Bug here, invalid value should not be returned
97+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: "invalid",
98+
},
99+
),
100+
(
101+
[RoborockDyadDataProtocol.SILENT_MODE_START_TIME],
102+
{
103+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: 85,
104+
RoborockDyadDataProtocol.POWER: 2,
105+
9999: -3,
106+
},
107+
{
108+
# Note: Bug here, should return time value
109+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: 85,
110+
# Note: Bug here, additional values should not be returned
111+
RoborockDyadDataProtocol.POWER: 2,
112+
9999: -3,
113+
},
114+
),
115+
],
116+
ids=[
117+
"ignored-unknown-protocol",
118+
"invalid-value",
119+
"additional-returned-values",
120+
],
121+
)
122+
async def test_dyad_invalid_response_value(
123+
mock_channel: AsyncMock,
124+
mock_send: AsyncMock,
125+
query: list[RoborockDyadDataProtocol],
126+
response: dict[int, Any],
127+
expected_result: dict[RoborockDyadDataProtocol, Any],
128+
):
129+
"""Test that DyadApi currently returns raw values without conversion."""
130+
api = DyadApi(mock_channel)
131+
132+
mock_send.return_value = response
133+
result = await api.query_values(query)
134+
assert result == expected_result
135+
136+
137+
async def test_zeo_api_query_values(mock_channel: AsyncMock, mock_send: AsyncMock):
138+
"""Test that ZeoApi currently returns raw values without conversion."""
139+
api = ZeoApi(mock_channel)
140+
141+
mock_send.return_value = {
142+
RoborockZeoProtocol.STATE: 1,
143+
RoborockZeoProtocol.MODE: 3,
144+
RoborockZeoProtocol.WASHING_LEFT: 4,
145+
}
146+
result = await api.query_values(
147+
[RoborockZeoProtocol.STATE, RoborockZeoProtocol.MODE, RoborockZeoProtocol.WASHING_LEFT]
148+
)
149+
assert result == {
150+
# Note: Bug here, should return enum values
151+
RoborockZeoProtocol.STATE: 1,
152+
RoborockZeoProtocol.MODE: 3,
153+
RoborockZeoProtocol.WASHING_LEFT: 4,
154+
}
155+
# Note: Bug here, this is the wrong encoding for the query
156+
assert mock_send.call_args_list == [
157+
call(
158+
mock_channel,
159+
{
160+
RoborockZeoProtocol.ID_QUERY: [203, 204, 218],
161+
},
162+
),
163+
]
164+
165+
166+
@pytest.mark.parametrize(
167+
("query", "response", "expected_result"),
168+
[
169+
(
170+
[RoborockZeoProtocol.STATE],
171+
{
172+
7: 1,
173+
RoborockZeoProtocol.STATE: 1,
174+
9999: -3,
175+
},
176+
{
177+
# Note: Bug here, should return enum value
178+
RoborockZeoProtocol.STATE: 1,
179+
# Note: Bug here, unknown value should not be returned
180+
7: 1,
181+
9999: -3,
182+
},
183+
),
184+
(
185+
[RoborockZeoProtocol.WASHING_LEFT],
186+
{
187+
RoborockZeoProtocol.WASHING_LEFT: "invalid",
188+
},
189+
{
190+
# Note: Bug here, invalid value should not be returned
191+
RoborockZeoProtocol.WASHING_LEFT: "invalid",
192+
},
193+
),
194+
(
195+
[RoborockZeoProtocol.STATE],
196+
{
197+
RoborockZeoProtocol.STATE: 1,
198+
RoborockZeoProtocol.WASHING_LEFT: 2,
199+
9999: -3,
200+
},
201+
{
202+
RoborockZeoProtocol.STATE: 1,
203+
# Note: Bug here, these values were not requested and should not be returned
204+
RoborockZeoProtocol.WASHING_LEFT: 2,
205+
9999: -3,
206+
},
207+
),
208+
],
209+
ids=[
210+
"ignored-unknown-protocol",
211+
"invalid-value",
212+
"additional-returned-values",
213+
],
214+
)
215+
async def test_zeo_invalid_response_value(
216+
mock_channel: AsyncMock,
217+
mock_send: AsyncMock,
218+
query: list[RoborockZeoProtocol],
219+
response: dict[int, Any],
220+
expected_result: dict[RoborockZeoProtocol, Any],
221+
):
222+
"""Test that ZeoApi currently returns raw values without conversion."""
223+
api = ZeoApi(mock_channel)
224+
225+
mock_send.return_value = response
226+
result = await api.query_values(query)
227+
assert result == expected_result

0 commit comments

Comments
 (0)