Lumiera  0.pre.03
»edit your freedom«
advice-index-test.cpp
Go to the documentation of this file.
1 /*
2  AdviceIndex(Test) - cover the index datastructure used to implement Advice dispatch
3 
4  Copyright (C)
5  2010, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
19 #include "lib/test/run.hpp"
20 #include "lib/hash-value.h"
21 #include "common/advice/index.hpp"
22 
23 #include <vector>
24 
25 using lib::Literal;
26 
27 
28 
29 namespace lumiera {
30 namespace advice {
31 namespace test {
32 
33  namespace { // test support definitions
34 
43  struct TestPOA
44  {
45  TestPOA* solution_;
46  Binding::Matcher pattern_;
47 
48  explicit
49  TestPOA(Literal spec="missing")
50  : solution_(0)
51  , pattern_(Binding(spec).buildMatcher())
52  { }
53 
54  bool
55  matches (Literal refSpec) const
56  {
57  return pattern_.matches (Binding(refSpec));
58  }
59 
60  void
61  changeBinding (Literal newSpec)
62  {
63  pattern_ = Binding(newSpec).buildMatcher();
64  }
65 
66 
67  /* == Adapter interface for use within the Index == */
68 
69  void setSolution (TestPOA* p) { solution_ = p; }
70  const TestPOA* getSolution () const { return solution_;}
71  Binding::Matcher getMatcher () const { return pattern_; }
72 
73  friend HashVal
74  hash_value (TestPOA const& entry)
75  {
76  return hash_value (entry.pattern_);
77  }
78  };
79 
80 
81 
82 
83  const uint MAX_TEST_ENTRIES = 10;
84 
85  std::vector<TestPOA> testEntries(MAX_TEST_ENTRIES);
86 
87 
88 
90  inline TestPOA&
91  _entry (uint id, Literal spec)
92  {
93  REQUIRE (id < testEntries.size());
94 
95  if (!testEntries[id].matches(spec))
96  testEntries[id] = TestPOA(spec);
97 
98  return testEntries[id];
99  }
100 
102  inline bool
103  _hasSolution (uint req, uint prov)
104  {
105  REQUIRE (req < testEntries.size());
106  REQUIRE (prov < testEntries.size());
107 
108  return testEntries[req].solution_ == & testEntries[prov];
109  }
110 
112  inline bool
113  _hasDefault (uint req)
114  {
115  REQUIRE (req < testEntries.size());
116  return NULL == testEntries[req].solution_;
117  }
118  }
119 
120  typedef Index<TestPOA> Index;
121 
122 
123 
124  /**************************************************************************************/
139  class AdviceIndex_test : public Test
140  {
141 
142  virtual void
143  run (Arg)
144  {
145  Index idx;
146  buildIndex (idx);
147 
148  addRequest (idx);
149  addProvision (idx);
150  removeRequest (idx);
151  retractProvision (idx);
152  modifyRequest (idx);
153  modifyProvision (idx);
154 
155  clearIndex (idx);
156  }
157 
158 
159  void
160  buildIndex (Index& idx)
161  {
162  CHECK (idx.isValid());
163  CHECK (0 == idx.size());
164 
165  idx.addRequest (_entry (1,"cat"));
166  idx.addRequest (_entry (2,"cat"));
167  idx.addRequest (_entry (3,"dog"));
168  CHECK (3 == idx.size());
169  CHECK (3 == idx.request_count());
170  CHECK (0 == idx.provision_count());
171 
172  idx.addProvision (_entry (4,"dog"));
173  CHECK (4 == idx.size());
174  CHECK (3 == idx.request_count());
175  CHECK (1 == idx.provision_count());
176 
177  CHECK (_hasDefault (1));
178  CHECK (_hasDefault (2));
179  CHECK (_hasSolution (3,4));
180  CHECK (idx.isValid());
181  }
182 
183 
184  void
185  addRequest (Index& idx)
186  {
187  CHECK (idx.isValid());
188  uint req_cnt = idx.request_count();
189 
190  idx.addRequest (_entry (5,"dog"));
191  idx.addRequest (_entry (6,"cat"));
192 
193  CHECK (idx.hasRequest (_entry (5,"dog")));
194  CHECK (idx.hasRequest (_entry (6,"cat")));
195 
196  CHECK (_hasDefault (6));
197  CHECK (_hasSolution (5,4));
198  CHECK (idx.isValid());
199  CHECK (2 + req_cnt == idx.request_count());
200  }
201 
202 
203  void
204  addProvision (Index& idx)
205  {
206  CHECK (idx.isValid());
207  uint r_cnt = idx.request_count();
208  uint p_cnt = idx.provision_count();
209 
210  CHECK (_hasDefault (1));
211  CHECK (_hasDefault (2));
212  CHECK (_hasDefault (6));
213  CHECK (_hasSolution (3,4));
214  CHECK (_hasSolution (5,4));
215 
216  idx.addProvision (_entry (7,"cat"));
217  CHECK (idx.hasProvision (_entry (7,"cat")));
218 
219  CHECK (_hasSolution (1,7)); // all cats got the cat solution
220  CHECK (_hasSolution (2,7));
221  CHECK (_hasSolution (6,7));
222  CHECK (_hasSolution (3,4)); // dogs unaltered
223  CHECK (_hasSolution (5,4));
224  CHECK (idx.isValid());
225  CHECK (1 + p_cnt == idx.provision_count());
226  CHECK (0 + r_cnt == idx.request_count());
227 
228  idx.addProvision (_entry (8,"dog"));
229 
230  CHECK (_hasSolution (1,7)); // cats remain unaffected
231  CHECK (_hasSolution (2,7));
232  CHECK (_hasSolution (6,7));
233  CHECK (_hasSolution (3,8)); // all dogs got the new solution
234  CHECK (_hasSolution (5,8));
235  CHECK (idx.isValid());
236  CHECK (2 + p_cnt == idx.provision_count());
237  CHECK (0 + r_cnt == idx.request_count());
238  }
239 
240 
241  void
242  removeRequest (Index& idx)
243  {
244  CHECK (idx.isValid());
245  uint r_cnt = idx.request_count();
246  uint p_cnt = idx.provision_count();
247  CHECK (_hasSolution (1,7));
248  CHECK (_hasSolution (2,7));
249  CHECK (_hasSolution (6,7));
250  CHECK (_hasSolution (3,8));
251  CHECK (_hasSolution (5,8));
252 
253  CHECK ( idx.hasRequest (_entry (2,"cat")));
254 
255  idx.removeRequest (_entry (2,"cat"));
256 
257  CHECK (!idx.hasRequest (_entry (2,"cat")));
258  CHECK (p_cnt == idx.provision_count());
259  CHECK (r_cnt-1 == idx.request_count());
260 
261  CHECK (_hasSolution (1,7)); // no effect on the other requests
262  CHECK (_hasSolution (6,7));
263  CHECK (_hasSolution (3,8));
264  CHECK (_hasSolution (5,8));
265 
266  idx.removeRequest (_entry (2,"cat")); // idempotent
267  CHECK (!idx.hasRequest (_entry (2,"cat")));
268  CHECK (p_cnt == idx.provision_count());
269  CHECK (r_cnt-1 == idx.request_count());
270  CHECK (idx.isValid());
271  }
272 
273 
274  void
275  retractProvision (Index& idx)
276  {
277  CHECK (idx.isValid());
278  uint r_cnt = idx.request_count();
279  uint p_cnt = idx.provision_count();
280  CHECK (_hasSolution (1,7));
281  CHECK (_hasSolution (6,7));
282  CHECK (_hasSolution (3,8));
283  CHECK (_hasSolution (5,8));
284 
285  CHECK ( idx.hasProvision (_entry (4,"dog")));
286 
287  idx.removeProvision (_entry (4,"dog"));
288 
289  CHECK (!idx.hasProvision (_entry (4,"dog")));
290  CHECK (p_cnt-1 == idx.provision_count());
291  CHECK (r_cnt == idx.request_count());
292 
293  CHECK (_hasSolution (1,7)); // no effect on the solutions, because of the more recent dog solution 8
294  CHECK (_hasSolution (6,7));
295  CHECK (_hasSolution (3,8));
296  CHECK (_hasSolution (5,8));
297 
298  CHECK ( idx.hasProvision (_entry (8,"dog")));
299 
300  idx.removeProvision (_entry (8,"dog"));
301 
302  CHECK (!idx.hasProvision (_entry (8,"dog")));
303  CHECK (p_cnt-2 == idx.provision_count());
304  CHECK (r_cnt == idx.request_count());
305 
306  CHECK (_hasSolution (1,7)); // no effect on the cat solutions
307  CHECK (_hasSolution (6,7));
308  CHECK (!_hasSolution (3,8));
309  CHECK (!_hasSolution (5,8));
310  CHECK (_hasDefault (3)); // but all dog requests reverted to default
311  CHECK (_hasDefault (5));
312 
313  idx.removeProvision (_entry (8,"dog")); // idempotent
314  CHECK (!idx.hasProvision (_entry (8,"dog")));
315  CHECK (p_cnt-2 == idx.provision_count());
316  CHECK (r_cnt == idx.request_count());
317  CHECK (idx.isValid());
318  }
319 
320 
321  void
322  modifyRequest (Index& idx)
323  {
324  CHECK (idx.isValid());
325  uint r_cnt = idx.request_count();
326  uint p_cnt = idx.provision_count();
327  CHECK (_hasSolution (1,7));
328  CHECK (_hasSolution (6,7));
329  CHECK (_hasDefault (3));
330  CHECK (_hasDefault (5));
331 
332  HashVal dogHash (hash_value (_entry (5,"dog")));
333 
334  CHECK ( idx.hasRequest (_entry (5,"dog")));
335  _entry (5,"dog").changeBinding("cat"); // transmogrify existing request into cat-request
336  CHECK (_hasDefault (5)); // of course this didn't change the solution
337  CHECK (!idx.hasRequest (_entry (5,"cat"))); // can't find it anymore because of changed binding
338 
339  idx.modifyRequest (dogHash, _entry (5,"cat"));
340 
341  CHECK ( idx.hasRequest (_entry (5,"cat")));
342  CHECK (p_cnt == idx.provision_count());
343  CHECK (r_cnt == idx.request_count());
344  CHECK (_hasSolution (1,7));
345  CHECK (_hasSolution (6,7));
346  CHECK (_hasDefault (3));
347  CHECK (_hasSolution (5,7)); // automatically got the current cat solution
348  }
349 
350 
351  void
352  modifyProvision (Index& idx)
353  {
354  CHECK (idx.isValid());
355  uint r_cnt = idx.request_count();
356  uint p_cnt = idx.provision_count();
357  CHECK (_hasSolution (1,7));
358  CHECK (_hasSolution (5,7));
359  CHECK (_hasSolution (6,7));
360  CHECK (_hasDefault (3));
361 
362  CHECK ( idx.hasProvision (_entry (7,"cat")));
363  CHECK (!idx.hasProvision (_entry (8,"dog")));
364 
365  idx.modifyProvision (_entry (7,"cat"), _entry (8,"dog"));
366  CHECK (!idx.hasProvision (_entry (7,"cat")));
367  CHECK ( idx.hasProvision (_entry (8,"dog")));
368  CHECK (p_cnt == idx.provision_count());
369  CHECK (r_cnt == idx.request_count());
370  CHECK (_hasDefault (1));
371  CHECK (_hasDefault (5));
372  CHECK (_hasDefault (6));
373  CHECK (_hasSolution (3,8));
374 
375  idx.addProvision (_entry (7,"cat"));
376  idx.addProvision (_entry (9,"cat"));
377  CHECK (p_cnt+2 == idx.provision_count());
378  CHECK (idx.hasProvision (_entry (7,"cat")));
379  CHECK (idx.hasProvision (_entry (9,"cat")));
380  CHECK (_hasSolution (1,9)); // all cats got the second cat solution
381  CHECK (_hasSolution (5,9));
382  CHECK (_hasSolution (6,9));
383  CHECK (_hasSolution (3,8)); // the dog is unaffected
384 
385  CHECK ( idx.hasProvision (_entry (7,"cat")));
386  CHECK (!idx.hasProvision (_entry (4,"dog")));
387 
388  idx.modifyProvision (_entry (7,"cat"), _entry (4,"dog"));
389 
390  CHECK (!idx.hasProvision (_entry (7,"cat")));
391  CHECK ( idx.hasProvision (_entry (4,"dog")));
392  CHECK (_hasSolution (1,9)); // cats unaffected, because we're changing a shadowed cat provision
393  CHECK (_hasSolution (5,9));
394  CHECK (_hasSolution (6,9));
395  CHECK (_hasSolution (3,4)); // but the dog got switched to the replaced-by-dog solution,
396  // because it was added later than the existing solution 8
397 
398  // a switch within the same cluster ("cat")
399  idx.modifyProvision (_entry (9,"cat"), _entry (7,"cat"));
400  CHECK (!idx.hasProvision (_entry (9,"cat")));
401  CHECK ( idx.hasProvision (_entry (7,"cat")));
402  CHECK ( idx.hasProvision (_entry (4,"dog")));
403  CHECK (_hasSolution (1,7)); // because cat-7 is newly added, it shadows the older cat-9
404  CHECK (_hasSolution (5,7));
405  CHECK (_hasSolution (6,7));
406  CHECK (_hasSolution (3,4)); // but dog remains dog
407 
408  CHECK (p_cnt+2 == idx.provision_count());
409  CHECK (r_cnt == idx.request_count());
410  CHECK (idx.isValid());
411  }
412 
413 
414  void
415  clearIndex (Index& idx)
416  {
417  idx.clear();
418  CHECK (idx.isValid());
419  CHECK (0 == idx.size());
420  }
421  };
422 
423 
424 
426  LAUNCHER (AdviceIndex_test, "function common");
427 
428 
429 }}} // namespace lumiera::advice::test
bool _hasSolution(uint req, uint prov)
check if the given request got the denoted solution
Conjunction of predicates to be matched against a collaboration partner for establishing an Advice co...
TestPOA & _entry(uint id, Literal spec)
convenience shortcut for writing testcases inline
Functor object for matching against another Binding.
bool _hasDefault(uint req)
check if the given request holds a default solution
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Definition: run.hpp:40
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Implementation datastructure for use by the Advice system.
Simplistic test class runner.
Test dummy record, representing either a provision or an request.
Hash value types and utilities.
size_t HashVal
a STL compatible hash value
Definition: hash-value.h:52
Lumiera public interface.
Definition: advice.cpp:104