Lumiera  0.pre.03
»edit your freedom«
iter-chain-search-test.cpp
Go to the documentation of this file.
1 /*
2  IterChainSearch(Test) - verify chained search operations with backtracking
3 
4  Copyright (C) Lumiera.org
5  2018, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
29 #include "lib/test/run.hpp"
30 #include "lib/test/test-helper.hpp"
31 #include "lib/format-util.hpp"
33 #include "lib/iter-cursor.hpp"
34 #include "lib/util.hpp"
35 
36 #include <vector>
37 #include <string>
38 
39 
40 
41 namespace lib {
42 namespace iter{
43 namespace test{
44 
45  using ::Test;
46  using util::join;
47  using util::isnil;
48  using util::startsWith;
49  using util::isSameObject;
50  using std::vector;
51  using std::string;
52 
53  using LERR_(ITER_EXHAUST);
54 
55 
56  namespace { // test fixture
57 
58  using Spam = vector<string>;
59 
60  const Spam SPAM{"spam"
61  ,"sausage"
62  ,"spam"
63  ,"spam"
64  ,"bacon"
65  ,"spam"
66  ,"tomato"
67  ,"and"
68  ,"spam"
69  };
70 
71 
73  template<class II>
74  inline string
75  materialise (II&& ii)
76  {
77  return util::join (std::forward<II> (ii), "-");
78  }
79  }// (END)fixture
80 
81 
82 
83 
84 
85 
86 
87  /*****************************************************************/
104  class IterChainSearch_test : public Test
105  {
106 
107  virtual void
108  run (Arg)
109  {
110  simpleSearch();
112  backtracking();
113  }
114 
115 
117  void
119  {
120  auto search = chainSearch(SPAM)
121  .search("bacon")
122  .search("tomato");
123 
124  CHECK (search);
125  CHECK (not isnil(search));
126  CHECK ("tomato" == *search);
127  CHECK (isSameObject (*search, SPAM[6]));
128 
129  search.clearFilter();
130  CHECK ("tomato" == *search);
131  ++search;
132  CHECK ("and" == *search);
133  search.search("spam");
134  CHECK ("spam" == *search);
135  CHECK (isSameObject (*search, SPAM[8]));
136 
137  ++search;
138  CHECK (not search);
139  CHECK (isnil (search));
140  VERIFY_ERROR (ITER_EXHAUST, *search);
141  }
142 
143 
144 
152  void
154  {
155  auto search = chainSearch(SPAM) // Note: 1st filter step picks all s-words
156  .search([](string const& str){ return startsWith (str, "s"); });
157 
158  CHECK (materialise (search) =="spam-sausage-spam-spam-spam-spam");
159  CHECK ("spam" == *search);
160 
161  search.addStep([](auto& filter)
162  { // Note: pick the current value at the point
163  string currVal = *filter; // where the 2nd filter step is (re)applied
164  filter.setNewFilter ([=](string const& val) // ...and bake this value into the lambda closure
165  {
166  return val != currVal;
167  });
168  });
169 
170  CHECK ("sausage" == *search);
171  CHECK (materialise (search)
172  == "sausage-bacon-tomato-and-" // everything in the rest, which is not "spam"
173  "spam-spam-bacon-spam-tomato-and-spam-" // everything starting at "sausage" which is not "sausage"
174  "bacon-tomato-and-" // any non-spam behind the 2nd spam
175  "bacon-tomato-and-" // any non-spam behind the 3rd spam
176  "tomato-and" // any non-spam behind the 4th spam
177  ""); // and any non-spam behind the final spam
178  }
179 
180 
181 
190  void
192  {
193  using Cursor = IterCursor<decltype(SPAM.begin())>;
194 
195  auto search = chainSearch(Cursor{SPAM.begin(), SPAM.end()})
196  .search("spam")
197  .addStep([](auto& filter)
198  {
199  filter.switchBackwards(); // switch search direction without moving the cursor
200  filter.flipFilter(); // flip from match on "spam" to match on non-spam
201  })
202  .addStep([](auto& filter)
203  { // filter is still configured to search non-spam backwards
204  ++filter; // just "advance" this filter by one step (backward)
205  });
206 
207  CHECK (materialise (search) // Layer-0: 1-3 spam fail altogether, too greedy. Try 4rd spam....
208  // Layer-1: turn back, toggle to non-spam, find bacon
209  == "sausage-" // Layer-2: non-spam and one step further backwards yields sausage
210  //
211  // BACKTRACK to Layer-0: pick 5th (and last) spam...
212  // Layer-1: turn back, toggle to non-spam, find "and"
213  "tomato-bacon-sausage-" // Layer-2: non-spam and one step back yields tomato, next bacon, next sausage.
214  // BACKTRACK to Layer-1: take previous one, which is tomato
215  "bacon-sausage-" // Layer-2: non-spam and one step further back yields bacon, then next sausage.
216  // BACKTRACK to Layer-1: take previous non-spam, which is bacon
217  "sausage" // Layer-2: non-spam and one step further back yields sausage.
218  ""); // BACKTRACK to Layer-1: exhausted, BACKTRACK to Layer-0: exhausted. Done.
219  }
220  };
221 
222  LAUNCHER (IterChainSearch_test, "unit common");
223 
224 
225 }}} // namespace lib::iter::test
auto chainSearch(SRC &&srcData)
setup a chain search configuration by suitably wrapping the given container.
bool filter(Placement< DummyMO > const &candidate)
a filter predicate to pick some objects from a resultset.
Definition: run.hpp:49
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
An iterator with the ability to switch direction.
Implementation namespace for support and library code.
Evaluation mechanism to apply a sequence of conditions onto a linear search.
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
A collection of frequently used helper functions to support unit testing.
A cursor-like iterator with the ability to switch iteration direction.
string materialise(II &&ii)
Diagnostic helper: join all the elements from a copy of the iterator.
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
bool isSameObject(A const &a, B const &b)
compare plain object identity, bypassing any custom comparison operators.
Definition: util.hpp:372