1- import mock
2-
1+ from s2e2 . converter import Converter
2+ from s2e2 . error import ExpressionError
33from s2e2 .evaluator import Evaluator
44from s2e2 .token_type import TokenType
55from s2e2 .token import Token
66from s2e2 .tokenizer import Tokenizer
77
88from s2e2 .functions .function import Function
9+ from s2e2 .operators .operator import Operator
10+
11+ import mock
12+ import pytest
913
1014
1115class 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