]> git.stg.codes - stg.git/blob - tests/tut/tut_runner.hpp
Some more BSD-related issues.
[stg.git] / tests / tut / tut_runner.hpp
1 #ifndef TUT_RUNNER_H_GUARD
2 #define TUT_RUNNER_H_GUARD
3
4 #include <string>
5 #include <vector>
6 #include <set>
7 #include "tut_exception.hpp"
8
9 namespace tut
10 {
11
12 /**
13  * Interface.
14  * Test group operations.
15  */
16 struct group_base
17 {
18     virtual ~group_base()
19     {
20     }
21
22     // execute tests iteratively
23     virtual void rewind() = 0;
24     virtual bool run_next(test_result &) = 0;
25
26     // execute one test
27     virtual bool run_test(int n, test_result &tr) = 0;
28 };
29
30
31 /**
32  * Test runner callback interface.
33  * Can be implemented by caller to update
34  * tests results in real-time. User can implement
35  * any of callback methods, and leave unused
36  * in default implementation.
37  */
38 struct callback
39 {
40     /**
41      * Default constructor.
42      */
43     callback()
44     {
45     }
46
47     /**
48      * Virtual destructor is a must for subclassed types.
49      */
50     virtual ~callback()
51     {
52     }
53
54     /**
55      * Called when new test run started.
56      */
57     virtual void run_started()
58     {
59     }
60
61     /**
62      * Called when a group started
63      * @param name Name of the group
64      */
65     virtual void group_started(const std::string& name)
66     {
67         (void)name;
68     }
69
70     /**
71      * Called when a test finished.
72      * @param tr Test results.
73      */
74     virtual void test_completed(const test_result& tr)
75     {
76         (void)tr;
77     }
78
79     /**
80      * Called when a group is completed
81      * @param name Name of the group
82      */
83     virtual void group_completed(const std::string& name)
84     {
85         (void)name;
86     }
87
88     /**
89      * Called when all tests in run completed.
90      */
91     virtual void run_completed()
92     {
93     }
94
95     virtual bool all_ok() const
96     {
97         return true;
98     }
99 private:
100     callback(const callback &);
101     void operator=(const callback&);
102 };
103
104 /**
105  * Typedef for runner::list_groups()
106  */
107 typedef std::vector<std::string> groupnames;
108 typedef std::set<callback*> callbacks;
109
110 /**
111  * Test runner.
112  */
113 class test_runner
114 {
115
116 public:
117
118     /**
119      * Constructor
120      */
121     test_runner()
122         : groups_(),
123           callbacks_()
124     {
125     }
126
127     /**
128      * Stores another group for getting by name.
129      * @param name new group object
130      * @param gr new callback object
131      */
132     void register_group(const std::string& name, group_base* gr)
133     {
134         if (gr == 0)
135         {
136             throw tut_error("group shall be non-null");
137         }
138
139         if (groups_.find(name) != groups_.end())
140         {
141             std::string msg("attempt to add already existent group " + name);
142             throw tut_error(msg);
143         }
144
145         groups_.insert( std::make_pair(name, gr) );
146     }
147
148     /**
149      * Stores one callback object.
150      * @param cb new callback object
151      */
152     void set_callback(callback *cb)
153     {
154         clear_callbacks();
155         insert_callback(cb);
156     }
157
158     /**
159      * Add callback object.
160      * @param cb new callback object
161      */
162     void insert_callback(callback* cb)
163     {
164         if(cb != NULL)
165         {
166             callbacks_.insert(cb);
167         }
168     }
169
170     /**
171      * Remove callback object.
172      * @param cb callback to remove
173      */
174     void erase_callback(callback* cb)
175     {
176         callbacks_.erase(cb);
177     }
178
179     /**
180      * Remove all callback objects.
181      */
182     void clear_callbacks()
183     {
184         callbacks_.clear();
185     }
186
187     /**
188      * Returns callback list.
189      * @return     callback list
190      */
191     const callbacks &get_callbacks() const
192     {
193         return callbacks_;
194     }
195
196     /**
197      * Set callback list.
198      * @param cb new callback list
199      */
200     void set_callbacks(const callbacks &cb)
201     {
202         callbacks_ = cb;
203     }
204
205     /**
206      * Returns list of known test groups.
207      * @return     groups list
208      */
209     const groupnames list_groups() const
210     {
211         groupnames ret;
212         for(const_iterator i = groups_.begin(); i != groups_.end(); ++i)
213         {
214             ret.push_back(i->first);
215         }
216         return ret;
217     }
218
219     /**
220      * Runs all tests in all groups.
221      */
222     void run_tests() const
223     {
224         cb_run_started_();
225
226         const_iterator i = groups_.begin();
227         const_iterator e = groups_.end();
228         while (i != e)
229         {
230             cb_group_started_(i->first);
231             run_all_tests_in_group_(i);
232             cb_group_completed_(i->first);
233
234             ++i;
235         }
236
237         cb_run_completed_();
238     }
239
240     /**
241      * Runs all tests in specified group.
242      * @param group_name group to test
243      */
244     void run_tests(const std::string& group_name) const
245     {
246         cb_run_started_();
247
248         const_iterator i = groups_.find(group_name);
249         if (i == groups_.end())
250         {
251             cb_run_completed_();
252             throw no_such_group(group_name);
253         }
254
255         cb_group_started_(group_name);
256         run_all_tests_in_group_(i);
257         cb_group_completed_(group_name);
258         cb_run_completed_();
259     }
260
261     /**
262      * Runs one test in specified group.
263      * @param group_name group to test
264      * @param n run case in test
265      * @param tr result of this case
266      * @return  true if test is ok, otherwise false
267      */
268     bool run_test(const std::string& group_name, int n, test_result &tr) const
269     {
270         cb_run_started_();
271
272         const_iterator i = groups_.find(group_name);
273         if (i == groups_.end())
274         {
275             cb_run_completed_();
276             throw no_such_group(group_name);
277         }
278
279         cb_group_started_(group_name);
280
281         bool t = i->second->run_test(n, tr);
282
283         if(t && tr.result != test_result::dummy)
284         {
285             cb_test_completed_(tr);
286         }
287
288         cb_group_completed_(group_name);
289         cb_run_completed_();
290
291         return t;
292     }
293
294 protected:
295
296     typedef std::map<std::string, group_base*> groups;
297     typedef groups::iterator iterator;
298     typedef groups::const_iterator const_iterator;
299     groups groups_;
300
301     callbacks callbacks_;
302
303 private:
304     friend class restartable_wrapper;
305
306     void cb_run_started_() const
307     {
308         for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
309         {
310             (*i)->run_started();
311         }
312     }
313
314     void cb_run_completed_() const
315     {
316         for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
317         {
318             (*i)->run_completed();
319         }
320     }
321
322     void cb_group_started_(const std::string &group_name) const
323     {
324         for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
325         {
326             (*i)->group_started(group_name);
327         }
328     }
329
330     void cb_group_completed_(const std::string &group_name) const
331     {
332         for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
333         {
334             (*i)->group_completed(group_name);
335         }
336     }
337
338     void cb_test_completed_(const test_result &tr) const
339     {
340         for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
341         {
342             (*i)->test_completed(tr);
343         }
344     }
345
346     void run_all_tests_in_group_(const_iterator i) const
347     {
348         i->second->rewind();
349
350         test_result tr;
351         while(i->second->run_next(tr))
352         {
353             if(tr.result != test_result::dummy)
354             {
355                 cb_test_completed_(tr);
356             }
357
358             if (tr.result == test_result::ex_ctor)
359             {
360                 // test object ctor failed, skip whole group
361                 break;
362             }
363         }
364     }
365 };
366
367 /**
368  * Singleton for test_runner implementation.
369  * Instance with name runner_singleton shall be implemented
370  * by user.
371  */
372 class test_runner_singleton
373 {
374 public:
375
376     static test_runner& get()
377     {
378         static test_runner tr;
379         return tr;
380     }
381 };
382
383 extern test_runner_singleton runner;
384
385 }
386
387 #endif // TUT_RUNNER_H_GUARD
388