1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestSmartPointer.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 // .NAME Test of Observers.
16 // .SECTION Description
17 // Tests vtkObject::AddObserver templated API
18 
19 #include "vtkObjectFactory.h"
20 #include "vtkSmartPointer.h"
21 #include <map>
22 
23 class vtkHandler : public vtkObject
24 {
25 public:
26   static std::map<int, int> EventCounts;
27   static int VoidEventCounts;
28 
29   static vtkHandler* New();
30   vtkTypeMacro(vtkHandler, vtkObject);
31 
VoidCallback()32   void VoidCallback() { vtkHandler::VoidEventCounts++; }
CallbackWithArguments(vtkObject *,unsigned long event,void *)33   void CallbackWithArguments(vtkObject*, unsigned long event, void*)
34   {
35     vtkHandler::EventCounts[event]++;
36   }
37 };
38 vtkStandardNewMacro(vtkHandler);
39 
40 int vtkHandler::VoidEventCounts = 0;
41 std::map<int, int> vtkHandler::EventCounts;
42 
43 class OtherHandler
44 {
45 public:
46   static std::map<int, int> EventCounts;
47   static int VoidEventCounts;
48 
VoidCallback()49   void VoidCallback() { OtherHandler::VoidEventCounts++; }
CallbackWithArguments(vtkObject *,unsigned long event,void *)50   void CallbackWithArguments(vtkObject*, unsigned long event, void*)
51   {
52     OtherHandler::EventCounts[event]++;
53   }
54 };
55 
56 int OtherHandler::VoidEventCounts = 0;
57 std::map<int, int> OtherHandler::EventCounts;
58 
TestObservers(int,char * [])59 int TestObservers(int, char*[])
60 {
61   unsigned long event0 = 0;
62   unsigned long event1 = 0;
63   unsigned long event2 = 0;
64 
65   vtkObject* volcano = vtkObject::New();
66 
67   // First the base test, with a vtkObject pointer
68   vtkHandler* handler = vtkHandler::New();
69 
70   event0 = volcano->AddObserver(1000, handler, &vtkHandler::VoidCallback);
71   event1 = volcano->AddObserver(1001, handler, &vtkHandler::CallbackWithArguments);
72   event2 = volcano->AddObserver(1002, handler, &vtkHandler::CallbackWithArguments);
73 
74   volcano->InvokeEvent(1000);
75   volcano->InvokeEvent(1001);
76   volcano->InvokeEvent(1002);
77 
78   // let's see if removing an observer works
79   volcano->RemoveObserver(event2);
80   volcano->InvokeEvent(1000);
81   volcano->InvokeEvent(1001);
82   volcano->InvokeEvent(1002);
83 
84   // now delete the observer, we shouldn't have any dangling pointers.
85   handler->Delete();
86 
87   volcano->InvokeEvent(1000);
88   volcano->InvokeEvent(1001);
89   volcano->InvokeEvent(1002);
90 
91   // remove an observer after the handler has been deleted, should work.
92   volcano->RemoveObserver(event1);
93   volcano->InvokeEvent(1000);
94   volcano->InvokeEvent(1001);
95   volcano->InvokeEvent(1002);
96 
97   // remove the final observer
98   volcano->RemoveObserver(event0);
99 
100   if (vtkHandler::VoidEventCounts == 2 && vtkHandler::EventCounts[1000] == 0 &&
101     vtkHandler::EventCounts[1001] == 2 && vtkHandler::EventCounts[1002] == 1)
102   {
103     cout << "All vtkObject callback counts as expected." << endl;
104   }
105   else
106   {
107     cerr << "Mismatched callback counts for VTK observer." << endl;
108     volcano->Delete();
109     return 1;
110   }
111 
112   // ---------------------------------
113   // Test again, with smart pointers
114   vtkHandler::VoidEventCounts = 0;
115 
116   // Make a scope for the smart pointer
117   {
118     vtkSmartPointer<vtkHandler> handler2 = vtkSmartPointer<vtkHandler>::New();
119 
120     event0 = volcano->AddObserver(1003, handler2, &vtkHandler::VoidCallback);
121     event1 = volcano->AddObserver(1004, handler2, &vtkHandler::CallbackWithArguments);
122     event2 = volcano->AddObserver(1005, handler2, &vtkHandler::CallbackWithArguments);
123 
124     volcano->InvokeEvent(1003);
125     volcano->InvokeEvent(1004);
126     volcano->InvokeEvent(1005);
127 
128     // let's see if removing an observer works
129     volcano->RemoveObserver(event2);
130     volcano->InvokeEvent(1003);
131     volcano->InvokeEvent(1004);
132     volcano->InvokeEvent(1005);
133 
134     // end the scope, which deletes the observer
135   }
136 
137   // continue invoking, to make sure that
138   // no events to to the deleted observer
139   volcano->InvokeEvent(1003);
140   volcano->InvokeEvent(1004);
141   volcano->InvokeEvent(1005);
142 
143   // remove an observer after the handler2 has been deleted, should work.
144   volcano->RemoveObserver(event1);
145   volcano->InvokeEvent(1003);
146   volcano->InvokeEvent(1004);
147   volcano->InvokeEvent(1005);
148 
149   // remove the final observer
150   volcano->RemoveObserver(event0);
151 
152   if (vtkHandler::VoidEventCounts == 2 && vtkHandler::EventCounts[1003] == 0 &&
153     vtkHandler::EventCounts[1004] == 2 && vtkHandler::EventCounts[1005] == 1)
154   {
155     cout << "All smart pointer callback counts as expected." << endl;
156   }
157   else
158   {
159     cerr << "Mismatched callback counts for smart pointer observer." << endl;
160     volcano->Delete();
161     return 1;
162   }
163 
164   // ---------------------------------
165   // Test yet again, this time with a non-VTK object
166   // (this _can_ leave dangling pointers!!!)
167 
168   OtherHandler* handler3 = new OtherHandler();
169 
170   event0 = volcano->AddObserver(1006, handler3, &OtherHandler::VoidCallback);
171   event1 = volcano->AddObserver(1007, handler3, &OtherHandler::CallbackWithArguments);
172   event2 = volcano->AddObserver(1008, handler3, &OtherHandler::CallbackWithArguments);
173 
174   volcano->InvokeEvent(1006);
175   volcano->InvokeEvent(1007);
176   volcano->InvokeEvent(1008);
177 
178   // let's see if removing an observer works
179   volcano->RemoveObserver(event2);
180   volcano->InvokeEvent(1006);
181   volcano->InvokeEvent(1007);
182   volcano->InvokeEvent(1008);
183 
184   // if we delete this non-vtkObject observer, we will
185   // have dangling pointers and will see a crash...
186   // so let's not do that until the events are removed
187 
188   volcano->RemoveObserver(event0);
189   volcano->RemoveObserver(event1);
190   delete handler3;
191 
192   // delete the observed object
193   volcano->Delete();
194 
195   if (OtherHandler::VoidEventCounts == 2 && OtherHandler::EventCounts[1006] == 0 &&
196     OtherHandler::EventCounts[1007] == 2 && OtherHandler::EventCounts[1008] == 1)
197   {
198     cout << "All non-VTK observer callback counts as expected." << endl;
199     return 0;
200   }
201 
202   cerr << "Mismatched callback counts for non-VTK observer." << endl;
203   return 1;
204 }
205