Skip to content
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

Unit tests for philips lights #133

Merged
merged 7 commits into from
Nov 26, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions miio/ceil.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ class CeilStatus:
"""Container for status reports from Xiaomi Philips LED Ceiling Lamp."""

def __init__(self, data: Dict[str, Any]) -> None:
# ['power', 'bright', 'snm', 'dv', 'cctsw', 'bl', 'mb', 'ac', 'ms'
# 'sw', 'cct']
# ['off', 0, 4, 0, [[0, 3], [0, 2], [0, 1]], 1, 1, 1, 1, 99]
# {'power': 'off', 'bright': 0, 'snm': 4, 'dv': 0,
# 'cctsw': [[0, 3], [0, 2], [0, 1]], 'bl': 1,
# 'mb': 1, 'ac': 1, 'mssw': 1, 'cct': 99}

# NOTE: Only 8 properties can be requested at the same time
self.data = data

Expand Down Expand Up @@ -47,14 +48,14 @@ def color_temperature(self) -> int:
return self.data["cct"]

@property
def smart_night_light(self) -> int:
def smart_night_light(self) -> bool:
"""Smart night mode state."""
return self.data["bl"]
return self.data["bl"] == 1

@property
def automatic_color_temperature(self) -> int:
def automatic_color_temperature(self) -> bool:
"""Automatic color temperature state."""
return self.data["ac"]
return self.data["ac"] == 1

def __str__(self) -> str:
s = "<CeilStatus power=%s, brightness=%s, " \
Expand Down
2 changes: 1 addition & 1 deletion miio/philips_eyecare.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class PhilipsEyecareStatus:

def __init__(self, data: Dict[str, Any]) -> None:
# ['power': 'off', 'bright': 5, 'notifystatus': 'off',
# 'ambstatus': 'off': 'ambvalue': 41, 'eyecare': 'on',
# 'ambstatus': 'off', 'ambvalue': 41, 'eyecare': 'on',
# 'scene_num': 3, 'bls': 'on', 'dvalue': 0]
self.data = data

Expand Down
126 changes: 126 additions & 0 deletions miio/tests/test_ceil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
from unittest import TestCase
from miio import Ceil
from .dummies import DummyDevice
import pytest


class DummyCeil(DummyDevice, Ceil):
def __init__(self, *args, **kwargs):
self.state = {'power': 'on',
'bright': 50,
'snm': 4,
'dv': 0,
'cctsw': [[0, 3], [0, 2], [0, 1]],
'bl': 1,
'mb': 1,
'ac': 1,
'mssw': 1,
'cct': 99
}
self.return_values = {
'get_prop': self._get_state,
'set_power': lambda x: self._set_state("power", x),
'set_bright': lambda x: self._set_state("bright", x),
'apply_fixed_scene': lambda x: self._set_state("snm", x),
'delay_off': lambda x: self._set_state("dv", x),
'enable_bl': lambda x: self._set_state("bl", x),
'enable_ac': lambda x: self._set_state("ac", x),
'set_cct': lambda x: self._set_state("cct", x),
}
super().__init__(args, kwargs)


@pytest.fixture(scope="class")
def ceil(request):
request.cls.device = DummyCeil()
# TODO add ability to test on a real device


@pytest.mark.usefixtures("ceil")
class TestCeil(TestCase):
def is_on(self):
return self.device.status().is_on

def state(self):
return self.device.status()

def test_on(self):
self.device.off() # ensure off

start_state = self.is_on()
assert start_state is False

self.device.on()
assert self.is_on() is True

def test_off(self):
self.device.on() # ensure on

assert self.is_on() is True
self.device.off()
assert self.is_on() is False
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering quite a few devices has the ability for turning on and off, maybe it makes sense to have a single set of tests for all of those devices. For now this is fine though.


def test_status(self):
self.device._reset_state()

assert self.is_on() is True
assert self.state().brightness == self.device.start_state["bright"]
assert self.state().color_temperature == self.device.start_state["cct"]
assert self.state().scene == self.device.start_state["snm"]
assert self.state().delay_off_countdown == self.device.start_state["dv"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (80 > 79 characters)

assert self.state().smart_night_light == (self.device.start_state["bl"] == 1)
assert self.state().automatic_color_temperature == (self.device.start_state["ac"] == 1)

def test_set_brightness(self):
def brightness():
return self.device.status().brightness

self.device.set_brightness(10)
assert brightness() == 10
self.device.set_brightness(20)
assert brightness() == 20
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test against incorrect values (brightness <0, >100), the bulbs should raise an exception if an incorrect value is thrown at them I think.


def test_set_color_temperature(self):
def color_temperature():
return self.device.status().color_temperature

self.device.set_color_temperature(30)
assert color_temperature() == 30
self.device.set_color_temperature(20)
assert color_temperature() == 20
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above for incorrect values.


def test_delay_off(self):
def delay_off_countdown():
return self.device.status().delay_off_countdown

self.device.delay_off(100)
assert delay_off_countdown() == 100
self.device.delay_off(200)
assert delay_off_countdown() == 200
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.


def test_set_scene(self):
def scene():
return self.device.status().scene

self.device.set_scene(1)
assert scene() == 1
self.device.set_scene(2)
assert scene() == 2
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.


def test_smart_night_light_on(self):
def smart_night_light():
return self.device.status().smart_night_light

self.device.smart_night_light_off()
assert smart_night_light() == False
self.device.smart_night_light_on()
assert smart_night_light() == True

def test_automatic_color_temperature_on(self):
def automatic_color_temperature():
return self.device.status().automatic_color_temperature

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line at end of file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line at end of file

self.device.automatic_color_temperature_on()
assert automatic_color_temperature() == True
self.device.automatic_color_temperature_off()
assert automatic_color_temperature() == False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'
no newline at end of file

53 changes: 53 additions & 0 deletions miio/tests/test_philips_bulb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from unittest import TestCase
from miio import PhilipsBulb
from .dummies import DummyDevice
import pytest


class DummyPhilipsBulb(DummyDevice, PhilipsBulb):
def __init__(self, *args, **kwargs):
self.state = {
'power': 'on',
}
self.return_values = {
'get_prop': self._get_state,
'set_power': lambda x: self._set_state("power", x),
}
super().__init__(args, kwargs)


@pytest.fixture(scope="class")
def philips_bulb(request):
request.cls.device = DummyPhilipsBulb()
# TODO add ability to test on a real device


@pytest.mark.usefixtures("philips_bulb")
class TestPhilipsBulb(TestCase):
def is_on(self):
return self.device.status().is_on

def state(self):
return self.device.status()

def test_on(self):
self.device.off() # ensure off

start_state = self.is_on()
assert start_state is False

self.device.on()
assert self.is_on() is True

def test_off(self):
self.device.on() # ensure on

assert self.is_on() is True
self.device.off()
assert self.is_on() is False

def test_status(self):
self.device._reset_state()

assert self.is_on() is True

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line at end of file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line at end of file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line at end of file

148 changes: 148 additions & 0 deletions miio/tests/test_philips_eyecare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
from unittest import TestCase
from miio import PhilipsEyecare
from .dummies import DummyDevice
import pytest


class DummyPhilipsEyecare(DummyDevice, PhilipsEyecare):
def __init__(self, *args, **kwargs):
self.state = {
'power': 'on',
'bright': 5,
'notifystatus': 'off',
'ambstatus': 'off',
'ambvalue': 41,
'eyecare': 'on',
'scene_num': 3,
'bls': 'on',
'dvalue': 0,
}
self.return_values = {
'get_prop': self._get_state,
'set_power': lambda x: self._set_state("power", x),
'set_eyecare': lambda x: self._set_state("eyecare", x),
'set_bright': lambda x: self._set_state("bright", x),
'set_user_scene': lambda x: self._set_state("scene_num", x),
'delay_off': lambda x: self._set_state("dvalue", x),
'enable_bl': lambda x: self._set_state("bls", x),
'set_notifyuser': lambda x: self._set_state("notifystatus", x),
'enable_amb': lambda x: self._set_state("ambstatus", x),
'set_amb_bright': lambda x: self._set_state("ambvalue", x),
}
super().__init__(args, kwargs)


@pytest.fixture(scope="class")
def philips_eyecare(request):
request.cls.device = DummyPhilipsEyecare()
# TODO add ability to test on a real device


@pytest.mark.usefixtures("philips_eyecare")
class TestPhilipsEyecare(TestCase):
def is_on(self):
return self.device.status().is_on

def state(self):
return self.device.status()

def test_on(self):
self.device.off() # ensure off

start_state = self.is_on()
assert start_state is False

self.device.on()
assert self.is_on() is True

def test_off(self):
self.device.on() # ensure on

assert self.is_on() is True
self.device.off()
assert self.is_on() is False

def test_status(self):
self.device._reset_state()

assert self.is_on() is True
assert self.state().brightness == self.device.start_state["bright"]
assert self.state().reminder == (self.device.start_state["notifystatus"] == 'on')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (89 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (89 > 79 characters)

assert self.state().ambient == (self.device.start_state["ambstatus"] == 'on')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (85 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (85 > 79 characters)

assert self.state().ambient_brightness == self.device.start_state["ambvalue"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (85 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (85 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (85 > 79 characters)

assert self.state().eyecare == (self.device.start_state["eyecare"] == 'on')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (83 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (83 > 79 characters)

assert self.state().scene == self.device.start_state["scene_num"]
assert self.state().smart_night_light == (self.device.start_state["bls"] == 'on')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (89 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (89 > 79 characters)

assert self.state().delay_off_countdown == self.device.start_state["dvalue"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (84 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (84 > 79 characters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (84 > 79 characters)


def test_eyecare(self):
def eyecare():
return self.device.status().eyecare

self.device.eyecare_on()
assert eyecare() == True

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

self.device.eyecare_off()
assert eyecare() == False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'


def test_set_brightness(self):
def brightness():
return self.device.status().brightness

self.device.set_brightness(10)
assert brightness() == 10
self.device.set_brightness(20)
assert brightness() == 20

def test_set_scene(self):
def scene():
return self.device.status().scene

self.device.set_scene(1)
assert scene() == 1
self.device.set_scene(2)
assert scene() == 2

def test_delay_off(self):
def delay_off_countdown():
return self.device.status().delay_off_countdown

self.device.delay_off(100)
assert delay_off_countdown() == 100
self.device.delay_off(200)
assert delay_off_countdown() == 200

def test_smart_night_light(self):
def smart_night_light():
return self.device.status().smart_night_light

self.device.smart_night_light_on()
assert smart_night_light() == True

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

self.device.smart_night_light_off()
assert smart_night_light() == False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'


def test_reminder(self):
def reminder():
return self.device.status().reminder

self.device.reminder_on()
assert reminder() == True

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

self.device.reminder_off()
assert reminder() == False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'


def test_ambient(self):
def ambient():
return self.device.status().ambient

self.device.ambient_on()
assert ambient() == True

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to True should be 'if cond is True:' or 'if cond:'

self.device.ambient_off()
assert ambient() == False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparison to False should be 'if cond is False:' or 'if not cond:'


def test_set_ambient_brightness(self):
def ambient_brightness():
return self.device.status().ambient_brightness

self.device.set_ambient_brightness(10)
assert ambient_brightness() == 10
self.device.set_ambient_brightness(20)
assert ambient_brightness() == 20