Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "kdbconfig.h"
10 :
11 : #include <kdbcontext.hpp>
12 : #include <kdbthread.hpp>
13 : #include <kdbvalue.hpp>
14 :
15 : #include <thread>
16 :
17 : #include <gtest/gtest.h>
18 :
19 : class TestValueSubject : public kdb::ValueSubject
20 : {
21 0 : virtual void notifyInThread () override
22 : {
23 0 : }
24 : };
25 :
26 0 : void fooxx (kdb::Command &)
27 : {
28 0 : }
29 :
30 20 : TEST (test_contextual_basic, command)
31 : {
32 : using namespace kdb;
33 :
34 2 : TestValueSubject v;
35 4 : Key k;
36 16 : Command::Func f = [k]() -> Command::Pair { return Command::Pair ("", ""); };
37 :
38 4 : Command c (v, f);
39 : fooxx (c);
40 4 : c ();
41 6 : ASSERT_EQ (&f, &c.execute);
42 6 : ASSERT_EQ (&v, &c.v);
43 : }
44 :
45 : const uint32_t i_value = 55;
46 : const char * s_value = "55";
47 :
48 86 : class CountryGermanyLayer : public kdb::Layer
49 : {
50 : public:
51 58 : std::string id () const override
52 : {
53 174 : return "country";
54 : }
55 64 : std::string operator() () const override
56 : {
57 192 : return "germany";
58 : }
59 : };
60 :
61 118 : class LanguageGermanLayer : public kdb::Layer
62 : {
63 : public:
64 128 : std::string id () const override
65 : {
66 384 : return "language";
67 : }
68 118 : std::string operator() () const override
69 : {
70 354 : return "german";
71 : }
72 : };
73 :
74 16 : class CountryGPSLayer : public kdb::Layer
75 : {
76 : public:
77 16 : CountryGPSLayer () : m_country ("austria")
78 : {
79 : }
80 8 : std::string id () const override
81 : {
82 24 : return "country";
83 : }
84 10 : std::string operator() () const override
85 : {
86 20 : return m_country;
87 : }
88 :
89 : private:
90 : std::string m_country;
91 : };
92 :
93 8 : class ThreadLayer : public kdb::Layer
94 : {
95 : public:
96 : ThreadLayer ()
97 8 : {
98 : }
99 8 : std::string id () const override
100 : {
101 24 : return "thread";
102 : }
103 8 : std::string operator() () const override
104 : {
105 16 : std::ostringstream os;
106 8 : std::thread::id tid = std::this_thread::get_id ();
107 8 : if (tid != g_main_id)
108 : {
109 4 : os << tid;
110 : }
111 16 : return os.str ();
112 : };
113 :
114 : private:
115 : static const std::thread::id g_main_id;
116 : };
117 :
118 2 : const std::thread::id ThreadLayer::g_main_id = std::this_thread::get_id ();
119 :
120 22 : class CountingLayer : public kdb::Layer
121 : {
122 : public:
123 24 : CountingLayer () : m_id ()
124 : {
125 : }
126 44 : std::string id () const override
127 : {
128 132 : return "counting";
129 : }
130 80 : std::string operator() () const override
131 : {
132 160 : std::ostringstream os;
133 160 : os << m_id++;
134 160 : return os.str ();
135 : };
136 :
137 : private:
138 : mutable long long m_id;
139 : };
140 :
141 :
142 20 : class SelectedPrinterLayer : public kdb::Layer
143 : {
144 : public:
145 10 : std::string id () const override
146 : {
147 30 : return "printer";
148 : }
149 18 : std::string operator() () const override
150 : {
151 54 : return "Laserdrucker";
152 : }
153 : };
154 :
155 14 : class MainApplicationLayer : public kdb::Layer
156 : {
157 : public:
158 22 : std::string id () const override
159 : {
160 66 : return "application";
161 : }
162 96 : std::string operator() () const override
163 : {
164 288 : return "main";
165 : }
166 : };
167 :
168 4 : class ProfileLayer : public kdb::Layer
169 : {
170 : public:
171 6 : explicit ProfileLayer (kdb::String const & profile) : m_profile (profile)
172 : {
173 : }
174 18 : std::string id () const override
175 : {
176 54 : return "profile";
177 : }
178 72 : std::string operator() () const override
179 : {
180 144 : return m_profile;
181 : }
182 :
183 : private:
184 : kdb::String const & m_profile;
185 : };
186 :
187 : template <typename T>
188 54 : class test_contextual_basic : public ::testing::Test
189 : {
190 : public:
191 : T context;
192 : };
193 :
194 : template <>
195 18 : class test_contextual_basic<kdb::ThreadContext> : public ::testing::Test
196 : {
197 : public:
198 18 : test_contextual_basic () : context (coordinator)
199 : {
200 18 : }
201 : static kdb::Coordinator coordinator;
202 : kdb::ThreadContext context;
203 : };
204 :
205 2 : kdb::Coordinator test_contextual_basic<kdb::ThreadContext>::coordinator{};
206 :
207 : typedef ::testing::Types<kdb::Context, kdb::ThreadContext> myContextualPolicies;
208 : TYPED_TEST_CASE (test_contextual_basic, myContextualPolicies);
209 :
210 28 : TYPED_TEST (test_contextual_basic, integer)
211 : {
212 : using namespace kdb;
213 8 : KeySet ks;
214 8 : TypeParam c = this->context;
215 36 : ASSERT_TRUE (!ks.lookup ("/%/%/%/test"));
216 : Value<int, ContextPolicyIs<TypeParam>> i (
217 12 : ks, c, Key ("/%language%/%country%/%dialect%/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
218 8 : ASSERT_EQ (i, i_value);
219 : // The value always needs a connection to a key
220 32 : ASSERT_TRUE (ks.lookup ("/%/%/%/test"));
221 4 : i = 5;
222 12 : ASSERT_EQ (i, 5);
223 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
224 4 : i.syncKeySet ();
225 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "5");
226 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
227 4 : i = 10;
228 12 : ASSERT_EQ (i, 10);
229 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
230 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
231 :
232 8 : c.template activate<LanguageGermanLayer> ();
233 8 : ASSERT_EQ (i, i_value);
234 : //{debug/ASSERT_TRUE}
235 28 : ASSERT_EQ (i.context ()["language"], "german");
236 16 : ASSERT_EQ (i.getName (), "/german/%/%/test");
237 : //{end}
238 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
239 32 : ASSERT_TRUE (ks.lookup ("/german/%/%/test"));
240 4 : i = 15;
241 12 : ASSERT_EQ (i, 15);
242 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
243 4 : i.syncKeySet ();
244 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
245 :
246 8 : c.template deactivate<LanguageGermanLayer> ();
247 12 : ASSERT_EQ (i, 10);
248 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
249 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
250 :
251 20 : c.template with<LanguageGermanLayer> () ([&]() {
252 20 : ASSERT_EQ (i, 15);
253 52 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
254 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
255 24 : c.template without<LanguageGermanLayer> () ([&]() {
256 12 : ASSERT_EQ (i, 10);
257 40 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
258 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
259 : });
260 12 : ASSERT_EQ (i, 15);
261 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
262 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
263 : });
264 12 : ASSERT_EQ (i, 10);
265 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
266 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
267 :
268 28 : c.template with<LanguageGermanLayer> ().template with<CountryGermanyLayer> () ([&]() {
269 24 : ASSERT_EQ (i, i_value);
270 48 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
271 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
272 32 : ASSERT_TRUE (ks.lookup ("/german/germany/%/test"));
273 4 : i = 20;
274 16 : ASSERT_EQ (i.getName (), "user/german/germany/%/test");
275 36 : ASSERT_EQ (ks.lookup ("/german/germany/%/test").getString (), "20");
276 : /*
277 : //{debug/backtrace}
278 : #3 0x0000000000407a56 in operator() at first.cpp:1521
279 : i = @0x7fffe36b69a0: { ...
280 : m_evaluated_name = "/german/germany/%/test" }
281 : //{end}
282 : //{debug/breakpoint}
283 : break 1520 if i.getName()
284 : .compare("/german/germany/%/test") == 0
285 : //{end}
286 : */
287 12 : ASSERT_EQ (i, 20);
288 : });
289 12 : ASSERT_EQ (i, 10);
290 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
291 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
292 36 : ASSERT_EQ (ks.lookup ("/german/germany/%/test").getString (), "20");
293 :
294 28 : c.template with<LanguageGermanLayer> ().template with<CountryGermanyLayer> () ([&]() {
295 20 : ASSERT_EQ (i, 20);
296 48 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
297 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
298 36 : ASSERT_EQ (ks.lookup ("/german/germany/%/test").getString (), "20");
299 4 : i = 30;
300 12 : ASSERT_EQ (i, 30);
301 36 : ASSERT_EQ (ks.lookup ("/german/germany/%/test").getString (), "30");
302 : });
303 12 : ASSERT_EQ (i, 10);
304 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
305 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
306 36 : ASSERT_EQ (ks.lookup ("/german/germany/%/test").getString (), "30");
307 :
308 24 : c.template with<LanguageGermanLayer> ().template with<CountryGermanyLayer> () ([&]() {
309 16 : ASSERT_EQ (i, 30);
310 48 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
311 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
312 36 : ASSERT_EQ (ks.lookup ("/german/germany/%/test").getString (), "30");
313 32 : c.template with<CountryGPSLayer> () ([&]() { ASSERT_EQ (i, i_value); });
314 36 : ASSERT_EQ (ks.lookup ("/german/austria/%/test").getString (), s_value);
315 : });
316 12 : ASSERT_EQ (i, 10);
317 36 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "10");
318 36 : ASSERT_EQ (ks.lookup ("/german/%/%/test").getString (), "15");
319 : }
320 :
321 28 : TYPED_TEST (test_contextual_basic, mixedWithActivate)
322 : {
323 : using namespace kdb;
324 8 : KeySet ks;
325 8 : TypeParam c = this->context;
326 36 : ASSERT_TRUE (!ks.lookup ("/%/%/%/test"));
327 : Value<int, ContextPolicyIs<TypeParam>> i (
328 12 : ks, c, Key ("/%language%/%country%/%dialect%/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
329 8 : ASSERT_EQ (i, i_value);
330 : // The value always needs a connection to a key
331 32 : ASSERT_TRUE (ks.lookup ("/%/%/%/test"));
332 4 : i = 5;
333 12 : ASSERT_EQ (i, 5);
334 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
335 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
336 :
337 8 : c.template activate<LanguageGermanLayer> ();
338 4 : i = 6;
339 12 : ASSERT_EQ (i, 6);
340 16 : ASSERT_EQ (i.getName (), "user/german/%/%/test");
341 36 : ASSERT_EQ (ks.lookup ("user/german/%/%/test").getString (), "6");
342 :
343 24 : c.template with<CountryGermanyLayer> () ([&]() {
344 16 : i = 7;
345 12 : ASSERT_EQ (i, 7);
346 16 : ASSERT_EQ (i.getName (), "user/german/germany/%/test");
347 36 : ASSERT_EQ (ks.lookup ("user/german/germany/%/test").getString (), "7");
348 : });
349 :
350 : // LanguageGermanLayer still active
351 12 : ASSERT_EQ (i, 6);
352 16 : ASSERT_EQ (i.getName (), "user/german/%/%/test");
353 36 : ASSERT_EQ (ks.lookup ("user/german/%/%/test").getString (), "6");
354 :
355 8 : c.template deactivate<LanguageGermanLayer> ();
356 12 : ASSERT_EQ (i, 5);
357 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
358 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
359 : }
360 :
361 28 : TYPED_TEST (test_contextual_basic, nestedWithActivate)
362 : {
363 : using namespace kdb;
364 8 : KeySet ks;
365 8 : TypeParam c = this->context;
366 36 : ASSERT_TRUE (!ks.lookup ("/%/%/%/test"));
367 : Value<int, ContextPolicyIs<TypeParam>> i (
368 12 : ks, c, Key ("/%language%/%country%/%dialect%/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
369 8 : ASSERT_EQ (i, i_value);
370 : // The value always needs a connection to a key
371 32 : ASSERT_TRUE (ks.lookup ("/%/%/%/test"));
372 4 : i = 5;
373 12 : ASSERT_EQ (i, 5);
374 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
375 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
376 :
377 20 : c.template with<CountryGermanyLayer> () ([&]() {
378 20 : i = 7;
379 12 : ASSERT_EQ (i, 7);
380 16 : ASSERT_EQ (i.getName (), "user/%/germany/%/test");
381 40 : ASSERT_EQ (ks.lookup ("user/%/germany/%/test").getString (), "7");
382 :
383 28 : c.template without<CountryGermanyLayer> () ([&]() {
384 8 : c.template activate<LanguageGermanLayer> ();
385 :
386 16 : i = 6;
387 12 : ASSERT_EQ (i, 6);
388 16 : ASSERT_EQ (i.getName (), "user/german/%/%/test");
389 36 : ASSERT_EQ (ks.lookup ("user/german/%/%/test").getString (), "6");
390 : });
391 : });
392 :
393 : // LanguageGermanLayer still active
394 12 : ASSERT_EQ (i, 6);
395 16 : ASSERT_EQ (i.getName (), "user/german/%/%/test");
396 36 : ASSERT_EQ (ks.lookup ("user/german/%/%/test").getString (), "6");
397 :
398 8 : c.template deactivate<LanguageGermanLayer> ();
399 12 : ASSERT_EQ (i, 5);
400 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
401 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
402 : }
403 :
404 :
405 28 : TYPED_TEST (test_contextual_basic, nestedWithActivateConflicting)
406 : {
407 : using namespace kdb;
408 8 : KeySet ks;
409 8 : TypeParam c = this->context;
410 36 : ASSERT_TRUE (!ks.lookup ("/%/%/%/test"));
411 : Value<int, ContextPolicyIs<TypeParam>> i (
412 12 : ks, c, Key ("/%language%/%country%/%dialect%/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
413 8 : ASSERT_EQ (i, i_value);
414 : // The value always needs a connection to a key
415 32 : ASSERT_TRUE (ks.lookup ("/%/%/%/test"));
416 4 : i = 5;
417 12 : ASSERT_EQ (i, 5);
418 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
419 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
420 :
421 20 : c.template with<CountryGermanyLayer> () ([&]() {
422 28 : i = 7;
423 12 : ASSERT_EQ (i, 7);
424 16 : ASSERT_EQ (i.getName (), "user/%/germany/%/test");
425 44 : ASSERT_EQ (ks.lookup ("user/%/germany/%/test").getString (), "7");
426 :
427 24 : c.template without<CountryGermanyLayer> () ([&]() {
428 24 : ASSERT_EQ (i, 5);
429 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
430 40 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
431 :
432 8 : c.template activate<CountryGermanyLayer> ();
433 :
434 4 : i = 6;
435 12 : ASSERT_EQ (i, 6);
436 16 : ASSERT_EQ (i.getName (), "user/%/germany/%/test");
437 36 : ASSERT_EQ (ks.lookup ("user/%/germany/%/test").getString (), "6");
438 : });
439 : // restore activation of layer
440 :
441 12 : ASSERT_EQ (i, 6);
442 16 : ASSERT_EQ (i.getName (), "user/%/germany/%/test");
443 36 : ASSERT_EQ (ks.lookup ("user/%/germany/%/test").getString (), "6");
444 : });
445 : // restore deactivation of layer (TODO: good idea in multi-thread setups if layer activation is pulled in? rather not..)
446 :
447 12 : ASSERT_EQ (i, 5);
448 16 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
449 36 : ASSERT_EQ (ks.lookup ("user/%/%/%/test").getString (), "5");
450 : }
451 :
452 :
453 28 : TYPED_TEST (test_contextual_basic, counting)
454 : {
455 : using namespace kdb;
456 :
457 12 : std::shared_ptr<kdb::Layer> l = std::make_shared<CountingLayer> ();
458 8 : KeySet ks;
459 8 : TypeParam c = this->context;
460 48 : c.template with<CountingLayer> () ([&] { ASSERT_EQ (c["counting"], "0"); });
461 : // is it a specification error to have counting
462 : // two times?
463 : Value<int, ContextPolicyIs<TypeParam>> i (
464 12 : ks, c, Key ("/%counting%/%counting%", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
465 :
466 16 : ASSERT_EQ ((*l) (), "0");
467 16 : ASSERT_EQ ((*l) (), "1");
468 20 : c.withl (l, [&] {
469 32 : ASSERT_EQ (c["counting"], "4");
470 32 : ASSERT_EQ (c["counting"], "5");
471 : });
472 16 : ASSERT_EQ ((*l) (), "6");
473 24 : c.template with<CountingLayer> () ([&] {
474 32 : ASSERT_EQ (c["counting"], "2");
475 32 : ASSERT_EQ (c["counting"], "3");
476 : });
477 32 : ASSERT_TRUE (c["counting"].empty ());
478 24 : c.template with<CountingLayer> () ([&] {
479 32 : ASSERT_EQ (c["counting"], "2");
480 32 : ASSERT_EQ (c["counting"], "3");
481 : });
482 32 : ASSERT_TRUE (c["counting"].empty ());
483 8 : c.template activate<CountingLayer> ();
484 28 : ASSERT_EQ (c["counting"], "2");
485 28 : ASSERT_EQ (c["counting"], "3");
486 8 : c.template deactivate<CountingLayer> ();
487 32 : ASSERT_TRUE (c["counting"].empty ());
488 : }
489 :
490 28 : TYPED_TEST (test_contextual_basic, groups)
491 : {
492 : using namespace kdb;
493 :
494 8 : KeySet ks;
495 8 : TypeParam c = this->context;
496 : Value<int, ContextPolicyIs<TypeParam>> i (
497 : ks, c,
498 : Key ("/%application%/%version profile thread module%/%manufacturer type family model%/serial_number", KEY_CASCADING_NAME,
499 12 : KEY_META, "default", s_value, KEY_END));
500 16 : ASSERT_EQ (i.getName (), "/%/%/%/serial_number");
501 8 : c.template activate<MainApplicationLayer> ();
502 12 : String s (ks, c, Key ("/%x%", KEY_CASCADING_NAME, KEY_META, "default", "anonymous", KEY_END));
503 8 : c.template activate<ProfileLayer> (s);
504 16 : ASSERT_EQ (i.getName (), "/main/%/%/serial_number");
505 32 : c.activate ("version", "1");
506 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous/%/serial_number");
507 32 : c.activate ("module", "M1");
508 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous/%/serial_number");
509 32 : c.activate ("manufacturer", "hp");
510 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous/%hp/serial_number");
511 32 : c.activate ("family", "EliteBook");
512 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous/%hp/serial_number");
513 8 : c.template activate<KeyValueLayer> ("type", "MobileWorkstation");
514 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous/%hp%MobileWorkstation%EliteBook/serial_number");
515 8 : c.template activate<KeyValueLayer> ("model", "8570");
516 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous/%hp%MobileWorkstation%EliteBook%8570/serial_number");
517 8 : c.template activate<KeyValueLayer> ("thread", "40");
518 16 : ASSERT_EQ (i.getName (), "/main/%1%anonymous%40%M1/%hp%MobileWorkstation%EliteBook%8570/serial_number");
519 8 : c.template deactivate<KeyValueLayer> ("version", "");
520 16 : ASSERT_EQ (i.getName (), "/main/%/%hp%MobileWorkstation%EliteBook%8570/serial_number");
521 8 : c.template activate<KeyValueLayer> ("version", "4");
522 16 : ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%hp%MobileWorkstation%EliteBook%8570/serial_number");
523 8 : c.template deactivate<KeyValueLayer> ("manufacturer", "");
524 16 : ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%/serial_number");
525 8 : c.template activate<KeyValueLayer> ("manufacturer", "HP");
526 16 : ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%HP%MobileWorkstation%EliteBook%8570/serial_number");
527 8 : c.template deactivate<KeyValueLayer> ("type", "");
528 16 : ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%HP/serial_number");
529 24 : c.template with<KeyValueLayer> ("type", "Notebook") ([&] {
530 24 : ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%HP%Notebook%EliteBook%8570/serial_number");
531 8 : c.template without<KeyValueLayer> ("type",
532 38 : "") ([&] { ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%HP/serial_number"); });
533 16 : ASSERT_EQ (i.getName (), "/main/%4%anonymous%40%M1/%HP%Notebook%EliteBook%8570/serial_number");
534 : });
535 : }
536 :
537 8 : class myId : public kdb::Wrapped
538 : {
539 14 : virtual std::string layerId () const
540 : {
541 42 : return "id";
542 : }
543 :
544 4 : virtual std::string layerVal () const
545 : {
546 12 : return "my";
547 : }
548 : };
549 :
550 :
551 28 : TYPED_TEST (test_contextual_basic, wrapped)
552 : {
553 : using namespace kdb;
554 :
555 8 : KeySet ks;
556 8 : TypeParam c = this->context;
557 12 : Value<int, ContextPolicyIs<TypeParam>> i (ks, c, Key ("/%id%/key", KEY_META, "default", s_value, KEY_END));
558 12 : ASSERT_EQ (i.getName (), "/%/key");
559 16 : c.activate (myId ());
560 16 : ASSERT_EQ (i.getName (), "/my/key");
561 : }
562 :
563 :
564 28 : TYPED_TEST (test_contextual_basic, cvWrapped)
565 : {
566 : using namespace kdb;
567 :
568 8 : KeySet ks;
569 8 : TypeParam c = this->context;
570 12 : Value<std::string, ContextPolicyIs<TypeParam>> i (ks, c, Key ("/ignore/id", KEY_META, "default", "my", KEY_END));
571 :
572 12 : Value<int, ContextPolicyIs<TypeParam>> x (ks, c, Key ("/%id%/key", KEY_META, "default", s_value, KEY_END));
573 :
574 16 : ASSERT_EQ (x.getName (), "/%/key");
575 32 : ASSERT_TRUE (ks.lookup ("/%/key"));
576 8 : c.activate (i);
577 16 : ASSERT_EQ (x.getName (), "/my/key");
578 32 : ASSERT_TRUE (ks.lookup ("/my/key"));
579 :
580 12 : ks.append (Key ("/other/key", KEY_VALUE, "88", KEY_END));
581 20 : i = "other";
582 8 : c.activate (i);
583 16 : ASSERT_EQ (x.getName (), "/other/key");
584 32 : ASSERT_TRUE (ks.lookup ("/other/key"));
585 12 : ASSERT_EQ (x, 88);
586 36 : ASSERT_EQ (ks.lookup ("/other/key").getString (), "88");
587 :
588 12 : ks.append (Key ("/other/key", KEY_VALUE, "100", KEY_END));
589 36 : ASSERT_EQ (ks.lookup ("/other/key").getString (), "100");
590 12 : ASSERT_EQ (x, 88) << "updated from KeySet?";
591 : }
592 :
593 :
594 28 : TYPED_TEST (test_contextual_basic, cvWrappedInt)
595 : {
596 : using namespace kdb;
597 :
598 8 : KeySet ks;
599 8 : TypeParam c = this->context;
600 12 : Value<int, ContextPolicyIs<TypeParam>> i (ks, c, Key ("/ignore/id", KEY_META, "default", "88", KEY_END));
601 :
602 12 : Value<int, ContextPolicyIs<TypeParam>> x (ks, c, Key ("/%id%/key", KEY_META, "default", s_value, KEY_END));
603 :
604 16 : ASSERT_EQ (x.getName (), "/%/key");
605 8 : c.activate (i);
606 16 : ASSERT_EQ (x.getName (), "/88/key");
607 : }
608 :
609 :
610 20 : TEST (test_contextual_basic, integer_copy)
611 : {
612 : using namespace kdb;
613 4 : KeySet ks;
614 4 : Context c;
615 18 : ASSERT_TRUE (!ks.lookup ("/%/%/%/test"));
616 6 : Integer i (ks, c, Key ("/%language%/%country%/%dialect%/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
617 4 : ASSERT_EQ (i, i_value);
618 16 : ASSERT_TRUE (ks.lookup ("/%/%/%/test"));
619 2 : i = 5;
620 6 : ASSERT_EQ (i, 5);
621 8 : ASSERT_EQ (i.getName (), "user/%/%/%/test");
622 2 : i.syncKeySet ();
623 18 : ASSERT_EQ (ks.lookup ("/%/%/%/test").getString (), "5");
624 : }
625 :
626 20 : TEST (test_contextual_basic, evaluate)
627 : {
628 : using namespace kdb;
629 4 : kdb::Context c;
630 14 : ASSERT_EQ (c["language"], "");
631 14 : ASSERT_EQ (c["country"], "");
632 14 : ASSERT_EQ (c["dialect"], "");
633 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/%/%/%/test");
634 14 : ASSERT_EQ (c.evaluate ("/%language country dialect%/test"), "/%/test");
635 :
636 4 : c.activate<LanguageGermanLayer> ();
637 14 : ASSERT_EQ (c["language"], "german");
638 14 : ASSERT_EQ (c["country"], "");
639 14 : ASSERT_EQ (c["dialect"], "");
640 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/%/%/test");
641 14 : ASSERT_EQ (c.evaluate ("/%language country dialect%/test"), "/%german/test");
642 :
643 4 : c.activate<LanguageGermanLayer> ();
644 4 : c.activate<CountryGermanyLayer> ();
645 14 : ASSERT_EQ (c["language"], "german");
646 14 : ASSERT_EQ (c["country"], "germany");
647 14 : ASSERT_EQ (c["dialect"], "");
648 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/germany/%/test");
649 14 : ASSERT_EQ (c.evaluate ("/%language country dialect%/test"), "/%german%germany/test");
650 4 : c.deactivate<CountryGermanyLayer> ();
651 :
652 4 : c.activate<LanguageGermanLayer> ();
653 4 : c.activate<KeyValueLayer> ("country", "%");
654 14 : ASSERT_EQ (c["language"], "german");
655 14 : ASSERT_EQ (c["country"], "%");
656 14 : ASSERT_EQ (c["dialect"], "");
657 : // TODO: Escaping not implemented
658 : // ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/\\%/%/test");
659 : // ASSERT_EQ (c.evaluate ("/%language country dialect%/test"), "/%german%\\%/test");
660 4 : c.deactivate<KeyValueLayer> ("country", "%");
661 :
662 4 : c.deactivate<LanguageGermanLayer> ();
663 14 : ASSERT_EQ (c["language"], "");
664 14 : ASSERT_EQ (c["country"], "");
665 14 : ASSERT_EQ (c["dialect"], "");
666 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/%/%/%/test");
667 :
668 4 : c.with<LanguageGermanLayer> () ([&]() {
669 32 : ASSERT_EQ (c["language"], "german");
670 16 : ASSERT_EQ (c["country"], "");
671 16 : ASSERT_EQ (c["dialect"], "");
672 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/%/%/test");
673 4 : c.without<LanguageGermanLayer> () ([&]() {
674 20 : ASSERT_EQ (c["language"], "");
675 16 : ASSERT_EQ (c["country"], "");
676 16 : ASSERT_EQ (c["dialect"], "");
677 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/%/%/%/test");
678 8 : });
679 16 : ASSERT_EQ (c["language"], "german");
680 16 : ASSERT_EQ (c["country"], "");
681 16 : ASSERT_EQ (c["dialect"], "");
682 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/%/%/test");
683 8 : });
684 14 : ASSERT_EQ (c["language"], "");
685 14 : ASSERT_EQ (c["country"], "");
686 14 : ASSERT_EQ (c["dialect"], "");
687 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/%/%/%/test");
688 :
689 6 : c.with<LanguageGermanLayer> ().with<CountryGermanyLayer> () ([&]() {
690 38 : ASSERT_EQ (c["language"], "german");
691 16 : ASSERT_EQ (c["country"], "germany");
692 16 : ASSERT_EQ (c["dialect"], "");
693 8 : ASSERT_EQ (c.size (), 2);
694 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/germany/%/test");
695 16 : ASSERT_EQ (c.evaluate ("/%language country dialect%/test"), "/%german%germany/test");
696 4 : c.with<CountryGPSLayer> () ([&]() {
697 26 : ASSERT_EQ (c["language"], "german");
698 16 : ASSERT_EQ (c["country"], "austria");
699 16 : ASSERT_EQ (c["dialect"], "");
700 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/austria/%/test");
701 16 : ASSERT_EQ (c.evaluate ("/%language country dialect%/test"), "/%german%austria/test");
702 4 : c.without<CountryGPSLayer> () ([&]() {
703 20 : ASSERT_EQ (c["language"], "german");
704 16 : ASSERT_EQ (c["country"], "");
705 16 : ASSERT_EQ (c["dialect"], "");
706 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/%/%/test");
707 8 : });
708 8 : });
709 16 : ASSERT_EQ (c["language"], "german");
710 16 : ASSERT_EQ (c["country"], "germany");
711 16 : ASSERT_EQ (c["dialect"], "");
712 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/germany/%/test");
713 16 : ASSERT_EQ (c.evaluate ("/%language country%/%dialect%/test"), "/%german%germany/%/test");
714 8 : });
715 14 : ASSERT_EQ (c["language"], "");
716 14 : ASSERT_EQ (c["country"], "");
717 14 : ASSERT_EQ (c["dialect"], "");
718 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/%/%/%/test");
719 :
720 6 : c.with<LanguageGermanLayer> ().with<CountryGermanyLayer> () ([&] {
721 26 : ASSERT_EQ (c["language"], "german");
722 16 : ASSERT_EQ (c["country"], "germany");
723 16 : ASSERT_EQ (c["dialect"], "");
724 16 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/german/germany/%/test");
725 16 : ASSERT_EQ (c.evaluate ("/%language%/%language%/%dialect%/test"), "/german/german/%/test");
726 :
727 16 : ASSERT_EQ (c.evaluate ("/%language%%country%%dialect%/test"), "/germangermany%/test");
728 16 : ASSERT_EQ (c.evaluate ("/%language%%language%%dialect%/test"), "/germangerman%/test");
729 8 : });
730 14 : ASSERT_EQ (c["language"], "");
731 14 : ASSERT_EQ (c["country"], "");
732 14 : ASSERT_EQ (c["dialect"], "");
733 14 : ASSERT_EQ (c.evaluate ("/%language%/%country%/%dialect%/test"), "/%/%/%/test");
734 :
735 14 : ASSERT_EQ (c["language"], "");
736 14 : ASSERT_EQ (c["country"], "");
737 14 : ASSERT_EQ (c["dialect"], "");
738 14 : ASSERT_EQ (c.evaluate ("/%language%%country%%dialect%/test"), "/%%%/test");
739 :
740 4 : KeySet ks;
741 : Integer i (ks, c,
742 4 : Key ("/%application%/%version%/%profile%/%thread%/%module%/%manufacturer%/%type%/%family%/%model%/serial_number",
743 6 : KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
744 : Integer j (ks, c,
745 4 : Key ("/%application version profile thread module manufacturer type family model%/serial_number", KEY_CASCADING_NAME,
746 6 : KEY_META, "default", s_value, KEY_END));
747 8 : ASSERT_EQ (i.getName (), "/%/%/%/%/%/%/%/%/%/serial_number");
748 8 : ASSERT_EQ (j.getName (), "/%/serial_number");
749 4 : c.activate<MainApplicationLayer> ();
750 8 : ASSERT_EQ (i.getName (), "/main/%/%/%/%/%/%/%/%/serial_number");
751 8 : ASSERT_EQ (j.getName (), "/%main/serial_number");
752 6 : String s (ks, c, Key ("/%x%", KEY_CASCADING_NAME, KEY_META, "default", "anonymous", KEY_END));
753 4 : c.activate<ProfileLayer> (s);
754 8 : ASSERT_EQ (i.getName (), "/main/%/anonymous/%/%/%/%/%/%/serial_number");
755 8 : ASSERT_EQ (j.getName (), "/%main/serial_number");
756 4 : c.activate<KeyValueLayer> ("module", "M1");
757 8 : ASSERT_EQ (i.getName (), "/main/%/anonymous/%/M1/%/%/%/%/serial_number");
758 8 : ASSERT_EQ (j.getName (), "/%main/serial_number");
759 4 : c.activate<KeyValueLayer> ("manufacturer", "hp");
760 8 : ASSERT_EQ (i.getName (), "/main/%/anonymous/%/M1/hp/%/%/%/serial_number");
761 8 : ASSERT_EQ (j.getName (), "/%main/serial_number");
762 4 : c.activate<KeyValueLayer> ("family", "EliteBook");
763 8 : ASSERT_EQ (i.getName (), "/main/%/anonymous/%/M1/hp/%/EliteBook/%/serial_number");
764 8 : ASSERT_EQ (j.getName (), "/%main/serial_number");
765 4 : c.activate<KeyValueLayer> ("version", "1");
766 8 : ASSERT_EQ (i.getName (), "/main/1/anonymous/%/M1/hp/%/EliteBook/%/serial_number");
767 8 : ASSERT_EQ (j.getName (), "/%main%1%anonymous/serial_number");
768 : }
769 :
770 :
771 6 : struct MockObserver : kdb::ValueObserver
772 : {
773 6 : MockObserver () : counter ()
774 : {
775 : }
776 :
777 22 : virtual void updateContext (bool) const override
778 : {
779 22 : ++counter;
780 22 : }
781 :
782 0 : virtual kdb::Key getDepKey () const override
783 : {
784 0 : throw "should not happen";
785 : }
786 :
787 : mutable long long counter;
788 : };
789 :
790 : // duplicates need to be filtered
791 20 : TEST (test_contextual_basic, valueObserver)
792 : {
793 4 : kdb::Context c;
794 4 : MockObserver o1;
795 4 : MockObserver o2;
796 4 : MockObserver o3;
797 8 : c.attachByName ("/%event1%/%event2%", o1);
798 8 : c.attachByName ("/%event1%/%event3%", o2);
799 8 : c.attachByName ("/%eventX%", o3);
800 8 : c.attachByName ("/%eventX%", o3);
801 6 : ASSERT_EQ (o1.counter, 0);
802 6 : ASSERT_EQ (o2.counter, 0);
803 12 : c.notifyByEvents ({ "event1" });
804 6 : ASSERT_EQ (o1.counter, 1);
805 6 : ASSERT_EQ (o2.counter, 1);
806 12 : c.notifyByEvents ({ "event2" });
807 6 : ASSERT_EQ (o1.counter, 2);
808 6 : ASSERT_EQ (o2.counter, 1);
809 12 : c.notifyByEvents ({ "event3" });
810 6 : ASSERT_EQ (o1.counter, 2);
811 6 : ASSERT_EQ (o2.counter, 2);
812 12 : c.notifyByEvents ({ "event4" });
813 6 : ASSERT_EQ (o1.counter, 2);
814 6 : ASSERT_EQ (o2.counter, 2);
815 16 : c.notifyByEvents ({ "event1", "event2" });
816 6 : ASSERT_EQ (o1.counter, 3);
817 6 : ASSERT_EQ (o2.counter, 3);
818 16 : c.notifyByEvents ({ "event1", "event3" });
819 6 : ASSERT_EQ (o1.counter, 4);
820 6 : ASSERT_EQ (o2.counter, 4);
821 6 : ASSERT_EQ (o3.counter, 0);
822 2 : c.notifyAllEvents ();
823 6 : ASSERT_EQ (o1.counter, 5);
824 6 : ASSERT_EQ (o2.counter, 5);
825 6 : ASSERT_EQ (o3.counter, 1);
826 : }
827 :
828 :
829 : bool fooFirst = true;
830 :
831 : //{foo}
832 6 : void foo (kdb::Integer & e)
833 : {
834 18 : e.context ().with<SelectedPrinterLayer> () ([&]() {
835 6 : if (fooFirst)
836 22 : ASSERT_EQ (e, i_value);
837 : else
838 12 : ASSERT_EQ (e, 20);
839 6 : e = 20;
840 18 : ASSERT_EQ (e, 20);
841 24 : });
842 18 : ASSERT_EQ (e, 12);
843 6 : fooFirst = false;
844 : }
845 : //{end}
846 :
847 : bool barFirst = true;
848 :
849 4 : void bar (kdb::Integer const & e)
850 : {
851 16 : e.context ().with<ThreadLayer> ().with<SelectedPrinterLayer> () ([&]() {
852 4 : if (barFirst)
853 10 : ASSERT_EQ (e, 20);
854 : else
855 4 : ASSERT_EQ (e, i_value);
856 :
857 32 : e.context ().without<ThreadLayer> () ([&]() { ASSERT_EQ (e, 20); });
858 16 : });
859 12 : ASSERT_EQ (e, 12);
860 4 : barFirst = false;
861 : }
862 :
863 20 : TEST (test_contextual_basic, threads)
864 : {
865 : using namespace kdb;
866 :
867 4 : KeySet ks;
868 4 : Context c;
869 6 : kdb::Integer n (ks, c, Key ("/%thread%/%printer%/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
870 :
871 :
872 4 : n.context ().activate<MainApplicationLayer> ();
873 4 : ASSERT_EQ (n, i_value);
874 :
875 2 : n = 18;
876 6 : ASSERT_EQ (n, 18);
877 :
878 2 : Integer & d = n;
879 :
880 2 : d = i_value;
881 4 : ASSERT_EQ (d, i_value);
882 :
883 2 : d = 12;
884 6 : ASSERT_EQ (d, 12);
885 :
886 2 : foo (d);
887 6 : ASSERT_EQ (d, 12);
888 :
889 2 : foo (d);
890 6 : ASSERT_EQ (d, 12);
891 :
892 2 : bar (d);
893 6 : ASSERT_EQ (d, 12);
894 :
895 4 : std::thread t1 (bar, std::cref (d));
896 2 : t1.join ();
897 6 : ASSERT_EQ (d, 12);
898 :
899 4 : std::thread t2 (foo, std::ref (d));
900 2 : t2.join ();
901 6 : ASSERT_EQ (d, 12);
902 : }
903 :
904 20 : TEST (test_contextual_basic, nocontext)
905 : {
906 : using namespace kdb;
907 4 : KeySet ks;
908 : NoContext c;
909 6 : kdb::Value<int> n (ks, c, Key ("/test", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
910 4 : ASSERT_EQ (n, i_value);
911 :
912 2 : n = 18;
913 6 : ASSERT_EQ (n, 18);
914 : }
915 :
916 20 : TEST (test_contextual_basic, operators)
917 : {
918 : using namespace kdb;
919 4 : KeySet ks;
920 : NoContext c;
921 6 : kdb::Value<int> n (ks, c, Key ("/test/n", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
922 6 : kdb::Value<int> m (ks, c, Key ("/test/m", KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
923 4 : ASSERT_EQ (n, i_value);
924 4 : ASSERT_EQ (m, i_value);
925 :
926 2 : n = 18;
927 6 : ASSERT_EQ (n, 18);
928 6 : ASSERT_EQ (18, n);
929 4 : ASSERT_EQ (n, n);
930 8 : ASSERT_EQ (!n, 0);
931 8 : ASSERT_EQ (0, !n);
932 8 : ASSERT_EQ (~n, ~18);
933 8 : ASSERT_EQ (~18, ~n);
934 :
935 4 : ASSERT_NE (n, 19);
936 4 : ASSERT_NE (19, n);
937 6 : ASSERT_NE (!n, n);
938 6 : ASSERT_NE (~n, n);
939 :
940 4 : ASSERT_LT (n, 19);
941 4 : ASSERT_GT (n, 17);
942 4 : ASSERT_LE (n, 19);
943 4 : ASSERT_GE (n, 17);
944 :
945 4 : ASSERT_LE (n, 18);
946 4 : ASSERT_GE (n, 18);
947 :
948 2 : n = 18;
949 2 : m = 18;
950 :
951 4 : ASSERT_EQ (n, m);
952 4 : ASSERT_EQ (m, n);
953 :
954 4 : n += 3;
955 4 : m += 3;
956 :
957 4 : ASSERT_EQ (n, m);
958 4 : ASSERT_EQ (m, n);
959 :
960 4 : m += n;
961 6 : ASSERT_EQ (n, 21);
962 6 : ASSERT_EQ (m, 42);
963 :
964 6 : ASSERT_EQ (n + n, m);
965 6 : ASSERT_EQ (m, n + n);
966 :
967 2 : --n;
968 6 : ASSERT_EQ (n, 20);
969 :
970 6 : ASSERT_EQ (n && n, true);
971 :
972 4 : n -= 10;
973 6 : ASSERT_EQ (n, 10);
974 :
975 4 : n *= 2;
976 6 : ASSERT_EQ (n, 20);
977 :
978 4 : n /= 2;
979 6 : ASSERT_EQ (n, 10);
980 :
981 4 : n %= 12;
982 6 : ASSERT_EQ (n, 10 % 12);
983 :
984 2 : n = 4 | 8;
985 4 : n |= 16;
986 6 : ASSERT_EQ (n, 4 | 8 | 16);
987 :
988 2 : n = 8;
989 2 : n = *&n; // *& added to suppress clang warning
990 2 : m = n;
991 6 : ASSERT_EQ (n, 8);
992 6 : ASSERT_EQ (m, 8);
993 6 : ASSERT_EQ (8, n);
994 6 : ASSERT_EQ (8, m);
995 :
996 2 : n = -8;
997 2 : m = 8;
998 8 : ASSERT_EQ (n, -m);
999 8 : ASSERT_EQ (-n, m);
1000 6 : }
|