migration from ha-cantegrill repo
This commit is contained in:
159
unittests.py
Normal file
159
unittests.py
Normal file
@@ -0,0 +1,159 @@
|
||||
import smartcondition
|
||||
import os
|
||||
import yaml
|
||||
from expressionparser import ParsingException
|
||||
|
||||
UNIT_TEST_PATH = "unit_tests"
|
||||
|
||||
class AppDaemonMokup:
|
||||
def __init__(self,fake_entitites):
|
||||
self.entities = fake_entitites
|
||||
|
||||
def log(self,message,**kwargs):
|
||||
error_level = f"[{kwargs['level']}]" if 'level' in kwargs else ""
|
||||
print(f'{error_level}{message}')
|
||||
|
||||
def get_state(self,entity_id,attribute = None):
|
||||
key = f"{entity_id}.{attribute}" if attribute != None else entity_id
|
||||
|
||||
return self.entities[key] if key in self.entities else None
|
||||
|
||||
def entity_exists(self,entity_id):
|
||||
return entity_id in self.entities
|
||||
|
||||
#added a couple of method to be directly compatible with Condition Parser
|
||||
def add_variable(self,variable_name): return self.entity_exists(variable_name)
|
||||
|
||||
def get_variable_value(self,variable_name): return self.get_state(variable_name)
|
||||
|
||||
def reset(self): pass
|
||||
|
||||
def execute_unit_test(test_file):
|
||||
failed_test = dict()
|
||||
|
||||
with open(test_file, 'r') as file:
|
||||
test_config = yaml.safe_load(file)
|
||||
if not 'fake_entities' in test_config:
|
||||
print(f"Can't run test {test_file} fake_entities is not defined")
|
||||
return False
|
||||
else:
|
||||
print(f"\nRunning test from {test_file}")
|
||||
|
||||
constants = test_config['constants'] if 'constants' in test_config else dict()
|
||||
templates_library = test_config['templates_library'] if 'templates_library' in test_config else None
|
||||
appdaemon = AppDaemonMokup(test_config['fake_entities'])
|
||||
|
||||
test_expression = None
|
||||
#test_expression = "binary_sensor.on == not binary_sensor.false"
|
||||
|
||||
if test_expression:
|
||||
condition_parser = smartcondition.ConditionsParser(test_expression,appdaemon)
|
||||
print(f"{condition_parser.parsed_data}")
|
||||
result = condition_parser.evaluate()
|
||||
|
||||
for test in test_config['tests']:
|
||||
try: conditions = smartcondition.Evaluator(appdaemon,test_config['tests'][test]['conditions'], constants = constants, log_init = False, log_no_valid_condition_details = True, templates_library = templates_library)
|
||||
except ParsingException as e:
|
||||
success = test_config['tests'][test]['expected_result'] == "ParsingException"
|
||||
|
||||
print(f"{test}: {'Success' if success else 'Failed'}")
|
||||
if not success:
|
||||
print(f"{os.path.basename(test_file)} {test}: 'Parsing failed' with Exception {e}")
|
||||
failed_test[test] = test_config['tests'][test]
|
||||
print()
|
||||
continue
|
||||
|
||||
else:
|
||||
if 'expected_entities_to_listen' in test_config['tests'][test]:
|
||||
expected_entities_to_listen = test_config['tests'][test]['expected_entities_to_listen']
|
||||
entities_to_listen = conditions.get_entities_to_listen_as_list()
|
||||
if sorted(expected_entities_to_listen) != sorted(entities_to_listen):
|
||||
failed_test[test] = test_config['tests'][test]
|
||||
print(f"{test}: Failed")
|
||||
print(f"entities_to_listen = {entities_to_listen}, expected : {expected_entities_to_listen}")
|
||||
continue
|
||||
|
||||
|
||||
result = conditions.evaluate(False)
|
||||
success = result.name == test_config['tests'][test]['expected_result']
|
||||
print(f"{test}: {'Success' if success else 'Failed'}")
|
||||
if not success:
|
||||
failed_test[test] = test_config['tests'][test]
|
||||
conditions.log_evaluation_result()
|
||||
print()
|
||||
continue
|
||||
|
||||
|
||||
print()
|
||||
if len(failed_test) > 0:
|
||||
print(f"{len(failed_test)} tests have failed in {os.path.basename(test_file)} :")
|
||||
for test in failed_test:
|
||||
print(f"{test} : {test_config['tests'][test]['conditions']}")
|
||||
print(f"Expected result was {test_config['tests'][test]['expected_result']}")
|
||||
else:
|
||||
print("All the tests have succeeded")
|
||||
|
||||
|
||||
return len(failed_test) == 0
|
||||
|
||||
def tiny_parser():
|
||||
import pyparsing
|
||||
|
||||
variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))
|
||||
|
||||
#integer = pyparsing.Word(pyparsing.nums)
|
||||
integer = pyparsing.pyparsing_common.signed_integer
|
||||
|
||||
double = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))
|
||||
|
||||
parser = pyparsing.infix_notation(
|
||||
variable_names | double | integer,
|
||||
[
|
||||
('not', 1, pyparsing.opAssoc.RIGHT),
|
||||
('**', 2, pyparsing.opAssoc.RIGHT),
|
||||
('-', 1, pyparsing.opAssoc.RIGHT),
|
||||
(pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),
|
||||
(pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),
|
||||
(pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),
|
||||
('and', 2, pyparsing.opAssoc.LEFT),
|
||||
('or', 2, pyparsing.opAssoc.LEFT)
|
||||
]
|
||||
)
|
||||
|
||||
examples = [
|
||||
"$true and not 10 == 9",
|
||||
"$true == $false",
|
||||
"$true == not $false",
|
||||
"$true == (not $false)",
|
||||
"5 * 10 ** -2",
|
||||
"5 * 10 * -2",
|
||||
"5 * 10 ** (-2)",
|
||||
"5 * -10 ** 2",
|
||||
"5 * (-10) ** 2",
|
||||
"5 and not 8",
|
||||
"5 and -8",
|
||||
"1 ** -2",
|
||||
"-1 ** 2",
|
||||
]
|
||||
|
||||
longest = max(map(len, examples))
|
||||
|
||||
for ex in examples:
|
||||
result = parser.parseString(ex)
|
||||
print(f'{ex:{longest}} <=> {result}')
|
||||
|
||||
|
||||
#tiny_parser()
|
||||
failed_test = list()
|
||||
|
||||
path = os.path.join(os.path.dirname(os.path.abspath(__file__)),UNIT_TEST_PATH)
|
||||
with os.scandir(path) as it:
|
||||
for entry in it:
|
||||
if entry.is_file() and entry.name.lower().endswith('.yaml'):
|
||||
if not execute_unit_test(os.path.join(path , entry.name)):
|
||||
failed_test.append(entry.name)
|
||||
|
||||
if len(failed_test):
|
||||
print(f"{len(failed_test)} test file(s) have failed :")
|
||||
for test in failed_test:
|
||||
print(f"{test}")
|
||||
Reference in New Issue
Block a user