/* * ObserverTest.cpp * * Created on: Jan 19, 2010 * Author: crueger */ #include "ObserverTest.hpp" #include #include #include #include "Patterns/Observer.hpp" #include using namespace std; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( ObserverTest ); /******************* Test stubs ************************/ class UpdateCountObserver : public Observer { public: UpdateCountObserver() : updates(0) {}; void update(Observable *publisher){ updates++; } void subjectKilled(Observable *publisher) { } int updates; }; class SimpleObservable : public Observable { public: void changeMethod() { OBSERVE; int i; i++; } }; class CallObservable : public Observable { public: void changeMethod1() { OBSERVE; int i; i++; } void changeMethod2() { OBSERVE; int i; i++; changeMethod1(); } }; class SuperObservable : public Observable { public: SuperObservable(){ subObservable = new SimpleObservable(); subObservable->signOn(this); } ~SuperObservable(){ delete subObservable; } void changeMethod() { OBSERVE; int i; i++; subObservable->changeMethod(); } SimpleObservable *subObservable; }; /******************* actuall tests ***************/ void ObserverTest::setUp() { simpleObservable1 = new SimpleObservable(); simpleObservable2 = new SimpleObservable(); callObservable = new CallObservable(); superObservable = new SuperObservable(); observer1 = new UpdateCountObserver(); observer2 = new UpdateCountObserver(); observer3 = new UpdateCountObserver(); observer4 = new UpdateCountObserver(); } void ObserverTest::tearDown() { delete simpleObservable1; delete simpleObservable2; delete callObservable; delete superObservable; delete observer1; delete observer2; delete observer3; delete observer4; } void ObserverTest::doesUpdateTest() { simpleObservable1->signOn(observer1); simpleObservable1->signOn(observer2); simpleObservable1->signOn(observer3); simpleObservable2->signOn(observer2); simpleObservable2->signOn(observer4); simpleObservable1->changeMethod(); CPPUNIT_ASSERT_EQUAL( 1, observer1->updates ); CPPUNIT_ASSERT_EQUAL( 1, observer2->updates ); CPPUNIT_ASSERT_EQUAL( 1, observer3->updates ); CPPUNIT_ASSERT_EQUAL( 0, observer4->updates ); simpleObservable1->signOff(observer3); simpleObservable1->changeMethod(); CPPUNIT_ASSERT_EQUAL( 2, observer1->updates ); CPPUNIT_ASSERT_EQUAL( 2, observer2->updates ); CPPUNIT_ASSERT_EQUAL( 1, observer3->updates ); CPPUNIT_ASSERT_EQUAL( 0, observer4->updates ); simpleObservable2->changeMethod(); CPPUNIT_ASSERT_EQUAL( 2, observer1->updates ); CPPUNIT_ASSERT_EQUAL( 3, observer2->updates ); CPPUNIT_ASSERT_EQUAL( 1, observer3->updates ); CPPUNIT_ASSERT_EQUAL( 1, observer4->updates ); } void ObserverTest::doesBlockUpdateTest() { callObservable->signOn(observer1); callObservable->changeMethod1(); CPPUNIT_ASSERT_EQUAL( 1, observer1->updates ); callObservable->changeMethod2(); CPPUNIT_ASSERT_EQUAL( 2, observer1->updates ); } void ObserverTest::doesSubObservableTest() { superObservable->signOn(observer1); superObservable->subObservable->signOn(observer2); superObservable->subObservable->changeMethod(); CPPUNIT_ASSERT_EQUAL( 1, observer1->updates ); CPPUNIT_ASSERT_EQUAL( 1, observer2->updates ); superObservable->changeMethod(); CPPUNIT_ASSERT_EQUAL( 2, observer1->updates ); CPPUNIT_ASSERT_EQUAL( 2, observer2->updates ); } void ObserverTest::CircleDetectionTest() { cout << endl << "Warning: the next test involved methods that can produce infinite loops." << endl; cout << "Errors in this methods can not be checked using the CPPUNIT_ASSERT Macros." << endl; cout << "Instead tests are run on these methods to see if termination is assured" << endl << endl; cout << "If this test does not complete in a few seconds, kill the test-suite and fix the Error in the circle detection mechanism" << endl; cout << endl << endl << "The following errors displayed by the observer framework can be ignored" << endl; // make this Observable its own subject. NEVER DO THIS IN ACTUAL CODE simpleObservable1->signOn(simpleObservable1); simpleObservable1->changeMethod(); // more complex test simpleObservable1->signOff(simpleObservable1); simpleObservable1->signOn(simpleObservable2); simpleObservable2->signOn(simpleObservable1); simpleObservable1->changeMethod(); simpleObservable1->signOff(simpleObservable2); simpleObservable2->signOff(simpleObservable1); // when we reach this line, although we broke the DAG assumption the circle check works fine CPPUNIT_ASSERT(true); } /********************************************** Main routine **************************************/ int main(int argc, char **argv) { // Get the top level suite from the registry CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); // Adds the test to the list of test to run CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); // Change the default outputter to a compiler error format outputter runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); // Run the tests. bool wasSucessful = runner.run(); // Return error code 1 if the one of test failed. return wasSucessful ? 0 : 1; };