Skip to content

Commit 9403333

Browse files
committed
Unit tests for Evaluator
1 parent dff1f07 commit 9403333

1 file changed

Lines changed: 285 additions & 12 deletions

File tree

test/test_evaluator.py

Lines changed: 285 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import mock
2-
1+
from s2e2.converter import Converter
2+
from s2e2.error import ExpressionError
33
from s2e2.evaluator import Evaluator
44
from s2e2.token_type import TokenType
55
from s2e2.token import Token
66
from s2e2.tokenizer import Tokenizer
77

88
from s2e2.functions.function import Function
9+
from s2e2.operators.operator import Operator
10+
11+
import mock
12+
import pytest
913

1014

1115
class TestEvaluator:
@@ -21,31 +25,300 @@ def _result(self):
2125
return 'FunctionResult'
2226

2327

28+
class DummyOperator(Operator):
29+
def __init__(self):
30+
super().__init__('Operator', 1, 2)
31+
32+
def _check_arguments(self):
33+
return True
34+
35+
def _result(self):
36+
return 'OperatorResult'
37+
38+
39+
def setup(self):
40+
self.evaluator = Evaluator()
41+
42+
43+
def teardown(self):
44+
self.evaluator = None
45+
46+
47+
def test_positive_nothing_added_supported_functions_size(self):
48+
assert len(self.evaluator.get_functions()) == 0
49+
50+
51+
def test_positive_nothing_added_supported_operators_size(self):
52+
assert len(self.evaluator.get_operators()) == 0
53+
54+
55+
def test_positive_nothing_added_evaluation_result(self):
56+
input_expression = 'A B C'
57+
output_expression = self.evaluator.evaluate(input_expression)
58+
assert input_expression == output_expression
59+
60+
61+
def test_positive_add_function_supported_functions_size(self):
62+
self.evaluator.add_function(TestEvaluator.DummyFunction())
63+
assert len(self.evaluator.get_functions()) == 1
64+
65+
2466
def test_positive_add_function_verify_tokenizer(self):
2567
tokenizer_mock = mock.Mock(spec=Tokenizer)
26-
evaluator = Evaluator.mocked(None, tokenizer_mock)
68+
self.evaluator = Evaluator.mocked(None, tokenizer_mock)
2769

2870
dummy_function = TestEvaluator.DummyFunction()
29-
evaluator.add_function(dummy_function)
71+
self.evaluator.add_function(dummy_function)
3072

3173
tokenizer_mock.add_function.assert_called_once_with(dummy_function.name)
3274

3375

76+
def test_positive_add_operator_supported_operators_size(self):
77+
self.evaluator.add_operator(TestEvaluator.DummyOperator())
78+
assert len(self.evaluator.get_operators()) == 1
79+
80+
81+
def test_positive_add_operator_verify_converter(self):
82+
converter_mock = mock.Mock(spec=Converter)
83+
tokenizer_mock = mock.Mock(spec=Tokenizer)
84+
self.evaluator = Evaluator.mocked(converter_mock, tokenizer_mock)
85+
86+
dummy_operator = TestEvaluator.DummyOperator()
87+
self.evaluator.add_operator(dummy_operator)
88+
89+
converter_mock.add_operator.assert_called_once_with(dummy_operator.name, dummy_operator.priority)
90+
91+
92+
def test_positive_add_operator_verify_tokenizer(self):
93+
converter_mock = mock.Mock(spec=Converter)
94+
tokenizer_mock = mock.Mock(spec=Tokenizer)
95+
self.evaluator = Evaluator.mocked(converter_mock, tokenizer_mock)
96+
97+
dummy_operator = TestEvaluator.DummyOperator()
98+
self.evaluator.add_operator(dummy_operator)
99+
100+
tokenizer_mock.add_operator.assert_called_once_with(dummy_operator.name)
101+
102+
103+
def test_positive_add_standard_functions_supported_functions_size(self):
104+
self.evaluator.add_standard_functions()
105+
assert len(self.evaluator.get_functions()) > 0
106+
107+
108+
def test_positive_add_standard_operators_supported_operators_size(self):
109+
self.evaluator.add_standard_operators()
110+
assert len(self.evaluator.get_operators()) > 0
111+
112+
113+
def test_positive_evaluate_verify_converter(self):
114+
converter_mock = mock.Mock(spec=Converter)
115+
self.evaluator = Evaluator.mocked(converter_mock, Tokenizer())
116+
117+
dummy_operator = TestEvaluator.DummyOperator()
118+
expression = 'A ' + dummy_operator.name + ' B'
119+
infix_tokens = [Token(TokenType.ATOM, 'A'),
120+
Token(TokenType.OPERATOR, dummy_operator.name),
121+
Token(TokenType.ATOM, 'B')]
122+
postfix_tokens = [Token(TokenType.ATOM, 'A'),
123+
Token(TokenType.ATOM, 'B'),
124+
Token(TokenType.OPERATOR, dummy_operator.name)]
125+
126+
converter_mock.convert.return_value = postfix_tokens
127+
128+
self.evaluator.add_operator(dummy_operator)
129+
self.evaluator.evaluate(expression)
130+
131+
converter_mock.convert.assert_called_once_with(infix_tokens)
132+
133+
134+
def test_positive_evaluate_verify_tokenizer(self):
135+
tokenizer_mock = mock.Mock(spec=Tokenizer)
136+
self.evaluator = Evaluator.mocked(Converter(), tokenizer_mock)
137+
138+
dummy_operator = TestEvaluator.DummyOperator()
139+
expression = 'A ' + dummy_operator.name + ' B'
140+
infix_tokens = [Token(TokenType.ATOM, 'A'),
141+
Token(TokenType.OPERATOR, dummy_operator.name),
142+
Token(TokenType.ATOM, 'B')]
143+
144+
tokenizer_mock.tokenize.return_value = infix_tokens
145+
146+
self.evaluator.add_operator(dummy_operator)
147+
self.evaluator.evaluate(expression)
148+
149+
tokenizer_mock.tokenize.assert_called_once_with(expression)
150+
151+
34152
def test_positive_one_operator_evaluation_result(self):
35-
evaluator = Evaluator()
36-
evaluator.add_standard_functions()
37-
evaluator.add_standard_operators()
153+
self.evaluator.add_standard_functions()
154+
self.evaluator.add_standard_operators()
38155

39-
result = evaluator.evaluate('A + B')
156+
result = self.evaluator.evaluate('A + B')
40157

41158
assert result == 'AB'
42159

43160

161+
def test_positive_two_operators_evaluation_result(self):
162+
self.evaluator.add_standard_functions()
163+
self.evaluator.add_standard_operators()
164+
165+
result = self.evaluator.evaluate('A + B + C')
166+
167+
assert result == 'ABC'
168+
169+
44170
def test_positive_one_function_evaluation_result(self):
45-
evaluator = Evaluator()
46-
evaluator.add_standard_functions()
47-
evaluator.add_standard_operators()
171+
self.evaluator.add_standard_functions()
172+
self.evaluator.add_standard_operators()
48173

49-
result = evaluator.evaluate('IF(A < B, 1, 2)')
174+
result = self.evaluator.evaluate('IF(A < B, 1, 2)')
50175

51176
assert result == '1'
177+
178+
179+
def test_positive_nested_functions_evaluation_result(self):
180+
self.evaluator.add_standard_functions()
181+
self.evaluator.add_standard_operators()
182+
183+
result = self.evaluator.evaluate('IF(A > B, 1, REPLACE(ABC, A, E))')
184+
185+
assert result == 'EBC'
186+
187+
188+
def test_positive_two_functions_one_operator_evaluation_result(self):
189+
self.evaluator.add_standard_functions()
190+
self.evaluator.add_standard_operators()
191+
192+
result = self.evaluator.evaluate('IF(A < B, 1, 2) + IF(A > B, 3, 4)')
193+
194+
assert result == '14'
195+
196+
197+
def test_positive_redundant_brackets_evaluation_result(self):
198+
self.evaluator.add_standard_functions()
199+
self.evaluator.add_standard_operators()
200+
201+
result = self.evaluator.evaluate('(((A + B)))')
202+
203+
assert result == 'AB'
204+
205+
206+
def test_positive_compare_with_null_evaluation_result(self):
207+
self.evaluator.add_standard_functions()
208+
self.evaluator.add_standard_operators()
209+
210+
result = self.evaluator.evaluate('IF(A == NULL, Wrong, Correct)')
211+
212+
assert result == 'Correct'
213+
214+
215+
def test_positive_null_as_result_evaluation_result(self):
216+
self.evaluator.add_standard_functions()
217+
self.evaluator.add_standard_operators()
218+
219+
result = self.evaluator.evaluate('IF(A == B, Wrong, NULL)')
220+
221+
assert result is None
222+
223+
224+
def test_negative_add_empty_function(self):
225+
with pytest.raises(TypeError) as ex:
226+
self.evaluator.add_function(None)
227+
assert 'Attempt to add empty function' in str(ex.value)
228+
229+
230+
def test_negative_add_empty_operator(self):
231+
with pytest.raises(TypeError) as ex:
232+
self.evaluator.add_operator(None)
233+
assert 'Attempt to add empty operator' in str(ex.value)
234+
235+
236+
def test_negative_two_functions_with_the_same_name(self):
237+
self.evaluator.add_function(TestEvaluator.DummyFunction())
238+
239+
with pytest.raises(ExpressionError) as ex:
240+
self.evaluator.add_function(TestEvaluator.DummyFunction())
241+
assert 'is alredy added' in str(ex.value)
242+
243+
244+
def test_negative_two_operators_with_the_same_name(self):
245+
self.evaluator.add_operator(TestEvaluator.DummyOperator())
246+
247+
with pytest.raises(ExpressionError) as ex:
248+
self.evaluator.add_operator(TestEvaluator.DummyOperator())
249+
assert 'is alredy added' in str(ex.value)
250+
251+
252+
def test_negative_unpaired_bracket(self):
253+
self.evaluator.add_standard_functions()
254+
self.evaluator.add_standard_operators()
255+
256+
with pytest.raises(ExpressionError) as ex:
257+
self.evaluator.evaluate('A + (B + C')
258+
assert 'Unpaired bracket' in str(ex.value)
259+
260+
261+
def test_negative_unexpected_token_type(self):
262+
converter_mock = mock.Mock(spec=Converter)
263+
self.evaluator = Evaluator.mocked(converter_mock, Tokenizer())
264+
self.evaluator.add_standard_functions()
265+
self.evaluator.add_standard_operators()
266+
267+
wrong_tokens = [Token(TokenType.ATOM, 'A'),
268+
Token(TokenType.ATOM, 'B'),
269+
Token(TokenType.LEFT_BRACKET, '(')]
270+
converter_mock.convert.return_value = wrong_tokens
271+
272+
with pytest.raises(ExpressionError) as ex:
273+
self.evaluator.evaluate('A + B')
274+
assert 'Unexpected token type' in str(ex.value)
275+
276+
277+
def test_negative_unsupported_operator(self):
278+
converter_mock = mock.Mock(spec=Converter)
279+
self.evaluator = Evaluator.mocked(converter_mock, Tokenizer())
280+
self.evaluator.add_standard_functions()
281+
self.evaluator.add_standard_operators()
282+
283+
wrong_tokens = [Token(TokenType.ATOM, 'A'),
284+
Token(TokenType.ATOM, 'B'),
285+
Token(TokenType.OPERATOR, '<>')]
286+
converter_mock.convert.return_value = wrong_tokens
287+
288+
with pytest.raises(ExpressionError) as ex:
289+
self.evaluator.evaluate('A + B')
290+
assert 'Unsupported operator <>' in str(ex.value)
291+
292+
293+
def test_negative_unsupported_function(self):
294+
converter_mock = mock.Mock(spec=Converter)
295+
self.evaluator = Evaluator.mocked(converter_mock, Tokenizer())
296+
self.evaluator.add_standard_functions()
297+
self.evaluator.add_standard_operators()
298+
299+
wrong_tokens = [Token(TokenType.ATOM, 'A'),
300+
Token(TokenType.ATOM, 'B'),
301+
Token(TokenType.FUNCTION, 'FUNC')]
302+
converter_mock.convert.return_value = wrong_tokens
303+
304+
with pytest.raises(ExpressionError) as ex:
305+
self.evaluator.evaluate('A + B')
306+
assert 'Unsupported function FUNC' in str(ex.value)
307+
308+
309+
def test_negative_few_arguments(self):
310+
self.evaluator.add_standard_functions()
311+
self.evaluator.add_standard_operators()
312+
313+
with pytest.raises(ExpressionError) as ex:
314+
self.evaluator.evaluate('A +')
315+
assert 'Not enough arguments' in str(ex.value)
316+
317+
318+
def test_negative_few_operators(self):
319+
self.evaluator.add_standard_functions()
320+
self.evaluator.add_standard_operators()
321+
322+
with pytest.raises(ExpressionError) as ex:
323+
self.evaluator.evaluate('A + B C')
324+
assert 'Invalid expression' in str(ex.value)

0 commit comments

Comments
 (0)