From f4b3ed1145c83228cfe4e7cbc3e351b4ac975f86 Mon Sep 17 00:00:00 2001 From: Freek Hoekstra Date: Tue, 25 May 2021 21:19:02 +0200 Subject: [PATCH 1/3] add Python and AppDaemon compatible versions to README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e9f7c6..dcc9d9a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Appdaemon Test Framework -[![Build Status](https://www.travis-ci.com/FlorianKempenich/Appdaemon-Test-Framework.svg?branch=master)](https://travis-ci.com/github/FlorianKempenich/Appdaemon-Test-Framework) [![PyPI](https://img.shields.io/pypi/v/appdaemontestframework.svg)](https://pypi.org/project/appdaemontestframework/) +[![Build Status](https://www.travis-ci.com/FlorianKempenich/Appdaemon-Test-Framework.svg?branch=master)](https://travis-ci.com/github/FlorianKempenich/Appdaemon-Test-Framework) [![PyPI](https://img.shields.io/pypi/v/appdaemontestframework.svg)](https://pypi.org/project/appdaemontestframework/) [![Python 3.7](https://img.shields.io/badge/appdaemon-4.x-blue.svg)](TODO) [![Python 3.6](https://img.shields.io/badge/python-3.7-yellow.svg)](https://www.python.org/downloads/release/python-370/) [![Python 3.8](https://img.shields.io/badge/python-3.8-yellow.svg)](https://www.python.org/downloads/release/python-380/) Clean, human-readable tests for your Appdaemon automations. From 6c01f15dbd47ccbf792767ad9370008ad5cdd55f Mon Sep 17 00:00:00 2001 From: Freek Hoekstra Date: Tue, 25 May 2021 21:42:36 +0200 Subject: [PATCH 2/3] add service name validation tests and code --- appdaemontestframework/assert_that.py | 12 ++++++----- test/test_assert_that.py | 29 ++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/appdaemontestframework/assert_that.py b/appdaemontestframework/assert_that.py index 0d210fe..3787ac0 100644 --- a/appdaemontestframework/assert_that.py +++ b/appdaemontestframework/assert_that.py @@ -1,3 +1,4 @@ +import re import textwrap from abc import ABC, abstractmethod @@ -76,7 +77,6 @@ class WasWrapper(Was): def __init__(self, thing_to_check, hass_functions): self.thing_to_check = thing_to_check self.hass_functions = hass_functions - def turned_on(self, **service_specific_parameters): """ Assert that a given entity_id has been turned on """ entity_id = self.thing_to_check @@ -116,15 +116,20 @@ def turned_off(self, **service_specific_parameters): def called_with(self, **kwargs): """ Assert that a given service has been called with the given arguments""" service_full_name = self.thing_to_check + if not _is_valid_service_name(service_full_name): + raise ValueError('Service names should be given as: domain/service in AppDaemon.') self.hass_functions['call_service'].assert_any_call( service_full_name, **kwargs) +def _is_valid_service_name(service_full_name: str): + return re.match(r'[\w]+/[\w]+', service_full_name) is not None + + class WasNotWrapper(Was): def __init__(self, was_wrapper): self.was_wrapper = was_wrapper - def turned_on(self, **service_specific_parameters): """ Assert that a given entity_id has NOT been turned ON w/ the given parameters""" thing_not_turned_on_with_given_params = _capture_assert_failure_exception( @@ -160,7 +165,6 @@ def __init__(self, automation_thing_to_check, hass_functions): self.automation_thing_to_check = automation_thing_to_check self.listen_event = hass_functions['listen_event'] self.listen_state = hass_functions['listen_state'] - def event(self, event, **event_data): listens_to_wrapper = self @@ -194,8 +198,6 @@ def __init__(self, automation_thing_to_check, hass_functions): self._run_daily = hass_functions['run_daily'] self._run_mintely = hass_functions['run_minutely'] self._run_at = hass_functions['run_at'] - - def run_daily(self, time_, **kwargs): registered_wrapper = self diff --git a/test/test_assert_that.py b/test/test_assert_that.py index ce23b19..757b0ca 100644 --- a/test/test_assert_that.py +++ b/test/test_assert_that.py @@ -1,8 +1,5 @@ -from datetime import time, datetime - import appdaemon.plugins.hass.hassapi as hass import pytest -from pytest import mark from appdaemontestframework import automation_fixture @@ -73,6 +70,12 @@ def turn_off_light_with_transition(self, via_helper=False): transition=TRANSITION_DURATION ) + def call_invalid_service_name(self): + self.call_service( + 'switch.turn_off', + entity_id=SWITCH + ) + @automation_fixture(MockAutomation) def automation(): @@ -141,3 +144,23 @@ def test_with_kwargs(self, assert_that, automation): assert_that(LIGHT).was_not.turned_off() automation.turn_off_light_with_transition(via_helper=True) assert_that(LIGHT).was.turned_off(transition=TRANSITION_DURATION) + + +class TestServiceNameValidation: + class TestValidServiceName: + def test_valid_service_asserted_and_is_called_does_not_raise(self, assert_that, automation): + automation.turn_off_switch(via_helper=False) + assert_that('switch/turn_off') \ + .was.called_with(entity_id=SWITCH) + + def test_valid_service_asserted_and_is_not_called_raises_assertion_error(self, assert_that, automation): + automation.turn_off_switch(via_helper=False) + assert_that('switch/turn_off') \ + .was.called_with(entity_id=SWITCH) + + class TestInvalidServiceName: + def test_invalid_service_asserted_and_is_called_raises_value_error(self, assert_that, automation): + automation.call_invalid_service_name() + with pytest.raises(ValueError): + assert_that('switch.turn_off')\ + .was.called_with(entity_id=SWITCH) From b0705288cfaa6e5f0be407edec27daa92e5e5fbd Mon Sep 17 00:00:00 2001 From: Freek Hoekstra Date: Tue, 25 May 2021 21:50:00 +0200 Subject: [PATCH 3/3] add missing case: raise either value or assertion error when both assert and validation should fail --- test/test_assert_that.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/test_assert_that.py b/test/test_assert_that.py index 757b0ca..7c827f0 100644 --- a/test/test_assert_that.py +++ b/test/test_assert_that.py @@ -154,9 +154,9 @@ def test_valid_service_asserted_and_is_called_does_not_raise(self, assert_that, .was.called_with(entity_id=SWITCH) def test_valid_service_asserted_and_is_not_called_raises_assertion_error(self, assert_that, automation): - automation.turn_off_switch(via_helper=False) - assert_that('switch/turn_off') \ - .was.called_with(entity_id=SWITCH) + with pytest.raises(AssertionError): + assert_that('switch/turn_off') \ + .was.called_with(entity_id=SWITCH) class TestInvalidServiceName: def test_invalid_service_asserted_and_is_called_raises_value_error(self, assert_that, automation): @@ -164,3 +164,8 @@ def test_invalid_service_asserted_and_is_called_raises_value_error(self, assert_ with pytest.raises(ValueError): assert_that('switch.turn_off')\ .was.called_with(entity_id=SWITCH) + + def test_invalid_service_asserted_and_is_not_called_raises_value_or_assertion_error(self, assert_that, automation): + with pytest.raises((ValueError, AssertionError)): + assert_that('switch.turn_off')\ + .was.called_with(entity_id=SWITCH)