Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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)
5 2018, 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
20#include "lib/test/run.hpp"
22#include "lib/format-util.hpp"
24#include "lib/iter-cursor.hpp"
25#include "lib/util.hpp"
26
27#include <vector>
28#include <string>
29
30
31
32namespace lib {
33namespace iter{
34namespace test{
35
36 using ::Test;
37 using util::join;
38 using util::isnil;
39 using util::startsWith;
41 using std::vector;
42 using std::string;
43
44 using LERR_(ITER_EXHAUST);
45
46
47 namespace { // test fixture
48
49 using Spam = vector<string>;
50
51 const Spam SPAM{"spam"
52 ,"sausage"
53 ,"spam"
54 ,"spam"
55 ,"bacon"
56 ,"spam"
57 ,"tomato"
58 ,"and"
59 ,"spam"
60 };
61
62
64 template<class II>
65 inline string
66 materialise (II&& ii)
67 {
68 return util::join (std::forward<II> (ii), "-");
69 }
70 }// (END)fixture
71
72
73
74
75
76
77
78 /*****************************************************************/
95 class IterChainSearch_test : public Test
96 {
97
98 virtual void
99 run (Arg)
100 {
101 simpleSearch();
103 backtracking();
104 }
105
106
108 void
110 {
111 auto search = chainSearch(SPAM)
112 .search("bacon")
113 .search("tomato");
114
115 CHECK (search);
116 CHECK (not isnil(search));
117 CHECK ("tomato" == *search);
118 CHECK (isSameObject (*search, SPAM[6]));
119
120 search.clearFilter();
121 CHECK ("tomato" == *search);
122 ++search;
123 CHECK ("and" == *search);
124 search.search("spam");
125 CHECK ("spam" == *search);
126 CHECK (isSameObject (*search, SPAM[8]));
127
128 ++search;
129 CHECK (not search);
130 CHECK (isnil (search));
131 VERIFY_ERROR (ITER_EXHAUST, *search);
132 }
133
134
135
143 void
145 {
146 auto search = chainSearch(SPAM) // Note: 1st filter step picks all s-words
147 .search([](string const& str){ return startsWith (str, "s"); });
148
149 CHECK (materialise (search) =="spam-sausage-spam-spam-spam-spam");
150 CHECK ("spam" == *search);
151
152 search.addStep([](auto& filter)
153 { // Note: pick the current value at the point
154 string currVal = *filter; // where the 2nd filter step is (re)applied
155 filter.setNewFilter ([=](string const& val) // ...and bake this value into the lambda closure
156 {
157 return val != currVal;
158 });
159 });
160
161 CHECK ("sausage" == *search);
162 CHECK (materialise (search)
163 == "sausage-bacon-tomato-and-" // everything in the rest, which is not "spam"
164 "spam-spam-bacon-spam-tomato-and-spam-" // everything starting at "sausage" which is not "sausage"
165 "bacon-tomato-and-" // any non-spam behind the 2nd spam
166 "bacon-tomato-and-" // any non-spam behind the 3rd spam
167 "tomato-and" // any non-spam behind the 4th spam
168 ""); // and any non-spam behind the final spam
169 }
170
171
172
181 void
183 {
184 using Cursor = IterCursor<decltype(SPAM.begin())>;
185
186 auto search = chainSearch(Cursor{SPAM.begin(), SPAM.end()})
187 .search("spam")
188 .addStep([](auto& filter)
189 {
190 filter.switchBackwards(); // switch search direction without moving the cursor
191 filter.flipFilter(); // flip from match on "spam" to match on non-spam
192 })
193 .addStep([](auto& filter)
194 { // filter is still configured to search non-spam backwards
195 ++filter; // just "advance" this filter by one step (backward)
196 });
197
198 CHECK (materialise (search) // Layer-0: 1-3 spam fail altogether, too greedy. Try 4rd spam....
199 // Layer-1: turn back, toggle to non-spam, find bacon
200 == "sausage-" // Layer-2: non-spam and one step further backwards yields sausage
201 //
202 // BACKTRACK to Layer-0: pick 5th (and last) spam...
203 // Layer-1: turn back, toggle to non-spam, find "and"
204 "tomato-bacon-sausage-" // Layer-2: non-spam and one step back yields tomato, next bacon, next sausage.
205 // BACKTRACK to Layer-1: take previous one, which is tomato
206 "bacon-sausage-" // Layer-2: non-spam and one step further back yields bacon, then next sausage.
207 // BACKTRACK to Layer-1: take previous non-spam, which is bacon
208 "sausage" // Layer-2: non-spam and one step further back yields sausage.
209 ""); // BACKTRACK to Layer-1: exhausted, BACKTRACK to Layer-0: exhausted. Done.
210 }
211 };
212
214
215
216}}} // namespace lib::iter::test
A cursor-like iterator with the ability to switch iteration direction.
#define LERR_(_NAME_)
Definition error.hpp:45
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
Evaluation mechanism to apply a sequence of conditions onto a linear search.
An iterator with the ability to switch direction.
auto chainSearch(SRC &&srcData)
setup a chain search configuration by suitably wrapping the given container.
Implementation namespace for support and library code.
Test runner and basic definitions for tests.
bool startsWith(string const &str, string const &prefix)
check if string starts with a given prefix
Definition util.hpp:185
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
Definition util.hpp:421
string join(COLL &&coll, string const &delim=", ")
enumerate a collection's contents, separated by delimiter.
bool isnil(lib::time::Duration const &dur)
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
A collection of frequently used helper functions to support unit testing.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...