11#include < attwoodn/expression_tree.hpp>
22#include " test_utils.hpp"
3+ #include < functional>
34#include < cassert>
45
56using namespace attwoodn ::expression_tree;
@@ -9,13 +10,15 @@ void test_simple_expression_tree();
910void test_complex_expression_tree ();
1011void test_moved_expression_tree ();
1112void test_copied_expression_tree ();
13+ void test_user_defined_operator ();
1214
1315int main (int argc, char ** argv) {
1416 test_expression_tree_std_string_template ();
1517 test_simple_expression_tree ();
1618 test_complex_expression_tree ();
1719 test_moved_expression_tree ();
1820 test_copied_expression_tree ();
21+ test_user_defined_operator ();
1922
2023 return EXIT_SUCCESS;
2124}
@@ -70,6 +73,140 @@ void test_simple_expression_tree() {
7073
7174void test_complex_expression_tree () {
7275
76+ // expression: (uint > 0 AND (some_string > "a" AND some_string < "z")) OR (some_string > "0" AND some_string < "9")
77+ expression_tree<test_fixture> expr {
78+ (make_expr (&test_fixture::is_some_uint_greater_than_zero, op::equals, true )
79+ ->AND ((make_expr (&test_fixture::some_string, op::greater_than, std::string (" a" ))
80+ ->AND (make_expr (&test_fixture::some_string, op::less_than, std::string (" z" )))
81+ ))
82+ )
83+ ->OR ((make_expr (&test_fixture::some_string, op::greater_than, std::string (" 0" ))
84+ ->AND (make_expr (&test_fixture::some_string, op::less_than, std::string (" 9" )))
85+ )
86+ )
87+ };
88+
89+ test_fixture fixture;
90+
91+ fixture.some_uint = 0 ;
92+
93+ // test left-hand side of the expression tree when some_uint is 0
94+ {
95+ fixture.some_string = " a" ;
96+ assert (!expr.evaluate (fixture));
97+
98+ fixture.some_string = " aaa" ;
99+ assert (!expr.evaluate (fixture));
100+
101+ fixture.some_string = " c" ;
102+ assert (!expr.evaluate (fixture));
103+
104+ fixture.some_string = " yyyyy" ;
105+ assert (!expr.evaluate (fixture));
106+
107+ fixture.some_string = " B" ;
108+ assert (!expr.evaluate (fixture));
109+
110+ fixture.some_string = " ZZZ" ;
111+ assert (!expr.evaluate (fixture));
112+
113+ fixture.some_string = " /" ;
114+ assert (!expr.evaluate (fixture));
115+
116+ fixture.some_string = " red" ;
117+ assert (!expr.evaluate (fixture));
118+
119+ fixture.some_string = " " ;
120+ assert (!expr.evaluate (fixture));
121+
122+ fixture.some_string = " tree fiddy" ;
123+ assert (!expr.evaluate (fixture));
124+ }
125+
126+ // test right-hand side of the expression tree when some_uint is 0
127+ {
128+ fixture.some_string = " 000" ;
129+ assert (expr.evaluate (fixture));
130+
131+ fixture.some_string = " 00" ;
132+ assert (expr.evaluate (fixture));
133+
134+ fixture.some_string = " 0" ;
135+ assert (!expr.evaluate (fixture));
136+
137+ fixture.some_string = " 12345" ;
138+ assert (expr.evaluate (fixture));
139+
140+ fixture.some_string = " 7" ;
141+ assert (expr.evaluate (fixture));
142+
143+ fixture.some_string = " 89999" ;
144+ assert (expr.evaluate (fixture));
145+
146+ fixture.some_string = " 9" ;
147+ assert (!expr.evaluate (fixture));
148+ }
149+
150+ fixture.some_uint = 1 ;
151+
152+ // test left-hand side of the expression tree when some_uint is 0
153+ {
154+ fixture.some_string = " a" ;
155+ assert (!expr.evaluate (fixture));
156+
157+ fixture.some_string = " aaa" ;
158+ assert (expr.evaluate (fixture));
159+
160+ fixture.some_string = " c" ;
161+ assert (expr.evaluate (fixture));
162+
163+ fixture.some_string = " yyyyy" ;
164+ assert (expr.evaluate (fixture));
165+
166+ fixture.some_string = " B" ;
167+ assert (!expr.evaluate (fixture));
168+
169+ fixture.some_string = " ZZZ" ;
170+ assert (!expr.evaluate (fixture));
171+
172+ fixture.some_string = " /" ;
173+ assert (!expr.evaluate (fixture));
174+
175+ fixture.some_string = " red" ;
176+ assert (expr.evaluate (fixture));
177+
178+ fixture.some_string = " " ;
179+ assert (!expr.evaluate (fixture));
180+
181+ fixture.some_string = " tree fiddy" ;
182+ assert (expr.evaluate (fixture));
183+ }
184+
185+ // test right-hand side of the expression tree when some_uint is 1
186+ {
187+ fixture.some_string = " 000" ;
188+ assert (expr.evaluate (fixture));
189+
190+ fixture.some_string = " 00" ;
191+ assert (expr.evaluate (fixture));
192+
193+ fixture.some_string = " 0" ;
194+ assert (!expr.evaluate (fixture));
195+
196+ fixture.some_string = " 12345" ;
197+ assert (expr.evaluate (fixture));
198+
199+ fixture.some_string = " 7" ;
200+ assert (expr.evaluate (fixture));
201+
202+ fixture.some_string = " 89999" ;
203+ assert (expr.evaluate (fixture));
204+
205+ fixture.some_string = " 9" ;
206+ assert (!expr.evaluate (fixture));
207+ }
208+
209+
73210}
74211
75212void test_moved_expression_tree () {
@@ -103,7 +240,7 @@ void test_moved_expression_tree() {
103240 };
104241 test_procedure (expr);
105242
106- expression_tree<test_fixture> move_constructed_expr ( std::move (expr) );
243+ expression_tree<test_fixture> move_constructed_expr (std::move (expr));
107244 test_procedure (move_constructed_expr);
108245
109246 expression_tree<test_fixture> move_assigned_expr = std::move (move_constructed_expr);
@@ -141,7 +278,7 @@ void test_copied_expression_tree() {
141278 };
142279 test_procedure (expr);
143280
144- expression_tree<test_fixture> copy_constructed_expr ( expr );
281+ expression_tree<test_fixture> copy_constructed_expr (expr);
145282 test_procedure (copy_constructed_expr);
146283
147284 expression_tree<test_fixture> copy_assigned_expr = copy_constructed_expr;
@@ -150,4 +287,51 @@ void test_copied_expression_tree() {
150287 // ensure both of the old copied versions still work after copying
151288 test_procedure (expr);
152289 test_procedure (copy_constructed_expr);
290+ }
291+
292+ void test_user_defined_operator () {
293+ auto is_small_packet_payload = [](const packet_payload& incoming, const packet_payload&) -> bool {
294+ if (incoming.error_code == 0 && incoming.checksum_ok && incoming.payload_size () <= 10 ) {
295+ return true ;
296+ }
297+ return false ;
298+ };
299+
300+ // only accept small, non-errored data packets from Jim.
301+ // evaluate packet contents using the user-defined lambda operator defined above
302+ expression_tree<data_packet> expr {
303+ make_expr (&data_packet::sender_name, op::equals, std::string (" Jim" ))
304+ ->AND (make_expr (&data_packet::payload, is_small_packet_payload, packet_payload ()))
305+ };
306+
307+ data_packet incoming_packet;
308+
309+ // Jim sends a small, non-errored data packet
310+ incoming_packet.sender_name = " Jim" ;
311+ incoming_packet.payload .checksum_ok = true ;
312+ incoming_packet.payload .data = " hello!" ;
313+ incoming_packet.payload .error_code = 0 ;
314+ assert (expr.evaluate (incoming_packet)); // passes evaluation
315+
316+ // Pam sends the same packet payload
317+ incoming_packet.sender_name = " Pam" ;
318+ assert (!expr.evaluate (incoming_packet)); // fails evaluation. No messages from Pam are accepted (sorry Pam)
319+
320+ // Jim sends a packet with a bad checksum
321+ incoming_packet.sender_name = " Jim" ;
322+ incoming_packet.payload .checksum_ok = false ;
323+ assert (!expr.evaluate (incoming_packet)); // fails evaluation. The packet was from Jim, but the checksum was bad
324+
325+ // Jim sends a packet whose payload is too big
326+ incoming_packet.payload .checksum_ok = true ;
327+ incoming_packet.payload .data = " Boy do I have a long story for you - so I was talking to Pam ..." ;
328+ assert (!expr.evaluate (incoming_packet)); // fails evaluation. The packet's payload was too big. Give me the TLDR next time, Jim
329+
330+ // Jim sends a small, rude packet
331+ incoming_packet.payload .data = " Dwight sux" ;
332+ assert (expr.evaluate (incoming_packet)); // passes evaluation. The packet's payload was the right size this time
333+
334+ // Jim sends a packet has an error code
335+ incoming_packet.payload .error_code = 404 ;
336+ assert (!expr.evaluate (incoming_packet)); // fails evaluation. The packet's payload had an error code
153337}
0 commit comments