110f824e08cd4494f55950743d171476c3518841
[platform/upstream/libzypp.git] / tests / zypp / PoolQuery_test.cc
1 #include "TestSetup.h"
2 #include "zypp/PoolQuery.h"
3 #include "zypp/PoolQueryUtil.tcc"
4
5 #define BOOST_TEST_MODULE PoolQuery
6
7 /////////////////////////////////////////////////////////////////////////////
8 static TestSetup test( Arch_x86_64 );
9
10 BOOST_AUTO_TEST_CASE(pool_query_init)
11 {
12   // Abuse;) vbox as System repo:
13   test.loadTargetRepo( TESTS_SRC_DIR "/data/obs_virtualbox_11_1" );
14   test.loadRepo( TESTS_SRC_DIR "/data/openSUSE-11.1", "opensuse" );
15   test.loadRepo( TESTS_SRC_DIR "/data/OBS_zypp_svn-11.1", "zyppsvn" );
16
17   dumpRange( USR, test.pool().knownRepositoriesBegin(),
18                   test.pool().knownRepositoriesEnd() );
19   USR << "pool: " << test.pool() << endl;
20 }
21 /////////////////////////////////////////////////////////////////////////////
22
23 static std::ofstream devNull;
24 #define COUT devNull
25
26 struct PrintAndCount
27 {
28   PrintAndCount() : _count(0) {}
29
30   bool operator()( const sat::Solvable & solvable )
31   {
32     zypp::PoolItem pi( zypp::ResPool::instance().find( solvable ) );
33     COUT << pi.resolvable() << endl;
34     ++_count;
35     return true;
36   }
37
38   unsigned _count;
39 };
40
41 void dumpQ( std::ostream & str, const PoolQuery & q, bool verbose = true )
42 {
43   q.begin();
44   str << q << endl;
45   unsigned nc = 0;
46   if ( 1 )
47   {
48     for_( it, q.begin(), q.end() )
49     {
50       ++nc;
51       if ( verbose )
52         str << it << endl;
53     }
54     str << "--> MATCHES: " << nc << endl;
55   }
56 }
57
58
59 #if 0
60 BOOST_AUTO_TEST_CASE(pool_query_experiment)
61 {
62   cout << "****experiment****"  << endl;
63
64   PoolQuery q;
65   q.addString("zypper");
66   q.addAttribute(sat::SolvAttr::name);
67
68   // should list 1 selectable?
69   cout << "****selectables****"  << endl;
70   for (PoolQuery::Selectable_iterator it = q.selectableBegin();
71        it != q.selectableEnd(); ++it)
72   {
73     ui::Selectable::Ptr s = *it;
74     cout << s->kind() << ":" << s->name() << " hasinstalled: " << s->installedEmpty() << endl;
75   }
76   cout << "****solvables****" << endl;
77   PrintAndCount cb;
78   std::for_each(q.begin(), q.end(), cb);
79 }
80 #endif
81
82 /////////////////////////////////////////////////////////////////////////////
83 //  0xx basic queries
84 /////////////////////////////////////////////////////////////////////////////
85
86 // no conditions, default query
87 // result: all available resolvables
88 BOOST_AUTO_TEST_CASE(pool_query_000)
89 {
90   cout << "****000****"  << endl;
91   PoolQuery q;
92   cout << q.size() << endl;
93   BOOST_CHECK(q.size() == 3811);
94
95   /* dumpsolv repo1.solv repo2.solv repo3.solv | \
96      grep '^name:.*\(noarch\|x86_64\|i386\|i586\|i686\|src\)$' | wc -l */
97 }
98
99 // default query + one search string
100 // q.addString("foo");
101 // result: all resolvables having at least one attribute matching foo
102 BOOST_AUTO_TEST_CASE(pool_query_001)
103 {
104   cout << "****001****"  << endl;
105   PoolQuery q;
106   q.addString("zypper");
107
108   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 11);
109 }
110
111 // default query + one attribute + one string
112 // q.addAttribute(foo, bar);
113 // should be the same as
114 // q.addAttribute(foo); q.addString(bar);
115 // result: resolvables with foo containing bar
116 BOOST_AUTO_TEST_CASE(pool_query_002)
117 {
118   cout << "****002****"  << endl;
119   PoolQuery q;
120   q.addString("zypper");
121   q.addAttribute(sat::SolvAttr::name);
122
123   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 5);
124
125   cout << endl;
126
127   PoolQuery q1;
128   q1.addAttribute(sat::SolvAttr::name, "zypper");
129
130   BOOST_CHECK(std::for_each(q1.begin(), q1.end(), PrintAndCount())._count == 5);
131 }
132
133 // kind filter
134 BOOST_AUTO_TEST_CASE(pool_query_003)
135 {
136   cout << "****003****"  << endl;
137   PoolQuery q;
138   q.addString("zypper");
139   q.addAttribute(sat::SolvAttr::name);
140   q.addKind(ResKind::package);
141
142   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 3);
143 }
144
145 // match exact
146 BOOST_AUTO_TEST_CASE(pool_query_004)
147 {
148   cout << "****004****"  << endl;
149   PoolQuery q;
150   q.addString("vim");
151   q.addAttribute(sat::SolvAttr::name);
152   q.setMatchExact();
153
154   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 1);
155
156   PoolQuery q1;
157   q1.addString("zypp");
158   q1.addAttribute(sat::SolvAttr::name);
159   q1.setMatchExact();
160
161   std::for_each(q1.begin(), q1.end(), PrintAndCount());
162   BOOST_CHECK(q1.empty());
163 }
164
165 // use globs
166 BOOST_AUTO_TEST_CASE(pool_query_005)
167 {
168   cout << "****005.1****"  << endl;
169   PoolQuery q;
170   q.addString("z?p*");
171   q.addAttribute(sat::SolvAttr::name);
172   q.setMatchGlob();
173
174   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 6);
175
176   cout << "****005.2****"  << endl;
177
178   PoolQuery q1;
179   q1.addString("*zypp*");
180   q1.addAttribute(sat::SolvAttr::name);
181   q1.setMatchGlob();
182
183   BOOST_CHECK(std::for_each(q1.begin(), q1.end(), PrintAndCount())._count == 26);
184
185   cout << "****005.3****"  << endl;
186
187   // should be the same as above
188   PoolQuery q2;
189   q2.addString("zypp");
190   q2.addAttribute(sat::SolvAttr::name);
191
192   BOOST_CHECK(q2.size() == 26);
193 }
194
195 // use regex
196 BOOST_AUTO_TEST_CASE(pool_query_006)
197 {
198   cout << "****006.1***"  << endl;
199
200   // should be the same as 005 1
201   PoolQuery q;
202   q.addString("^z.p.*");
203   q.addAttribute(sat::SolvAttr::name);
204   q.setMatchRegex();
205
206   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 6);
207
208   cout << "****006.2***"  << endl;
209
210   PoolQuery q1;
211   q1.addString("zypper|smart");
212   q1.addAttribute(sat::SolvAttr::name);
213   q1.setMatchRegex();
214
215   BOOST_CHECK(std::for_each(q1.begin(), q1.end(), PrintAndCount())._count == 8);
216
217   cout << "****006.3***"  << endl;
218
219   // invalid regex
220   PoolQuery q2;
221   q2.addString("zypp\\");
222   q2.setMatchRegex();
223   BOOST_CHECK_THROW(q2.begin(), Exception);
224 }
225
226
227 // match whole words
228 BOOST_AUTO_TEST_CASE(pool_query_007)
229 {
230   cout << "****007***"  << endl;
231
232   PoolQuery q;
233   q.addString("zypp");
234   q.addAttribute(sat::SolvAttr::name);
235   q.setMatchWord();
236
237   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 6);
238 }
239
240 // match by installed status (basically by system vs. repo)
241 BOOST_AUTO_TEST_CASE(pool_query_050)
242 {
243   cout << "****050****"  << endl;
244   PoolQuery q;
245   q.addString("yasm");
246   q.addAttribute(sat::SolvAttr::name);
247   q.setMatchExact();
248   q.setInstalledOnly();
249
250   BOOST_CHECK_EQUAL(std::for_each(q.begin(), q.end(), PrintAndCount())._count, 4);
251
252   cout << endl;
253
254   PoolQuery q1;
255   q1.addString("zypper");
256   q1.addAttribute(sat::SolvAttr::name);
257   q1.setMatchExact();
258   q1.setUninstalledOnly();
259   BOOST_CHECK_EQUAL(std::for_each(q1.begin(), q1.end(), PrintAndCount())._count, 5);
260 }
261
262 /////////////////////////////////////////////////////////////////////////////
263 //  1xx multiple attribute queries
264 /////////////////////////////////////////////////////////////////////////////
265
266
267 BOOST_AUTO_TEST_CASE(pool_query_100)
268 {
269   cout << "****100****"  << endl;
270   PoolQuery q;
271   /* This string is found sometimes only in only in summary (e.g. pgcalc)
272      and sometimes only in description (e.g. bc, lftp). We don't have
273      any package with 'revers' only in package name, but let's ignore this.
274      I didn't find a string with the same characteristics giving fewer matches
275      :-/ */
276   q.addString("revers");
277   q.addAttribute(sat::SolvAttr::name);
278   q.addAttribute(sat::SolvAttr::summary);
279   q.addAttribute(sat::SolvAttr::description);
280
281   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 5);
282
283   cout << endl;
284
285   {
286     PoolQuery q1;
287     q1.addAttribute(sat::SolvAttr::name, "zypper");
288     BOOST_CHECK_EQUAL(q1.size(),5);
289
290     PoolQuery q2;
291     q2.addAttribute(sat::SolvAttr::summary,"samba");
292     BOOST_CHECK_EQUAL(q2.size(),13);
293
294     // now summary and name in one go:
295     q1.addAttribute(sat::SolvAttr::summary,"samba");
296     BOOST_CHECK_EQUAL(q1.size(),18);
297   }
298 }
299
300
301 // multi attr (same value) substring matching (case sensitive and insensitive)
302 BOOST_AUTO_TEST_CASE(pool_query_101)
303 {
304   cout << "****101****"  << endl;
305
306   PoolQuery q;
307   q.addString("RELAX");
308   q.addAttribute(sat::SolvAttr::name);
309   q.addAttribute(sat::SolvAttr::summary);
310   q.addAttribute(sat::SolvAttr::description);
311
312   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 7);
313
314   cout << endl;
315
316   PoolQuery q2;
317   q2.addString("RELAX");
318   q2.addAttribute(sat::SolvAttr::name);
319   q2.addAttribute(sat::SolvAttr::summary);
320   q2.addAttribute(sat::SolvAttr::description);
321   q2.setCaseSensitive();
322
323   BOOST_CHECK(std::for_each(q2.begin(), q2.end(), PrintAndCount())._count == 4);
324 }
325
326
327 // multi attr (same value) glob matching (case sensitive and insensitive)
328 BOOST_AUTO_TEST_CASE(pool_query_102)
329 {
330   cout << "****102****"  << endl;
331   PoolQuery q;
332   q.addString("pack*");
333   q.addAttribute(sat::SolvAttr::name);
334   q.addAttribute(sat::SolvAttr::summary);
335   q.setMatchGlob();
336
337   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 23);
338 }
339
340
341 // multi attr (same value via addAttribute())
342 BOOST_AUTO_TEST_CASE(pool_query_103)
343 {
344   cout << "****103.1****"  << endl;
345   PoolQuery q;
346   q.addAttribute(sat::SolvAttr::name, "rest");
347   q.addAttribute(sat::SolvAttr::summary, "rest");
348
349   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 14);
350
351   cout << "****103.2****"  << endl;
352
353   PoolQuery q1;
354   q1.addString("rest");
355   q1.addAttribute(sat::SolvAttr::name);
356   q1.addAttribute(sat::SolvAttr::summary);
357
358   BOOST_CHECK(std::for_each(q1.begin(), q1.end(), PrintAndCount())._count == 14);
359 //  BOOST_CHECK(q1.size() == 42);
360
361   cout << endl;
362 }
363
364 // multiple attributes, different search strings (one string per attrbute)
365 BOOST_AUTO_TEST_CASE(pool_query_104)
366 {
367   cout << "****104****"  << endl;
368   PoolQuery q;
369   q.addAttribute(sat::SolvAttr::name, "zypper");
370   q.addAttribute(sat::SolvAttr::summary, "package management");
371
372   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 8);
373 }
374
375 // multiple attributes, different search strings (one string per attrbute), regex matching
376 BOOST_AUTO_TEST_CASE(pool_query_105)
377 {
378   cout << "****105****"  << endl;
379   PoolQuery q;
380   q.addAttribute(sat::SolvAttr::name, "zy..er");
381   q.addAttribute(sat::SolvAttr::summary, "package management");
382   q.setMatchRegex();
383
384   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 8);
385 }
386
387 /////////////////////////////////////////////////////////////////////////////
388 //  3xx repo filter queries (addRepo(alias_str))
389 /////////////////////////////////////////////////////////////////////////////
390
391 // default query + one attribute(one string) + one repo
392 BOOST_AUTO_TEST_CASE(pool_query_300)
393 {
394   cout << "****300****"  << endl;
395   PoolQuery q;
396   q.addAttribute(sat::SolvAttr::name, "zypper");
397   q.addRepo("zyppsvn");
398
399   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 4);
400 }
401
402 // default query + one repo
403 BOOST_AUTO_TEST_CASE(pool_query_301)
404 {
405   cout << "****301****"  << endl;
406   PoolQuery q;
407   q.addRepo("zyppsvn");
408
409   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 42);
410 }
411
412 // multiple repos + one attribute
413 BOOST_AUTO_TEST_CASE(pool_query_302)
414 {
415   cout << "****302****"  << endl;
416   PoolQuery q;
417   q.addString("zypper");
418   q.addAttribute(sat::SolvAttr::name);
419   q.addRepo("opensuse");
420   q.addRepo("zyppsvn");
421
422   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 5);
423 }
424
425 /////////////////////////////////////////////////////////////////////////////
426 //  4xx kind queries (addKind(ResKind))
427 /////////////////////////////////////////////////////////////////////////////
428
429 BOOST_AUTO_TEST_CASE(pool_query_400)
430 {
431   cout << "****400****"  << endl;
432   PoolQuery q;
433   q.addString("lamp_server");
434   q.addAttribute(sat::SolvAttr::name);
435   q.addKind(ResKind::pattern);
436   q.setMatchExact();
437
438   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 1);
439 }
440
441 // should find packages and patterns
442 BOOST_AUTO_TEST_CASE(pool_query_401)
443 {
444   cout << "****401****"  << endl;
445   PoolQuery q;
446   q.addString("mail*");
447   q.addAttribute(sat::SolvAttr::name);
448   q.setMatchGlob();
449
450   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 4);
451 }
452
453
454 /////////////////////////////////////////////////////////////////////////////
455 //  5xx multiple string/attribute queries
456 /////////////////////////////////////////////////////////////////////////////
457
458 // multiple strings for one attribute
459 BOOST_AUTO_TEST_CASE(pool_query_500)
460 {
461   cout << "****500.1****"  << endl;
462   PoolQuery q;
463   q.addString("zypper");
464   q.addString("yast2-packager");
465   q.addAttribute(sat::SolvAttr::name);
466   q.setMatchExact();
467   // creates: ^(apt|zypper)$
468   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 6);
469
470   cout << "****500.2****"  << endl;
471   q.addString("*bzypp");
472   q.setMatchGlob();
473   // creates: ^(.*zy.p|yast.*package.*|.*bzypp)$
474   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 11);
475
476   cout << "****500.3****"  << endl;
477   PoolQuery q1;
478   q1.addString("^libsm[a-z]*[0-9]$");
479   q1.addAttribute(sat::SolvAttr::name, "bzypp$");
480   q1.addKind(ResKind::package);
481   q1.setMatchRegex();
482   // creates: (^libsm[a-z]*[0-9]$|bzypp$)
483   BOOST_CHECK(std::for_each(q1.begin(), q1.end(), PrintAndCount())._count == 5);
484
485   cout << "****500.4****"  << endl;
486   PoolQuery q2;
487   q2.addString("Thunder");
488   q2.addAttribute(sat::SolvAttr::name, "sun");
489   q2.addKind(ResKind::package);
490   q2.addRepo("opensuse");
491   q2.setCaseSensitive();
492   // creates: (sun|Thunder)
493   BOOST_CHECK(std::for_each(q2.begin(), q2.end(), PrintAndCount())._count == 3);
494
495   cout << "****500.5****"  << endl;
496   PoolQuery q3;
497   q3.addString("audio");
498   q3.addAttribute(sat::SolvAttr::name, "zip");
499   q3.addKind(ResKind::package);
500   q3.addRepo("opensuse");
501   q3.setMatchWord();
502   // creates: \b(zip|audio)\b
503   BOOST_CHECK(std::for_each(q3.begin(), q3.end(), PrintAndCount())._count == 3);
504 }
505
506 // multiple strings, multiple attributes, same strings
507 BOOST_AUTO_TEST_CASE(pool_query_501)
508 {
509   cout << "****501****"  << endl;
510   PoolQuery q;
511   q.addString("Thunder");
512   q.addString("storm");
513   q.addAttribute(sat::SolvAttr::name);
514   q.addAttribute(sat::SolvAttr::description);
515   q.addKind(ResKind::package);
516   q.addRepo("opensuse");
517
518   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 14);
519 }
520
521 // multiple strings, multiple attributes, same strings
522 BOOST_AUTO_TEST_CASE(pool_query_502)
523 {
524   cout << "****502****"  << endl;
525   PoolQuery q;
526   q.addString("weather");
527   q.addAttribute(sat::SolvAttr::name, "thunder");
528   q.addAttribute(sat::SolvAttr::description, "storm");
529   q.addKind(ResKind::package);
530   q.addRepo("opensuse");
531
532   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 13);
533 }
534
535 /////////////////////////////////////////////////////////////////////////////
536 //  6xx queries with edition
537 /////////////////////////////////////////////////////////////////////////////
538
539 BOOST_AUTO_TEST_CASE(pool_query_X)
540 {
541   cout << "****600.1****"  << endl;
542   PoolQuery q;
543   q.addAttribute(sat::SolvAttr::name, "zypper");
544   q.setMatchExact();
545   q.setEdition(Edition("0.12.5"), Rel::GT);
546
547   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 4);
548
549   cout << "****600.2****"  << endl;
550   q.setEdition(Edition("0.12.5"), Rel::LT);
551
552   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 0);
553
554   cout << "****600.3****"  << endl;
555   q.setEdition(Edition("0.12.5"), Rel::LE);
556
557   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 1);
558
559   cout << "****600.4****"  << endl;
560   q.setEdition(Edition("0.12.5-5"), Rel::LT);
561
562   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 1);
563 }
564
565 //! \todo FIXME this segfaults currently - one addString() + (version or kind or installed status condition)
566 /*
567 BOOST_AUTO_TEST_CASE(pool_query_FIXME)
568 {
569   cout << "****FIXME****"  << endl;
570   PoolQuery q;
571   q.addString("zypper");
572   q.setEdition(Edition("0.10.3-4"), Rel::GE);
573
574   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 2);
575 }
576 */
577
578 /*
579 BOOST_AUTO_TEST_CASE(pool_query_X)
580 {
581   cout << "****X****"  << endl;
582   PoolQuery q;
583   q.addString("pack*");
584   q.addAttribute(sat::SolvAttr::name);
585
586   BOOST_CHECK(std::for_each(q.begin(), q.end(), PrintAndCount())._count == 28);
587 }
588 */
589
590
591 BOOST_AUTO_TEST_CASE(pool_query_recovery)
592 {
593   Pathname testfile(TESTS_SRC_DIR);
594     testfile += "/zypp/data/PoolQuery/savedqueries";
595   cout << "****recovery****"  << endl;
596
597   std::vector<PoolQuery> queries;
598   std::insert_iterator<std::vector<PoolQuery> > ii( queries,queries.begin());
599   readPoolQueriesFromFile(testfile,ii);
600   BOOST_REQUIRE_MESSAGE(queries.size() == 2, "Bad count of read queries.");
601
602   BOOST_CHECK_EQUAL(queries[0].size(), 8);
603
604   PoolQuery q;
605   q.addString("ma*");
606   q.addRepo("opensuse");
607   q.addKind(ResKind::patch);
608   q.setMatchRegex();
609   q.setCaseSensitive();
610   q.setUninstalledOnly();
611   q.setEdition(Edition("0.8.3"),Rel::NE);
612   BOOST_CHECK(q == queries[1]);
613 }
614
615 BOOST_AUTO_TEST_CASE(pool_query_serialize)
616 {
617   PoolQuery q;
618   q.addString("ma");
619   q.addAttribute(sat::SolvAttr::name);
620   q.addRepo("factory-nonoss");
621   q.addRepo("zypp_svn");
622
623   PoolQuery q2;
624   q2.addAttribute(sat::SolvAttr::name,"ma");
625   q2.addRepo("factory-nonoss");
626   q2.addRepo("zypp_svn");
627
628
629   //  Pathname testfile(TESTS_SRC_DIR);
630   //  testfile += "/zypp/data/PoolQuery/testqueries";
631   filesystem::TmpFile testfile;
632   cout << "****serialize****"  << endl;
633   std::vector<PoolQuery> queries;
634   queries.push_back(q);
635   queries.push_back(q2);
636   writePoolQueriesToFile(testfile,queries.begin(),queries.end());
637   BOOST_REQUIRE_MESSAGE(queries.size()==2,"Bad count of added queries.");
638
639   std::insert_iterator<std::vector<PoolQuery> > ii( queries,queries.end());
640   readPoolQueriesFromFile(testfile,ii);
641   BOOST_REQUIRE_MESSAGE(queries.size()==4,"Bad count of written/readed queries.");
642   BOOST_CHECK(queries[2] == queries[0]);
643   BOOST_CHECK(queries[3] == queries[1]);
644 }
645
646 // test matching
647 BOOST_AUTO_TEST_CASE(pool_query_equal)
648 {
649   cout << "****equal****"  << endl;
650   std::vector<PoolQuery> v;
651   {
652     PoolQuery q;
653     v.push_back( q );
654   }
655   {
656     PoolQuery q;
657     q.addAttribute( sat::SolvAttr::name, "zypper" );
658     q.setMatchExact();
659     q.setCaseSensitive(true);
660     v.push_back( q );
661   }
662   {
663     PoolQuery q;
664     q.addAttribute( sat::SolvAttr::name, "libzypp" );   // different
665     q.setMatchExact();
666     q.setCaseSensitive(true);
667     v.push_back( q );
668   }
669   {
670     PoolQuery q;
671     q.addAttribute( sat::SolvAttr::vendor, "zypper" );  // different
672     q.setMatchExact();
673     q.setCaseSensitive(true);
674     v.push_back( q );
675   }
676   {
677     PoolQuery q;
678     q.addAttribute( sat::SolvAttr::name, "zypper" );
679     q.setMatchExact();
680     q.setCaseSensitive(false);  // different
681     v.push_back( q );
682   }
683   {
684     PoolQuery q;
685     q.addAttribute( sat::SolvAttr::name, "zypper" );
686     q.setMatchSubstring();      // different
687     q.setCaseSensitive(true);
688     v.push_back( q );
689   }
690   {
691     PoolQuery q;
692     q.addDependency( sat::SolvAttr::provides, "zypper" );
693     v.push_back( q );
694   }
695   {
696     PoolQuery q;
697     q.addDependency( sat::SolvAttr::provides, "zypper", Rel::GT, Edition("1.0")  );
698     v.push_back( q );
699   }
700   {
701     PoolQuery q;
702     q.addDependency( sat::SolvAttr::provides, "zypper", Rel::GT, Edition("2.0")  );
703     v.push_back( q );
704   }
705
706   for (size_t li = 0; li < v.size(); ++li)
707   {
708     for (size_t ri = 0; ri < v.size(); ++ri)
709     {
710       COUT << li << " <> " << ri << endl;
711       bool equal( v[li] == v[ri] );
712       bool nequal( v[li] != v[ri] );
713       BOOST_CHECK_EQUAL( equal, li==ri );
714       BOOST_CHECK_EQUAL( equal, !nequal );
715     }
716   }
717 }
718
719 /////////////////////////////////////////////////////////////////////////////
720 //  Dependency Query
721 /////////////////////////////////////////////////////////////////////////////
722
723 BOOST_AUTO_TEST_CASE(addDependency)
724 {
725   {
726     cout << "****addDependency1****"  << endl;
727     PoolQuery q;
728     q.setCaseSensitive( false );
729     q.setMatchSubstring();
730     q.addString( "libzypp" );
731     q.addDependency( sat::SolvAttr::provides, "FOO" ); // ! finds 'perl(CPAN::InfoObj)' 'foO'
732     std::for_each(q.begin(), q.end(), PrintAndCount());
733     //dumpQ( std::cout, q );
734     BOOST_CHECK_EQUAL( q.size(), 13 );
735   }
736   {
737     cout << "****addDependency2****"  << endl;
738     PoolQuery q;
739     q.setCaseSensitive( false );
740     q.setMatchSubstring();
741     q.addString( "libzypp" );
742     q.addDependency( sat::SolvAttr::provides, "FOO", Rel::GT, Edition("5.0") );
743     std::for_each(q.begin(), q.end(), PrintAndCount());
744     //dumpQ( std::cout, q );
745     BOOST_CHECK_EQUAL( q.size(), 7 );
746   }
747   {
748     cout << "****addDependency2a****"  << endl;
749     PoolQuery q;
750     q.setCaseSensitive( false );
751     q.setMatchSubstring();
752     q.addDependency( sat::SolvAttr::provides, "libzypp", Rel::GT, Edition("5.0") );
753     q.addAttribute( sat::SolvAttr::arch, Arch_i586.asString() ); // OR with arch i585
754     std::for_each(q.begin(), q.end(), PrintAndCount());
755     //dumpQ( std::cout, q );
756     BOOST_CHECK_EQUAL( q.size(), 66 );
757   }
758   {
759     cout << "****addDependency2b****"  << endl;
760     PoolQuery q;
761     q.setCaseSensitive( false );
762     q.setMatchSubstring();
763     // libzypp provides yast2-packagemanager...
764     q.addDependency( sat::SolvAttr::provides, "yast2-packagemanager", Rel::GT, Edition("5.0"), Arch_i586 ); // AND with arch i585
765     std::for_each(q.begin(), q.end(), PrintAndCount());
766     //dumpQ( std::cout, q );
767     BOOST_CHECK_EQUAL( q.size(), 2 );
768   }
769   {
770     cout << "****addDependency2c****"  << endl;
771     PoolQuery q;
772     q.setCaseSensitive( false );
773     q.setMatchSubstring();
774     // but no package named yast2-packagemanager
775     q.addDependency( sat::SolvAttr::name, "yast2-packagemanager", Rel::GT, Edition("5.0"), Arch_i586 ); // AND with arch i585
776     std::for_each(q.begin(), q.end(), PrintAndCount());
777     //dumpQ( std::cout, q );
778     BOOST_CHECK_EQUAL( q.size(), 0 );
779   }
780   {
781     cout << "****addDependency2d****"  << endl;
782     PoolQuery q;
783     q.setCaseSensitive( false );
784     q.setMatchSubstring();
785     // libzypp provides yast2-packagemanager...
786     q.addDependency( sat::SolvAttr::provides, "yast2-packagemanager", Arch_i586 ); // AND with arch i585
787     std::for_each(q.begin(), q.end(), PrintAndCount());
788     //dumpQ( std::cout, q );
789     BOOST_CHECK_EQUAL( q.size(), 2 );
790   }
791   {
792     cout << "****addDependency2e****"  << endl;
793     PoolQuery q;
794     q.setCaseSensitive( false );
795     q.setMatchSubstring();
796     // but no package named yast2-packagemanager
797     q.addDependency( sat::SolvAttr::name, "yast2-packagemanager", Arch_i586 ); // AND with arch i585
798     std::for_each(q.begin(), q.end(), PrintAndCount());
799     //dumpQ( std::cout, q );
800     BOOST_CHECK_EQUAL( q.size(), 0 );
801   }
802
803   {
804     cout << "****addDependency3****"  << endl;
805     PoolQuery q;
806     // includes wine
807     q.addDependency( sat::SolvAttr::provides, "kernel" );
808     std::for_each(q.begin(), q.end(), PrintAndCount());
809     //dumpQ( std::cout, q );
810     BOOST_CHECK_EQUAL( q.size(), 12 );
811   }
812   {
813     cout << "****addDependency4****"  << endl;
814     PoolQuery q;
815     // no wine
816     q.addDependency( sat::SolvAttr::name, "kernel" );
817     std::for_each(q.begin(), q.end(), PrintAndCount());
818     //dumpQ( std::cout, q );
819     BOOST_CHECK_EQUAL( q.size(), 11 );
820   }
821   {
822     cout << "****addDependency5****"  << endl;
823     PoolQuery q;
824     // Capability always matches exact
825     q.addDependency( sat::SolvAttr::provides, Capability("kernel") );
826     std::for_each(q.begin(), q.end(), PrintAndCount());
827     //dumpQ( std::cout, q );
828     BOOST_CHECK_EQUAL( q.size(), 2 );
829   }
830   {
831     cout << "****addDependency6****"  << endl;
832     PoolQuery q;
833     // non dependecy + Capability matches solvable name!
834     q.addDependency( sat::SolvAttr::summary, Capability("kernel") );
835     std::for_each(q.begin(), q.end(), PrintAndCount());
836     //dumpQ( std::cout, q );
837     BOOST_CHECK_EQUAL( q.size(), 0 ); // non dependecy
838   }
839 }
840
841 namespace
842 {
843   std::string q2str( const PoolQuery & q_r )
844   {
845     str::Str s;
846     q_r.serialize( s.stream() );
847     return s;
848   }
849
850   template <class OutputIterator>
851   void str2q( const std::string & s_r, OutputIterator out_r )
852   {
853     std::istringstream s( s_r );
854     do {
855       PoolQuery q;
856       if ( q.recover( s ) )
857         *out_r++ = std::move(q);
858       else
859         break;
860     } while ( true );
861   }
862
863   typedef std::set<PoolQuery> Pqs;
864
865   PoolQuery str2q( const std::string & s_r )
866   {
867     Pqs ret;
868     str2q( s_r, std::insert_iterator<Pqs>( ret, ret.end() ) );
869     return *ret.begin();
870   }
871
872
873   std::string serialized( const std::string & arg_r )
874   { return "\n" + arg_r + "\n\n"; }
875
876   template <typename... Args>
877   std::string serialized( const std::string & arg_r, Args... args_r )
878   { return "\n" + arg_r + serialized( args_r... ); }
879
880
881   void testSerializeAndBack( const PoolQuery & q_r, const PoolQuery & expect_r, bool equal_r = true )
882   {
883     static unsigned i = 0;
884
885     std::string s { q2str( q_r ) };
886     PoolQuery   q { str2q( s ) };
887     BOOST_CHECK_EQUAL( (q == expect_r), equal_r );
888
889     if ( ++i && (q == expect_r) != equal_r )
890     {
891       cout << "+++" << endl;
892       cout << q << endl;
893       cout << "=== " << i << " ^v SerializeAndBack == " << equal_r << endl;
894       cout << expect_r << endl;
895       cout << "---" << endl;
896     }
897   }
898 }
899
900 BOOST_AUTO_TEST_CASE(zypperLocksSerialize)
901 {
902   // Fix/cleanup zypper locks (old style, new stule, complex) (bsc#1112911)
903   // As you may notice: locks (by now) ignore any arch component
904   cout << "****zypperLocksSerialize****"  << endl;
905   std::string n { "n*" };
906   Rel         o { Rel::EQ };
907   Edition     e { "v", "r", 1 };
908   Arch        a { "a" };
909
910   {
911     // old style
912     // solvable_name: n*
913     PoolQuery oldq;
914     oldq.addAttribute( sat::SolvAttr::name, n );
915     testSerializeAndBack( oldq, oldq );
916
917     { // new style
918       PoolQuery q;
919       q.addDependency( sat::SolvAttr::name, n, Rel::ANY, Edition(), Arch_empty );
920       testSerializeAndBack( q, oldq );
921     }
922
923     { // new style + arch rule however stays complex
924       PoolQuery q;
925       q.addDependency( sat::SolvAttr::name, n, Rel::ANY, Edition(), a );
926       testSerializeAndBack( q, oldq, false );
927       testSerializeAndBack( q, q );
928     }
929   }
930
931   {
932     // old style
933     // solvable_name: n*
934     // version: == 1:v-r
935     PoolQuery oldq;
936     oldq.addAttribute( sat::SolvAttr::name, n );
937     oldq.setEdition( e, o );
938     testSerializeAndBack( oldq, oldq );
939
940     { // new style
941       PoolQuery q;
942       q.addDependency( sat::SolvAttr::name, n, o, e, Arch_empty );
943       testSerializeAndBack( q, oldq );
944     }
945
946     { // new style + arch rule however stays complex
947       PoolQuery q;
948       q.addDependency( sat::SolvAttr::name, n, o, e, a );
949       testSerializeAndBack( q, oldq, false );
950       testSerializeAndBack( q, q );
951     }
952   }
953 }