source: src/Patterns/unittests/ObserverUnitTest.cpp@ a2c4f3

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since a2c4f3 was a2c4f3, checked in by Frederik Heber <heber@…>, 14 years ago

Moved ObserverTest to Patterns/unittests/ObserverUnitTest.

  • Property mode set to 100644
File size: 12.5 KB
Line 
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
25#include "Patterns/Observer.hpp"
26#include "Patterns/ObservedIterator.hpp"
27#include "Helpers/Assert.hpp"
28
29#include <iostream>
30
31#include "ObserverUnitTest.hpp"
32
33#ifdef HAVE_TESTRUNNER
34#include "UnitTestMain.hpp"
35#endif /*HAVE_TESTRUNNER*/
36
37// Registers the fixture into the 'registry'
38CPPUNIT_TEST_SUITE_REGISTRATION( ObserverTest );
39
40/******************* Test stubs ************************/
41
42class UpdateCountObserver : public Observer {
43public:
44 UpdateCountObserver() :
45 Observer("UpdateCountObserver"),
46 updates(0)
47 {};
48 void update(Observable *publisher){
49 updates++;
50 }
51 void subjectKilled(Observable *publisher) {
52 }
53 int updates;
54};
55
56class SimpleObservable : public Observable {
57public:
58 SimpleObservable() :
59 Observable("SimpleObservable")
60 {}
61
62 void changeMethod() {
63 OBSERVE;
64 int i = 0;
65 i++;
66 }
67};
68
69class CallObservable : public Observable {
70public:
71 CallObservable() :
72 Observable("CallObservable")
73 {}
74
75 void changeMethod1() {
76 OBSERVE;
77 int i = 0;
78 i++;
79 }
80
81 void changeMethod2() {
82 OBSERVE;
83 int i = 0;
84 i++;
85 changeMethod1();
86 }
87};
88
89class BlockObservable : public Observable {
90public:
91 BlockObservable() :
92 Observable("BlockObservable")
93 {}
94
95 void changeMethod1(){
96 OBSERVE;
97 // test if we report correctly as blocked
98 CPPUNIT_ASSERT(isBlocked());
99 }
100
101 void changeMethod2(){
102 OBSERVE;
103 internalMethod1();
104 internalMethod2();
105 }
106
107 void internalMethod1(){
108 // we did not block, but our caller did...
109 // see if this is found
110 CPPUNIT_ASSERT(isBlocked());
111 }
112
113 void internalMethod2(){
114 OBSERVE;
115 // Both this method and the caller do block
116 // Does the reporting still work as expected?
117 CPPUNIT_ASSERT(isBlocked());
118 }
119
120 void noChangeMethod(){
121 // No Block introduced here
122 // reported correctely?
123 CPPUNIT_ASSERT(!isBlocked());
124 }
125};
126
127class SuperObservable : public Observable {
128public:
129 SuperObservable():
130 Observable("SuperObservable")
131 {
132 subObservable = new SimpleObservable();
133 subObservable->signOn(this);
134 }
135 ~SuperObservable(){
136 delete subObservable;
137 }
138 void changeMethod() {
139 OBSERVE;
140 int i = 0;
141 i++;
142 subObservable->changeMethod();
143 }
144 SimpleObservable *subObservable;
145};
146
147class NotificationObservable : public Observable {
148public:
149 NotificationObservable() :
150 Observable("NotificationObservable"),
151 notification1(new Notification(this)),
152 notification2(new Notification(this))
153 {}
154
155 ~NotificationObservable(){
156 delete notification1;
157 delete notification2;
158 }
159
160 void operation1(){
161 OBSERVE;
162 NOTIFY(notification1);
163 }
164
165 void operation2(){
166 OBSERVE;
167 NOTIFY(notification2);
168 }
169
170 Notification_ptr notification1;
171 Notification_ptr notification2;
172};
173
174class NotificationObserver : public Observer {
175public:
176 NotificationObserver(Notification_ptr notification) :
177 Observer("NotificationObserver"),
178 requestedNotification(notification),
179 wasNotified(false)
180 {}
181
182 void update(Observable*){}
183 void subjectKilled(Observable*){}
184 void recieveNotification(Observable *publisher, Notification_ptr notification){
185 ASSERT(requestedNotification==notification,"Notification received that was not requested");
186 wasNotified = true;
187 }
188
189 Notification_ptr requestedNotification;
190
191 bool wasNotified;
192};
193
194class ObservableSet : public Observable {
195public:
196 typedef std::set<SimpleObservable*> set;
197 typedef ObservedIterator<set> iterator;
198 typedef set::const_iterator const_iterator;
199
200 ObservableSet(int _num) :
201 Observable("ObservableCollection"),
202 num(_num)
203 {
204 for(int i=0; i<num; ++i){
205 SimpleObservable *content = new SimpleObservable();
206 content->signOn(this);
207 theSet.insert(content);
208 }
209 }
210
211 ~ObservableSet(){
212 set::iterator iter;
213 for(iter=theSet.begin(); iter!=theSet.end(); ++iter ){
214 delete (*iter);
215 }
216 }
217
218 iterator begin(){
219 return iterator(theSet.begin(),this);
220 }
221
222 iterator end(){
223 return iterator(theSet.end(),this);
224 }
225
226 const int num;
227
228private:
229 set theSet;
230};
231
232class ObservableMap : public Observable {
233public:
234 typedef std::map<int,SimpleObservable*> set;
235 typedef ObservedIterator<set> iterator;
236 typedef set::const_iterator const_iterator;
237
238 ObservableMap(int _num) :
239 Observable("ObservableCollection"),
240 num(_num)
241 {
242 for(int i=0; i<num; ++i){
243 SimpleObservable *content = new SimpleObservable();
244 content->signOn(this);
245 theSet.insert(std::make_pair(i,content));
246 }
247 }
248
249 ~ObservableMap(){
250 set::iterator iter;
251 for(iter=theSet.begin(); iter!=theSet.end(); ++iter ){
252 delete iter->second;
253 }
254 }
255
256 iterator begin(){
257 return iterator(theSet.begin(),this);
258 }
259
260 iterator end(){
261 return iterator(theSet.end(),this);
262 }
263
264 const int num;
265
266private:
267 set theSet;
268};
269
270
271/******************* actuall tests ***************/
272
273void ObserverTest::setUp() {
274 ASSERT_DO(Assert::Throw);
275 simpleObservable1 = new SimpleObservable();
276 simpleObservable2 = new SimpleObservable();
277 callObservable = new CallObservable();
278 superObservable = new SuperObservable();
279 blockObservable = new BlockObservable();
280 notificationObservable = new NotificationObservable();
281 obsset = new ObservableSet(5);
282 obsmap = new ObservableMap(5);
283
284 observer1 = new UpdateCountObserver();
285 observer2 = new UpdateCountObserver();
286 observer3 = new UpdateCountObserver();
287 observer4 = new UpdateCountObserver();
288
289 notificationObserver1 = new NotificationObserver(notificationObservable->notification1);
290 notificationObserver2 = new NotificationObserver(notificationObservable->notification2);
291}
292
293void ObserverTest::tearDown() {
294 delete simpleObservable1;
295 delete simpleObservable2;
296 delete callObservable;
297 delete superObservable;
298 delete blockObservable;
299 delete notificationObservable;
300 delete obsset;
301 delete obsmap;
302
303 delete observer1;
304 delete observer2;
305 delete observer3;
306 delete observer4;
307 delete notificationObserver1;
308 delete notificationObserver2;
309}
310
311void ObserverTest::doesUpdateTest()
312{
313 simpleObservable1->signOn(observer1);
314 simpleObservable1->signOn(observer2);
315 simpleObservable1->signOn(observer3);
316
317 simpleObservable2->signOn(observer2);
318 simpleObservable2->signOn(observer4);
319
320 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
321 CPPUNIT_ASSERT_EQUAL( 0, observer2->updates );
322 CPPUNIT_ASSERT_EQUAL( 0, observer3->updates );
323 CPPUNIT_ASSERT_EQUAL( 0, observer4->updates );
324
325
326 simpleObservable1->changeMethod();
327 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
328 CPPUNIT_ASSERT_EQUAL( 1, observer2->updates );
329 CPPUNIT_ASSERT_EQUAL( 1, observer3->updates );
330 CPPUNIT_ASSERT_EQUAL( 0, observer4->updates );
331
332 simpleObservable1->signOff(observer3);
333
334 simpleObservable1->changeMethod();
335 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
336 CPPUNIT_ASSERT_EQUAL( 2, observer2->updates );
337 CPPUNIT_ASSERT_EQUAL( 1, observer3->updates );
338 CPPUNIT_ASSERT_EQUAL( 0, observer4->updates );
339
340 simpleObservable2->changeMethod();
341 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
342 CPPUNIT_ASSERT_EQUAL( 3, observer2->updates );
343 CPPUNIT_ASSERT_EQUAL( 1, observer3->updates );
344 CPPUNIT_ASSERT_EQUAL( 1, observer4->updates );
345}
346
347
348void ObserverTest::doesBlockUpdateTest() {
349 callObservable->signOn(observer1);
350 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
351
352 callObservable->changeMethod1();
353 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
354
355 callObservable->changeMethod2();
356 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
357}
358
359void ObserverTest::doesSubObservableTest() {
360 superObservable->signOn(observer1);
361 superObservable->subObservable->signOn(observer2);
362
363 superObservable->subObservable->changeMethod();
364 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
365 CPPUNIT_ASSERT_EQUAL( 1, observer2->updates );
366
367 superObservable->changeMethod();
368 CPPUNIT_ASSERT_EQUAL( 2, observer1->updates );
369 CPPUNIT_ASSERT_EQUAL( 2, observer2->updates );
370}
371
372void ObserverTest::outsideLockTest(){
373 callObservable->signOn(observer1);
374 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
375
376 {
377 LOCK_OBSERVABLE(*callObservable);
378 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates );
379 }
380 // lock is gone now, observer should have notified
381 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates );
382}
383
384void ObserverTest::doesNotifyTest(){
385 notificationObservable->signOn(notificationObserver1,
386 notificationObservable->notification1);
387 notificationObservable->signOn(notificationObserver2,
388 notificationObservable->notification2);
389
390 notificationObservable->operation1();
391 CPPUNIT_ASSERT(notificationObserver1->wasNotified);
392 CPPUNIT_ASSERT(!notificationObserver2->wasNotified);
393
394 notificationObserver1->wasNotified=false;
395
396 notificationObservable->operation2();
397 CPPUNIT_ASSERT(!notificationObserver1->wasNotified);
398 CPPUNIT_ASSERT(notificationObserver2->wasNotified);
399
400}
401
402void ObserverTest::doesReportTest(){
403 // Actual checks are in the Stub-methods for this
404 blockObservable->changeMethod1();
405 blockObservable->changeMethod2();
406 blockObservable->noChangeMethod();
407}
408
409void ObserverTest::iteratorTest(){
410 int i = 0;
411 // test the general iterator methods
412 for(ObservableSet::iterator iter=obsset->begin(); iter!=obsset->end();++iter){
413 CPPUNIT_ASSERT(i< obsset->num);
414 i++;
415 }
416
417 i=0;
418 for(ObservableSet::const_iterator iter=obsset->begin(); iter!=obsset->end();++iter){
419 CPPUNIT_ASSERT(i<obsset->num);
420 i++;
421 }
422
423 obsset->signOn(observer1);
424 {
425 // we construct this out of the loop, so the iterator dies at the end of
426 // the scope and not the end of the loop (allows more testing)
427 ObservableSet::iterator iter;
428 for(iter=obsset->begin(); iter!=obsset->end(); ++iter){
429 (*iter)->changeMethod();
430 }
431 // At this point no change should have been propagated
432 CPPUNIT_ASSERT_EQUAL( 0, observer1->updates);
433 }
434 // After the Iterator has died the propagation should take place
435 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates);
436
437 // when using a const_iterator no changes should be propagated
438 for(ObservableSet::const_iterator iter = obsset->begin(); iter!=obsset->end();++iter);
439 CPPUNIT_ASSERT_EQUAL( 1, observer1->updates);
440
441 // we need to test the operator-> as well
442 obsmap->signOn(observer2);
443 {
444 // we construct this out of the loop, so the iterator dies at the end of
445 // the scope and not the end of the loop (allows more testing)
446 ObservableMap::iterator iter;
447 for(iter=obsmap->begin(); iter!=obsmap->end(); ++iter){
448 iter->second->changeMethod();
449 }
450 // At this point no change should have been propagated
451 CPPUNIT_ASSERT_EQUAL( 0, observer2->updates);
452 }
453 // After the Iterator has died the propagation should take place
454 CPPUNIT_ASSERT_EQUAL( 1, observer2->updates);
455
456
457 obsset->signOff(observer1);
458 obsmap->signOff(observer2);
459}
460
461void ObserverTest::CircleDetectionTest() {
462 std::cout << std::endl << "Warning: the next test involved methods that can produce infinite loops." << std::endl;
463 std::cout << "Errors in this methods can not be checked using the CPPUNIT_ASSERT Macros." << std::endl;
464 std::cout << "Instead tests are run on these methods to see if termination is assured" << std::endl << std::endl;
465 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;
466
467 std::cout << std::endl << std::endl << "The following errors displayed by the observer framework can be ignored" << std::endl;
468
469 // make this Observable its own subject. NEVER DO THIS IN ACTUAL CODE
470 simpleObservable1->signOn(simpleObservable1);
471#ifndef NDEBUG
472 CPPUNIT_ASSERT_THROW(simpleObservable1->changeMethod(),Assert::AssertionFailure);
473#else
474 simpleObservable1->changeMethod();
475#endif
476
477 // more complex test
478 simpleObservable1->signOff(simpleObservable1);
479 simpleObservable1->signOn(simpleObservable2);
480 simpleObservable2->signOn(simpleObservable1);
481#ifndef NDEBUG
482 CPPUNIT_ASSERT_THROW(simpleObservable1->changeMethod(),Assert::AssertionFailure);
483#else
484 simpleObservable1->changeMethod();
485#endif
486
487
488 simpleObservable1->signOff(simpleObservable2);
489 simpleObservable2->signOff(simpleObservable1);
490 // when we reach this line, although we broke the DAG assumption the circle check works fine
491 CPPUNIT_ASSERT(true);
492}
Note: See TracBrowser for help on using the repository browser.