1 #include "server/api/parameters_parser.hpp"
2 
3 #include "parameters_io.hpp"
4 
5 #include "engine/api/base_parameters.hpp"
6 #include "engine/api/match_parameters.hpp"
7 #include "engine/api/nearest_parameters.hpp"
8 #include "engine/api/route_parameters.hpp"
9 #include "engine/api/table_parameters.hpp"
10 #include "engine/api/tile_parameters.hpp"
11 #include "engine/api/trip_parameters.hpp"
12 
13 #include "util/debug.hpp"
14 
15 #include <boost/optional/optional_io.hpp>
16 #include <boost/test/test_tools.hpp>
17 #include <boost/test/unit_test.hpp>
18 
19 #define CHECK_EQUAL_RANGE(R1, R2)                                                                  \
20     BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
21 
22 BOOST_AUTO_TEST_SUITE(api_parameters_parser)
23 
24 using namespace osrm;
25 using namespace osrm::server;
26 using namespace osrm::server::api;
27 using namespace osrm::engine::api;
28 
29 // returns distance to front
testInvalidOptions(std::string options)30 template <typename ParameterT> std::size_t testInvalidOptions(std::string options)
31 {
32     auto iter = options.begin();
33     auto result = parseParameters<ParameterT>(iter, options.end());
34     BOOST_CHECK(!result);
35     return std::distance(options.begin(), iter);
36 }
37 
BOOST_AUTO_TEST_CASE(invalid_route_urls)38 BOOST_AUTO_TEST_CASE(invalid_route_urls)
39 {
40     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("a;3,4"), 0UL);
41     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("120;3,4"), 3UL);
42     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("90000000,2;3,4"), 0UL);
43     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&bla=foo"), 22UL);
44     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&bearings=foo"),
45                       32UL);
46     BOOST_CHECK_EQUAL(
47         testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&continue_straight=foo"), 41UL);
48     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&radiuses=foo"),
49                       32UL);
50     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&approaches=foo"),
51                       34UL);
52     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&hints=foo"),
53                       29UL);
54     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&hints=;;; ;"),
55                       32UL);
56     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?generate_hints=notboolean"),
57                       23UL);
58     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&geometries=foo"),
59                       34UL);
60     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&overview=foo"),
61                       32L);
62     BOOST_CHECK_EQUAL(
63         testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&alternatives=foo"), 36UL);
64     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&alternatives=-1"),
65                       36UL);
66     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(""), 0);
67     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3.4.unsupported"), 7);
68     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4.json?nooptions"), 13);
69     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4..json?nooptions"), 14);
70     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4.0.json?nooptions"), 15);
71     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(std::string{"1,2;3,4"} + '\0' + ".json"),
72                       7);
73     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(std::string{"1,2;3,"} + '\0'), 6);
74     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?annotations=distances"), 28UL);
75     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?annotations="), 20UL);
76     BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?annotations=true,false"), 24UL);
77     BOOST_CHECK_EQUAL(
78         testInvalidOptions<RouteParameters>("1,2;3,4?annotations=&overview=simplified"), 20UL);
79 }
80 
BOOST_AUTO_TEST_CASE(invalid_table_urls)81 BOOST_AUTO_TEST_CASE(invalid_table_urls)
82 {
83     BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?sources=1&bla=foo"), 17UL);
84     BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=1&bla=foo"), 22UL);
85     BOOST_CHECK_EQUAL(
86         testInvalidOptions<TableParameters>("1,2;3,4?sources=1&destinations=1&bla=foo"), 32UL);
87     BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?sources=foo"), 16UL);
88     BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=foo"), 21UL);
89     BOOST_CHECK_EQUAL(
90         testInvalidOptions<TableParameters>("1,2;3,4?sources=all&destinations=all&annotations=bla"),
91         49UL);
92     BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?fallback_coordinate=asdf"),
93                       28UL);
94     BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?fallback_coordinate=10"), 28UL);
95     BOOST_CHECK_EQUAL(
96         testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&scale_factor=-1"), 28UL);
97     BOOST_CHECK_EQUAL(
98         testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&scale_factor=0"), 28UL);
99     BOOST_CHECK_EQUAL(
100         testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=0"),
101         28UL);
102     BOOST_CHECK_EQUAL(
103         testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=-1"),
104         28UL);
105     BOOST_CHECK_EQUAL(
106         testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=0"),
107         28UL);
108     BOOST_CHECK_EQUAL(
109         testInvalidOptions<TableParameters>("1,2;3,4?annotations=durations&fallback_speed=-1"),
110         28UL);
111     // TODO(danpat): this is only testing invalid grammar which isn't capable of checking
112     //               for values that need to reference other things currently.  These
113     //               requests are gramatically correct, but semantically incorrect.
114     //               The table service properly fails these, as it checks IsValid() after
115     //               parsing, which fails when sources/destinations are too large
116     // BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?sources=2"), 7UL);
117     // BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=2"), 7UL);
118 }
119 
BOOST_AUTO_TEST_CASE(valid_route_hint)120 BOOST_AUTO_TEST_CASE(valid_route_hint)
121 {
122     engine::PhantomNode reference_node;
123     reference_node.input_location =
124         util::Coordinate(util::FloatLongitude{7.432251}, util::FloatLatitude{43.745995});
125     engine::Hint reference_hint{reference_node, 0x1337};
126     auto encoded_hint = reference_hint.ToBase64();
127     auto hint = engine::Hint::FromBase64(encoded_hint);
128     BOOST_CHECK_EQUAL(hint.phantom.input_location, reference_hint.phantom.input_location);
129 }
130 
BOOST_AUTO_TEST_CASE(valid_route_urls)131 BOOST_AUTO_TEST_CASE(valid_route_urls)
132 {
133     std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
134                                               {util::FloatLongitude{3}, util::FloatLatitude{4}}};
135 
136     RouteParameters reference_1{};
137     reference_1.coordinates = coords_1;
138     auto result_1 = parseParameters<RouteParameters>("1,2;3,4");
139     BOOST_CHECK(result_1);
140     BOOST_CHECK_EQUAL(reference_1.steps, result_1->steps);
141     BOOST_CHECK_EQUAL(reference_1.alternatives, result_1->alternatives);
142     BOOST_CHECK_EQUAL(reference_1.geometries, result_1->geometries);
143     BOOST_CHECK_EQUAL(reference_1.annotations, result_1->annotations);
144     BOOST_CHECK_EQUAL(reference_1.overview, result_1->overview);
145     BOOST_CHECK_EQUAL(reference_1.continue_straight, result_1->continue_straight);
146     CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
147     CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
148     CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
149     CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
150     CHECK_EQUAL_RANGE(reference_1.hints, result_1->hints);
151 
152     RouteParameters reference_2{};
153     reference_2.alternatives = true;
154     reference_2.number_of_alternatives = 1;
155     reference_2.steps = true;
156     reference_2.annotations = true;
157     reference_2.coordinates = coords_1;
158     auto result_2 =
159         parseParameters<RouteParameters>("1,2;3,4?steps=true&alternatives=true&geometries=polyline&"
160                                          "overview=simplified&annotations=true");
161     BOOST_CHECK(result_2);
162     BOOST_CHECK_EQUAL(reference_2.steps, result_2->steps);
163     BOOST_CHECK_EQUAL(reference_2.alternatives, result_2->alternatives);
164     BOOST_CHECK_EQUAL(reference_2.number_of_alternatives, result_2->number_of_alternatives);
165     BOOST_CHECK_EQUAL(reference_2.geometries, result_2->geometries);
166     BOOST_CHECK_EQUAL(reference_2.annotations, result_2->annotations);
167     BOOST_CHECK_EQUAL(reference_2.overview, result_2->overview);
168     BOOST_CHECK_EQUAL(reference_2.continue_straight, result_2->continue_straight);
169     CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
170     CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
171     CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
172     CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
173     CHECK_EQUAL_RANGE(reference_2.hints, result_2->hints);
174     BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true);
175 
176     RouteParameters reference_3{false,
177                                 false,
178                                 false,
179                                 RouteParameters::GeometriesType::GeoJSON,
180                                 RouteParameters::OverviewType::False,
181                                 true};
182     reference_3.coordinates = coords_1;
183     auto result_3 = api::parseParameters<engine::api::RouteParameters>(
184         "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&continue_"
185         "straight=true");
186     BOOST_CHECK(result_3);
187     BOOST_CHECK_EQUAL(reference_3.steps, result_3->steps);
188     BOOST_CHECK_EQUAL(reference_3.alternatives, result_3->alternatives);
189     BOOST_CHECK_EQUAL(reference_3.number_of_alternatives, result_3->number_of_alternatives);
190     BOOST_CHECK_EQUAL(reference_3.geometries, result_3->geometries);
191     BOOST_CHECK_EQUAL(reference_3.annotations, result_3->annotations);
192     BOOST_CHECK_EQUAL(reference_3.overview, result_3->overview);
193     BOOST_CHECK_EQUAL(reference_3.continue_straight, result_3->continue_straight);
194     CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
195     CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
196     CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches);
197     CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
198     CHECK_EQUAL_RANGE(reference_3.hints, result_3->hints);
199 
200     engine::PhantomNode phantom_1;
201     phantom_1.input_location = coords_1[0];
202     engine::PhantomNode phantom_2;
203     phantom_2.input_location = coords_1[1];
204     std::vector<boost::optional<engine::Hint>> hints_4 = {engine::Hint{phantom_1, 0x1337},
205                                                           engine::Hint{phantom_2, 0x1337}};
206     RouteParameters reference_4{false,
207                                 false,
208                                 false,
209                                 RouteParameters::GeometriesType::Polyline,
210                                 RouteParameters::OverviewType::Simplified,
211                                 boost::optional<bool>{},
212                                 coords_1,
213                                 hints_4,
214                                 std::vector<boost::optional<double>>{},
215                                 std::vector<boost::optional<engine::Bearing>>{}};
216     auto result_4 = parseParameters<RouteParameters>(
217         "1,2;3,4?steps=false&hints=" + hints_4[0]->ToBase64() + ";" + hints_4[1]->ToBase64());
218     BOOST_CHECK(result_4);
219     BOOST_CHECK_EQUAL(reference_4.steps, result_4->steps);
220     BOOST_CHECK_EQUAL(reference_4.alternatives, result_4->alternatives);
221     BOOST_CHECK_EQUAL(reference_4.geometries, result_4->geometries);
222     BOOST_CHECK_EQUAL(reference_4.annotations, result_4->annotations);
223     BOOST_CHECK_EQUAL(reference_4.overview, result_4->overview);
224     BOOST_CHECK_EQUAL(reference_4.continue_straight, result_4->continue_straight);
225     CHECK_EQUAL_RANGE(reference_4.bearings, result_4->bearings);
226     CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
227     CHECK_EQUAL_RANGE(reference_4.approaches, result_4->approaches);
228     CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
229     CHECK_EQUAL_RANGE(reference_4.hints, result_4->hints);
230 
231     std::vector<boost::optional<engine::Bearing>> bearings_4 = {
232         boost::none,
233         engine::Bearing{200, 10},
234         engine::Bearing{100, 5},
235     };
236     RouteParameters reference_5{false,
237                                 false,
238                                 false,
239                                 RouteParameters::GeometriesType::Polyline,
240                                 RouteParameters::OverviewType::Simplified,
241                                 boost::optional<bool>{},
242                                 coords_1,
243                                 std::vector<boost::optional<engine::Hint>>{},
244                                 std::vector<boost::optional<double>>{},
245                                 bearings_4};
246     auto result_5 = parseParameters<RouteParameters>("1,2;3,4?steps=false&bearings=;200,10;100,5");
247     BOOST_CHECK(result_5);
248     BOOST_CHECK_EQUAL(reference_5.steps, result_5->steps);
249     BOOST_CHECK_EQUAL(reference_5.alternatives, result_5->alternatives);
250     BOOST_CHECK_EQUAL(reference_5.geometries, result_5->geometries);
251     BOOST_CHECK_EQUAL(reference_5.annotations, result_5->annotations);
252     BOOST_CHECK_EQUAL(reference_5.overview, result_5->overview);
253     BOOST_CHECK_EQUAL(reference_5.continue_straight, result_5->continue_straight);
254     CHECK_EQUAL_RANGE(reference_5.bearings, result_5->bearings);
255     CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
256     CHECK_EQUAL_RANGE(reference_5.approaches, result_5->approaches);
257     CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
258     CHECK_EQUAL_RANGE(reference_5.hints, result_5->hints);
259 
260     std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{0}, util::FloatLatitude{1}},
261                                               {util::FloatLongitude{2}, util::FloatLatitude{3}},
262                                               {util::FloatLongitude{4}, util::FloatLatitude{5}}};
263 
264     RouteParameters reference_6{};
265     reference_6.coordinates = coords_2;
266     auto result_6 = parseParameters<RouteParameters>("polyline(_ibE?_seK_seK_seK_seK)");
267     BOOST_CHECK(result_6);
268     BOOST_CHECK_EQUAL(reference_6.steps, result_6->steps);
269     BOOST_CHECK_EQUAL(reference_6.alternatives, result_6->alternatives);
270     BOOST_CHECK_EQUAL(reference_6.geometries, result_6->geometries);
271     BOOST_CHECK_EQUAL(reference_6.annotations, result_6->annotations);
272     BOOST_CHECK_EQUAL(reference_6.overview, result_6->overview);
273     BOOST_CHECK_EQUAL(reference_6.continue_straight, result_6->continue_straight);
274     CHECK_EQUAL_RANGE(reference_6.bearings, result_6->bearings);
275     CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
276     CHECK_EQUAL_RANGE(reference_6.approaches, result_6->approaches);
277     CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
278     CHECK_EQUAL_RANGE(reference_6.hints, result_6->hints);
279 
280     auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited");
281     RouteParameters reference_7{};
282     reference_7.coordinates = coords_1;
283     reference_7.radiuses = {boost::none,
284                             boost::make_optional(std::numeric_limits<double>::infinity())};
285     BOOST_CHECK(result_7);
286     BOOST_CHECK_EQUAL(reference_7.steps, result_7->steps);
287     BOOST_CHECK_EQUAL(reference_7.alternatives, result_7->alternatives);
288     BOOST_CHECK_EQUAL(reference_7.geometries, result_7->geometries);
289     BOOST_CHECK_EQUAL(reference_7.annotations, result_7->annotations);
290     BOOST_CHECK_EQUAL(reference_7.overview, result_7->overview);
291     BOOST_CHECK_EQUAL(reference_7.continue_straight, result_7->continue_straight);
292     CHECK_EQUAL_RANGE(reference_7.bearings, result_7->bearings);
293     CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses);
294     CHECK_EQUAL_RANGE(reference_7.approaches, result_7->approaches);
295     CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates);
296     CHECK_EQUAL_RANGE(reference_7.hints, result_7->hints);
297 
298     auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;");
299     RouteParameters reference_8{};
300     reference_8.coordinates = coords_1;
301     reference_8.radiuses = {boost::none, boost::none};
302     BOOST_CHECK(result_8);
303     CHECK_EQUAL_RANGE(reference_8.radiuses, result_8->radiuses);
304 
305     auto result_9 = parseParameters<RouteParameters>("1,2?radiuses=");
306     RouteParameters reference_9{};
307     reference_9.coordinates = coords_1;
308     reference_9.radiuses = {boost::none};
309     BOOST_CHECK(result_9);
310     CHECK_EQUAL_RANGE(reference_9.radiuses, result_9->radiuses);
311 
312     // Some Hint's are empty
313     std::vector<util::Coordinate> coords_3 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
314                                               {util::FloatLongitude{3}, util::FloatLatitude{4}},
315                                               {util::FloatLongitude{5}, util::FloatLatitude{6}},
316                                               {util::FloatLongitude{7}, util::FloatLatitude{8}}};
317 
318     engine::PhantomNode phantom_3;
319     phantom_3.input_location = coords_3[0];
320     engine::PhantomNode phantom_4;
321     phantom_4.input_location = coords_3[2];
322     std::vector<boost::optional<engine::Hint>> hints_10 = {
323         engine::Hint{phantom_3, 0x1337}, boost::none, engine::Hint{phantom_4, 0x1337}, boost::none};
324 
325     RouteParameters reference_10{false,
326                                  false,
327                                  false,
328                                  RouteParameters::GeometriesType::Polyline,
329                                  RouteParameters::OverviewType::Simplified,
330                                  boost::optional<bool>{},
331                                  coords_3,
332                                  hints_10,
333                                  std::vector<boost::optional<double>>{},
334                                  std::vector<boost::optional<engine::Bearing>>{}};
335     auto result_10 = parseParameters<RouteParameters>(
336         "1,2;3,4;5,6;7,8?steps=false&hints=" + hints_10[0]->ToBase64() + ";;" +
337         hints_10[2]->ToBase64() + ";");
338     BOOST_CHECK(result_10);
339     BOOST_CHECK_EQUAL(reference_10.steps, result_10->steps);
340     BOOST_CHECK_EQUAL(reference_10.alternatives, result_10->alternatives);
341     BOOST_CHECK_EQUAL(reference_10.geometries, result_10->geometries);
342     BOOST_CHECK_EQUAL(reference_10.annotations, result_10->annotations);
343     BOOST_CHECK_EQUAL(reference_10.overview, result_10->overview);
344     BOOST_CHECK_EQUAL(reference_10.continue_straight, result_10->continue_straight);
345     CHECK_EQUAL_RANGE(reference_10.bearings, result_10->bearings);
346     CHECK_EQUAL_RANGE(reference_10.radiuses, result_10->radiuses);
347     CHECK_EQUAL_RANGE(reference_10.approaches, result_10->approaches);
348     CHECK_EQUAL_RANGE(reference_10.coordinates, result_10->coordinates);
349     CHECK_EQUAL_RANGE(reference_10.hints, result_10->hints);
350 
351     // Do not generate Hints when they are explicitly disabled
352     auto result_11 = parseParameters<RouteParameters>("1,2;3,4?generate_hints=false");
353     BOOST_CHECK(result_11);
354     BOOST_CHECK_EQUAL(result_11->generate_hints, false);
355 
356     auto result_12 = parseParameters<RouteParameters>("1,2;3,4?generate_hints=true");
357     BOOST_CHECK(result_12);
358     BOOST_CHECK_EQUAL(result_12->generate_hints, true);
359 
360     auto result_13 = parseParameters<RouteParameters>("1,2;3,4");
361     BOOST_CHECK(result_13);
362     BOOST_CHECK_EQUAL(result_13->generate_hints, true);
363 
364     // parse none annotations value correctly
365     RouteParameters reference_14{};
366     reference_14.annotations_type = RouteParameters::AnnotationsType::None;
367     reference_14.coordinates = coords_1;
368     auto result_14 = parseParameters<RouteParameters>("1,2;3,4?geometries=polyline");
369     BOOST_CHECK(result_14);
370     BOOST_CHECK_EQUAL(reference_14.geometries, result_14->geometries);
371     BOOST_CHECK_EQUAL(result_14->annotations_type == RouteParameters::AnnotationsType::None, true);
372     BOOST_CHECK_EQUAL(result_14->annotations, false);
373 
374     // parse single annotations value correctly
375     RouteParameters reference_15{};
376     reference_15.annotations_type = RouteParameters::AnnotationsType::Duration;
377     reference_15.coordinates = coords_1;
378     auto result_15 = parseParameters<RouteParameters>("1,2;3,4?geometries=polyline&"
379                                                       "overview=simplified&annotations=duration");
380     BOOST_CHECK(result_15);
381     BOOST_CHECK_EQUAL(reference_15.geometries, result_15->geometries);
382     BOOST_CHECK_EQUAL(result_15->annotations_type == RouteParameters::AnnotationsType::Duration,
383                       true);
384     BOOST_CHECK_EQUAL(result_15->annotations, true);
385 
386     RouteParameters reference_speed{};
387     reference_speed.annotations_type = RouteParameters::AnnotationsType::Duration;
388     reference_speed.coordinates = coords_1;
389     auto result_speed =
390         parseParameters<RouteParameters>("1,2;3,4?geometries=polyline&"
391                                          "overview=simplified&annotations=duration,distance,speed");
392     BOOST_CHECK(result_speed);
393     BOOST_CHECK_EQUAL(reference_speed.geometries, result_speed->geometries);
394     BOOST_CHECK_EQUAL(reference_speed.overview, result_speed->overview);
395     BOOST_CHECK_EQUAL(result_speed->annotations_type ==
396                           (RouteParameters::AnnotationsType::Duration |
397                            RouteParameters::AnnotationsType::Distance |
398                            RouteParameters::AnnotationsType::Speed),
399                       true);
400     BOOST_CHECK_EQUAL(result_speed->annotations, true);
401 
402     // parse multiple annotations correctly
403     RouteParameters reference_16{};
404     reference_16.annotations_type = RouteParameters::AnnotationsType::Duration |
405                                     RouteParameters::AnnotationsType::Weight |
406                                     RouteParameters::AnnotationsType::Nodes;
407     reference_16.coordinates = coords_1;
408     auto result_16 =
409         parseParameters<RouteParameters>("1,2;3,4?geometries=polyline&"
410                                          "overview=simplified&annotations=duration,weight,nodes");
411     BOOST_CHECK(result_16);
412     BOOST_CHECK_EQUAL(reference_16.geometries, result_16->geometries);
413     BOOST_CHECK_EQUAL(static_cast<bool>(result_16->annotations_type &
414                                         (RouteParameters::AnnotationsType::Weight |
415                                          RouteParameters::AnnotationsType::Duration |
416                                          RouteParameters::AnnotationsType::Nodes)),
417                       true);
418     BOOST_CHECK_EQUAL(result_16->annotations, true);
419 
420     // parse all annotations correctly
421     RouteParameters reference_17{};
422     reference_17.annotations_type = RouteParameters::AnnotationsType::All;
423     reference_17.coordinates = coords_1;
424     auto result_17 = parseParameters<RouteParameters>(
425         "1,2;3,4?overview=simplified&annotations=duration,weight,nodes,datasources,distance");
426     BOOST_CHECK(result_17);
427     BOOST_CHECK_EQUAL(reference_17.geometries, result_17->geometries);
428     BOOST_CHECK_EQUAL(result_2->annotations_type == RouteParameters::AnnotationsType::All, true);
429     BOOST_CHECK_EQUAL(result_17->annotations, true);
430 
431     std::vector<boost::optional<engine::Approach>> approaches_18 = {
432         boost::none,
433         engine::Approach::CURB,
434         engine::Approach::UNRESTRICTED,
435         engine::Approach::CURB,
436     };
437     RouteParameters reference_18{false,
438                                  false,
439                                  false,
440                                  RouteParameters::GeometriesType::Polyline,
441                                  RouteParameters::OverviewType::Simplified,
442                                  boost::optional<bool>{},
443                                  coords_3,
444                                  std::vector<boost::optional<engine::Hint>>{},
445                                  std::vector<boost::optional<double>>{},
446                                  std::vector<boost::optional<engine::Bearing>>{},
447                                  approaches_18};
448 
449     auto result_18 = parseParameters<RouteParameters>(
450         "1,2;3,4;5,6;7,8?steps=false&approaches=;curb;unrestricted;curb");
451     BOOST_CHECK(result_18);
452     BOOST_CHECK_EQUAL(reference_18.steps, result_18->steps);
453     BOOST_CHECK_EQUAL(reference_18.alternatives, result_18->alternatives);
454     BOOST_CHECK_EQUAL(reference_18.geometries, result_18->geometries);
455     BOOST_CHECK_EQUAL(reference_18.annotations, result_18->annotations);
456     BOOST_CHECK_EQUAL(reference_18.overview, result_18->overview);
457     BOOST_CHECK_EQUAL(reference_18.continue_straight, result_18->continue_straight);
458     CHECK_EQUAL_RANGE(reference_18.bearings, result_18->bearings);
459     CHECK_EQUAL_RANGE(reference_18.radiuses, result_18->radiuses);
460     CHECK_EQUAL_RANGE(reference_18.approaches, result_18->approaches);
461     CHECK_EQUAL_RANGE(reference_18.coordinates, result_18->coordinates);
462     CHECK_EQUAL_RANGE(reference_18.hints, result_18->hints);
463 
464     RouteParameters reference_19{};
465     reference_19.alternatives = true;
466     reference_19.number_of_alternatives = 3;
467     reference_19.coordinates = coords_1;
468     auto result_19 = parseParameters<RouteParameters>("1,2;3,4?alternatives=3");
469     BOOST_CHECK(result_19);
470     BOOST_CHECK_EQUAL(reference_19.steps, result_19->steps);
471     BOOST_CHECK_EQUAL(reference_19.alternatives, result_19->alternatives);
472     BOOST_CHECK_EQUAL(reference_19.number_of_alternatives, result_19->number_of_alternatives);
473     BOOST_CHECK_EQUAL(reference_19.geometries, result_19->geometries);
474     BOOST_CHECK_EQUAL(reference_19.annotations, result_19->annotations);
475     BOOST_CHECK_EQUAL(reference_19.overview, result_19->overview);
476     BOOST_CHECK_EQUAL(reference_19.continue_straight, result_19->continue_straight);
477     CHECK_EQUAL_RANGE(reference_19.bearings, result_19->bearings);
478     CHECK_EQUAL_RANGE(reference_19.radiuses, result_19->radiuses);
479     CHECK_EQUAL_RANGE(reference_19.approaches, result_19->approaches);
480     CHECK_EQUAL_RANGE(reference_19.coordinates, result_19->coordinates);
481     CHECK_EQUAL_RANGE(reference_19.hints, result_19->hints);
482 
483     RouteParameters reference_20{};
484     reference_20.alternatives = false;
485     reference_20.number_of_alternatives = 0;
486     reference_20.coordinates = coords_1;
487     auto result_20 = parseParameters<RouteParameters>("1,2;3,4?alternatives=0");
488     BOOST_CHECK(result_20);
489     BOOST_CHECK_EQUAL(reference_20.steps, result_20->steps);
490     BOOST_CHECK_EQUAL(reference_20.alternatives, result_20->alternatives);
491     BOOST_CHECK_EQUAL(reference_20.number_of_alternatives, result_20->number_of_alternatives);
492     BOOST_CHECK_EQUAL(reference_20.geometries, result_20->geometries);
493     BOOST_CHECK_EQUAL(reference_20.annotations, result_20->annotations);
494     BOOST_CHECK_EQUAL(reference_20.overview, result_20->overview);
495     BOOST_CHECK_EQUAL(reference_20.continue_straight, result_20->continue_straight);
496     CHECK_EQUAL_RANGE(reference_20.bearings, result_20->bearings);
497     CHECK_EQUAL_RANGE(reference_20.radiuses, result_20->radiuses);
498     CHECK_EQUAL_RANGE(reference_20.approaches, result_20->approaches);
499     CHECK_EQUAL_RANGE(reference_20.coordinates, result_20->coordinates);
500     CHECK_EQUAL_RANGE(reference_20.hints, result_20->hints);
501 
502     // exclude flags
503     RouteParameters reference_21{};
504     reference_21.exclude = {"ferry", "motorway"};
505     reference_21.coordinates = coords_1;
506     auto result_21 = parseParameters<RouteParameters>("1,2;3,4?exclude=ferry,motorway");
507     BOOST_CHECK(result_21);
508     BOOST_CHECK_EQUAL(reference_21.steps, result_21->steps);
509     BOOST_CHECK_EQUAL(reference_21.alternatives, result_21->alternatives);
510     BOOST_CHECK_EQUAL(reference_21.number_of_alternatives, result_21->number_of_alternatives);
511     BOOST_CHECK_EQUAL(reference_21.geometries, result_21->geometries);
512     BOOST_CHECK_EQUAL(reference_21.annotations, result_21->annotations);
513     BOOST_CHECK_EQUAL(reference_21.overview, result_21->overview);
514     BOOST_CHECK_EQUAL(reference_21.continue_straight, result_21->continue_straight);
515     CHECK_EQUAL_RANGE(reference_21.bearings, result_21->bearings);
516     CHECK_EQUAL_RANGE(reference_21.radiuses, result_21->radiuses);
517     CHECK_EQUAL_RANGE(reference_21.approaches, result_21->approaches);
518     CHECK_EQUAL_RANGE(reference_21.coordinates, result_21->coordinates);
519     CHECK_EQUAL_RANGE(reference_21.hints, result_21->hints);
520     CHECK_EQUAL_RANGE(reference_21.exclude, result_21->exclude);
521 }
522 
BOOST_AUTO_TEST_CASE(valid_table_urls)523 BOOST_AUTO_TEST_CASE(valid_table_urls)
524 {
525     std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
526                                               {util::FloatLongitude{3}, util::FloatLatitude{4}}};
527 
528     TableParameters reference_1{};
529     reference_1.coordinates = coords_1;
530     auto result_1 = parseParameters<TableParameters>("1,2;3,4");
531     BOOST_CHECK(result_1);
532     CHECK_EQUAL_RANGE(reference_1.sources, result_1->sources);
533     CHECK_EQUAL_RANGE(reference_1.destinations, result_1->destinations);
534     CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
535     CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
536     CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
537     CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
538 
539     std::vector<std::size_t> sources_2 = {1, 2, 3};
540     std::vector<std::size_t> destinations_2 = {4, 5};
541     TableParameters reference_2{sources_2, destinations_2};
542     reference_2.coordinates = coords_1;
543     auto result_2 = parseParameters<TableParameters>("1,2;3,4?sources=1;2;3&destinations=4;5");
544     BOOST_CHECK(result_2);
545     CHECK_EQUAL_RANGE(reference_2.sources, result_2->sources);
546     CHECK_EQUAL_RANGE(reference_2.destinations, result_2->destinations);
547     CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
548     CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
549     CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
550     CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
551 
552     auto result_3 = parseParameters<TableParameters>("1,2;3,4?sources=all&destinations=all");
553     BOOST_CHECK(result_3);
554     CHECK_EQUAL_RANGE(reference_1.sources, result_3->sources);
555     CHECK_EQUAL_RANGE(reference_1.destinations, result_3->destinations);
556     CHECK_EQUAL_RANGE(reference_1.bearings, result_3->bearings);
557     CHECK_EQUAL_RANGE(reference_1.radiuses, result_3->radiuses);
558     CHECK_EQUAL_RANGE(reference_1.approaches, result_3->approaches);
559     CHECK_EQUAL_RANGE(reference_1.coordinates, result_3->coordinates);
560 
561     TableParameters reference_4{};
562     reference_4.coordinates = coords_1;
563     auto result_4 = parseParameters<TableParameters>(
564         "1,2;3,4?sources=all&destinations=all&annotations=duration");
565     BOOST_CHECK(result_4);
566     BOOST_CHECK_EQUAL(result_4->annotations & (TableParameters::AnnotationsType::Distance |
567                                                TableParameters::AnnotationsType::Duration),
568                       true);
569     CHECK_EQUAL_RANGE(reference_4.sources, result_4->sources);
570     CHECK_EQUAL_RANGE(reference_4.destinations, result_4->destinations);
571 
572     TableParameters reference_5{};
573     reference_5.coordinates = coords_1;
574     auto result_5 = parseParameters<TableParameters>(
575         "1,2;3,4?sources=all&destinations=all&annotations=duration");
576     BOOST_CHECK(result_5);
577     BOOST_CHECK_EQUAL(result_5->annotations & TableParameters::AnnotationsType::Duration, true);
578     CHECK_EQUAL_RANGE(reference_5.sources, result_5->sources);
579     CHECK_EQUAL_RANGE(reference_5.destinations, result_5->destinations);
580 
581     TableParameters reference_6{};
582     reference_6.coordinates = coords_1;
583     auto result_6 = parseParameters<TableParameters>(
584         "1,2;3,4?sources=all&destinations=all&annotations=distance");
585     BOOST_CHECK(result_6);
586     BOOST_CHECK_EQUAL(result_6->annotations & TableParameters::AnnotationsType::Distance, true);
587     CHECK_EQUAL_RANGE(reference_6.sources, result_6->sources);
588     CHECK_EQUAL_RANGE(reference_6.destinations, result_6->destinations);
589 
590     TableParameters reference_7{};
591     reference_7.coordinates = coords_1;
592     auto result_7 = parseParameters<TableParameters>("1,2;3,4?annotations=distance");
593     BOOST_CHECK(result_7);
594     BOOST_CHECK_EQUAL(result_7->annotations & TableParameters::AnnotationsType::Distance, true);
595     CHECK_EQUAL_RANGE(reference_7.sources, result_7->sources);
596     CHECK_EQUAL_RANGE(reference_7.destinations, result_7->destinations);
597 
598     TableParameters reference_8{};
599     reference_8.coordinates = coords_1;
600     auto result_8 =
601         parseParameters<TableParameters>("1,2;3,4?annotations=distance&fallback_speed=2.5");
602     BOOST_CHECK(result_8);
603     BOOST_CHECK_EQUAL(result_8->annotations & TableParameters::AnnotationsType::Distance, true);
604     CHECK_EQUAL_RANGE(reference_8.sources, result_8->sources);
605     CHECK_EQUAL_RANGE(reference_8.destinations, result_8->destinations);
606 
607     TableParameters reference_9{};
608     reference_9.coordinates = coords_1;
609     auto result_9 = parseParameters<TableParameters>(
610         "1,2;3,4?annotations=distance&fallback_speed=2.5&fallback_coordinate=input");
611     BOOST_CHECK(result_9);
612     BOOST_CHECK_EQUAL(result_9->annotations & TableParameters::AnnotationsType::Distance, true);
613     CHECK_EQUAL_RANGE(reference_9.sources, result_9->sources);
614     CHECK_EQUAL_RANGE(reference_9.destinations, result_9->destinations);
615 
616     TableParameters reference_10{};
617     reference_10.coordinates = coords_1;
618     auto result_10 = parseParameters<TableParameters>(
619         "1,2;3,4?annotations=distance&fallback_speed=20&fallback_coordinate=snapped");
620     BOOST_CHECK(result_10);
621     BOOST_CHECK_EQUAL(result_10->annotations & TableParameters::AnnotationsType::Distance, true);
622     CHECK_EQUAL_RANGE(reference_10.sources, result_10->sources);
623     CHECK_EQUAL_RANGE(reference_10.destinations, result_10->destinations);
624 
625     auto result_11 = parseParameters<TableParameters>("1,2;3,4?sources=all&destinations=all&"
626                                                       "annotations=duration&fallback_speed=1&"
627                                                       "fallback_coordinate=snapped&scale_factor=2");
628     BOOST_CHECK(result_11);
629     CHECK_EQUAL_RANGE(reference_1.sources, result_11->sources);
630     CHECK_EQUAL_RANGE(reference_1.destinations, result_11->destinations);
631     CHECK_EQUAL_RANGE(reference_1.bearings, result_11->bearings);
632     CHECK_EQUAL_RANGE(reference_1.radiuses, result_11->radiuses);
633     CHECK_EQUAL_RANGE(reference_1.approaches, result_11->approaches);
634     CHECK_EQUAL_RANGE(reference_1.coordinates, result_11->coordinates);
635 }
636 
BOOST_AUTO_TEST_CASE(valid_match_urls)637 BOOST_AUTO_TEST_CASE(valid_match_urls)
638 {
639     std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
640                                               {util::FloatLongitude{3}, util::FloatLatitude{4}}};
641 
642     MatchParameters reference_1{};
643     reference_1.coordinates = coords_1;
644     auto result_1 = parseParameters<MatchParameters>("1,2;3,4");
645     BOOST_CHECK(result_1);
646     CHECK_EQUAL_RANGE(reference_1.timestamps, result_1->timestamps);
647     CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
648     CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
649     CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
650     CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
651 
652     MatchParameters reference_2{};
653     reference_2.coordinates = coords_1;
654     reference_2.timestamps = {5, 6};
655     auto result_2 = parseParameters<MatchParameters>("1,2;3,4?timestamps=5;6");
656     BOOST_CHECK(result_2);
657     CHECK_EQUAL_RANGE(reference_2.timestamps, result_2->timestamps);
658     CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
659     CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
660     CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
661     CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
662 
663     std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
664                                               {util::FloatLongitude{3}, util::FloatLatitude{4}},
665                                               {util::FloatLongitude{5}, util::FloatLatitude{6}}};
666 
667     MatchParameters reference_3{};
668     reference_3.coordinates = coords_2;
669     reference_3.waypoints = {0, 2};
670     auto result_3 = parseParameters<MatchParameters>("1,2;3,4;5,6?waypoints=0;2");
671     BOOST_CHECK(result_3);
672     CHECK_EQUAL_RANGE(reference_3.waypoints, result_3->waypoints);
673     CHECK_EQUAL_RANGE(reference_3.timestamps, result_3->timestamps);
674     CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
675     CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
676     CHECK_EQUAL_RANGE(reference_3.approaches, result_3->approaches);
677     CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
678 }
679 
BOOST_AUTO_TEST_CASE(invalid_match_urls)680 BOOST_AUTO_TEST_CASE(invalid_match_urls)
681 {
682     std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
683                                               {util::FloatLongitude{3}, util::FloatLatitude{4}}};
684 
685     MatchParameters reference_1{};
686     reference_1.coordinates = coords_1;
687     auto result_1 = parseParameters<MatchParameters>("1,2;3,4?radiuses=unlimited;60");
688     BOOST_CHECK(result_1);
689     CHECK_EQUAL_RANGE(reference_1.timestamps, result_1->timestamps);
690     CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
691     BOOST_CHECK(reference_1.radiuses != result_1->radiuses);
692     CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
693     CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
694 
695     std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
696                                               {util::FloatLongitude{3}, util::FloatLatitude{4}}};
697 
698     MatchParameters reference_2{};
699     reference_2.coordinates = coords_2;
700     BOOST_CHECK_EQUAL(testInvalidOptions<MatchParameters>("1,2;3,4?waypoints=0,4"), 19UL);
701     BOOST_CHECK_EQUAL(testInvalidOptions<MatchParameters>("1,2;3,4?waypoints=x;4"), 18UL);
702     BOOST_CHECK_EQUAL(testInvalidOptions<MatchParameters>("1,2;3,4?waypoints=0;3.5"), 21UL);
703 }
704 
BOOST_AUTO_TEST_CASE(valid_nearest_urls)705 BOOST_AUTO_TEST_CASE(valid_nearest_urls)
706 {
707     std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude{1}, util::FloatLatitude{2}}};
708 
709     NearestParameters reference_1{};
710     reference_1.coordinates = coords_1;
711     auto result_1 = parseParameters<NearestParameters>("1,2");
712     BOOST_CHECK(result_1);
713     BOOST_CHECK_EQUAL(reference_1.number_of_results, result_1->number_of_results);
714     CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
715     CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
716     CHECK_EQUAL_RANGE(reference_1.approaches, result_1->approaches);
717     CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
718 
719     NearestParameters reference_2{};
720     reference_2.coordinates = coords_1;
721     reference_2.number_of_results = 42;
722     auto result_2 = parseParameters<NearestParameters>("1,2?number=42");
723     BOOST_CHECK(result_2);
724     BOOST_CHECK_EQUAL(reference_2.number_of_results, result_2->number_of_results);
725     CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
726     CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
727     CHECK_EQUAL_RANGE(reference_2.approaches, result_2->approaches);
728     CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
729 }
730 
BOOST_AUTO_TEST_CASE(invalid_tile_urls)731 BOOST_AUTO_TEST_CASE(invalid_tile_urls)
732 {
733     TileParameters reference_1{1, 2, 3};
734     auto result_1 = parseParameters<TileParameters>("tile(1,2,3).mvt");
735     BOOST_CHECK(result_1);
736     BOOST_CHECK(!result_1->IsValid());
737     BOOST_CHECK_EQUAL(reference_1.x, result_1->x);
738     BOOST_CHECK_EQUAL(reference_1.y, result_1->y);
739     BOOST_CHECK_EQUAL(reference_1.z, result_1->z);
740 }
741 
BOOST_AUTO_TEST_CASE(valid_tile_urls)742 BOOST_AUTO_TEST_CASE(valid_tile_urls)
743 {
744     TileParameters reference_1{1, 2, 12};
745     auto result_1 = parseParameters<TileParameters>("tile(1,2,12).mvt");
746     BOOST_CHECK(result_1->IsValid());
747     BOOST_CHECK(result_1);
748     BOOST_CHECK_EQUAL(reference_1.x, result_1->x);
749     BOOST_CHECK_EQUAL(reference_1.y, result_1->y);
750     BOOST_CHECK_EQUAL(reference_1.z, result_1->z);
751 }
752 
BOOST_AUTO_TEST_CASE(valid_trip_urls)753 BOOST_AUTO_TEST_CASE(valid_trip_urls)
754 {
755     std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude{1}, util::FloatLatitude{2}},
756                                               {util::FloatLongitude{3}, util::FloatLatitude{4}}};
757 
758     TripParameters reference_1{};
759     reference_1.coordinates = coords_1;
760     auto result_1 = parseParameters<TripParameters>("1,2;3,4");
761     BOOST_CHECK(result_1);
762     CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
763     CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
764 
765     TripParameters reference_2{};
766     reference_2.coordinates = coords_1;
767     reference_2.source = TripParameters::SourceType::First;
768     reference_2.destination = TripParameters::DestinationType::Last;
769     auto result_2 = parseParameters<TripParameters>("1,2;3,4?source=first&destination=last");
770     BOOST_CHECK(result_2);
771     CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
772     CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
773 
774     // check supported source/destination/rountrip combinations
775     auto param_fse_r =
776         parseParameters<TripParameters>("1,2;3,4?source=first&destination=last&roundtrip=true");
777     BOOST_CHECK(param_fse_r->IsValid());
778     auto param_fse_nr_ =
779         parseParameters<TripParameters>("1,2;3,4?source=first&destination=last&roundtrip=false");
780     BOOST_CHECK(param_fse_nr_->IsValid());
781     auto param_fs_r = parseParameters<TripParameters>("1,2;3,4?source=first&roundtrip=true");
782     BOOST_CHECK(param_fs_r->IsValid());
783     auto param_fs_nr = parseParameters<TripParameters>("1,2;3,4?source=first&roundtrip=false");
784     BOOST_CHECK(param_fs_nr->IsValid());
785     auto param_fe_r = parseParameters<TripParameters>("1,2;3,4?destination=last&roundtrip=true");
786     BOOST_CHECK(param_fe_r->IsValid());
787     auto param_fe_nr = parseParameters<TripParameters>("1,2;3,4?destination=last&roundtrip=false");
788     BOOST_CHECK(param_fe_nr->IsValid());
789     auto param_r = parseParameters<TripParameters>("1,2;3,4?roundtrip=true");
790     BOOST_CHECK(param_r->IsValid());
791     auto param_nr = parseParameters<TripParameters>("1,2;3,4?roundtrip=false");
792     BOOST_CHECK(param_nr->IsValid());
793 
794     auto param_fail_1 =
795         testInvalidOptions<TripParameters>("1,2;3,4?source=blubb&destination=random");
796     BOOST_CHECK_EQUAL(param_fail_1, 15UL);
797     auto param_fail_2 = testInvalidOptions<TripParameters>("1,2;3,4?source=first&destination=nah");
798     BOOST_CHECK_EQUAL(param_fail_2, 33UL);
799 }
800 
801 BOOST_AUTO_TEST_SUITE_END()
802