Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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"
22
23#include <vector>
24
25using lib::Literal;
26
27
28
29namespace lumiera {
30namespace advice {
31namespace test {
32
33 namespace { // test support definitions
34
43 struct TestPOA
44 {
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
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
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
104 {
105 REQUIRE (req < testEntries.size());
106 REQUIRE (prov < testEntries.size());
107
108 return testEntries[req].solution_ == & testEntries[prov];
109 }
110
112 inline bool
114 {
115 REQUIRE (req < testEntries.size());
116 return NULL == testEntries[req].solution_;
117 }
118 }
119
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
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
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
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
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
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
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
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
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
Inline string literal.
Definition symbol.hpp:78
Functor object for matching against another Binding.
bool matches(Binding const &obi) const
Conjunction of predicates to be matched against a collaboration partner for establishing an Advice co...
Hash value types and utilities.
Implementation datastructure for use by the Advice system.
unsigned int uint
Definition integral.hpp:29
return NULL
Definition llist.h:586
bool _hasSolution(uint req, uint prov)
check if the given request got the denoted solution
TestPOA & _entry(uint id, Literal spec)
convenience shortcut for writing testcases inline
bool _hasDefault(uint req)
check if the given request holds a default solution
std::vector< TestPOA > testEntries(MAX_TEST_ENTRIES)
HashVal hash_value(Binding::Matcher const &bm)
bool matches(Binding const &b1, Binding const &b2)
Lumiera public interface.
Definition advice.hpp:102
Test runner and basic definitions for tests.
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Test dummy record, representing either a provision or an request.