tests.test_parser   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 16
eloc 89
dl 0
loc 128
rs 10
c 0
b 0
f 0

8 Functions

Rating   Name   Duplication   Size   Complexity  
A _load_json_file() 0 4 2
A test_sources_parsed_correctly() 0 12 2
A test_validation_fails_with_invalid_definition() 0 18 4
A test_rules_parsed_correctly() 0 8 2
A test_engines_parsed_correctly() 0 9 2
A test_validation_errors() 0 9 2
A test_valid_test_definition() 0 8 1
A test_fully_parsed_engine() 0 22 1
1
import json
2
from pathlib import Path
3
4
import pytest
5
from jsonschema import ValidationError
6
7
from decision_engine import parser
8
9
10
defs_dir = Path(__file__).parents[0] / 'test_definitions'
11
schema_dir = defs_dir.parents[1] / 'decision_engine'
12
13
schema_file = 'schema.json'
14
schema_path = schema_dir / schema_file
15
16
definition_path = defs_dir / 'test_definition.json'
17
nested_sources_def_path = defs_dir / 'test_nested_sources.json'
18
full_def_path = defs_dir / 'full_definition.json'
19
20
21
def _load_json_file(file: str) -> dict:
22
    with (open(file)) as fp:
23
        contents = json.load(fp)
24
    return contents
25
26
27
@pytest.mark.parametrize('definition_file', [
28
    definition_path,
29
    nested_sources_def_path,
30
    full_def_path
31
])
32
def test_sources_parsed_correctly(definition_file):
33
    definition = _load_json_file(definition_file)
34
    sources = parser.parse_sources(definition['sources'])
35
    assert len(sources) == len(definition['sources'])
36
    for i in range(len(definition['sources'])):
37
        assert sources[i].name == definition['sources'][i]['name']
38
        assert type(sources[i]).__name__ == definition['sources'][i]['class']
39
40
41
def test_rules_parsed_correctly():
42
    definition = _load_json_file(definition_path)
43
    sources = parser.parse_sources(definition['sources'])
44
    rules = parser.parse_rules(definition['rules'], sources)
45
    assert len(rules) == len(definition['rules'])
46
    for i in range(len(definition['rules'])):
47
        assert rules[i].name == definition['rules'][i]['name']
48
        assert type(rules[i]).__name__ == definition['rules'][i]['class']
49
50
51
def test_engines_parsed_correctly():
52
    definition = _load_json_file(definition_path)
53
    sources = parser.parse_sources(definition['sources'])
54
    rules = parser.parse_rules(definition['rules'], sources)
55
    engines = parser.parse_engines(definition['engines'], rules)
56
    assert len(engines) == len(definition['engines'])
57
    for i in range(len(definition['engines'])):
58
        assert engines[i].name == definition['engines'][i]['name']
59
        assert len(engines[i].rules) == len(rules)
60
61
62
def test_valid_test_definition():
63
    """
64
    Make sure our test definition is valid,
65
    otherwise there's no point in using it for testing.
66
    """
67
    schema = _load_json_file(schema_path)
68
    definition = _load_json_file(definition_path)
69
    parser.validate(definition, schema)
70
71
72
@pytest.mark.parametrize('file_name', [
73
    'wrong_param_type.json',
74
    'inexistent_source.json',
75
    'inexistent_rule.json'
76
])
77
def test_validation_errors(file_name):
78
    with pytest.raises(ValidationError):
79
        path = defs_dir / file_name
80
        parser.parse_json_file(path)
81
82
83
@pytest.mark.parametrize("air_miles, land_miles, age, vip, expected", [
84
    (500, 100, 37, 'yes', True),
85
    (150, 100, 37, 'yes', False),
86
    (500, 501, 37, 'yes', False),
87
    (500, 100, 16, 'yes', False),
88
    (500, 100, 70, 'yes', False),
89
    (500, 100, 37, 'no', False),
90
    (10, 50, 15, 'no', False)
91
])
92
def test_fully_parsed_engine(air_miles, land_miles, age, vip, expected):
93
    engines = parser.parse_json_file(full_def_path)
94
95
    engine = engines['engines'][0]
96
97
    data = {
98
        'air_miles': air_miles,
99
        'land_miles': land_miles,
100
        'age': age,
101
        'vip': vip
102
    }
103
104
    assert engine.decide(data) == expected
105
106
107
# These are probably not needed, since what we're really doing here is
108
# testing that jsonschema validates correctly, which should be done in
109
# its own package, not here.
110
def test_validation_fails_with_invalid_definition():
111
    schema = _load_json_file(schema_path)
112
    definition = _load_json_file(definition_path)
113
114
    definition_without_sources = definition.copy()
115
    del definition_without_sources['sources']
116
    with pytest.raises(ValidationError):
117
        parser.validate(definition_without_sources, schema)
118
119
    definition_without_rules = definition.copy()
120
    del definition_without_rules['rules']
121
    with pytest.raises(ValidationError):
122
        parser.validate(definition_without_rules, schema)
123
124
    definition_without_engines = definition.copy()
125
    del definition_without_engines['engines']
126
    with pytest.raises(ValidationError):
127
        parser.validate(definition_without_engines, schema)
128