summaryrefslogtreecommitdiff
path: root/tests/test_incremental_expression.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_incremental_expression.cc')
-rw-r--r--tests/test_incremental_expression.cc1008
1 files changed, 1008 insertions, 0 deletions
diff --git a/tests/test_incremental_expression.cc b/tests/test_incremental_expression.cc
new file mode 100644
index 00000000..5f91964c
--- /dev/null
+++ b/tests/test_incremental_expression.cc
@@ -0,0 +1,1008 @@
+// test_incremental_expression.cc
+//
+// Copyright (C) 2010 Daniel Burrows
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; see the file COPYING. If not, write to
+// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+#include <generic/problemresolver/incremental_expression.h>
+
+#include <boost/variant.hpp>
+
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace cw = cwidget;
+
+namespace
+{
+ // Make it possible to "show" vectors.
+ template<typename T, typename Alloc>
+ std::ostream &operator<<(std::ostream &out, const std::vector<T, Alloc> &v)
+ {
+ out << "[";
+
+ for(typename std::vector<T, Alloc>::const_iterator it =
+ v.begin(); it != v.end(); ++it)
+ {
+ if(it != v.begin())
+ out << ", ";
+
+ out << *it;
+ }
+
+ out << "]";
+
+ return out;
+ }
+
+ // Helper class for the code below that records a single call to
+ // child_modified().
+ template<typename T>
+ class child_modified_call
+ {
+ cw::util::ref_ptr<expression<T> > child;
+ T old_value, new_value;
+
+ public:
+ child_modified_call(const cw::util::ref_ptr<expression<T> > &_child,
+ const T &_old_value, const T &_new_value)
+ : child(_child), old_value(_old_value), new_value(_new_value)
+ {
+ }
+
+ const cw::util::ref_ptr<expression<T> > &get_child() const { return child; }
+ const T &get_old_value() const { return old_value; }
+ const T &get_new_value() const { return new_value; }
+
+ bool operator==(const child_modified_call &other) const
+ {
+ return
+ child == other.child &&
+ old_value == other.old_value &&
+ new_value == other.new_value;
+ }
+ };
+
+ template<typename T>
+ std::ostream &operator<<(std::ostream &out, const child_modified_call<T> &t)
+ {
+ return out << "child_modified(child = " << t.get_child()
+ << ", old_value = " << t.get_old_value()
+ << ", new_value = " << t.get_new_value() << ")";
+ }
+
+ template<typename T>
+ class get_value_call
+ {
+ T return_value;
+
+ public:
+ get_value_call(const T &_return_value)
+ : return_value(_return_value)
+ {
+ }
+
+ const T &get_return_value() const { return return_value; }
+
+ bool operator==(const get_value_call &other) const
+ {
+ return return_value == other.return_value;
+ }
+ };
+
+ template<typename T>
+ std::ostream &operator<<(std::ostream &out, const get_value_call<T> &c)
+ {
+ return out << "get_value() => " << c.get_return_value();
+ }
+
+ // A class that implements the expression container interface,
+ // passing all interesting calls to a single sub-object and
+ // recording all the calls to child_modified.
+ template<typename T>
+ class fake_container : public expression_container<T>
+ {
+ cw::util::ref_ptr<expression<T> > real_object;
+ std::vector<child_modified_call<T> > calls;
+
+ fake_container(const cw::util::ref_ptr<expression<T> > &_real_object)
+ : real_object(_real_object)
+ {
+ real_object->add_parent(this);
+ }
+
+ public:
+ ~fake_container()
+ {
+ real_object->remove_parent(this);
+ }
+
+ static cw::util::ref_ptr<fake_container<T> >
+ create(const cw::util::ref_ptr<expression<T> > &child)
+ {
+ return new fake_container<T>(child);
+ }
+
+ const std::vector<child_modified_call<T> > &get_calls() const { return calls; }
+
+ void child_modified(const cw::util::ref_ptr<expression<T> > &child,
+ T old_value,
+ T new_value)
+ {
+ calls.push_back(child_modified_call<T>(child, old_value, new_value));
+ }
+
+ T get_value()
+ {
+ return real_object->get_value();
+ }
+
+ void dump(std::ostream &out)
+ {
+ real_object->dump(out);
+ }
+ };
+
+ // Records calls to expression_box::changed.
+ template<typename T>
+ class changed_call
+ {
+ T new_value;
+
+ public:
+ changed_call(const T &_new_value)
+ : new_value(_new_value)
+ {
+ }
+
+ const T &get_new_value() const { return new_value; }
+ };
+
+ template<typename T>
+ std::ostream &operator<<(std::ostream &out, const changed_call<T> &c)
+ {
+ return out << "changed(" << c.get_new_value() << ")";
+ }
+
+ // A helper class used to test that expression_wrapper behaves as
+ // advertised.
+ //
+ // Wraps its subexpression and records all the calls to
+ // child_modified() and changed().
+ template<typename T>
+ class fake_wrapper : public expression_wrapper<T>
+ {
+ std::vector<boost::variant<child_modified_call<T>, changed_call<T> > > calls;
+
+ fake_wrapper() : expression_wrapper<T>() { }
+ fake_wrapper(const cw::util::ref_ptr<expression<T> > &child)
+ : expression_wrapper<T>(child)
+ {
+ }
+
+ public:
+ static cw::util::ref_ptr<fake_wrapper> create()
+ {
+ return new fake_wrapper;
+ }
+
+ static cw::util::ref_ptr<fake_wrapper>
+ create(const cw::util::ref_ptr<expression<T> > &child)
+ {
+ return new fake_wrapper(child);
+ }
+
+ void child_modified(const cw::util::ref_ptr<expression<T> > &child,
+ T old_value,
+ T new_value)
+ {
+ calls.push_back(child_modified_call<T>(child, old_value, new_value));
+
+ expression_wrapper<T>::child_modified(child, old_value, new_value);
+ }
+
+ void changed(T new_value)
+ {
+ calls.push_back(changed_call<T>(new_value));
+
+ expression_wrapper<T>::changed(this->get_child());
+ }
+ };
+}
+
+class TestIncrementalExpression : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestIncrementalExpression);
+
+ CPPUNIT_TEST(testIncrementalExpressionGetVarValue);
+ CPPUNIT_TEST(testIncrementalExpressionSetVarValue);
+ CPPUNIT_TEST(testIncrementalExpressionVarSignalChange);
+ // TODO: test comparisons?
+ // TODO: test conversions to string?
+
+ CPPUNIT_TEST(testIncrementalExpressionWeakRefDeref);
+ CPPUNIT_TEST(testIncrementalExpressionWeakRefGetValidLive);
+ CPPUNIT_TEST(testIncrementalExpressionWeakRefGetValidDead);
+
+ CPPUNIT_TEST(testNotFalse);
+ CPPUNIT_TEST(testNotTrue);
+ CPPUNIT_TEST(testNotRaiseInput);
+ CPPUNIT_TEST(testNotLowerInput);
+ CPPUNIT_TEST(testNotNull);
+
+ CPPUNIT_TEST(testAndEmpty);
+
+ CPPUNIT_TEST(testAndSingletonRaise);
+ CPPUNIT_TEST(testAndSingletonLower);
+ CPPUNIT_TEST(testAndSingletonRaiseByRemoving);
+ CPPUNIT_TEST(testAndSingletonLowerByAppending);
+ CPPUNIT_TEST(testAndSingletonNull);
+
+ CPPUNIT_TEST(testAndDoubletonFirstNull);
+ CPPUNIT_TEST(testAndDoubletonSecondNull);
+ CPPUNIT_TEST(testAndDoubletonBothNull);
+
+ CPPUNIT_TEST(testAndDoubletonRaiseFirst);
+ CPPUNIT_TEST(testAndDoubletonRaiseSecond);
+ CPPUNIT_TEST(testAndDoubletonRaiseFirstNoEffect);
+ CPPUNIT_TEST(testAndDoubletonRaiseSecondNoEffect);
+
+ CPPUNIT_TEST(testAndDoubletonLowerFirst);
+ CPPUNIT_TEST(testAndDoubletonLowerSecond);
+ CPPUNIT_TEST(testAndDoubletonLowerFirstNoEffect);
+ CPPUNIT_TEST(testAndDoubletonLowerSecondNoEffect);
+
+ CPPUNIT_TEST(testOrEmpty);
+
+ CPPUNIT_TEST(testOrSingletonRaise);
+ CPPUNIT_TEST(testOrSingletonLower);
+ CPPUNIT_TEST(testOrSingletonLowerByRemoving);
+ CPPUNIT_TEST(testOrSingletonRaiseByAppending);
+ CPPUNIT_TEST(testOrSingletonNull);
+
+ CPPUNIT_TEST(testOrDoubletonFirstNull);
+ CPPUNIT_TEST(testOrDoubletonSecondNull);
+ CPPUNIT_TEST(testOrDoubletonBothNull);
+
+ CPPUNIT_TEST(testOrDoubletonRaiseFirst);
+ CPPUNIT_TEST(testOrDoubletonRaiseSecond);
+ CPPUNIT_TEST(testOrDoubletonRaiseFirstNoEffect);
+ CPPUNIT_TEST(testOrDoubletonRaiseSecondNoEffect);
+
+ CPPUNIT_TEST(testOrDoubletonLowerFirst);
+ CPPUNIT_TEST(testOrDoubletonLowerSecond);
+ CPPUNIT_TEST(testOrDoubletonLowerFirstNoEffect);
+ CPPUNIT_TEST(testOrDoubletonLowerSecondNoEffect);
+
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void testIncrementalExpressionGetVarValue()
+ {
+ cw::util::ref_ptr<var_e<int> >
+ v0 = var_e<int>::create(0),
+ v5 = var_e<int>::create(5),
+ v9 = var_e<int>::create(9);
+
+ CPPUNIT_ASSERT_EQUAL(0, v0->get_value());
+ CPPUNIT_ASSERT_EQUAL(5, v5->get_value());
+ CPPUNIT_ASSERT_EQUAL(9, v9->get_value());
+ }
+
+ void testIncrementalExpressionSetVarValue()
+ {
+ cw::util::ref_ptr<var_e<int> > v = var_e<int>::create(123456);
+
+ v->set_value(987654);
+ CPPUNIT_ASSERT_EQUAL(987654, v->get_value());
+ }
+
+ void testIncrementalExpressionVarSignalChange()
+ {
+ cw::util::ref_ptr<var_e<int> > v = var_e<int>::create(55555);
+
+ cw::util::ref_ptr<fake_container<int> > c = fake_container<int>::create(v);
+
+ std::vector<child_modified_call<int> > expected_calls;
+ expected_calls.push_back(child_modified_call<int>(v, 55555, 42));
+ expected_calls.push_back(child_modified_call<int>(v, 42, 10));
+
+ v->set_value(42);
+ // Test that setting to the same value doesn't emit a signal.
+ v->set_value(42);
+ v->set_value(10);
+
+ CPPUNIT_ASSERT_EQUAL(expected_calls, c->get_calls());
+ }
+
+
+ void testIncrementalExpressionWeakRefDeref()
+ {
+ cw::util::ref_ptr<expression<int> > e = var_e<int>::create(5);
+ expression_weak_ref<expression<int> > e_ref = e;
+
+ CPPUNIT_ASSERT_EQUAL(e.unsafe_get_ref(), e_ref.get_value());
+ }
+
+ void testIncrementalExpressionWeakRefGetValidLive()
+ {
+ cw::util::ref_ptr<expression<int> > e = var_e<int>::create(5);
+ expression_weak_ref<expression<int> > e_ref = e;
+
+ CPPUNIT_ASSERT(e_ref.get_valid());
+ }
+
+ void testIncrementalExpressionWeakRefGetValidDead()
+ {
+ cw::util::ref_ptr<expression<int> > e = var_e<int>::create(5);
+ expression_weak_ref<expression<int> > e_ref = e;
+
+ e = cw::util::ref_ptr<expression<int> >();
+
+ CPPUNIT_ASSERT(!e_ref.get_valid());
+ }
+
+
+ void testNotFalse()
+ {
+ cw::util::ref_ptr<expression<bool> > v = var_e<bool>::create(true);
+ cw::util::ref_ptr<expression<bool> > not_v = not_e::create(v);
+
+ CPPUNIT_ASSERT(!not_v->get_value());
+ }
+
+ void testNotTrue()
+ {
+ cw::util::ref_ptr<expression<bool> > v = var_e<bool>::create(false);
+ cw::util::ref_ptr<expression<bool> > not_v = not_e::create(v);
+
+ CPPUNIT_ASSERT(not_v->get_value());
+ }
+
+ void testNotRaiseInput()
+ {
+ cw::util::ref_ptr<var_e<bool> > v = var_e<bool>::create(false);
+ cw::util::ref_ptr<expression<bool> > not_v = not_e::create(v);
+
+ cw::util::ref_ptr<fake_container<bool> > not_v_wrap =
+ fake_container<bool>::create(not_v);
+
+ CPPUNIT_ASSERT(not_v->get_value());
+ v->set_value(true);
+ CPPUNIT_ASSERT(!not_v->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(not_v, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, not_v_wrap->get_calls());
+ }
+
+ void testNotLowerInput()
+ {
+ cw::util::ref_ptr<var_e<bool> > v = var_e<bool>::create(true);
+ cw::util::ref_ptr<expression<bool> > not_v = not_e::create(v);
+
+ cw::util::ref_ptr<fake_container<bool> > not_v_wrap =
+ fake_container<bool>::create(not_v);
+
+ CPPUNIT_ASSERT(!not_v->get_value());
+ v->set_value(false);
+ CPPUNIT_ASSERT(not_v->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(not_v, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, not_v_wrap->get_calls());
+ }
+
+ void testNotNull()
+ {
+ cw::util::ref_ptr<expression<bool> > not_null = not_e::create(cw::util::ref_ptr<expression<bool> >());
+
+ CPPUNIT_ASSERT(!not_null->get_value());
+ }
+
+
+ void testAndEmpty()
+ {
+ cw::util::ref_ptr<expression<bool> > empty[] = { };
+ cw::util::ref_ptr<expression<bool> > e = and_e::create(empty, empty);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+private:
+ cw::util::ref_ptr<and_e> getAndSingleton(cw::util::ref_ptr<var_e<bool> > v1)
+ {
+ cw::util::ref_ptr<expression<bool> > subexprs_begin[] = { v1 };
+ cw::util::ref_ptr<expression<bool> > *subexprs_end =
+ subexprs_begin + sizeof(subexprs_begin) / sizeof(subexprs_begin[0]);
+
+ return and_e::create(subexprs_begin, subexprs_end);
+ }
+
+public:
+ void testAndSingletonRaise()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(false);
+ cw::util::ref_ptr<and_e> e = getAndSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v1->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndSingletonLower()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(true);
+ cw::util::ref_ptr<and_e> e = getAndSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v1->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndSingletonRaiseByRemoving()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(false);
+ cw::util::ref_ptr<and_e> e = getAndSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ e->remove_child(v1);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndSingletonLowerByAppending()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(true);
+ cw::util::ref_ptr<and_e> e = getAndSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ e->add_child(var_e<bool>::create(false));
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndSingletonNull()
+ {
+ cw::util::ref_ptr<and_e> e = getAndSingleton(cw::util::ref_ptr<var_e<bool> >());
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+private:
+ cw::util::ref_ptr<and_e> getAndDoubleton(const cw::util::ref_ptr<var_e<bool> > &v1,
+ const cw::util::ref_ptr<var_e<bool> > &v2)
+ {
+ cw::util::ref_ptr<expression<bool> > subexprs_begin[] = { v1, v2 };
+ cw::util::ref_ptr<expression<bool> > *subexprs_end =
+ subexprs_begin + sizeof(subexprs_begin) / sizeof(subexprs_begin[0]);
+
+ return and_e::create(subexprs_begin, subexprs_end);
+ }
+
+public:
+ void testAndDoubletonFirstNull()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1,
+ v2 = var_e<bool>::create(true);
+
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+ void testAndDoubletonSecondNull()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2;
+
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+ void testAndDoubletonBothNull()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1,
+ v2;
+
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+ void testAndDoubletonRaiseSecond()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v2->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndDoubletonRaiseFirst()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v1->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndDoubletonRaiseFirstNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v1->set_value(true);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndDoubletonRaiseSecondNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v2->set_value(true);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+
+ void testAndDoubletonLowerFirst()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v1->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndDoubletonLowerSecond()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v2->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+
+ void testAndDoubletonLowerFirstNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v1->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testAndDoubletonLowerSecondNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<and_e> e = getAndDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v2->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+
+
+
+ void testOrEmpty()
+ {
+ cw::util::ref_ptr<expression<bool> > empty[] = { };
+ cw::util::ref_ptr<expression<bool> > e = or_e::create(empty, empty);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ }
+
+private:
+ cw::util::ref_ptr<or_e> getOrSingleton(cw::util::ref_ptr<var_e<bool> > v1)
+ {
+ cw::util::ref_ptr<expression<bool> > subexprs_begin[] = { v1 };
+ cw::util::ref_ptr<expression<bool> > *subexprs_end =
+ subexprs_begin + sizeof(subexprs_begin) / sizeof(subexprs_begin[0]);
+
+ return or_e::create(subexprs_begin, subexprs_end);
+ }
+
+public:
+ void testOrSingletonRaise()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(false);
+ cw::util::ref_ptr<or_e> e = getOrSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v1->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrSingletonLower()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(true);
+ cw::util::ref_ptr<or_e> e = getOrSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v1->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrSingletonLowerByRemoving()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(true);
+ cw::util::ref_ptr<or_e> e = getOrSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ e->remove_child(v1);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrSingletonRaiseByAppending()
+ {
+ cw::util::ref_ptr<var_e<bool> > v1 = var_e<bool>::create(false);
+ cw::util::ref_ptr<or_e> e = getOrSingleton(v1);
+
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ e->add_child(var_e<bool>::create(true));
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrSingletonNull()
+ {
+ cw::util::ref_ptr<or_e> e = getOrSingleton(cw::util::ref_ptr<var_e<bool> >());
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+private:
+ cw::util::ref_ptr<or_e> getOrDoubleton(const cw::util::ref_ptr<var_e<bool> > &v1,
+ const cw::util::ref_ptr<var_e<bool> > &v2)
+ {
+ cw::util::ref_ptr<expression<bool> > subexprs_begin[] = { v1, v2 };
+ cw::util::ref_ptr<expression<bool> > *subexprs_end =
+ subexprs_begin + sizeof(subexprs_begin) / sizeof(subexprs_begin[0]);
+
+ return or_e::create(subexprs_begin, subexprs_end);
+ }
+
+public:
+ void testOrDoubletonFirstNull()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1,
+ v2 = var_e<bool>::create(false);
+
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+ void testOrDoubletonSecondNull()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2;
+
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+ void testOrDoubletonBothNull()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1,
+ v2;
+
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+
+ CPPUNIT_ASSERT(e->get_value());
+ }
+
+ void testOrDoubletonRaiseFirst()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v1->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrDoubletonRaiseSecond()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(!e->get_value());
+ v2->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, false, true));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrDoubletonRaiseFirstNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v1->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrDoubletonRaiseSecondNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v2->set_value(true);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+
+ void testOrDoubletonLowerFirst()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(false);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v1->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrDoubletonLowerSecond()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(false),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v2->set_value(false);
+ CPPUNIT_ASSERT(!e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+ expected.push_back(child_modified_call<bool>(e, true, false));
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+
+ void testOrDoubletonLowerFirstNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v1->set_value(false);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+
+ void testOrDoubletonLowerSecondNoEffect()
+ {
+ cw::util::ref_ptr<var_e<bool> >
+ v1 = var_e<bool>::create(true),
+ v2 = var_e<bool>::create(true);
+ cw::util::ref_ptr<or_e> e = getOrDoubleton(v1, v2);
+ cw::util::ref_ptr<fake_container<bool> > e_wrap =
+ fake_container<bool>::create(e);
+
+ CPPUNIT_ASSERT(e->get_value());
+ v2->set_value(false);
+ CPPUNIT_ASSERT(e->get_value());
+
+ std::vector<child_modified_call<bool> > expected;
+
+ CPPUNIT_ASSERT_EQUAL(expected, e_wrap->get_calls());
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestIncrementalExpression);