Skip to content
This repository was archived by the owner on Dec 23, 2021. It is now read-only.

Commit 97b074f

Browse files
authored
Added python unit tests to adafruit_circuitplayground library (#174)
* Added python unit tests to adafruit_circuitplayground library * Updated package.json script for python tests
1 parent 61d8149 commit 97b074f

File tree

9 files changed

+268
-114
lines changed

9 files changed

+268
-114
lines changed

docs/developers-setup.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343

4444
6. Start running the extension locally by pressing F5 or going to VS Code Debug menu and select 'Start debugging'
4545

46+
## Testing
47+
48+
- To run unit tests, run the command: `npm run test` in the root level directory.
49+
- You will need Pytest installed for the Python tests to run correctly
50+
- To run just the python tests, run the command: `pytest src` or `python -m pytest src` in the root level directory.
51+
4652
## Notes on how to use it
4753

4854
- [Documentation to use the Extension](/docs/how-to-use.md)

src/adafruit_circuitplayground/debugger_communication_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,5 @@ def button_press(data):
4747

4848
# Event : Sensor changed (Temperature, light, Motion)
4949
@sio.on("sensor_changed")
50-
def button_press(data):
50+
def sensor_changed(data):
5151
__update_api_state(data, CONSTANTS.EVENTS_SENSOR_CHANGED)

src/adafruit_circuitplayground/express.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import json
55
import sys
66
import os
7-
from playsound import playsound
7+
import playsound
88
from .pixel import Pixel
99
from . import utils
1010
from . import constants as CONSTANTS
@@ -162,7 +162,7 @@ def play_file(self, file_name):
162162
if sys.implementation.version[0] >= 3:
163163
if file_name.endswith(".wav"):
164164
try:
165-
playsound(abs_path_wav_file)
165+
playsound.playsound(abs_path_wav_file)
166166
except:
167167
# TODO TASK: 29054 Verfication of a "valid" .wav file
168168
raise EnvironmentError(CONSTANTS.NOT_SUITABLE_FILE_ERROR)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import pytest
2+
import json # Remove
3+
from unittest import mock
4+
import socketio
5+
6+
from .. import express
7+
from .. import debugger_communication_client
8+
9+
10+
class TestDebuggerCommunicationClient(object):
11+
@mock.patch("socketio.Client.connect")
12+
def test_init_connection(self, mock_connect):
13+
mock_connect.return_value = None
14+
debugger_communication_client.init_connection()
15+
mock_connect.assert_called_once()
16+
17+
def test_init_connection1(self):
18+
socketio.Client.connect = mock.Mock()
19+
socketio.Client.connect.return_value = None
20+
debugger_communication_client.init_connection()
21+
socketio.Client.connect.assert_called_once()
22+
23+
def test_update_state(self):
24+
socketio.Client.emit = mock.Mock()
25+
socketio.Client.emit.return_value = None
26+
debugger_communication_client.update_state({})
27+
socketio.Client.emit.assert_called_once()
28+
29+
@mock.patch.dict(
30+
express.cpx._Express__state,
31+
{"button_a": False, "button_b": False, "switch": True},
32+
clear=True,
33+
)
34+
def test_button_press(self):
35+
data = {"button_a": True, "button_b": True, "switch": True}
36+
serialized_data = json.dumps(data)
37+
debugger_communication_client.button_press(serialized_data)
38+
assert data == express.cpx._Express__state
39+
40+
@mock.patch.dict(
41+
express.cpx._Express__state,
42+
{"temperature": 0, "light": 0, "motion_x": 0, "motion_y": 0, "motion_z": 0},
43+
clear=True,
44+
)
45+
def test_sensor_changed(self):
46+
data = {
47+
"temperature": 1,
48+
"light": 2,
49+
"motion_x": 3,
50+
"motion_y": 4,
51+
"motion_z": 5,
52+
}
53+
serialized_data = json.dumps(data)
54+
debugger_communication_client.sensor_changed(serialized_data)
55+
assert data == express.cpx._Express__state
56+
57+
@mock.patch("builtins.print")
58+
@mock.patch.dict(express.cpx._Express__state, {}, clear=True)
59+
def test_update_api_state_fail(self, mocked_print):
60+
data = []
61+
debugger_communication_client.sensor_changed(data)
62+
# Exception is caught and a print is stated to stderr
63+
mocked_print.assert_called_once()
Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import pytest
2+
from unittest import mock
23

4+
import playsound
35
from ..express import Express
46
from ..pixel import Pixel
57

@@ -18,105 +20,96 @@ def setup_method(self):
1820
self.pixels = Pixel(self.__state)
1921
self.__speaker_enabled = False
2022

23+
def test_acceleration(self):
24+
mock_motion_x = 10
25+
mock_motion_y = -10
26+
mock_motion_z = -20
27+
self.cpx._Express__state["motion_x"] = mock_motion_x
28+
self.cpx._Express__state["motion_y"] = mock_motion_y
29+
self.cpx._Express__state["motion_z"] = mock_motion_z
30+
accel = self.cpx.acceleration
31+
assert accel[0] == 10
32+
assert accel[1] == -10
33+
assert accel[2] == -20
34+
2135
def test_button_a(self):
2236
self.cpx._Express__state["button_a"] = True
23-
assert True == self.cpx.button_a
37+
assert self.cpx.button_a
2438

2539
def test_button_b(self):
2640
self.cpx._Express__state["button_b"] = True
27-
assert True == self.cpx.button_b
41+
assert self.cpx.button_b
42+
43+
def test_taps(self):
44+
self.cpx._Express__state["detect_taps"] = 2
45+
assert 2 == self.cpx.detect_taps
46+
47+
@pytest.mark.parametrize("taps, expected", [(1, 1), (2, 2), (3, 1)])
48+
def test_taps_setter(self, taps, expected):
49+
self.cpx.detect_taps = taps
50+
assert expected == self.cpx.detect_taps
2851

2952
def test_red_led(self):
3053
self.cpx._Express__state["red_led"] = True
31-
assert True == self.cpx.red_led
54+
assert self.cpx.red_led
3255

3356
def test_red_led_int(self):
3457
self.cpx.red_led = 3
35-
assert True == self.cpx.red_led
58+
assert self.cpx.red_led
3659

3760
def test_red_led_string(self):
3861
self.cpx.red_led = "foo"
39-
assert True == self.cpx.red_led
62+
assert self.cpx.red_led
4063

4164
def test_switch(self):
4265
self.cpx._Express__state["switch"] = True
43-
assert True == self.cpx.switch
44-
45-
def test_set_item_tuple(self):
46-
self.cpx.pixels[0] = (255, 255, 255)
47-
assert (255, 255, 255) == self.cpx._Express__state["pixels"][0]
66+
assert self.cpx.switch
4867

49-
def test_set_item_list(self):
50-
self.cpx.pixels[0] = [255, 255, 255]
51-
assert (255, 255, 255) == self.cpx._Express__state["pixels"][0]
68+
def test_temperature(self):
69+
self.cpx._Express__state["temperature"] = 31
70+
assert 31 == self.cpx.temperature
5271

53-
def test_set_item_hex(self):
54-
self.cpx.pixels[0] = 0xFFFFFF
55-
assert (255, 255, 255) == self.cpx._Express__state["pixels"][0]
56-
57-
def test_set_item_invalid(self):
58-
with pytest.raises(ValueError):
59-
self.cpx.pixels[0] = "hello"
72+
def test_light(self):
73+
self.cpx._Express__state["light"] = 255
74+
assert 255 == self.cpx.light
6075

6176
def test_shake(self):
6277
self.cpx._Express__state["shake"] = True
63-
assert True == self.cpx.shake()
78+
assert self.cpx.shake()
6479

6580
def test_touch_A1(self):
6681
self.cpx._Express__state["touch"][0] = True
67-
assert True == self.cpx.touch_A1
82+
assert self.cpx.touch_A1
6883

6984
def test_touch_A2(self):
7085
self.cpx._Express__state["touch"][1] = True
71-
assert True == self.cpx.touch_A2
86+
assert self.cpx.touch_A2
7287

7388
def test_touch_A3(self):
7489
self.cpx._Express__state["touch"][2] = True
75-
assert True == self.cpx.touch_A3
90+
assert self.cpx.touch_A3
7691

7792
def test_touch_A4(self):
7893
self.cpx._Express__state["touch"][3] = True
79-
assert True == self.cpx.touch_A4
94+
assert self.cpx.touch_A4
8095

8196
def test_touch_A5(self):
8297
self.cpx._Express__state["touch"][4] = True
83-
assert True == self.cpx.touch_A5
98+
assert self.cpx.touch_A5
8499

85100
def test_touch_A6(self):
86101
self.cpx._Express__state["touch"][5] = True
87-
assert True == self.cpx.touch_A6
102+
assert self.cpx.touch_A6
88103

89104
def test_touch_A7(self):
90105
self.cpx._Express__state["touch"][6] = True
91-
assert True == self.cpx.touch_A7
106+
assert self.cpx.touch_A7
92107

93-
def test_play_file_mp4(self):
108+
def test_play_file_mp4_wrong_type(self):
94109
with pytest.raises(TypeError):
95110
self.cpx.play_file("sample.mp4")
96111

97-
def test_fill(self):
98-
self.cpx.pixels.fill((0, 255, 0))
99-
expected_pixels = [(0, 255, 0)] * 10
100-
assert expected_pixels == self.cpx._Express__state["pixels"]
101-
102-
def test_extract_pixel_value_list(self):
103-
assert (0, 255, 0) == self.cpx.pixels._Pixel__extract_pixel_value((0, 255, 0))
104-
105-
def test_extract_pixel_value_list1(self):
106-
assert (123, 123, 123) == self.cpx.pixels._Pixel__extract_pixel_value(
107-
[123, 123, 123]
108-
)
109-
110-
def test_extract_pixel_value_int(self):
111-
assert (0, 0, 255) == self.cpx.pixels._Pixel__extract_pixel_value(255)
112-
113-
def test_extract_pixel_value_tuple(self):
114-
assert (0, 255, 0) == self.cpx.pixels._Pixel__extract_pixel_value((0, 255, 0))
115-
116-
def test_extract_pixel_value_invalid_length(self):
117-
with pytest.raises(ValueError):
118-
self.cpx.pixels._Pixel__extract_pixel_value((1, 2, 3, 4))
119-
120-
def test_extract_pixel_value_invalid_tuple_value(self):
121-
with pytest.raises(ValueError):
122-
self.cpx.pixels._Pixel__extract_pixel_value((0, 222, "hello"))
112+
def test_play_file_mp4(self):
113+
playsound.playsound = mock.Mock()
114+
self.cpx.play_file("sample.wav")
115+
playsound.playsound.assert_called_once()
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import pytest
2+
3+
from ..pixel import Pixel
4+
5+
6+
class TestPixel(object):
7+
def setup_method(self):
8+
self.pixel = Pixel(
9+
{
10+
"brightness": 1.0,
11+
"button_a": False,
12+
"button_b": False,
13+
"pixels": [(255, 0, 0), (0, 255, 0), (0, 0, 255)],
14+
"red_led": False,
15+
"switch": False,
16+
}
17+
)
18+
19+
@pytest.mark.parametrize("debug_mode", [True, False])
20+
def test_set_debug_mode(self, debug_mode):
21+
self.pixel._Pixel__set_debug_mode(debug_mode)
22+
assert debug_mode == self.pixel._Pixel__debug_mode
23+
24+
def test_get_item_out_of_bounds(self):
25+
with pytest.raises(IndexError):
26+
p = self.pixel[3]
27+
28+
def test_get_item(self):
29+
assert (0, 0, 255) == self.pixel[2]
30+
31+
def test_get_item_splice(self):
32+
assert [(255, 0, 0), (0, 255, 0)] == self.pixel[0:2]
33+
34+
def test_set_item(self):
35+
self.pixel[1] = (50, 50, 50)
36+
assert (50, 50, 50) == self.pixel[1]
37+
38+
def test_set_item_splice(self):
39+
self.pixel[0:1] = [(100, 100, 100), (0, 0, 100)]
40+
assert (100, 100, 100) == self.pixel[0]
41+
assert (0, 0, 100) == self.pixel[1]
42+
43+
def test_set_item_out_of_bounds(self):
44+
with pytest.raises(IndexError):
45+
self.pixel[3] = (0, 0, 0)
46+
47+
def test_set_item_invalid(self):
48+
with pytest.raises(ValueError):
49+
self.pixel[0] = "hello"
50+
51+
def test_len(self):
52+
assert 3 == len(self.pixel)
53+
54+
@pytest.mark.parametrize("index, expected", [(0, True), (3, False)])
55+
def test_valid_index(self, index, expected):
56+
assert self.pixel._Pixel__valid_index(index) == expected
57+
58+
def test_fill(self):
59+
self.pixel.fill((123, 123, 123))
60+
assert all(p == (123, 123, 123) for p in self.pixel._Pixel__state["pixels"])
61+
62+
@pytest.mark.parametrize(
63+
"val, expected",
64+
[([3, 4, 5], (3, 4, 5)), (432, (0, 1, 176)), ((1, 2, 3), (1, 2, 3))],
65+
)
66+
def test_extract_pixel_values_not_slice(self, val, expected):
67+
assert expected == self.pixel._Pixel__extract_pixel_value(val)
68+
69+
@pytest.mark.parametrize(
70+
"val, expected",
71+
[
72+
([[3, 4, 5], [6, 7, 8]], [(3, 4, 5), (6, 7, 8)]),
73+
([444555, 666777], [(6, 200, 139), (10, 44, 153)]),
74+
([(10, 10, 10), (20, 20, 20)], [(10, 10, 10), (20, 20, 20)]),
75+
],
76+
)
77+
def test_extract_pixel_values_slice(self, val, expected):
78+
assert expected == self.pixel._Pixel__extract_pixel_value(val, is_slice=True)
79+
80+
@pytest.mark.parametrize("val", [[1, 2, 3, 4], [1, 2], 0.3])
81+
def test_extract_pixel_values_fail(self, val):
82+
with pytest.raises(ValueError):
83+
self.pixel._Pixel__extract_pixel_value(val)
84+
85+
def test_hex_to_rgb_fail(self):
86+
with pytest.raises(ValueError):
87+
self.pixel._Pixel__hex_to_rgb("x")
88+
89+
@pytest.mark.parametrize(
90+
"hex, expected",
91+
[
92+
("0xffffff", (255, 255, 255)),
93+
("0x0", (0, 0, 0)),
94+
("0xff0000", (255, 0, 0)),
95+
("0xabcdef", (171, 205, 239)),
96+
],
97+
)
98+
def test_hex_to_rgb(self, hex, expected):
99+
assert expected == self.pixel._Pixel__hex_to_rgb(hex)
100+
101+
@pytest.mark.parametrize(
102+
"pixValue, expected",
103+
[(0, True), (200, True), (255, True), (-1, False), (256, False), ("1", False)],
104+
)
105+
def test_valid_rgb_value(self, pixValue, expected):
106+
assert expected == self.pixel._Pixel__valid_rgb_value(pixValue)
107+
108+
def test_get_brightness(self):
109+
self.pixel._Pixel__state["brightness"] = 0.4
110+
assert 0.4 == pytest.approx(self.pixel.brightness)
111+
112+
@pytest.mark.parametrize("brightness", [-0.1, 1.1])
113+
def test_set_brightness_fail(self, brightness):
114+
with pytest.raises(ValueError):
115+
self.pixel.brightness = brightness
116+
117+
@pytest.mark.parametrize("brightness", [0, 1, 0.4, 0.333])
118+
def test_set_brightness(self, brightness):
119+
self.pixel.brightness = brightness
120+
assert self.pixel._Pixel__valid_brightness(brightness)

0 commit comments

Comments
 (0)