1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-02 03:12:20 +01:00

Merge branch 'dev' into bump-1.17.0b1

This commit is contained in:
Jesse Hills
2021-03-22 20:08:57 +13:00
553 changed files with 27573 additions and 13992 deletions

View File

@@ -1,4 +1,4 @@
""" Tests for the binary sensor component """
"""Tests for the binary sensor component."""
def test_binary_sensor_is_setup(generate_main):
@@ -8,7 +8,9 @@ def test_binary_sensor_is_setup(generate_main):
# Given
# When
main_cpp = generate_main("tests/component_tests/binary_sensor/test_binary_sensor.yaml")
main_cpp = generate_main(
"tests/component_tests/binary_sensor/test_binary_sensor.yaml"
)
# Then
assert "new gpio::GPIOBinarySensor();" in main_cpp
@@ -22,10 +24,12 @@ def test_binary_sensor_sets_mandatory_fields(generate_main):
# Given
# When
main_cpp = generate_main("tests/component_tests/binary_sensor/test_binary_sensor.yaml")
main_cpp = generate_main(
"tests/component_tests/binary_sensor/test_binary_sensor.yaml"
)
# Then
assert "bs_1->set_name(\"test bs1\");" in main_cpp
assert 'bs_1->set_name("test bs1");' in main_cpp
assert "bs_1->set_pin(new GPIOPin" in main_cpp
@@ -36,7 +40,9 @@ def test_binary_sensor_config_value_internal_set(generate_main):
# Given
# When
main_cpp = generate_main("tests/component_tests/binary_sensor/test_binary_sensor.yaml")
main_cpp = generate_main(
"tests/component_tests/binary_sensor/test_binary_sensor.yaml"
)
# Then
assert "bs_1->set_internal(true);" in main_cpp

View File

@@ -1,4 +1,12 @@
""" Fixtures for component tests """
"""Fixtures for component tests."""
import sys
from pathlib import Path
# Add package root to python path
here = Path(__file__).parent
package_root = here.parent.parent
sys.path.insert(0, package_root.as_posix())
import pytest
@@ -9,7 +17,7 @@ from esphome.__main__ import generate_cpp_contents
@pytest.fixture
def generate_main():
""" Generates the C++ main.cpp file and returns it in string form """
"""Generates the C++ main.cpp file and returns it in string form."""
def generator(path: str) -> str:
CORE.config_path = path

View File

@@ -0,0 +1,14 @@
"""Tests for the sensor component."""
def test_sensor_device_class_set(generate_main):
"""
When the device_class of sensor is set in the yaml file, it should be registered in main
"""
# Given
# When
main_cpp = generate_main("tests/component_tests/sensor/test_sensor.yaml")
# Then
assert 's_1->set_device_class("voltage");' in main_cpp

View File

@@ -0,0 +1,12 @@
esphome:
name: test
platform: ESP8266
board: d1_mini_lite
sensor:
- platform: adc
pin: A0
id: s_1
name: "test s1"
update_interval: 60s
device_class: "voltage"

View File

@@ -1,8 +1,12 @@
substitutions:
devicename: test1
sensorname: my
textname: template
roomname: living_room
esphome:
name: test1
name_add_mac_suffix: true
platform: ESP32
board: nodemcu-32s
on_boot:
@@ -26,6 +30,31 @@ esphome:
green: !lambda 'return 255;'
blue: 0%
white: 100%
- http_request.get:
url: https://esphome.io
headers:
Content-Type: application/json
verify_ssl: false
- http_request.post:
url: https://esphome.io
verify_ssl: false
json:
key: !lambda |-
return id(${textname}_text).state;
greeting: 'Hello World'
- http_request.send:
method: PUT
url: https://esphome.io
headers:
Content-Type: application/json
body: 'Some data'
verify_ssl: false
on_response:
then:
- logger.log:
format: 'Response status: %d'
args:
- status_code
build_path: build/test1
packages:
@@ -50,6 +79,10 @@ wifi:
reboot_timeout: 120s
power_save_mode: none
http_request:
useragent: esphome/device
timeout: 10s
mqtt:
broker: '192.168.178.84'
port: 1883
@@ -98,7 +131,7 @@ mqtt:
int data = x["my_data"];
ESP_LOGD("main", "The data is: %d", data);
- light.turn_on:
id: living_room_lights
id: ${roomname}_lights
brightness: !lambda |-
float brightness = 1.0;
if (x.containsKey("brightness"))
@@ -110,17 +143,21 @@ mqtt:
effect = x["effect"];
return effect;
- light.control:
id: living_room_lights
brightness: !lambda 'return id(living_room_lights).current_values.get_brightness() + 0.5;'
id: ${roomname}_lights
brightness: !lambda 'return id(${roomname}_lights).current_values.get_brightness() + 0.5;'
- light.dim_relative:
id: living_room_lights
id: ${roomname}_lights
relative_brightness: 5%
- uart.write:
id: uart0
data: Hello World
- uart.write: [0x00, 0x20, 0x30]
- uart.write: !lambda |-
return {};
- uart.write:
id: uart0
data: [0x00, 0x20, 0x30]
- uart.write:
id: uart0
data: !lambda |-
return {};
i2c:
sda: 21
@@ -143,6 +180,7 @@ uart:
data_bits: 8
stop_bits: 1
rx_buffer_size: 512
invert: false
- id: adalight_uart
tx_pin: GPIO25
@@ -237,6 +275,14 @@ sensor:
window_size: 5
send_every: 5
send_first_at: 3
- min:
window_size: 5
send_every: 5
send_first_at: 3
- max:
window_size: 5
send_every: 5
send_first_at: 3
- sliding_window_moving_average:
window_size: 15
send_every: 15
@@ -256,9 +302,9 @@ sensor:
then:
- lambda: |-
ESP_LOGD("main", "Got value %f", x);
id(my_sensor).publish_state(42.0);
ESP_LOGI("main", "Value of my sensor: %f", id(my_sensor).state);
ESP_LOGI("main", "Raw Value of my sensor: %f", id(my_sensor).state);
id(${sensorname}_sensor).publish_state(42.0);
ESP_LOGI("main", "Value of my sensor: %f", id(${sensorname}_sensor).state);
ESP_LOGI("main", "Raw Value of my sensor: %f", id(${sensorname}_sensor).state);
on_value_range:
above: 5
below: 10
@@ -285,7 +331,7 @@ sensor:
- platform: ads1115
multiplexer: 'A0_A1'
gain: 1.024
id: my_sensor
id: ${sensorname}_sensor
filters:
state_topic: hi/me
retain: false
@@ -435,7 +481,7 @@ sensor:
name: 'HLW8012 Power'
id: hlw8012_power
energy:
name: "HLW8012 Energy"
name: 'HLW8012 Energy'
id: hlw8012_energy
update_interval: 15s
current_resistor: 0.001 ohm
@@ -549,6 +595,7 @@ sensor:
reference_resistance: '430 Ω'
rtd_nominal_resistance: '100 Ω'
- platform: mhz19
uart_id: uart0
co2:
name: 'MH-Z19 CO2 Value'
temperature:
@@ -586,6 +633,13 @@ sensor:
falling_edge: DECREMENT
internal_filter: 13us
update_interval: 15s
- platform: pulse_meter
name: 'Pulse Meter'
pin: GPIO12
internal_filter: 100ms
timeout: 2 min
total:
name: 'Pulse Meter Total'
- platform: rotary_encoder
name: 'Rotary Encoder'
id: rotary_encoder1
@@ -613,10 +667,23 @@ sensor:
- platform: pulse_width
name: Pulse Width
pin: GPIO12
- platform: senseair
- platform: sm300d2
uart_id: uart0
co2:
name: 'SenseAir CO2 Value'
update_interval: 15s
name: 'SM300D2 CO2 Value'
formaldehyde:
name: 'SM300D2 Formaldehyde Value'
tvoc:
name: 'SM300D2 TVOC Value'
pm_2_5:
name: 'SM300D2 PM2.5 Value'
pm_10_0:
name: 'SM300D2 PM10 Value'
temperature:
name: 'SM300D2 Temperature Value'
humidity:
name: 'SM300D2 Humidity Value'
update_interval: 60s
- platform: sht3xd
temperature:
name: 'Living Room Temperature 8'
@@ -735,6 +802,7 @@ sensor:
root["key"] = id(the_sensor).state;
root["greeting"] = "Hello World";
- platform: sds011
uart_id: uart0
pm_2_5:
name: 'SDS011 PM2.5'
pm_10_0:
@@ -784,6 +852,7 @@ sensor:
name: 'AQI'
calculation_type: 'CAQI'
- platform: teleinfo
uart_id: uart0
tags:
- tag_name: 'HCHC'
sensor:
@@ -829,7 +898,7 @@ binary_sensor:
- platform: gpio
name: 'MCP23S08 Pin #1'
pin:
mcp23s08: mcp23s08_hub
mcp23xxx: mcp23s08_hub
# Use pin number 1
number: 1
# One of INPUT or INPUT_PULLUP
@@ -838,12 +907,22 @@ binary_sensor:
- platform: gpio
name: 'MCP23S17 Pin #1'
pin:
mcp23s17: mcp23s17_hub
mcp23xxx: mcp23s17_hub
# Use pin number 1
number: 1
# One of INPUT or INPUT_PULLUP
mode: INPUT_PULLUP
inverted: False
- platform: gpio
name: 'MCP23S17 Pin #1 with interrupt'
pin:
mcp23xxx: mcp23s17_hub
# Use pin number 1
number: 1
# One of INPUT or INPUT_PULLUP
mode: INPUT_PULLUP
inverted: False
interrupt: FALLING
- platform: gpio
pin: GPIO9
name: 'Living Room Window'
@@ -924,12 +1003,12 @@ binary_sensor:
name: 'Garage Door Open'
id: garage_door
lambda: |-
if (isnan(id(my_sensor).state)) {
if (isnan(id(${sensorname}_sensor).state)) {
// isnan checks if the ultrasonic sensor echo
// has timed out, resulting in a NaN (not a number) state
// in that case, return {} to indicate that we don't know.
return {};
} else if (id(my_sensor).state > 30) {
} else if (id(${sensorname}_sensor).state > 30) {
// Garage Door is open.
return true;
} else {
@@ -947,6 +1026,7 @@ binary_sensor:
id: gpio_19
frequency: !lambda 'return 500.0;'
- platform: pn532
pn532_id: pn532_bs
uid: 74-10-37-94
name: 'PN532 NFC Tag'
- platform: rdm6300
@@ -962,14 +1042,14 @@ binary_sensor:
- platform: gpio
name: 'MCP21 binary sensor'
pin:
mcp23017: mcp23017_hub
mcp23xxx: mcp23017_hub
number: 1
mode: INPUT
inverted: True
- platform: gpio
name: 'MCP22 binary sensor'
pin:
mcp23008: mcp23008_hub
mcp23xxx: mcp23008_hub
number: 7
mode: INPUT_PULLUP
inverted: False
@@ -1126,14 +1206,14 @@ output:
- platform: gpio
id: id22
pin:
mcp23017: mcp23017_hub
mcp23xxx: mcp23017_hub
number: 0
mode: OUTPUT
inverted: False
- platform: gpio
id: id23
pin:
mcp23008: mcp23008_hub
mcp23xxx: mcp23008_hub
number: 0
mode: OUTPUT
inverted: False
@@ -1173,6 +1253,8 @@ output:
- platform: esp32_dac
pin: GPIO25
id: dac_output
- platform: mcp4725
id: mcp4725_dac_output
e131:
@@ -1220,7 +1302,7 @@ light:
state = 0;
- platform: rgb
name: 'Living Room Lights'
id: living_room_lights
id: ${roomname}_lights
red: pca_0
green: pca_1
blue: pca_2
@@ -1376,14 +1458,14 @@ climate:
name: TCL112 Climate With Sensor
supports_heat: True
supports_cool: True
sensor: my_sensor
sensor: ${sensorname}_sensor
- platform: tcl112
name: TCL112 Climate
- platform: coolix
name: Coolix Climate With Sensor
supports_heat: True
supports_cool: True
sensor: my_sensor
sensor: ${sensorname}_sensor
- platform: coolix
name: Coolix Climate
- platform: fujitsu_general
@@ -1402,12 +1484,29 @@ climate:
name: Toshiba Climate
- platform: hitachi_ac344
name: Hitachi Climate
- platform: midea_ac
visual:
min_temperature: 18 °C
max_temperature: 25 °C
temperature_step: 0.1 °C
name: "Electrolux EACS"
beeper: true
outdoor_temperature:
name: "Temp"
power_usage:
name: "Power"
humidity_setpoint:
name: "Hum"
midea_dongle:
uart_id: uart0
strength_icon: true
switch:
- platform: gpio
name: 'MCP23S08 Pin #0'
pin:
mcp23s08: mcp23s08_hub
mcp23xxx: mcp23s08_hub
# Use pin number 0
number: 0
mode: OUTPUT
@@ -1415,7 +1514,7 @@ switch:
- platform: gpio
name: 'MCP23S17 Pin #0'
pin:
mcp23s17: mcp23s17_hub
mcp23xxx: mcp23s17_hub
# Use pin number 0
number: 1
mode: OUTPUT
@@ -1451,6 +1550,12 @@ switch:
turn_on_action:
remote_transmitter.transmit_samsung:
data: 0xABCDEF
- platform: template
name: Samsung36
turn_on_action:
remote_transmitter.transmit_samsung36:
address: 0x0400
command: 0x000E00FF
- platform: template
name: Sony
turn_on_action:
@@ -1542,6 +1647,9 @@ switch:
- output.set_level:
id: dac_output
level: !lambda 'return 0.5;'
- output.set_level:
id: mcp4725_dac_output
level: !lambda 'return 0.5;'
turn_off_action:
- switch.turn_on: living_room_lights_off
restore_state: False
@@ -1582,11 +1690,18 @@ switch:
id: my_switch
state: !lambda 'return false;'
- platform: uart
uart_id: uart0
name: 'UART String Output'
data: 'DataToSend'
- platform: uart
uart_id: uart0
name: 'UART Bytes Output'
data: [0xDE, 0xAD, 0xBE, 0xEF]
- platform: uart
uart_id: uart0
name: 'UART Recurring Output'
data: [0xDE, 0xAD, 0xBE, 0xEF]
send_every: 1s
- platform: template
assumed_state: yes
name: Stepper Switch
@@ -1620,13 +1735,10 @@ fan:
direction_output: gpio_26
- platform: speed
output: pca_6
speed_count: 10
name: 'Living Room Fan 2'
oscillation_output: gpio_19
direction_output: gpio_26
speed:
low: 0.45
medium: 0.75
high: 1.0
oscillation_state_topic: oscillation/state/topic
oscillation_command_topic: oscillation/command/topic
speed_state_topic: speed/state/topic
@@ -1653,7 +1765,7 @@ interval:
color:
- id: kbx_red
red: 100%
green: 1%
green_int: 123
blue: 2%
- id: kbx_blue
red: 0%
@@ -1690,15 +1802,16 @@ display:
it.print("1234");
- platform: tm1637
clk_pin:
mcp23017: mcp23017_hub
mcp23xxx: mcp23017_hub
number: 1
dio_pin:
mcp23017: mcp23017_hub
mcp23xxx: mcp23017_hub
number: 2
intensity: 3
lambda: |-
it.print("1234");
- platform: nextion
uart_id: uart0
lambda: |-
it.set_component_value("gauge", 50);
it.set_component_text("textview", "Hello World!");
@@ -1730,7 +1843,7 @@ display:
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
- platform: ssd1322_spi
model: "SSD1322 256x64"
model: 'SSD1322 256x64'
cs_pin: GPIO23
dc_pin: GPIO23
reset_pin: GPIO23
@@ -1776,24 +1889,6 @@ display:
reset_pin: GPIO23
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
- platform: waveshare_epaper
cs_pin: GPIO23
dc_pin: GPIO23
busy_pin: GPIO23
reset_pin: GPIO23
model: 2.90in
full_update_every: 30
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
- platform: waveshare_epaper
cs_pin: GPIO23
dc_pin: GPIO23
busy_pin: GPIO23
reset_pin: GPIO23
model: 2.90inv2
full_update_every: 30
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
- platform: st7789v
cs_pin: GPIO5
dc_pin: GPIO16
@@ -1807,10 +1902,10 @@ display:
dc_pin: GPIO16
reset_pin: GPIO23
rotation: 0
devicewidth: 128
deviceheight: 160
colstart: 0
rowstart: 0
device_width: 128
device_height: 160
col_start: 0
row_start: 0
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
tm1651:
@@ -1826,6 +1921,7 @@ status_led:
pin: GPIO2
pn532_spi:
id: pn532_bs
cs_pin: GPIO23
update_interval: 1s
on_tag:
@@ -1838,6 +1934,7 @@ pn532_spi:
pn532_i2c:
rdm6300:
uart_id: uart0
rc522_spi:
cs_pin: GPIO23
@@ -1853,6 +1950,7 @@ rc522_i2c:
ESP_LOGD("main", "Found tag %s", x.c_str());
gps:
uart_id: uart0
time:
- platform: sntp
@@ -1875,8 +1973,7 @@ time:
update_interval: never
on_time:
seconds: 0
then:
ds1307.read_time
then: ds1307.read_time
cover:
- platform: template
@@ -1950,10 +2047,10 @@ text_sensor:
qos: 2
on_value:
- text_sensor.template.publish:
id: template_text
id: ${textname}_text
state: Hello World
- text_sensor.template.publish:
id: template_text
id: ${textname}_text
state: |-
return "Hello World2";
- globals.set:
@@ -1964,7 +2061,7 @@ text_sensor:
data: [0x10, 0x20, 0x30]
- platform: template
name: Template Text Sensor
id: template_text
id: ${textname}_text
- platform: wifi_info
ip_address:
name: 'IP Address'
@@ -2006,4 +2103,4 @@ canbus:
condition:
lambda: 'return x[0] == 0x11;'
then:
light.toggle: living_room_lights
light.toggle: ${roomname}_lights

View File

@@ -45,6 +45,12 @@ ota:
logger:
level: DEBUG
deep_sleep:
run_duration: 20s
sleep_duration: 50s
wakeup_pin: GPIO39
wakeup_pin_mode: INVERT_WAKEUP
as3935_i2c:
irq_pin: GPIO12
@@ -64,6 +70,18 @@ sensor:
- platform: ble_rssi
service_uuid: '11223344-5566-7788-99aa-bbccddeeff00'
name: 'BLE Test Service 128'
- platform: senseair
id: senseair0
co2:
name: 'SenseAir CO2 Value'
on_value:
then:
- senseair.background_calibration: senseair0
- senseair.background_calibration_result: senseair0
- senseair.abc_get_period: senseair0
- senseair.abc_enable: senseair0
- senseair.abc_disable: senseair0
update_interval: 15s
- platform: ruuvitag
mac_address: FF:56:D3:2F:7D:E8
humidity:
@@ -181,6 +199,14 @@ sensor:
name: 'ATC Battery-Level'
battery_voltage:
name: 'ATC Battery-Voltage'
- platform: inkbird_ibsth1_mini
mac_address: 38:81:D7:0A:9C:11
temperature:
name: 'Inkbird IBS-TH1 Temperature'
humidity:
name: 'Inkbird IBS-TH1 Humidity'
battery_level:
name: 'Inkbird IBS-TH1 Battery Level'
time:
- platform: homeassistant
@@ -294,6 +320,8 @@ text_sensor:
- homeassistant.tag_scanned:
tag: 1234-abcd
- homeassistant.tag_scanned: 1234-abcd
- deep_sleep.enter:
sleep_duration: 30min
- platform: template
name: 'Template Text Sensor'
lambda: |-

View File

@@ -197,10 +197,6 @@ uart:
rx_pin: GPIO3
baud_rate: 115200
- id: adalight_uart
rx_pin: GPIO3
baud_rate: 115200
ota:
safe_mode: True
port: 3286
@@ -229,6 +225,8 @@ sensor:
name: 'VL53L0x Distance'
address: 0x29
update_interval: 60s
enable_pin: GPIO13
timeout: 200us
- platform: apds9960
type: clear
name: APDS9960 Clear
@@ -558,14 +556,14 @@ switch:
- platform: gpio
id: gpio_switch1
pin:
mcp23017: mcp23017_hub
mcp23xxx: mcp23017_hub
number: 0
mode: OUTPUT
interlock: &interlock [gpio_switch1, gpio_switch2, gpio_switch3]
- platform: gpio
id: gpio_switch2
pin:
mcp23008: mcp23008_hub
mcp23xxx: mcp23008_hub
number: 0
mode: OUTPUT
interlock: *interlock
@@ -812,7 +810,6 @@ light:
effects:
- wled:
- adalight:
uart_id: adalight_uart
- e131:
universe: 1
- platform: hbridge
@@ -842,6 +839,8 @@ sim800l:
- sim800l.send_sms:
message: 'hello you'
recipient: '+1234'
- sim800l.dial:
recipient: '+1234'
dfplayer:
on_finished_playback:
@@ -886,6 +885,25 @@ rf_bridge:
code: 'ABC123'
- rf_bridge.send_raw:
raw: 'AAA5070008001000ABC12355'
- http_request.get:
url: https://esphome.io
headers:
Content-Type: application/json
verify_ssl: false
- http_request.post:
url: https://esphome.io
verify_ssl: false
json:
key: !lambda |-
return id(version_sensor).state;
greeting: 'Hello World'
- http_request.send:
method: PUT
url: https://esphome.io
headers:
Content-Type: application/json
body: 'Some data'
verify_ssl: false
display:
- platform: max7219digit
@@ -897,3 +915,7 @@ display:
id: my_matrix
lambda: |-
it.printdigit("hello");
http_request:
useragent: esphome/device
timeout: 10s

View File

@@ -99,3 +99,64 @@ switch:
- platform: tuya
id: tuya_switch
switch_datapoint: 1
light:
- platform: fastled_clockless
id: led_matrix_32x8
name: "led_matrix_32x8"
chipset: WS2812B
pin: GPIO15
num_leds: 256
rgb_order: GRB
default_transition_length: 0s
color_correct: [50%, 50%, 50%]
display:
- platform: addressable_light
id: led_matrix_32x8_display
addressable_light_id: led_matrix_32x8
width: 32
height: 8
pixel_mapper: |-
if (x % 2 == 0) {
return (x * 8) + y;
}
return (x * 8) + (7 - y);
lambda: |-
Color red = Color(0xFF0000);
Color green = Color(0x00FF00);
Color blue = Color(0x0000FF);
it.rectangle(0, 0, it.get_width(), it.get_height(), red);
it.rectangle(1, 1, it.get_width()-2, it.get_height()-2, green);
it.rectangle(2, 2, it.get_width()-4, it.get_height()-4, blue);
it.rectangle(3, 3, it.get_width()-6, it.get_height()-6, red);
rotation: 0°
update_interval: 16ms
- platform: waveshare_epaper
cs_pin: GPIO23
dc_pin: GPIO23
busy_pin: GPIO23
reset_pin: GPIO23
model: 2.13in-ttgo-b1
full_update_every: 30
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
- platform: waveshare_epaper
cs_pin: GPIO23
dc_pin: GPIO23
busy_pin: GPIO23
reset_pin: GPIO23
model: 2.90in
full_update_every: 30
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());
- platform: waveshare_epaper
cs_pin: GPIO23
dc_pin: GPIO23
busy_pin: GPIO23
reset_pin: GPIO23
model: 2.90inv2
full_update_every: 30
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height());

View File

@@ -27,4 +27,3 @@ def fixture_path() -> Path:
Location of all fixture files.
"""
return here / "fixtures"

View File

@@ -12,4 +12,6 @@ def mac_addr_strings():
This consists of six strings representing integers [0..255],
without zero-padding, joined by dots.
"""
return st.builds("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}".format, *(6 * [st.integers(0, 255)]))
return st.builds(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}".format, *(6 * [st.integers(0, 255)])
)

View File

@@ -4,23 +4,75 @@ from esphome import codegen as cg
# Test interface remains the same.
@pytest.mark.parametrize("attr", (
# from cpp_generator
"Expression", "RawExpression", "RawStatement", "TemplateArguments",
"StructInitializer", "ArrayInitializer", "safe_exp", "Statement", "LineComment",
"progmem_array", "statement", "variable", "Pvariable", "new_Pvariable",
"add", "add_global", "add_library", "add_build_flag", "add_define",
"get_variable", "get_variable_with_full_id", "process_lambda", "is_template", "templatable", "MockObj",
"MockObjClass",
# from cpp_helpers
"gpio_pin_expression", "register_component", "build_registry_entry",
"build_registry_list", "extract_registry_entry_config", "register_parented",
"global_ns", "void", "nullptr", "float_", "double", "bool_", "int_", "std_ns", "std_string",
"std_vector", "uint8", "uint16", "uint32", "int32", "const_char_ptr", "NAN",
"esphome_ns", "App", "Nameable", "Component", "ComponentPtr",
# from cpp_types
"PollingComponent", "Application", "optional", "arduino_json_ns", "JsonObject",
"JsonObjectRef", "JsonObjectConstRef", "Controller", "GPIOPin"
))
@pytest.mark.parametrize(
"attr",
(
# from cpp_generator
"Expression",
"RawExpression",
"RawStatement",
"TemplateArguments",
"StructInitializer",
"ArrayInitializer",
"safe_exp",
"Statement",
"LineComment",
"progmem_array",
"statement",
"variable",
"Pvariable",
"new_Pvariable",
"add",
"add_global",
"add_library",
"add_build_flag",
"add_define",
"get_variable",
"get_variable_with_full_id",
"process_lambda",
"is_template",
"templatable",
"MockObj",
"MockObjClass",
# from cpp_helpers
"gpio_pin_expression",
"register_component",
"build_registry_entry",
"build_registry_list",
"extract_registry_entry_config",
"register_parented",
"global_ns",
"void",
"nullptr",
"float_",
"double",
"bool_",
"int_",
"std_ns",
"std_string",
"std_vector",
"uint8",
"uint16",
"uint32",
"int32",
"const_char_ptr",
"NAN",
"esphome_ns",
"App",
"Nameable",
"Component",
"ComponentPtr",
# from cpp_types
"PollingComponent",
"Application",
"optional",
"arduino_json_ns",
"JsonObject",
"JsonObjectRef",
"JsonObjectConstRef",
"Controller",
"GPIOPin",
),
)
def test_exists(attr):
assert hasattr(cg, attr)

View File

@@ -2,7 +2,7 @@ import pytest
import string
from hypothesis import given, example
from hypothesis.strategies import one_of, text, integers, booleans, builds
from hypothesis.strategies import one_of, text, integers, builds
from esphome import config_validation
from esphome.config_validation import Invalid
@@ -24,7 +24,7 @@ def test_alphanumeric__valid(value):
@pytest.mark.parametrize("value", ("£23", "Foo!"))
def test_alphanumeric__invalid(value):
with pytest.raises(Invalid):
actual = config_validation.alphanumeric(value)
config_validation.alphanumeric(value)
@given(value=text(alphabet=string.ascii_lowercase + string.digits + "_-"))
@@ -34,9 +34,7 @@ def test_valid_name__valid(value):
assert actual == value
@pytest.mark.parametrize("value", (
"foo bar", "FooBar", "foo::bar"
))
@pytest.mark.parametrize("value", ("foo bar", "FooBar", "foo::bar"))
def test_valid_name__invalid(value):
with pytest.raises(Invalid):
config_validation.valid_name(value)
@@ -49,9 +47,7 @@ def test_string__valid(value):
assert actual == str(value)
@pytest.mark.parametrize("value", (
{}, [], True, False, None
))
@pytest.mark.parametrize("value", ({}, [], True, False, None))
def test_string__invalid(value):
with pytest.raises(Invalid):
config_validation.string(value)
@@ -83,23 +79,17 @@ def test_icon__invalid():
config_validation.icon("foo")
@pytest.mark.parametrize("value", (
"True", "YES", "on", "enAblE", True
))
@pytest.mark.parametrize("value", ("True", "YES", "on", "enAblE", True))
def test_boolean__valid_true(value):
assert config_validation.boolean(value) is True
@pytest.mark.parametrize("value", (
"False", "NO", "off", "disAblE", False
))
@pytest.mark.parametrize("value", ("False", "NO", "off", "disAblE", False))
def test_boolean__valid_false(value):
assert config_validation.boolean(value) is False
@pytest.mark.parametrize("value", (
None, 1, 0, "foo"
))
@pytest.mark.parametrize("value", (None, 1, 0, "foo"))
def test_boolean__invalid(value):
with pytest.raises(Invalid, match="Expected boolean value"):
config_validation.boolean(value)

View File

@@ -8,13 +8,16 @@ from esphome import core, const
class TestHexInt:
@pytest.mark.parametrize("value, expected", (
(1, "0x01"),
(255, "0xFF"),
(128, "0x80"),
(256, "0x100"),
(-1, "-0x01"), # TODO: this currently fails
))
@pytest.mark.parametrize(
"value, expected",
(
(1, "0x01"),
(255, "0xFF"),
(128, "0x80"),
(256, "0x100"),
(-1, "-0x01"), # TODO: this currently fails
),
)
def test_str(self, value, expected):
target = core.HexInt(value)
@@ -68,18 +71,14 @@ class TestMACAddress:
assert actual.text == "0xDEADBEEF00FFULL"
@pytest.mark.parametrize("value", (
1, 2, -1, 0, 1.0, -1.0, 42.0009, -42.0009
))
@pytest.mark.parametrize("value", (1, 2, -1, 0, 1.0, -1.0, 42.0009, -42.0009))
def test_is_approximately_integer__in_range(value):
actual = core.is_approximately_integer(value)
assert actual is True
@pytest.mark.parametrize("value", (
42.01, -42.01, 1.5
))
@pytest.mark.parametrize("value", (42.01, -42.01, 1.5))
def test_is_approximately_integer__not_in_range(value):
actual = core.is_approximately_integer(value)
@@ -87,26 +86,29 @@ def test_is_approximately_integer__not_in_range(value):
class TestTimePeriod:
@pytest.mark.parametrize("kwargs, expected", (
({}, {}),
({"microseconds": 1}, {"microseconds": 1}),
({"microseconds": 1.0001}, {"microseconds": 1}),
({"milliseconds": 2}, {"milliseconds": 2}),
({"milliseconds": 2.0001}, {"milliseconds": 2}),
({"milliseconds": 2.01}, {"milliseconds": 2, "microseconds": 10}),
({"seconds": 3}, {"seconds": 3}),
({"seconds": 3.0001}, {"seconds": 3}),
({"seconds": 3.01}, {"seconds": 3, "milliseconds": 10}),
({"minutes": 4}, {"minutes": 4}),
({"minutes": 4.0001}, {"minutes": 4}),
({"minutes": 4.1}, {"minutes": 4, "seconds": 6}),
({"hours": 5}, {"hours": 5}),
({"hours": 5.0001}, {"hours": 5}),
({"hours": 5.1}, {"hours": 5, "minutes": 6}),
({"days": 6}, {"days": 6}),
({"days": 6.0001}, {"days": 6}),
({"days": 6.1}, {"days": 6, "hours": 2, "minutes": 24}),
))
@pytest.mark.parametrize(
"kwargs, expected",
(
({}, {}),
({"microseconds": 1}, {"microseconds": 1}),
({"microseconds": 1.0001}, {"microseconds": 1}),
({"milliseconds": 2}, {"milliseconds": 2}),
({"milliseconds": 2.0001}, {"milliseconds": 2}),
({"milliseconds": 2.01}, {"milliseconds": 2, "microseconds": 10}),
({"seconds": 3}, {"seconds": 3}),
({"seconds": 3.0001}, {"seconds": 3}),
({"seconds": 3.01}, {"seconds": 3, "milliseconds": 10}),
({"minutes": 4}, {"minutes": 4}),
({"minutes": 4.0001}, {"minutes": 4}),
({"minutes": 4.1}, {"minutes": 4, "seconds": 6}),
({"hours": 5}, {"hours": 5}),
({"hours": 5.0001}, {"hours": 5}),
({"hours": 5.1}, {"hours": 5, "minutes": 6}),
({"days": 6}, {"days": 6}),
({"days": 6.0001}, {"days": 6}),
({"days": 6.1}, {"days": 6, "hours": 2, "minutes": 24}),
),
)
def test_init(self, kwargs, expected):
target = core.TimePeriod(**kwargs)
@@ -118,26 +120,29 @@ class TestTimePeriod:
with pytest.raises(ValueError, match="Maximum precision is microseconds"):
core.TimePeriod(microseconds=1.1)
@pytest.mark.parametrize("kwargs, expected", (
({}, "0s"),
({"microseconds": 1}, "1us"),
({"microseconds": 1.0001}, "1us"),
({"milliseconds": 2}, "2ms"),
({"milliseconds": 2.0001}, "2ms"),
({"milliseconds": 2.01}, "2010us"),
({"seconds": 3}, "3s"),
({"seconds": 3.0001}, "3s"),
({"seconds": 3.01}, "3010ms"),
({"minutes": 4}, "4min"),
({"minutes": 4.0001}, "4min"),
({"minutes": 4.1}, "246s"),
({"hours": 5}, "5h"),
({"hours": 5.0001}, "5h"),
({"hours": 5.1}, "306min"),
({"days": 6}, "6d"),
({"days": 6.0001}, "6d"),
({"days": 6.1}, "8784min"),
))
@pytest.mark.parametrize(
"kwargs, expected",
(
({}, "0s"),
({"microseconds": 1}, "1us"),
({"microseconds": 1.0001}, "1us"),
({"milliseconds": 2}, "2ms"),
({"milliseconds": 2.0001}, "2ms"),
({"milliseconds": 2.01}, "2010us"),
({"seconds": 3}, "3s"),
({"seconds": 3.0001}, "3s"),
({"seconds": 3.01}, "3010ms"),
({"minutes": 4}, "4min"),
({"minutes": 4.0001}, "4min"),
({"minutes": 4.1}, "246s"),
({"hours": 5}, "5h"),
({"hours": 5.0001}, "5h"),
({"hours": 5.1}, "306min"),
({"days": 6}, "6d"),
({"days": 6.0001}, "6d"),
({"days": 6.1}, "8784min"),
),
)
def test_str(self, kwargs, expected):
target = core.TimePeriod(**kwargs)
@@ -145,61 +150,59 @@ class TestTimePeriod:
assert actual == expected
@pytest.mark.parametrize("comparison, other, expected", (
("__eq__", core.TimePeriod(microseconds=900), False),
("__eq__", core.TimePeriod(milliseconds=1), True),
("__eq__", core.TimePeriod(microseconds=1100), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
("__ne__", core.TimePeriod(microseconds=900), True),
("__ne__", core.TimePeriod(milliseconds=1), False),
("__ne__", core.TimePeriod(microseconds=1100), True),
("__ne__", 1000, NotImplemented),
("__ne__", "1000", NotImplemented),
("__ne__", True, NotImplemented),
("__ne__", object(), NotImplemented),
("__ne__", None, NotImplemented),
("__lt__", core.TimePeriod(microseconds=900), False),
("__lt__", core.TimePeriod(milliseconds=1), False),
("__lt__", core.TimePeriod(microseconds=1100), True),
("__lt__", 1000, NotImplemented),
("__lt__", "1000", NotImplemented),
("__lt__", True, NotImplemented),
("__lt__", object(), NotImplemented),
("__lt__", None, NotImplemented),
("__gt__", core.TimePeriod(microseconds=900), True),
("__gt__", core.TimePeriod(milliseconds=1), False),
("__gt__", core.TimePeriod(microseconds=1100), False),
("__gt__", 1000, NotImplemented),
("__gt__", "1000", NotImplemented),
("__gt__", True, NotImplemented),
("__gt__", object(), NotImplemented),
("__gt__", None, NotImplemented),
("__le__", core.TimePeriod(microseconds=900), False),
("__le__", core.TimePeriod(milliseconds=1), True),
("__le__", core.TimePeriod(microseconds=1100), True),
("__le__", 1000, NotImplemented),
("__le__", "1000", NotImplemented),
("__le__", True, NotImplemented),
("__le__", object(), NotImplemented),
("__le__", None, NotImplemented),
("__ge__", core.TimePeriod(microseconds=900), True),
("__ge__", core.TimePeriod(milliseconds=1), True),
("__ge__", core.TimePeriod(microseconds=1100), False),
("__ge__", 1000, NotImplemented),
("__ge__", "1000", NotImplemented),
("__ge__", True, NotImplemented),
("__ge__", object(), NotImplemented),
("__ge__", None, NotImplemented),
))
@pytest.mark.parametrize(
"comparison, other, expected",
(
("__eq__", core.TimePeriod(microseconds=900), False),
("__eq__", core.TimePeriod(milliseconds=1), True),
("__eq__", core.TimePeriod(microseconds=1100), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
("__ne__", core.TimePeriod(microseconds=900), True),
("__ne__", core.TimePeriod(milliseconds=1), False),
("__ne__", core.TimePeriod(microseconds=1100), True),
("__ne__", 1000, NotImplemented),
("__ne__", "1000", NotImplemented),
("__ne__", True, NotImplemented),
("__ne__", object(), NotImplemented),
("__ne__", None, NotImplemented),
("__lt__", core.TimePeriod(microseconds=900), False),
("__lt__", core.TimePeriod(milliseconds=1), False),
("__lt__", core.TimePeriod(microseconds=1100), True),
("__lt__", 1000, NotImplemented),
("__lt__", "1000", NotImplemented),
("__lt__", True, NotImplemented),
("__lt__", object(), NotImplemented),
("__lt__", None, NotImplemented),
("__gt__", core.TimePeriod(microseconds=900), True),
("__gt__", core.TimePeriod(milliseconds=1), False),
("__gt__", core.TimePeriod(microseconds=1100), False),
("__gt__", 1000, NotImplemented),
("__gt__", "1000", NotImplemented),
("__gt__", True, NotImplemented),
("__gt__", object(), NotImplemented),
("__gt__", None, NotImplemented),
("__le__", core.TimePeriod(microseconds=900), False),
("__le__", core.TimePeriod(milliseconds=1), True),
("__le__", core.TimePeriod(microseconds=1100), True),
("__le__", 1000, NotImplemented),
("__le__", "1000", NotImplemented),
("__le__", True, NotImplemented),
("__le__", object(), NotImplemented),
("__le__", None, NotImplemented),
("__ge__", core.TimePeriod(microseconds=900), True),
("__ge__", core.TimePeriod(milliseconds=1), True),
("__ge__", core.TimePeriod(microseconds=1100), False),
("__ge__", 1000, NotImplemented),
("__ge__", "1000", NotImplemented),
("__ge__", True, NotImplemented),
("__ge__", object(), NotImplemented),
("__ge__", None, NotImplemented),
),
)
def test_comparison(self, comparison, other, expected):
target = core.TimePeriod(microseconds=1000)
@@ -238,19 +241,19 @@ class TestLambda:
"it.strftime(64, 0, ",
"my_font",
"",
", TextAlign::TOP_CENTER, \"%H:%M:%S\", ",
', TextAlign::TOP_CENTER, "%H:%M:%S", ',
"esptime",
".",
"now());\nit.printf(64, 16, ",
"my_font2",
"",
", TextAlign::TOP_CENTER, \"%.1f°C (%.1f%%)\", ",
', TextAlign::TOP_CENTER, "%.1f°C (%.1f%%)", ',
"office_tmp",
".",
"state, ",
"office_hmd",
".",
"state);\n \nint x = 4; "
"state);\n \nint x = 4; ",
]
def test_requires_ids(self):
@@ -296,24 +299,33 @@ class TestID:
def target(self):
return core.ID(None, is_declaration=True, type="binary_sensor::Example")
@pytest.mark.parametrize("id, is_manual, expected", (
("foo", None, True),
(None, None, False),
("foo", True, True),
("foo", False, False),
(None, True, True),
))
@pytest.mark.parametrize(
"id, is_manual, expected",
(
("foo", None, True),
(None, None, False),
("foo", True, True),
("foo", False, False),
(None, True, True),
),
)
def test_init__resolve_is_manual(self, id, is_manual, expected):
target = core.ID(id, is_manual=is_manual)
assert target.is_manual == expected
@pytest.mark.parametrize("registered_ids, expected", (
([], "binary_sensor_example"),
(["binary_sensor_example"], "binary_sensor_example_2"),
(["foo"], "binary_sensor_example"),
(["binary_sensor_example", "foo", "binary_sensor_example_2"], "binary_sensor_example_3"),
))
@pytest.mark.parametrize(
"registered_ids, expected",
(
([], "binary_sensor_example"),
(["binary_sensor_example"], "binary_sensor_example_2"),
(["foo"], "binary_sensor_example"),
(
["binary_sensor_example", "foo", "binary_sensor_example_2"],
"binary_sensor_example_3",
),
),
)
def test_resolve(self, target, registered_ids, expected):
actual = target.resolve(registered_ids)
@@ -326,18 +338,23 @@ class TestID:
actual = target.copy()
assert actual is not target
assert all(getattr(actual, n) == getattr(target, n)
for n in ("id", "is_declaration", "type", "is_manual"))
assert all(
getattr(actual, n) == getattr(target, n)
for n in ("id", "is_declaration", "type", "is_manual")
)
@pytest.mark.parametrize("comparison, other, expected", (
("__eq__", core.ID(id="foo"), True),
("__eq__", core.ID(id="bar"), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
))
@pytest.mark.parametrize(
"comparison, other, expected",
(
("__eq__", core.ID(id="foo"), True),
("__eq__", core.ID(id="bar"), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
),
)
def test_comparison(self, comparison, other, expected):
target = core.ID(id="foo")
@@ -384,14 +401,17 @@ class TestDocumentRange:
class TestDefine:
@pytest.mark.parametrize("name, value, prop, expected", (
("ANSWER", None, "as_build_flag", "-DANSWER"),
("ANSWER", None, "as_macro", "#define ANSWER"),
("ANSWER", None, "as_tuple", ("ANSWER", None)),
("ANSWER", 42, "as_build_flag", "-DANSWER=42"),
("ANSWER", 42, "as_macro", "#define ANSWER 42"),
("ANSWER", 42, "as_tuple", ("ANSWER", 42)),
))
@pytest.mark.parametrize(
"name, value, prop, expected",
(
("ANSWER", None, "as_build_flag", "-DANSWER"),
("ANSWER", None, "as_macro", "#define ANSWER"),
("ANSWER", None, "as_tuple", ("ANSWER", None)),
("ANSWER", 42, "as_build_flag", "-DANSWER=42"),
("ANSWER", 42, "as_macro", "#define ANSWER 42"),
("ANSWER", 42, "as_tuple", ("ANSWER", 42)),
),
)
def test_properties(self, name, value, prop, expected):
target = core.Define(name, value)
@@ -399,18 +419,21 @@ class TestDefine:
assert actual == expected
@pytest.mark.parametrize("comparison, other, expected", (
("__eq__", core.Define(name="FOO", value=42), True),
("__eq__", core.Define(name="FOO", value=13), False),
("__eq__", core.Define(name="FOO"), False),
("__eq__", core.Define(name="BAR", value=42), False),
("__eq__", core.Define(name="BAR"), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
))
@pytest.mark.parametrize(
"comparison, other, expected",
(
("__eq__", core.Define(name="FOO", value=42), True),
("__eq__", core.Define(name="FOO", value=13), False),
("__eq__", core.Define(name="FOO"), False),
("__eq__", core.Define(name="BAR", value=42), False),
("__eq__", core.Define(name="BAR"), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
),
)
def test_comparison(self, comparison, other, expected):
target = core.Define(name="FOO", value=42)
@@ -420,12 +443,15 @@ class TestDefine:
class TestLibrary:
@pytest.mark.parametrize("name, value, prop, expected", (
("mylib", None, "as_lib_dep", "mylib"),
("mylib", None, "as_tuple", ("mylib", None)),
("mylib", "1.2.3", "as_lib_dep", "mylib@1.2.3"),
("mylib", "1.2.3", "as_tuple", ("mylib", "1.2.3")),
))
@pytest.mark.parametrize(
"name, value, prop, expected",
(
("mylib", None, "as_lib_dep", "mylib"),
("mylib", None, "as_tuple", ("mylib", None)),
("mylib", "1.2.3", "as_lib_dep", "mylib@1.2.3"),
("mylib", "1.2.3", "as_tuple", ("mylib", "1.2.3")),
),
)
def test_properties(self, name, value, prop, expected):
target = core.Library(name, value)
@@ -433,16 +459,19 @@ class TestLibrary:
assert actual == expected
@pytest.mark.parametrize("comparison, other, expected", (
("__eq__", core.Library(name="libfoo", version="1.2.3"), True),
("__eq__", core.Library(name="libfoo", version="1.2.4"), False),
("__eq__", core.Library(name="libbar", version="1.2.3"), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
))
@pytest.mark.parametrize(
"comparison, other, expected",
(
("__eq__", core.Library(name="libfoo", version="1.2.3"), True),
("__eq__", core.Library(name="libfoo", version="1.2.4"), False),
("__eq__", core.Library(name="libbar", version="1.2.3"), False),
("__eq__", 1000, NotImplemented),
("__eq__", "1000", NotImplemented),
("__eq__", True, NotImplemented),
("__eq__", object(), NotImplemented),
("__eq__", None, NotImplemented),
),
)
def test_comparison(self, comparison, other, expected):
target = core.Library(name="libfoo", version="1.2.3")

View File

@@ -9,18 +9,18 @@ from esphome import cpp_types as ct
class TestExpressions:
@pytest.mark.parametrize("target, expected", (
(cg.RawExpression("foo && bar"), "foo && bar"),
(cg.AssignmentExpression(None, None, "foo", "bar", None), 'foo = "bar"'),
(cg.AssignmentExpression(ct.float_, "*", "foo", 1, None), 'float *foo = 1'),
(cg.AssignmentExpression(ct.float_, "", "foo", 1, None), 'float foo = 1'),
(cg.VariableDeclarationExpression(ct.int32, "*", "foo"), "int32_t *foo"),
(cg.VariableDeclarationExpression(ct.int32, "", "foo"), "int32_t foo"),
(cg.ParameterExpression(ct.std_string, "foo"), "std::string foo"),
))
@pytest.mark.parametrize(
"target, expected",
(
(cg.RawExpression("foo && bar"), "foo && bar"),
(cg.AssignmentExpression(None, None, "foo", "bar", None), 'foo = "bar"'),
(cg.AssignmentExpression(ct.float_, "*", "foo", 1, None), "float *foo = 1"),
(cg.AssignmentExpression(ct.float_, "", "foo", 1, None), "float foo = 1"),
(cg.VariableDeclarationExpression(ct.int32, "*", "foo"), "int32_t *foo"),
(cg.VariableDeclarationExpression(ct.int32, "", "foo"), "int32_t foo"),
(cg.ParameterExpression(ct.std_string, "foo"), "std::string foo"),
),
)
def test_str__simple(self, target: cg.Expression, expected: str):
actual = str(target)
@@ -67,10 +67,7 @@ class TestTemplateArguments:
class TestCallExpression:
def test_str__no_template_args(self):
target = cg.CallExpression(
cg.RawExpression("my_function"),
1, "2", False
)
target = cg.CallExpression(cg.RawExpression("my_function"), 1, "2", False)
actual = str(target)
@@ -80,7 +77,9 @@ class TestCallExpression:
target = cg.CallExpression(
cg.RawExpression("my_function"),
cg.TemplateArguments(int, float),
1, "2", False
1,
"2",
False,
)
actual = str(target)
@@ -100,36 +99,32 @@ class TestStructInitializer:
actual = str(target)
assert actual == 'foo::MyStruct{\n' \
' .state = "on",\n' \
' .min_length = 1,\n' \
' .max_length = 5,\n' \
'}'
assert (
actual == "foo::MyStruct{\n"
' .state = "on",\n'
" .min_length = 1,\n"
" .max_length = 5,\n"
"}"
)
class TestArrayInitializer:
def test_str__empty(self):
target = cg.ArrayInitializer(
None, None
)
target = cg.ArrayInitializer(None, None)
actual = str(target)
assert actual == "{}"
def test_str__not_multiline(self):
target = cg.ArrayInitializer(
1, 2, 3, 4
)
target = cg.ArrayInitializer(1, 2, 3, 4)
actual = str(target)
assert actual == "{1, 2, 3, 4}"
def test_str__multiline(self):
target = cg.ArrayInitializer(
1, 2, 3, 4, multiline=True
)
target = cg.ArrayInitializer(1, 2, 3, 4, multiline=True)
actual = str(target)
@@ -169,7 +164,7 @@ class TestLambdaExpression:
def test_str__with_return(self):
target = cg.LambdaExpression(
("return (foo == 5) && (bar < 10));", ),
("return (foo == 5) && (bar < 10));",),
cg.ParameterListExpression((int, "foo"), (float, "bar")),
"=",
bool,
@@ -185,27 +180,26 @@ class TestLambdaExpression:
class TestLiterals:
@pytest.mark.parametrize("target, expected", (
(cg.StringLiteral("foo"), '"foo"'),
(cg.IntLiteral(0), "0"),
(cg.IntLiteral(42), "42"),
(cg.IntLiteral(4304967295), "4304967295ULL"),
(cg.IntLiteral(2150483647), "2150483647UL"),
(cg.IntLiteral(-2150083647), "-2150083647LL"),
(cg.BoolLiteral(True), "true"),
(cg.BoolLiteral(False), "false"),
(cg.HexIntLiteral(0), "0x00"),
(cg.HexIntLiteral(42), "0x2A"),
(cg.HexIntLiteral(682), "0x2AA"),
(cg.FloatLiteral(0.0), "0.0f"),
(cg.FloatLiteral(4.2), "4.2f"),
(cg.FloatLiteral(1.23456789), "1.23456789f"),
(cg.FloatLiteral(math.nan), "NAN"),
))
@pytest.mark.parametrize(
"target, expected",
(
(cg.StringLiteral("foo"), '"foo"'),
(cg.IntLiteral(0), "0"),
(cg.IntLiteral(42), "42"),
(cg.IntLiteral(4304967295), "4304967295ULL"),
(cg.IntLiteral(2150483647), "2150483647UL"),
(cg.IntLiteral(-2150083647), "-2150083647LL"),
(cg.BoolLiteral(True), "true"),
(cg.BoolLiteral(False), "false"),
(cg.HexIntLiteral(0), "0x00"),
(cg.HexIntLiteral(42), "0x2A"),
(cg.HexIntLiteral(682), "0x2AA"),
(cg.FloatLiteral(0.0), "0.0f"),
(cg.FloatLiteral(4.2), "4.2f"),
(cg.FloatLiteral(1.23456789), "1.23456789f"),
(cg.FloatLiteral(math.nan), "NAN"),
),
)
def test_str__simple(self, target: cg.Literal, expected: str):
actual = str(target)
@@ -216,7 +210,9 @@ FAKE_ENUM_VALUE = cg.EnumValue()
FAKE_ENUM_VALUE.enum_value = "foo"
@pytest.mark.parametrize("obj, expected_type", (
@pytest.mark.parametrize(
"obj, expected_type",
(
(cg.RawExpression("foo"), cg.RawExpression),
(FAKE_ENUM_VALUE, cg.StringLiteral),
(True, cg.BoolLiteral),
@@ -230,49 +226,59 @@ FAKE_ENUM_VALUE.enum_value = "foo"
(cg.TimePeriodMinutes(minutes=42), cg.IntLiteral),
((1, 2, 3), cg.ArrayInitializer),
([1, 2, 3], cg.ArrayInitializer),
))
),
)
def test_safe_exp__allowed_values(obj, expected_type):
actual = cg.safe_exp(obj)
assert isinstance(actual, expected_type)
@pytest.mark.parametrize("obj, expected_type", (
@pytest.mark.parametrize(
"obj, expected_type",
(
(bool, ct.bool_),
(int, ct.int32),
(float, ct.float_),
))
),
)
def test_safe_exp__allowed_types(obj, expected_type):
actual = cg.safe_exp(obj)
assert actual is expected_type
@pytest.mark.parametrize("obj, expected_error", (
@pytest.mark.parametrize(
"obj, expected_error",
(
(cg.ID("foo"), "Object foo is an ID."),
((x for x in "foo"), r"Object <.*> is a coroutine."),
(None, "Object is not an expression"),
))
),
)
def test_safe_exp__invalid_values(obj, expected_error):
with pytest.raises(ValueError, match=expected_error):
cg.safe_exp(obj)
class TestStatements:
@pytest.mark.parametrize("target, expected", (
(cg.RawStatement("foo && bar"), "foo && bar"),
(cg.ExpressionStatement("foo"), '"foo";'),
(cg.ExpressionStatement(42), '42;'),
(cg.LineComment("The point of foo is..."), "// The point of foo is..."),
(cg.LineComment("Help help\nI'm being repressed"), "// Help help\n// I'm being repressed"),
@pytest.mark.parametrize(
"target, expected",
(
cg.ProgmemAssignmentExpression(ct.uint16, "foo", "bar", None),
'static const uint16_t foo[] PROGMEM = "bar"'
)
))
(cg.RawStatement("foo && bar"), "foo && bar"),
(cg.ExpressionStatement("foo"), '"foo";'),
(cg.ExpressionStatement(42), "42;"),
(cg.LineComment("The point of foo is..."), "// The point of foo is..."),
(
cg.LineComment("Help help\nI'm being repressed"),
"// Help help\n// I'm being repressed",
),
(
cg.ProgmemAssignmentExpression(ct.uint16, "foo", "bar", None),
'static const uint16_t foo[] PROGMEM = "bar"',
),
),
)
def test_str__simple(self, target: cg.Statement, expected: str):
actual = str(target)

View File

@@ -15,11 +15,9 @@ def test_gpio_pin_expression__conf_is_none(monkeypatch):
def test_gpio_pin_expression__new_pin(monkeypatch):
target = ch.gpio_pin_expression({
const.CONF_NUMBER: 42,
const.CONF_MODE: "input",
const.CONF_INVERTED: False
})
target = ch.gpio_pin_expression(
{const.CONF_NUMBER: 42, const.CONF_MODE: "input", const.CONF_INVERTED: False}
)
actual = next(target)
@@ -71,10 +69,13 @@ def test_register_component__with_setup_priority(monkeypatch):
add_mock = Mock()
monkeypatch.setattr(ch, "add", add_mock)
target = ch.register_component(var, {
const.CONF_SETUP_PRIORITY: "123",
const.CONF_UPDATE_INTERVAL: "456",
})
target = ch.register_component(
var,
{
const.CONF_SETUP_PRIORITY: "123",
const.CONF_UPDATE_INTERVAL: "456",
},
)
actual = next(target)

View File

@@ -6,69 +6,89 @@ from hypothesis.provisional import ip_addresses
from esphome import helpers
@pytest.mark.parametrize("preferred_string, current_strings, expected", (
("foo", [], "foo"),
# TODO: Should this actually start at 1?
("foo", ["foo"], "foo_2"),
("foo", ("foo",), "foo_2"),
("foo", ("foo", "foo_2"), "foo_3"),
("foo", ("foo", "foo_2", "foo_2"), "foo_3"),
))
@pytest.mark.parametrize(
"preferred_string, current_strings, expected",
(
("foo", [], "foo"),
# TODO: Should this actually start at 1?
("foo", ["foo"], "foo_2"),
("foo", ("foo",), "foo_2"),
("foo", ("foo", "foo_2"), "foo_3"),
("foo", ("foo", "foo_2", "foo_2"), "foo_3"),
),
)
def test_ensure_unique_string(preferred_string, current_strings, expected):
actual = helpers.ensure_unique_string(preferred_string, current_strings)
assert actual == expected
@pytest.mark.parametrize("text, expected", (
("foo", "foo"),
("foo\nbar", "foo\nbar"),
("foo\nbar\neek", "foo\n bar\neek"),
))
@pytest.mark.parametrize(
"text, expected",
(
("foo", "foo"),
("foo\nbar", "foo\nbar"),
("foo\nbar\neek", "foo\n bar\neek"),
),
)
def test_indent_all_but_first_and_last(text, expected):
actual = helpers.indent_all_but_first_and_last(text)
assert actual == expected
@pytest.mark.parametrize("text, expected", (
("foo", [" foo"]),
("foo\nbar", [" foo", " bar"]),
("foo\nbar\neek", [" foo", " bar", " eek"]),
))
@pytest.mark.parametrize(
"text, expected",
(
("foo", [" foo"]),
("foo\nbar", [" foo", " bar"]),
("foo\nbar\neek", [" foo", " bar", " eek"]),
),
)
def test_indent_list(text, expected):
actual = helpers.indent_list(text)
assert actual == expected
@pytest.mark.parametrize("text, expected", (
("foo", " foo"),
("foo\nbar", " foo\n bar"),
("foo\nbar\neek", " foo\n bar\n eek"),
))
@pytest.mark.parametrize(
"text, expected",
(
("foo", " foo"),
("foo\nbar", " foo\n bar"),
("foo\nbar\neek", " foo\n bar\n eek"),
),
)
def test_indent(text, expected):
actual = helpers.indent(text)
assert actual == expected
@pytest.mark.parametrize("string, expected", (
("foo", '"foo"'),
("foo\nbar", '"foo\\012bar"'),
("foo\\bar", '"foo\\134bar"'),
('foo "bar"', '"foo \\042bar\\042"'),
('foo 🐍', '"foo \\360\\237\\220\\215"'),
))
@pytest.mark.parametrize(
"string, expected",
(
("foo", '"foo"'),
("foo\nbar", '"foo\\012bar"'),
("foo\\bar", '"foo\\134bar"'),
('foo "bar"', '"foo \\042bar\\042"'),
("foo 🐍", '"foo \\360\\237\\220\\215"'),
),
)
def test_cpp_string_escape(string, expected):
actual = helpers.cpp_string_escape(string)
assert actual == expected
@pytest.mark.parametrize("host", (
"127.0.0", "localhost", "127.0.0.b",
))
@pytest.mark.parametrize(
"host",
(
"127.0.0",
"localhost",
"127.0.0.b",
),
)
def test_is_ip_address__invalid(host):
actual = helpers.is_ip_address(host)
@@ -82,13 +102,16 @@ def test_is_ip_address__valid(value):
assert actual is True
@pytest.mark.parametrize("var, value, default, expected", (
("FOO", None, False, False),
("FOO", None, True, True),
("FOO", "", False, False),
("FOO", "Yes", False, True),
("FOO", "123", False, True),
))
@pytest.mark.parametrize(
"var, value, default, expected",
(
("FOO", None, False, False),
("FOO", None, True, True),
("FOO", "", False, False),
("FOO", "Yes", False, True),
("FOO", "123", False, True),
),
)
def test_get_bool_env(monkeypatch, var, value, default, expected):
if value is None:
monkeypatch.delenv(var, raising=False)
@@ -100,10 +123,7 @@ def test_get_bool_env(monkeypatch, var, value, default, expected):
assert actual == expected
@pytest.mark.parametrize("value, expected", (
(None, False),
("Yes", True)
))
@pytest.mark.parametrize("value, expected", ((None, False), ("Yes", True)))
def test_is_hassio(monkeypatch, value, expected):
if value is None:
monkeypatch.delenv("ESPHOME_IS_HASSIO", raising=False)
@@ -185,20 +205,23 @@ class Test_copy_file_if_changed:
assert src.read_text() == dst.read_text()
@pytest.mark.parametrize("file1, file2, expected", (
# Same file
("file-a.txt", "file-a.txt", True),
# Different files, different size
("file-a.txt", "file-b_1.txt", False),
# Different files, same size
("file-a.txt", "file-c.txt", False),
# Same files
("file-b_1.txt", "file-b_2.txt", True),
# Not a file
("file-a.txt", "", False),
# File doesn't exist
("file-a.txt", "file-d.txt", False),
))
@pytest.mark.parametrize(
"file1, file2, expected",
(
# Same file
("file-a.txt", "file-a.txt", True),
# Different files, different size
("file-a.txt", "file-b_1.txt", False),
# Different files, same size
("file-a.txt", "file-c.txt", False),
# Same files
("file-b_1.txt", "file-b_2.txt", True),
# Not a file
("file-a.txt", "", False),
# File doesn't exist
("file-a.txt", "file-d.txt", False),
),
)
def test_file_compare(fixture_path, file1, file2, expected):
path1 = fixture_path / "helpers" / file1
path2 = fixture_path / "helpers" / file2

View File

@@ -15,12 +15,12 @@ from esphome import pins
MOCK_ESP8266_BOARD_ID = "_mock_esp8266"
MOCK_ESP8266_PINS = {'X0': 16, 'X1': 5, 'X2': 4, 'LED': 2}
MOCK_ESP8266_PINS = {"X0": 16, "X1": 5, "X2": 4, "LED": 2}
MOCK_ESP8266_BOARD_ALIAS_ID = "_mock_esp8266_alias"
MOCK_ESP8266_FLASH_SIZE = pins.FLASH_SIZE_2_MB
MOCK_ESP32_BOARD_ID = "_mock_esp32"
MOCK_ESP32_PINS = {'Y0': 12, 'Y1': 8, 'Y2': 3, 'LED': 9, "A0": 8}
MOCK_ESP32_PINS = {"Y0": 12, "Y1": 8, "Y2": 3, "LED": 9, "A0": 8}
MOCK_ESP32_BOARD_ALIAS_ID = "_mock_esp32_alias"
UNKNOWN_PLATFORM = "STM32"
@@ -68,10 +68,13 @@ def core_esp32(core):
class Test_lookup_pin:
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
("X1", 5),
("MOSI", 13),
))
),
)
def test_valid_esp8266_pin(self, core_esp8266, value, expected):
actual = pins._lookup_pin(value)
@@ -84,11 +87,14 @@ class Test_lookup_pin:
assert actual == 4
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
("Y1", 8),
("A0", 8),
("MOSI", 23),
))
),
)
def test_valid_esp32_pin(self, core_esp32, value, expected):
actual = pins._lookup_pin(value)
@@ -102,7 +108,9 @@ class Test_lookup_pin:
assert actual == 3
def test_invalid_pin(self, core_esp8266):
with pytest.raises(Invalid, match="Cannot resolve pin name 'X42' for board _mock_esp8266."):
with pytest.raises(
Invalid, match="Cannot resolve pin name 'X42' for board _mock_esp8266."
):
pins._lookup_pin("X42")
def test_unsupported_platform(self, core):
@@ -113,13 +121,16 @@ class Test_lookup_pin:
class Test_translate_pin:
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
(2, 2),
("3", 3),
("GPIO4", 4),
("TX", 1),
("Y0", 12),
))
),
)
def test_valid_values(self, core_esp32, value, expected):
actual = pins._translate_pin(value)
@@ -137,7 +148,9 @@ class Test_validate_gpio_pin:
assert actual == 22
@pytest.mark.parametrize("value, match", (
@pytest.mark.parametrize(
"value, match",
(
(-1, "ESP32: Invalid pin number: -1"),
(40, "ESP32: Invalid pin number: 40"),
(6, "This pin cannot be used on ESP32s and"),
@@ -150,7 +163,8 @@ class Test_validate_gpio_pin:
(29, "The pin GPIO29 is not usable on ESP32s"),
(30, "The pin GPIO30 is not usable on ESP32s"),
(31, "The pin GPIO31 is not usable on ESP32s"),
))
),
)
def test_esp32_invalid_pin(self, core_esp32, value, match):
with pytest.raises(Invalid, match=match):
pins.validate_gpio_pin(value)
@@ -168,14 +182,17 @@ class Test_validate_gpio_pin:
assert actual == 12
@pytest.mark.parametrize("value, match", (
@pytest.mark.parametrize(
"value, match",
(
(-1, "ESP8266: Invalid pin number: -1"),
(18, "ESP8266: Invalid pin number: 18"),
(6, "This pin cannot be used on ESP8266s and"),
(7, "This pin cannot be used on ESP8266s and"),
(8, "This pin cannot be used on ESP8266s and"),
(11, "This pin cannot be used on ESP8266s and"),
))
),
)
def test_esp8266_invalid_pin(self, core_esp8266, value, match):
with pytest.raises(Invalid, match=match):
pins.validate_gpio_pin(value)
@@ -196,18 +213,19 @@ class Test_validate_gpio_pin:
class Test_input_pin:
@pytest.mark.parametrize("value, expected", (
("X0", 16),
))
@pytest.mark.parametrize("value, expected", (("X0", 16),))
def test_valid_esp8266_values(self, core_esp8266, value, expected):
actual = pins.input_pin(value)
assert actual == expected
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
("Y0", 12),
(17, 17),
))
),
)
def test_valid_esp32_values(self, core_esp32, value, expected):
actual = pins.input_pin(value)
@@ -226,18 +244,19 @@ class Test_input_pin:
class Test_input_pullup_pin:
@pytest.mark.parametrize("value, expected", (
("X0", 16),
))
@pytest.mark.parametrize("value, expected", (("X0", 16),))
def test_valid_esp8266_values(self, core_esp8266, value, expected):
actual = pins.input_pullup_pin(value)
assert actual == expected
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
("Y0", 12),
(17, 17),
))
),
)
def test_valid_esp32_values(self, core_esp32, value, expected):
actual = pins.input_pullup_pin(value)
@@ -256,18 +275,19 @@ class Test_input_pullup_pin:
class Test_output_pin:
@pytest.mark.parametrize("value, expected", (
("X0", 16),
))
@pytest.mark.parametrize("value, expected", (("X0", 16),))
def test_valid_esp8266_values(self, core_esp8266, value, expected):
actual = pins.output_pin(value)
assert actual == expected
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
("Y0", 12),
(17, 17),
))
),
)
def test_valid_esp32_values(self, core_esp32, value, expected):
actual = pins.output_pin(value)
@@ -291,18 +311,19 @@ class Test_output_pin:
class Test_analog_pin:
@pytest.mark.parametrize("value, expected", (
(17, 17),
))
@pytest.mark.parametrize("value, expected", ((17, 17),))
def test_valid_esp8266_values(self, core_esp8266, value, expected):
actual = pins.analog_pin(value)
assert actual == expected
@pytest.mark.parametrize("value, expected", (
@pytest.mark.parametrize(
"value, expected",
(
(32, 32),
(39, 39),
))
),
)
def test_valid_esp32_values(self, core_esp32, value, expected):
actual = pins.analog_pin(value)

View File

@@ -1,4 +1,4 @@
""" Tests for the wizard.py file """
"""Tests for the wizard.py file."""
import esphome.wizard as wz
import pytest
@@ -14,7 +14,7 @@ def default_config():
"board": "test_board",
"ssid": "test_ssid",
"psk": "test_psk",
"password": ""
"password": "",
}
@@ -35,13 +35,13 @@ def test_sanitize_quotes_replaces_with_escaped_char():
The sanitize_quotes function should replace double quotes with their escaped equivalents
"""
# Given
input_str = "\"key\": \"value\""
input_str = '"key": "value"'
# When
output_str = wz.sanitize_double_quotes(input_str)
# Then
assert output_str == "\\\"key\\\": \\\"value\\\""
assert output_str == '\\"key\\": \\"value\\"'
def test_config_file_fallback_ap_includes_descriptive_name(default_config):
@@ -55,7 +55,7 @@ def test_config_file_fallback_ap_includes_descriptive_name(default_config):
config = wz.wizard_file(**default_config)
# Then
assert f"ssid: \"Test Node Fallback Hotspot\"" in config
assert 'ssid: "Test Node Fallback Hotspot"' in config
def test_config_file_fallback_ap_name_less_than_32_chars(default_config):
@@ -70,7 +70,7 @@ def test_config_file_fallback_ap_name_less_than_32_chars(default_config):
config = wz.wizard_file(**default_config)
# Then
assert f"ssid: \"A Very Long Name For This Node\"" in config
assert 'ssid: "A Very Long Name For This Node"' in config
def test_config_file_should_include_ota(default_config):
@@ -115,7 +115,9 @@ def test_wizard_write_sets_platform(default_config, tmp_path, monkeypatch):
assert f"platform: {default_config['platform']}" in generated_config
def test_wizard_write_defaults_platform_from_board_esp8266(default_config, tmp_path, monkeypatch):
def test_wizard_write_defaults_platform_from_board_esp8266(
default_config, tmp_path, monkeypatch
):
"""
If the platform is not explicitly set, use "ESP8266" if the board is one of the ESP8266 boards
"""
@@ -133,7 +135,9 @@ def test_wizard_write_defaults_platform_from_board_esp8266(default_config, tmp_p
assert "platform: ESP8266" in generated_config
def test_wizard_write_defaults_platform_from_board_esp32(default_config, tmp_path, monkeypatch):
def test_wizard_write_defaults_platform_from_board_esp32(
default_config, tmp_path, monkeypatch
):
"""
If the platform is not explicitly set, use "ESP32" if the board is not one of the ESP8266 boards
"""
@@ -167,7 +171,9 @@ def test_safe_print_step_prints_step_number_and_description(monkeypatch):
# Then
# Collect arguments to all safe_print() calls (substituting "" for any empty ones)
all_args = [call.args[0] if len(call.args) else "" for call in wz.safe_print.call_args_list]
all_args = [
call.args[0] if len(call.args) else "" for call in wz.safe_print.call_args_list
]
assert any(step_desc == arg for arg in all_args)
assert any(f"STEP {step_num}" in arg for arg in all_args)
@@ -212,7 +218,7 @@ def test_strip_accents_removes_diacritics():
"""
# Given
input_str = u"Kühne"
input_str = "Kühne"
expected_str = "Kuhne"
# When
@@ -264,7 +270,7 @@ def test_wizard_accepts_default_answers_esp8266(tmpdir, monkeypatch, wizard_answ
monkeypatch.setattr("builtins.input", input_mock)
monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
monkeypatch.setattr(wz, "sleep", lambda _: 0)
monkeypatch.setattr(wz, "wizard_write", MagicMock())
monkeypatch.setattr(wz, "wizard_write", MagicMock())
# When
retval = wz.wizard(str(config_file))
@@ -286,7 +292,7 @@ def test_wizard_accepts_default_answers_esp32(tmpdir, monkeypatch, wizard_answer
monkeypatch.setattr("builtins.input", input_mock)
monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
monkeypatch.setattr(wz, "sleep", lambda _: 0)
monkeypatch.setattr(wz, "wizard_write", MagicMock())
monkeypatch.setattr(wz, "wizard_write", MagicMock())
# When
retval = wz.wizard(str(config_file))
@@ -306,14 +312,16 @@ def test_wizard_offers_better_node_name(tmpdir, monkeypatch, wizard_answers):
# Given
wizard_answers[0] = "Küche #2"
expected_name = "kuche_2"
monkeypatch.setattr(wz, "default_input", MagicMock(side_effect=lambda _, default: default))
monkeypatch.setattr(
wz, "default_input", MagicMock(side_effect=lambda _, default: default)
)
config_file = tmpdir.join("test.yaml")
input_mock = MagicMock(side_effect=wizard_answers)
monkeypatch.setattr("builtins.input", input_mock)
monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
monkeypatch.setattr(wz, "sleep", lambda _: 0)
monkeypatch.setattr(wz, "wizard_write", MagicMock())
monkeypatch.setattr(wz, "wizard_write", MagicMock())
# When
retval = wz.wizard(str(config_file))
@@ -336,7 +344,7 @@ def test_wizard_requires_correct_platform(tmpdir, monkeypatch, wizard_answers):
monkeypatch.setattr("builtins.input", input_mock)
monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
monkeypatch.setattr(wz, "sleep", lambda _: 0)
monkeypatch.setattr(wz, "wizard_write", MagicMock())
monkeypatch.setattr(wz, "wizard_write", MagicMock())
# When
retval = wz.wizard(str(config_file))
@@ -358,7 +366,7 @@ def test_wizard_requires_correct_board(tmpdir, monkeypatch, wizard_answers):
monkeypatch.setattr("builtins.input", input_mock)
monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
monkeypatch.setattr(wz, "sleep", lambda _: 0)
monkeypatch.setattr(wz, "wizard_write", MagicMock())
monkeypatch.setattr(wz, "wizard_write", MagicMock())
# When
retval = wz.wizard(str(config_file))
@@ -380,7 +388,7 @@ def test_wizard_requires_valid_ssid(tmpdir, monkeypatch, wizard_answers):
monkeypatch.setattr("builtins.input", input_mock)
monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
monkeypatch.setattr(wz, "sleep", lambda _: 0)
monkeypatch.setattr(wz, "wizard_write", MagicMock())
monkeypatch.setattr(wz, "wizard_write", MagicMock())
# When
retval = wz.wizard(str(config_file))