source: src/Patterns/Observer/unittests/ObserverUnitTest.cpp@ 3324cf

Last change on this file since 3324cf was b760ac5, checked in by Frederik Heber <heber@…>, 14 years ago

Relay can now also relay notifications.

  • NOTE: We do not yet notify the Observables, whose update() we combine, when the Relay is destroyed. They have to signOff before by themselves (or by some other means, e.g. be destroyed before.).
  • Property mode set to 100644
File size: 11.1 KB
RevLine 
[a80f419]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * ObserverTest.cpp
10 *
11 * Created on: Jan 19, 2010
12 * Author: crueger
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include <cppunit/CompilerOutputter.h>
21#include <cppunit/extensions/TestFactoryRegistry.h>
22#include <cppunit/ui/text/TestRunner.h>
23#include <set>
24
[9098f9]25#include "Assert.hpp"
[a80f419]26
27#include <iostream>
28
[56d62f]29#include "stubs/ObserverStub.hpp"
[e2e035e]30#include "Observer/Notification.hpp"
31#include "Observer/ObservedContainer.hpp"
32#include "Observer/ObservedContainer_impl.hpp"
[2c11c1]33#include "Observer/ObserverLog.hpp"
[56d62f]34
[a80f419]35#include "ObserverUnitTest.hpp"
36
37#ifdef HAVE_TESTRUNNER
38#include "UnitTestMain.hpp"
39#endif /*HAVE_TESTRUNNER*/
40
41// Registers the fixture into the 'registry'
42CPPUNIT_TEST_SUITE_REGISTRATION( ObserverTest );
43
44/******************* Test stubs ************************/
45
46
47/******************* actuall tests ***************/
48
49void ObserverTest::setUp() {
50 ASSERT_DO(Assert::Throw);
[2c11c1]51
[a80f419]52 simpleObservable1 = new SimpleObservable();
53 simpleObservable2 = new SimpleObservable();
54 callObservable = new CallObservable();
55 superObservable = new SuperObservable();
56 blockObservable = new BlockObservable();
57 notificationObservable = new NotificationObservable();
58 obsset = new ObservableSet(5);
59 obsmap = new ObservableMap(5);
60
61 observer1 = new UpdateCountObserver();
62 observer2 = new UpdateCountObserver();
63 observer3 = new UpdateCountObserver();
64 observer4 = new UpdateCountObserver();
65
[74e0f7]66 notificationObserver1 = new NotificationObserver(
67 notificationObservable->getChannel(NotificationObservable::Operation1Notify));
68 notificationObserver2 = new NotificationObserver(
69 notificationObservable->getChannel(NotificationObservable::Operation2Notify));
[d85532]70
71 RelayObservable = new RelayTest;
72 RelayObserver = new RelayCountObserver(RelayObservable);
[b760ac5]73
74 RelayNotifier = new RelayNotification;
75 RelayNotified = new RelayNotificationObserver(RelayObservable);
[a80f419]76}
77
78void ObserverTest::tearDown() {
79 delete simpleObservable1;
80 delete simpleObservable2;
81 delete callObservable;
82 delete superObservable;
83 delete blockObservable;
84 delete notificationObservable;
85 delete obsset;
86 delete obsmap;
[d85532]87 delete RelayObservable;
88 delete RelayObserver;
[b760ac5]89 delete RelayNotifier;
90 delete RelayNotified;
[a80f419]91
92 delete observer1;
93 delete observer2;
94 delete observer3;
95 delete observer4;
96 delete notificationObserver1;
97 delete notificationObserver2;
[2c11c1]98#ifdef LOG_OBSERVER
99 ObserverLog::purgeInstance();
100#endif
[a80f419]101}
102
103void ObserverTest::doesUpdateTest()
104{
105 simpleObservable1->signOn(observer1);
106 simpleObservable1->signOn(observer2);
107 simpleObservable1->signOn(observer3);
108
109 simpleObservable2->signOn(observer2);
110 simpleObservable2->signOn(observer4);
111
112 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
113 CPPUNIT_ASSERT_EQUAL( 0, observer2->updates );
114 CPPUNIT_ASSERT_EQUAL( 0, observer3->updates );
115 CPPUNIT_ASSERT_EQUAL( 0, observer4->updates );
116
117
118 simpleObservable1->changeMethod();
119 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
120 CPPUNIT_ASSERT_EQUAL( 1, observer2->updates );
121 CPPUNIT_ASSERT_EQUAL( 1, observer3->updates );
122 CPPUNIT_ASSERT_EQUAL( 0, observer4->updates );
123
124 simpleObservable1->signOff(observer3);
125
126 simpleObservable1->changeMethod();
127 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
128 CPPUNIT_ASSERT_EQUAL( 2, observer2->updates );
129 CPPUNIT_ASSERT_EQUAL( 1, observer3->updates );
130 CPPUNIT_ASSERT_EQUAL( 0, observer4->updates );
131
132 simpleObservable2->changeMethod();
133 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
134 CPPUNIT_ASSERT_EQUAL( 3, observer2->updates );
135 CPPUNIT_ASSERT_EQUAL( 1, observer3->updates );
136 CPPUNIT_ASSERT_EQUAL( 1, observer4->updates );
137}
138
139
140void ObserverTest::doesBlockUpdateTest() {
141 callObservable->signOn(observer1);
142 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
143
144 callObservable->changeMethod1();
145 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
146
147 callObservable->changeMethod2();
148 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
149}
150
151void ObserverTest::doesSubObservableTest() {
152 superObservable->signOn(observer1);
153 superObservable->subObservable->signOn(observer2);
154
155 superObservable->subObservable->changeMethod();
156 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
157 CPPUNIT_ASSERT_EQUAL( 1, observer2->updates );
158
159 superObservable->changeMethod();
160 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
161 CPPUNIT_ASSERT_EQUAL( 2, observer2->updates );
162}
163
164void ObserverTest::outsideLockTest(){
165 callObservable->signOn(observer1);
166 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
167
168 {
169 LOCK_OBSERVABLE(*callObservable);
170 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
171 }
172 // lock is gone now, observer should have notified
173 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
174}
175
176void ObserverTest::doesNotifyTest(){
[40f2e6]177 notificationObservable->signOn(notificationObserver1, NotificationObservable::Operation1Notify);
178 notificationObservable->signOn(notificationObserver2, NotificationObservable::Operation2Notify);
[a80f419]179
180 notificationObservable->operation1();
181 CPPUNIT_ASSERT(notificationObserver1->wasNotified);
182 CPPUNIT_ASSERT(!notificationObserver2->wasNotified);
183
184 notificationObserver1->wasNotified=false;
185
186 notificationObservable->operation2();
187 CPPUNIT_ASSERT(!notificationObserver1->wasNotified);
188 CPPUNIT_ASSERT(notificationObserver2->wasNotified);
189}
190
191void ObserverTest::doesReportTest(){
192 // Actual checks are in the Stub-methods for this
193 blockObservable->changeMethod1();
194 blockObservable->changeMethod2();
195 blockObservable->noChangeMethod();
196}
197
198void ObserverTest::iteratorTest(){
199 int i = 0;
200 // test the general iterator methods
201 for(ObservableSet::iterator iter=obsset->begin(); iter!=obsset->end();++iter){
202 CPPUNIT_ASSERT(i< obsset->num);
203 i++;
204 }
205
206 i=0;
207 for(ObservableSet::const_iterator iter=obsset->begin(); iter!=obsset->end();++iter){
208 CPPUNIT_ASSERT(i<obsset->num);
209 i++;
210 }
211
212 obsset->signOn(observer1);
213 {
214 // we construct this out of the loop, so the iterator dies at the end of
215 // the scope and not the end of the loop (allows more testing)
216 ObservableSet::iterator iter;
217 for(iter=obsset->begin(); iter!=obsset->end(); ++iter){
218 (*iter)->changeMethod();
219 }
220 // At this point no change should have been propagated
221 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates);
222 }
223 // After the Iterator has died the propagation should take place
224 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates);
225
226 // when using a const_iterator no changes should be propagated
227 for(ObservableSet::const_iterator iter = obsset->begin(); iter!=obsset->end();++iter);
228 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates);
229
230 // we need to test the operator-> as well
231 obsmap->signOn(observer2);
232 {
233 // we construct this out of the loop, so the iterator dies at the end of
234 // the scope and not the end of the loop (allows more testing)
235 ObservableMap::iterator iter;
236 for(iter=obsmap->begin(); iter!=obsmap->end(); ++iter){
237 iter->second->changeMethod();
238 }
239 // At this point no change should have been propagated
240 CPPUNIT_ASSERT_EQUAL( 0, observer2->updates);
241 }
242 // After the Iterator has died the propagation should take place
243 CPPUNIT_ASSERT_EQUAL( 1, observer2->updates);
244
245 obsset->signOff(observer1);
246 obsmap->signOff(observer2);
247}
248
[d85532]249void ObserverTest::relayTest()
250{
251 // sign on some observables to the relay
252 simpleObservable1->signOn(RelayObservable);
253 simpleObservable2->signOn(RelayObservable);
254
255 // sign on an observer to the relay
256 RelayObservable->signOn(RelayObserver);
257 simpleObservable1->signOn(observer1);
258
259 // check that all is zero
260 CPPUNIT_ASSERT_EQUAL( 0, RelayObserver->updates );
261 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
262
263 // signal update
264 simpleObservable1->changeMethod();
265
266 // check that both the change
267 // (and RelayObserver checks being called correctly)
268 CPPUNIT_ASSERT_EQUAL( 1, RelayObserver->updates );
269 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
270
271 // signal update through relay only
272 simpleObservable2->changeMethod();
273
274 // check that only one got the change
275 CPPUNIT_ASSERT_EQUAL( 2, RelayObserver->updates );
276 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
277
278 // check on signOff
279 simpleObservable1->signOff(RelayObservable);
280 simpleObservable1->signOff(observer1);
281}
282
[b760ac5]283void ObserverTest::relayNotificationTest()
284{
285 observerLog().enableLogging();
286
287 // sign on some observables to the relay
288 notificationObservable->signOn(RelayNotifier, NotificationObservable::Operation1Notify);
289 notificationObservable->signOn(RelayNotifier, NotificationObservable::Operation2Notify);
290 notificationObservable->signOn(notificationObserver1, NotificationObservable::Operation1Notify);
291
292 RelayNotifier->signOn(RelayNotified, NotificationObservable::Operation1Notify);
293
294 // operation1
295 notificationObservable->operation1();
296 CPPUNIT_ASSERT(RelayNotified->wasNotified);
297 CPPUNIT_ASSERT(notificationObserver1->wasNotified);
298
299 RelayNotified->wasNotified=false;
300
301 // operation2
302 notificationObservable->operation2();
303 CPPUNIT_ASSERT(!RelayNotified->wasNotified);
304 CPPUNIT_ASSERT(notificationObserver1->wasNotified);
305
306 // signOff relay from 1 and operation1
307 notificationObserver1->wasNotified=false;
308 notificationObservable->signOff(RelayNotifier, NotificationObservable::Operation1Notify);
309
310 notificationObservable->operation1();
311 CPPUNIT_ASSERT(!RelayNotified->wasNotified);
312 CPPUNIT_ASSERT(notificationObserver1->wasNotified);
313
314 // test kill subject
315 delete RelayNotified;
316 RelayNotified = NULL; // delete in tearDown is allowed for NULL
317 notificationObservable->operation1();
318 delete notificationObservable;
319 notificationObservable = NULL; // delete in tearDown is allowed for NULL
320
321 observerLog().disableLogging();
322}
323
[a80f419]324void ObserverTest::CircleDetectionTest() {
325 std::cout << std::endl << "Warning: the next test involved methods that can produce infinite loops." << std::endl;
326 std::cout << "Errors in this methods can not be checked using the CPPUNIT_ASSERT Macros." << std::endl;
327 std::cout << "Instead tests are run on these methods to see if termination is assured" << std::endl << std::endl;
328 std::cout << "If this test does not complete in a few seconds, kill the test-suite and fix the Error in the circle detection mechanism" << std::endl;
329
330 std::cout << std::endl << std::endl << "The following errors displayed by the observer framework can be ignored" << std::endl;
331
332 // make this Observable its own subject. NEVER DO THIS IN ACTUAL CODE
333 simpleObservable1->signOn(simpleObservable1);
334#ifndef NDEBUG
335 CPPUNIT_ASSERT_THROW(simpleObservable1->changeMethod(),Assert::AssertionFailure);
336#else
337 simpleObservable1->changeMethod();
338#endif
339
340 // more complex test
341 simpleObservable1->signOff(simpleObservable1);
342 simpleObservable1->signOn(simpleObservable2);
343 simpleObservable2->signOn(simpleObservable1);
344#ifndef NDEBUG
345 CPPUNIT_ASSERT_THROW(simpleObservable1->changeMethod(),Assert::AssertionFailure);
346#else
347 simpleObservable1->changeMethod();
348#endif
349
350
351 simpleObservable1->signOff(simpleObservable2);
352 simpleObservable2->signOff(simpleObservable1);
353 // when we reach this line, although we broke the DAG assumption the circle check works fine
354 CPPUNIT_ASSERT(true);
355}
Note: See TracBrowser for help on using the repository browser.