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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
import datetime
from unittest import TestCase
import pytest
from miio import Vacuum, VacuumStatus
from .dummies import DummyDevice
class DummyVacuum(DummyDevice, Vacuum):
STATE_CHARGING = 8
STATE_CLEANING = 5
STATE_ZONED_CLEAN = 9
STATE_IDLE = 3
STATE_HOME = 6
STATE_SPOT = 11
STATE_GOTO = 4
STATE_ERROR = 12
STATE_PAUSED = 10
STATE_MANUAL = 7
def __init__(self, *args, **kwargs):
self.state = {
"state": 8,
"dnd_enabled": 1,
"clean_time": 0,
"msg_ver": 4,
"map_present": 1,
"error_code": 0,
"in_cleaning": 0,
"clean_area": 0,
"battery": 100,
"fan_power": 20,
"msg_seq": 320,
}
self.return_values = {
"get_status": self.vacuum_state,
"app_start": lambda x: self.change_mode("start"),
"app_stop": lambda x: self.change_mode("stop"),
"app_pause": lambda x: self.change_mode("pause"),
"app_spot": lambda x: self.change_mode("spot"),
"app_goto_target": lambda x: self.change_mode("goto"),
"app_zoned_clean": lambda x: self.change_mode("zoned clean"),
"app_charge": lambda x: self.change_mode("charge"),
}
super().__init__(args, kwargs)
def change_mode(self, new_mode):
if new_mode == "spot":
self.state["state"] = DummyVacuum.STATE_SPOT
elif new_mode == "home":
self.state["state"] = DummyVacuum.STATE_HOME
elif new_mode == "pause":
self.state["state"] = DummyVacuum.STATE_PAUSED
elif new_mode == "start":
self.state["state"] = DummyVacuum.STATE_CLEANING
elif new_mode == "stop":
self.state["state"] = DummyVacuum.STATE_IDLE
elif new_mode == "goto":
self.state["state"] = DummyVacuum.STATE_GOTO
elif new_mode == "zoned clean":
self.state["state"] = DummyVacuum.STATE_ZONED_CLEAN
elif new_mode == "charge":
self.state["state"] = DummyVacuum.STATE_CHARGING
def vacuum_state(self, _):
return [self.state]
@pytest.fixture(scope="class")
def dummyvacuum(request):
request.cls.device = DummyVacuum()
# TODO add ability to test on a real device
@pytest.mark.usefixtures("dummyvacuum")
class TestVacuum(TestCase):
def status(self):
return self.device.status()
def test_status(self):
self.device._reset_state()
assert repr(self.status()) == repr(VacuumStatus(self.device.start_state))
status = self.status()
assert status.is_on is False
assert status.dnd is True
assert status.clean_time == datetime.timedelta()
assert status.error_code == 0
assert status.error == "No error"
assert status.fanspeed == self.device.start_state["fan_power"]
assert status.battery == self.device.start_state["battery"]
def test_status_with_errors(self):
errors = {5: "Clean main brush", 19: "Unpowered charging station"}
for errcode, error in errors.items():
self.device.state["state"] = self.device.STATE_ERROR
self.device.state["error_code"] = errcode
assert self.status().is_on is False
assert self.status().got_error is True
assert self.status().error_code == errcode
assert self.status().error == error
def test_start_and_stop(self):
assert self.status().is_on is False
self.device.start()
assert self.status().is_on is True
assert self.status().state_code == self.device.STATE_CLEANING
self.device.stop()
assert self.status().is_on is False
def test_spot(self):
assert self.status().is_on is False
self.device.spot()
assert self.status().is_on is True
assert self.status().state_code == self.device.STATE_SPOT
self.device.stop()
assert self.status().is_on is False
def test_pause(self):
self.device.start()
assert self.status().is_on is True
self.device.pause()
assert self.status().state_code == self.device.STATE_PAUSED
def test_home(self):
self.device.start()
assert self.status().is_on is True
self.device.home()
assert self.status().state_code == self.device.STATE_CHARGING
# TODO pause here and update to idle/charging and assert for that?
# Another option is to mock that app_stop mode is entered before
# the charging is activated.
def test_goto(self):
self.device.start()
assert self.status().is_on is True
self.device.goto(24000, 24000)
assert self.status().state_code == self.device.STATE_GOTO
def test_zoned_clean(self):
self.device.start()
assert self.status().is_on is True
self.device.zoned_clean(
[[25000, 25000, 25500, 25500, 3], [23000, 23000, 22500, 22500, 1]]
)
assert self.status().state_code == self.device.STATE_ZONED_CLEAN
@pytest.mark.xfail
def test_manual_control(self):
self.fail()
@pytest.mark.skip("unknown handling")
def test_log_upload(self):
self.fail()
@pytest.mark.xfail
def test_consumable_status(self):
self.fail()
@pytest.mark.skip("consumable reset is not implemented")
def test_consumable_reset(self):
self.fail()
@pytest.mark.xfail
def test_map(self):
self.fail()
@pytest.mark.xfail
def test_clean_history(self):
self.fail()
@pytest.mark.xfail
def test_clean_details(self):
self.fail()
@pytest.mark.skip("hard to test")
def test_find(self):
self.fail()
@pytest.mark.xfail
def test_timer(self):
self.fail()
@pytest.mark.xfail
def test_dnd(self):
self.fail()
@pytest.mark.xfail
def test_fan_speed(self):
self.fail()
@pytest.mark.xfail
def test_sound_info(self):
self.fail()
@pytest.mark.xfail
def test_serial_number(self):
self.fail()
@pytest.mark.xfail
def test_timezone(self):
self.fail()
@pytest.mark.xfail
def test_raw_command(self):
self.fail()
|