1 #include "catch.hpp"
2
3 #include <osmium/builder/attr.hpp>
4 #include <osmium/memory/buffer.hpp>
5 #include <osmium/osm/tag.hpp>
6 #include <osmium/tags/filter.hpp>
7 #include <osmium/tags/regex_filter.hpp>
8 #include <osmium/tags/taglist.hpp>
9
10 #include <algorithm>
11 #include <initializer_list>
12 #include <iterator>
13 #include <regex>
14 #include <utility>
15 #include <vector>
16
17 template <class TFilter>
check_filter(const osmium::TagList & tag_list,const TFilter filter,const std::vector<bool> & reference)18 void check_filter(const osmium::TagList& tag_list,
19 const TFilter filter,
20 const std::vector<bool>& reference) {
21 REQUIRE(tag_list.size() == reference.size());
22 auto t_it = tag_list.begin();
23 for (auto it = reference.begin(); it != reference.end(); ++t_it, ++it) {
24 REQUIRE(filter(*t_it) == *it);
25 }
26
27 typename TFilter::iterator fi_begin{filter, tag_list.begin(), tag_list.end()};
28 typename TFilter::iterator fi_end{filter, tag_list.end(), tag_list.end()};
29
30 REQUIRE(std::distance(fi_begin, fi_end) == std::count(reference.begin(), reference.end(), true));
31 }
32
make_tag_list(osmium::memory::Buffer & buffer,const std::initializer_list<std::pair<const char *,const char * >> & tags)33 const osmium::TagList& make_tag_list(osmium::memory::Buffer& buffer,
34 const std::initializer_list<std::pair<const char*, const char*>>& tags) {
35 const auto pos = osmium::builder::add_tag_list(buffer, osmium::builder::attr::_tags(tags));
36 return buffer.get<osmium::TagList>(pos);
37 }
38
39
40 TEST_CASE("KeyFilter") {
41 osmium::memory::Buffer buffer{10240};
42 osmium::tags::KeyFilter filter{false};
43
44 const osmium::TagList& tag_list = make_tag_list(buffer, {
45 { "highway", "primary" },
46 { "name", "Main Street" },
47 { "source", "GPS" }
48 });
49
50 SECTION("KeyFilter matches some tags") {
51 filter.add(true, "highway")
52 .add(true, "railway");
53
54 const std::vector<bool> results = { true, false, false };
55
56 check_filter(tag_list, filter, results);
57 }
58
59 SECTION("KeyFilter iterator filters tags") {
60 filter.add(true, "highway")
61 .add(true, "source");
62
63 osmium::tags::KeyFilter::iterator it{filter, tag_list.begin(),
64 tag_list.end()};
65
66 const osmium::tags::KeyFilter::iterator end{filter, tag_list.end(),
67 tag_list.end()};
68
69 REQUIRE(2 == std::distance(it, end));
70
71 REQUIRE(it != end);
72 REQUIRE(std::string("highway") == it->key());
73 REQUIRE(std::string("primary") == it->value());
74 ++it;
75 REQUIRE(std::string("source") == it->key());
76 REQUIRE(std::string("GPS") == it->value());
77 REQUIRE(++it == end);
78 }
79
80 }
81
82 TEST_CASE("KeyValueFilter") {
83 osmium::memory::Buffer buffer{10240};
84
85 SECTION("KeyValueFilter matches some tags") {
86 osmium::tags::KeyValueFilter filter{false};
87
88 filter.add(true, "highway", "residential")
89 .add(true, "highway", "primary")
90 .add(true, "railway");
91
92 const osmium::TagList& tag_list = make_tag_list(buffer, {
93 { "highway", "primary" },
94 { "railway", "tram" },
95 { "source", "GPS" }
96 });
97
98 const std::vector<bool> results = {true, true, false};
99
100 check_filter(tag_list, filter, results);
101 }
102
103 SECTION("KeyValueFilter ordering matters") {
104 osmium::tags::KeyValueFilter filter1(false);
105 filter1.add(true, "highway")
106 .add(false, "highway", "road");
107
108 osmium::tags::KeyValueFilter filter2(false);
109 filter2.add(false, "highway", "road")
110 .add(true, "highway");
111
112 const osmium::TagList& tag_list1 = make_tag_list(buffer, {
113 { "highway", "road" },
114 { "name", "Main Street" }
115 });
116
117 const osmium::TagList& tag_list2 = make_tag_list(buffer, {
118 { "highway", "primary" },
119 { "name", "Main Street" }
120 });
121
122 check_filter(tag_list1, filter1, {true, false});
123 check_filter(tag_list1, filter2, {false, false});
124 check_filter(tag_list2, filter2, {true, false});
125 }
126
127 SECTION("KeyValueFilter matches against taglist with any") {
128 osmium::tags::KeyValueFilter filter{false};
129
130 filter.add(true, "highway", "primary")
131 .add(true, "name");
132
133 const osmium::TagList& tag_list = make_tag_list(buffer, {
134 { "highway", "primary" },
135 { "railway", "tram" },
136 { "source", "GPS" }
137 });
138
139 REQUIRE( osmium::tags::match_any_of(tag_list, filter));
140 REQUIRE_FALSE(osmium::tags::match_all_of(tag_list, filter));
141 REQUIRE_FALSE(osmium::tags::match_none_of(tag_list, filter));
142 }
143
144 SECTION("KeyValueFilter matches against taglist with_all") {
145 osmium::tags::KeyValueFilter filter{false};
146
147 filter.add(true, "highway", "primary")
148 .add(true, "name");
149
150 const osmium::TagList& tag_list = make_tag_list(buffer, {
151 { "highway", "primary" },
152 { "name", "Main Street" }
153 });
154
155 REQUIRE( osmium::tags::match_any_of(tag_list, filter));
156 REQUIRE( osmium::tags::match_all_of(tag_list, filter));
157 REQUIRE_FALSE(osmium::tags::match_none_of(tag_list, filter));
158 }
159
160 SECTION("KeyValueFilter matches against taglist with none") {
161 osmium::tags::KeyValueFilter filter{false};
162
163 filter.add(true, "highway", "road")
164 .add(true, "source");
165
166 const osmium::TagList& tag_list = make_tag_list(buffer, {
167 { "highway", "primary" },
168 { "name", "Main Street" }
169 });
170
171 REQUIRE_FALSE(osmium::tags::match_any_of(tag_list, filter));
172 REQUIRE_FALSE(osmium::tags::match_all_of(tag_list, filter));
173 REQUIRE( osmium::tags::match_none_of(tag_list, filter));
174 }
175
176 SECTION("KeyValueFilter matches against taglist with any called with rvalue") {
177 const osmium::TagList& tag_list = make_tag_list(buffer, {
178 { "highway", "primary" },
179 { "railway", "tram" },
180 { "source", "GPS" }
181 });
182
183 REQUIRE(osmium::tags::match_any_of(tag_list,
184 osmium::tags::KeyValueFilter()
185 .add(true, "highway", "primary")
186 .add(true, "name")));
187 }
188
189 }
190
191 TEST_CASE("RegexFilter matches some tags") {
192 osmium::memory::Buffer buffer{10240};
193
194 osmium::tags::RegexFilter filter{false};
195 filter.add(true, "highway", std::regex{".*_link"});
196
197 const osmium::TagList& tag_list1 = make_tag_list(buffer, {
198 { "highway", "primary_link" },
199 { "source", "GPS" }
200 });
201 const osmium::TagList& tag_list2 = make_tag_list(buffer, {
202 { "highway", "primary" },
203 { "source", "GPS" }
204 });
205
206 check_filter(tag_list1, filter, {true, false});
207 check_filter(tag_list2, filter, {false, false});
208 }
209
210 TEST_CASE("RegexFilter matches some tags with lvalue regex") {
211 osmium::memory::Buffer buffer{10240};
212 osmium::tags::RegexFilter filter{false};
213 std::regex r{".*straße"};
214 filter.add(true, "name", r);
215
216 const osmium::TagList& tag_list = make_tag_list(buffer, {
217 { "highway", "primary" },
218 { "name", "Hauptstraße" }
219 });
220
221 check_filter(tag_list, filter, {false, true});
222 }
223
224 TEST_CASE("KeyPrefixFilter matches some keys") {
225 osmium::memory::Buffer buffer{10240};
226
227 osmium::tags::KeyPrefixFilter filter{false};
228 filter.add(true, "name:");
229
230 const osmium::TagList& tag_list = make_tag_list(buffer, {
231 { "highway", "primary" },
232 { "name:de", "Hauptstraße" }
233 });
234
235 check_filter(tag_list, filter, {false, true});
236
237 }
238
239 TEST_CASE("Generic Filter with regex matches some keys") {
240 osmium::memory::Buffer buffer{10240};
241
242 osmium::tags::Filter<std::regex> filter{false};
243 filter.add(true, std::regex{"restriction.+conditional"});
244
245 const osmium::TagList& tag_list = make_tag_list(buffer, {
246 { "highway", "primary" },
247 { "restrictionconditional", "only_right_turn @ (Mo-Fr 07:00-14:00)" },
248 { "restriction:conditional", "only_right_turn @ (Mo-Fr 07:00-14:00)" },
249 { "restriction:psv:conditional", "only_right_turn @ (Mo-Fr 07:00-14:00)" }
250 });
251
252 check_filter(tag_list, filter, {false, false, true, true});
253
254 }
255