Skip to content

Commit b6d1a9f

Browse files
committed
adds new test suite for expression_tree class, cleans up some duplicate include directives, and improves various constructors and assignment operators
1 parent c438286 commit b6d1a9f

File tree

5 files changed

+188
-16
lines changed

5 files changed

+188
-16
lines changed

include/attwoodn/expression_tree.hpp

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ namespace attwoodn::expression_tree {
8484
* False if the given object did not satisfy the expression in this node and the expressions of all
8585
* nodes under this node in the expression tree.
8686
*/
87-
virtual bool evaluate(const Obj& obj) = 0;
87+
virtual bool evaluate(const Obj& obj) const = 0;
8888

8989
/**
9090
* @brief Performs a deep clone of pointers to this base class to avoid object slicing.
9191
*/
92-
auto clone() {
92+
auto clone() const {
9393
return std::unique_ptr<expression_tree_node<Obj>>(clone_impl());
9494
}
9595

@@ -106,6 +106,11 @@ namespace attwoodn::expression_tree {
106106
public:
107107
using this_type = expression_tree_op_node<Obj, LeftChild, RightChild>;
108108

109+
expression_tree_op_node() = delete;
110+
expression_tree_op_node(expression_tree_op_node&& other) = delete;
111+
expression_tree_op_node& operator=(const expression_tree_op_node& other) = delete;
112+
expression_tree_op_node& operator=(expression_tree_op_node&& other) = delete;
113+
109114
expression_tree_op_node(boolean_op bool_op)
110115
: bool_op_(bool_op) {}
111116

@@ -134,7 +139,7 @@ namespace attwoodn::expression_tree {
134139
delete l;
135140
}
136141

137-
bool evaluate(const Obj& obj) override {
142+
bool evaluate(const Obj& obj) const override {
138143
if(!left_ || !right_) {
139144
throw std::runtime_error("expression_tree_op_node has a missing child node");
140145
}
@@ -237,6 +242,13 @@ namespace attwoodn::expression_tree {
237242
public:
238243
using this_type = expression_tree_leaf_node<Obj, Op, CompValue>;
239244

245+
expression_tree_leaf_node() = delete;
246+
247+
expression_tree_leaf_node(const expression_tree_leaf_node& other) = default;
248+
expression_tree_leaf_node(expression_tree_leaf_node&& other) = default;
249+
expression_tree_leaf_node& operator=(const expression_tree_leaf_node& other) = default;
250+
expression_tree_leaf_node& operator=(expression_tree_leaf_node&& other) = default;
251+
240252
/**
241253
* @brief Constructor that accepts a reference to a member variable of Obj
242254
*/
@@ -255,7 +267,7 @@ namespace attwoodn::expression_tree {
255267

256268
~expression_tree_leaf_node() override {};
257269

258-
bool evaluate(const Obj& obj) override {
270+
bool evaluate(const Obj& obj) const override {
259271
if (member_func_ && member_var_) {
260272
throw std::runtime_error("expression_tree_leaf_node has both a member function reference " +
261273
std::string("and member variable reference. Only one is permitted"));
@@ -391,28 +403,46 @@ namespace attwoodn::expression_tree {
391403

392404
expression_tree(node::expression_tree_node<Obj>* expr) {
393405
if(!expr) {
394-
throw std::runtime_error("Attempted to construct an expression_tree with a null root expression node");
406+
throw std::runtime_error("Attempted to construct an expression_tree using a null expression");
395407
}
396-
397408
expr_ = expr->clone().release();
398409
delete expr;
399410
}
400411

401-
expression_tree(const expression_tree& other)
402-
: expr_(other.expr_->clone().release()) {}
412+
expression_tree(std::unique_ptr<node::expression_tree_node<Obj>> expr)
413+
: expression_tree(expr.release()) {}
414+
415+
expression_tree(const expression_tree& other) {
416+
if(!other.expr_) {
417+
throw std::runtime_error("Attempted to copy construct an expression_tree " +
418+
std::string("from an expression_tree with a null expression"));
419+
}
420+
expr_ = other.expr_->clone().release();
421+
}
403422

404-
expression_tree(expression_tree&& other)
405-
: expr_(other.expr_) {
423+
expression_tree(expression_tree&& other) {
424+
if(!other.expr_) {
425+
throw std::runtime_error("Attempted to move construct an expression_tree " +
426+
std::string("from an expression_tree with a null expression"));
427+
}
428+
expr_ = other.expr_;
406429
other.expr_ = nullptr;
407430
}
408431

409432
expression_tree& operator=(const expression_tree& other) {
433+
if(!other.expr_) {
434+
throw std::runtime_error("Attempted copy assignment from an expression_tree with a null expression");
435+
}
410436
delete expr_;
411437
expr_ = other.expr_->clone().release();
412438
return *this;
413439
}
414440

415-
expression_tree& operator=(const expression_tree&& other) {
441+
expression_tree& operator=(expression_tree&& other) {
442+
if(!other.expr_) {
443+
throw std::runtime_error("Attempted move assignment from an expression_tree with a null expression");
444+
}
445+
416446
if(this != &other) {
417447
delete expr_;
418448
expr_ = other.expr_;
@@ -431,7 +461,7 @@ namespace attwoodn::expression_tree {
431461
* @returns True if the given object satisfied the expression tree conditions;
432462
* False if the given object did not satisfy the expression tree conditions.
433463
*/
434-
bool evaluate(const Obj& obj) {
464+
bool evaluate(const Obj& obj) const {
435465
if(!expr_) {
436466
throw std::runtime_error("expression_tree has a null root expression node");
437467
}
@@ -446,4 +476,4 @@ namespace attwoodn::expression_tree {
446476
private:
447477
node::expression_tree_node<Obj>* expr_ = nullptr;
448478
};
449-
}
479+
}

tests/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ if(BUILD_TESTING)
1515
target_compile_options( expression_tree_op_node_test PRIVATE -fsanitize=address )
1616
add_test( expression_tree_op_node_test ${EXECUTABLE_OUTPUT_PATH}/expression_tree_op_node_test )
1717

18+
add_executable( expression_tree_test expression_tree.cpp )
19+
target_link_libraries( expression_tree_test "-fsanitize=address" )
20+
target_compile_options( expression_tree_test PRIVATE -fsanitize=address )
21+
add_test( expression_tree_test ${EXECUTABLE_OUTPUT_PATH}/expression_tree_test )
22+
1823
endif()

tests/expression_tree.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include <attwoodn/expression_tree.hpp>
2+
#include "test_utils.hpp"
3+
#include <cassert>
4+
5+
using namespace attwoodn::expression_tree;
6+
7+
void test_simple_expression_tree();
8+
void test_complex_expression_tree();
9+
void test_moved_expression_tree();
10+
void test_copied_expression_tree();
11+
12+
int main(int argc, char** argv) {
13+
test_simple_expression_tree();
14+
test_complex_expression_tree();
15+
test_moved_expression_tree();
16+
test_copied_expression_tree();
17+
18+
return EXIT_SUCCESS;
19+
}
20+
21+
void test_simple_expression_tree() {
22+
auto test_procedure = [](const expression_tree<test_fixture>& expr) {
23+
test_fixture fixture;
24+
fixture.some_string = "hello!";
25+
assert(!expr.evaluate(fixture));
26+
27+
fixture.some_string = "hello world!";
28+
assert(!expr.evaluate(fixture));
29+
30+
fixture.some_string = "hello,world!";
31+
assert(!expr.evaluate(fixture));
32+
33+
fixture.some_string = "hello, world!";
34+
assert(expr.evaluate(fixture));
35+
};
36+
37+
// test raw pointer creation of expression_tree
38+
{
39+
expression_tree<test_fixture> expr {
40+
make_expr(&test_fixture::some_string, op::equals, std::string("hello, world!"))
41+
};
42+
43+
test_procedure(expr);
44+
}
45+
46+
// test unique_ptr creation of expression_tree
47+
{
48+
expression_tree<test_fixture> expr {
49+
std::unique_ptr<node::expression_tree_node<test_fixture>>(
50+
make_expr(&test_fixture::some_string, op::equals, std::string("hello, world!"))
51+
)
52+
};
53+
54+
test_procedure(expr);
55+
}
56+
}
57+
58+
void test_complex_expression_tree() {
59+
60+
}
61+
62+
void test_moved_expression_tree() {
63+
auto test_procedure = [](const expression_tree<test_fixture>& expr) {
64+
test_fixture fixture;
65+
66+
fixture.some_uint = 345;
67+
assert(expr.evaluate(fixture));
68+
69+
fixture.some_uint = 123;
70+
assert(!expr.evaluate(fixture));
71+
72+
fixture.some_uint = 543;
73+
assert(!expr.evaluate(fixture));
74+
75+
fixture.some_uint = 0x04;
76+
assert(!expr.evaluate(fixture));
77+
78+
fixture.some_uint = -1;
79+
assert(!expr.evaluate(fixture));
80+
81+
fixture.some_uint = 0;
82+
assert(!expr.evaluate(fixture));
83+
84+
fixture.some_uint = 3;
85+
assert(!expr.evaluate(fixture));
86+
};
87+
88+
expression_tree<test_fixture> expr {
89+
make_expr(&test_fixture::some_uint, op::equals, (uint16_t) 345)
90+
};
91+
test_procedure(expr);
92+
93+
expression_tree<test_fixture> move_constructed_expr( std::move(expr) );
94+
test_procedure(move_constructed_expr);
95+
96+
expression_tree<test_fixture> move_assigned_expr = std::move(move_constructed_expr);
97+
test_procedure(move_assigned_expr);
98+
}
99+
100+
void test_copied_expression_tree() {
101+
auto test_procedure = [](const expression_tree<test_fixture>& expr) {
102+
test_fixture fixture;
103+
104+
fixture.some_uint = 345;
105+
assert(expr.evaluate(fixture));
106+
107+
fixture.some_uint = 123;
108+
assert(!expr.evaluate(fixture));
109+
110+
fixture.some_uint = 543;
111+
assert(!expr.evaluate(fixture));
112+
113+
fixture.some_uint = 0x04;
114+
assert(!expr.evaluate(fixture));
115+
116+
fixture.some_uint = -1;
117+
assert(!expr.evaluate(fixture));
118+
119+
fixture.some_uint = 0;
120+
assert(!expr.evaluate(fixture));
121+
122+
fixture.some_uint = 3;
123+
assert(!expr.evaluate(fixture));
124+
};
125+
126+
expression_tree<test_fixture> expr {
127+
make_expr(&test_fixture::some_uint, op::equals, (uint16_t) 345)
128+
};
129+
test_procedure(expr);
130+
131+
expression_tree<test_fixture> copy_constructed_expr( expr );
132+
test_procedure(copy_constructed_expr);
133+
134+
expression_tree<test_fixture> copy_assigned_expr = copy_constructed_expr;
135+
test_procedure(copy_assigned_expr);
136+
137+
// ensure both of the old copied versions still work after copying
138+
test_procedure(expr);
139+
test_procedure(copy_constructed_expr);
140+
}

tests/expression_tree_leaf_node.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include <attwoodn/expression_tree.hpp>
22
#include "test_utils.hpp"
33
#include <limits>
4-
#include <iostream>
54
#include <cassert>
65

76
using namespace attwoodn::expression_tree;

tests/expression_tree_op_node.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include <attwoodn/expression_tree.hpp>
22
#include "test_utils.hpp"
33
#include <limits>
4-
#include <memory>
5-
#include <iostream>
64
#include <cassert>
75

86
using namespace attwoodn::expression_tree;

0 commit comments

Comments
 (0)