Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////////
2 : //
3 : // Project: C++ Test Suite for GDAL/OGR
4 : // Purpose: Test GDALAlgorithm
5 : // Author: Even Rouault <even.rouault at spatialys.com>
6 : //
7 : ///////////////////////////////////////////////////////////////////////////////
8 : // Copyright (c) 2024, Even Rouault <even.rouault at spatialys.com>
9 : /*
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdal_unit_test.h"
14 :
15 : #include "cpl_error.h"
16 : #include "cpl_string.h"
17 : #include "cpl_multiproc.h"
18 : #include "gdalalgorithm.h"
19 : #include "gdal_priv.h"
20 : #include "ogr_spatialref.h"
21 :
22 : #include "test_data.h"
23 :
24 : #include "gtest_include.h"
25 :
26 : #include <algorithm>
27 : #include <limits>
28 :
29 : #if defined(__clang__)
30 : #pragma clang diagnostic push
31 : #pragma clang diagnostic ignored "-Wweak-vtables"
32 : #endif
33 :
34 : namespace test_gdal_algorithm
35 : {
36 :
37 : struct test_gdal_algorithm : public ::testing::Test
38 : {
39 : };
40 :
41 4 : TEST_F(test_gdal_algorithm, GDALAlgorithmArgTypeName)
42 : {
43 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_BOOLEAN), "boolean");
44 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_STRING), "string");
45 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_INTEGER), "integer");
46 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_REAL), "real");
47 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_DATASET), "dataset");
48 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_STRING_LIST), "string_list");
49 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_INTEGER_LIST), "integer_list");
50 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_REAL_LIST), "real_list");
51 1 : EXPECT_STREQ(GDALAlgorithmArgTypeName(GAAT_DATASET_LIST), "dataset_list");
52 1 : }
53 :
54 4 : TEST_F(test_gdal_algorithm, GDALAlgorithmArgDatasetTypeName)
55 : {
56 2 : EXPECT_STREQ(GDALAlgorithmArgDatasetTypeName(GDAL_OF_RASTER).c_str(),
57 : "raster");
58 2 : EXPECT_STREQ(GDALAlgorithmArgDatasetTypeName(GDAL_OF_VECTOR).c_str(),
59 : "vector");
60 2 : EXPECT_STREQ(
61 : GDALAlgorithmArgDatasetTypeName(GDAL_OF_MULTIDIM_RASTER).c_str(),
62 : "multidimensional raster");
63 2 : EXPECT_STREQ(
64 : GDALAlgorithmArgDatasetTypeName(GDAL_OF_RASTER | GDAL_OF_VECTOR)
65 : .c_str(),
66 : "raster or vector");
67 2 : EXPECT_STREQ(GDALAlgorithmArgDatasetTypeName(GDAL_OF_RASTER |
68 : GDAL_OF_MULTIDIM_RASTER)
69 : .c_str(),
70 : "raster or multidimensional raster");
71 2 : EXPECT_STREQ(GDALAlgorithmArgDatasetTypeName(
72 : GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER)
73 : .c_str(),
74 : "raster, vector or multidimensional raster");
75 2 : EXPECT_STREQ(GDALAlgorithmArgDatasetTypeName(GDAL_OF_VECTOR |
76 : GDAL_OF_MULTIDIM_RASTER)
77 : .c_str(),
78 : "vector or multidimensional raster");
79 1 : }
80 :
81 4 : TEST_F(test_gdal_algorithm, GDALAlgorithmArgDecl_SetMinCount)
82 : {
83 : {
84 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
85 1 : CPLErrorReset();
86 1 : EXPECT_EQ(GDALAlgorithmArgDecl("", 0, "", GAAT_BOOLEAN)
87 : .SetMinCount(2)
88 : .GetMinCount(),
89 : 0);
90 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
91 : }
92 1 : EXPECT_EQ(GDALAlgorithmArgDecl("", 0, "", GAAT_STRING_LIST)
93 : .SetMinCount(2)
94 : .GetMinCount(),
95 : 2);
96 1 : }
97 :
98 4 : TEST_F(test_gdal_algorithm, GDALAlgorithmArgDecl_SetMaxCount)
99 : {
100 : {
101 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
102 1 : CPLErrorReset();
103 1 : EXPECT_EQ(GDALAlgorithmArgDecl("", 0, "", GAAT_BOOLEAN)
104 : .SetMaxCount(2)
105 : .GetMaxCount(),
106 : 1);
107 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
108 : }
109 1 : EXPECT_EQ(GDALAlgorithmArgDecl("", 0, "", GAAT_STRING_LIST)
110 : .SetMaxCount(2)
111 : .GetMaxCount(),
112 : 2);
113 1 : }
114 :
115 : class MyAlgorithmWithDummyRun : public GDALAlgorithm
116 : {
117 : public:
118 211 : MyAlgorithmWithDummyRun(const std::string &name = "test",
119 : const std::string &description = "",
120 : const std::string &url = "https://example.com")
121 211 : : GDALAlgorithm(name, description, url)
122 : {
123 211 : }
124 :
125 1 : bool RunImpl(GDALProgressFunc, void *) override
126 : {
127 1 : return true;
128 : }
129 : };
130 :
131 4 : TEST_F(test_gdal_algorithm, GDALAlgorithmArg_SetDefault)
132 : {
133 :
134 : class MyAlgorithm : public MyAlgorithmWithDummyRun
135 : {
136 : public:
137 1 : MyAlgorithm()
138 1 : {
139 : {
140 : bool v;
141 1 : auto &arg = AddArg("", 0, "", &v);
142 1 : arg.SetDefault(true);
143 1 : EXPECT_TRUE(arg.GetDefault<bool>());
144 :
145 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
146 1 : CPLErrorReset();
147 1 : arg.SetDefault("invalid");
148 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
149 : }
150 :
151 : {
152 : int v;
153 1 : auto &arg = AddArg("", 0, "", &v);
154 1 : arg.SetDefault(5);
155 1 : EXPECT_EQ(arg.GetDefault<int>(), 5);
156 :
157 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
158 1 : CPLErrorReset();
159 1 : arg.SetDefault("invalid");
160 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
161 : }
162 :
163 : {
164 : double v;
165 1 : auto &arg = AddArg("", 0, "", &v);
166 1 : arg.SetDefault(4.5);
167 1 : EXPECT_EQ(arg.GetDefault<double>(), 4.5);
168 :
169 1 : arg.SetDefault(5);
170 1 : EXPECT_EQ(arg.GetDefault<double>(), 5);
171 :
172 1 : arg.SetDefault(2.5f);
173 1 : EXPECT_EQ(arg.GetDefault<double>(), 2.5);
174 :
175 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
176 1 : CPLErrorReset();
177 1 : arg.SetDefault("invalid");
178 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
179 : }
180 :
181 : {
182 2 : std::string v;
183 1 : auto &arg = AddArg("", 0, "", &v);
184 :
185 1 : arg.SetDefault("ab");
186 1 : EXPECT_STREQ(arg.GetDefault<std::string>().c_str(), "ab");
187 :
188 1 : arg.SetDefault(std::string("cd"));
189 1 : EXPECT_STREQ(arg.GetDefault<std::string>().c_str(), "cd");
190 :
191 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
192 1 : CPLErrorReset();
193 1 : arg.SetDefault(0);
194 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
195 : }
196 :
197 : {
198 2 : std::vector<int> v;
199 1 : auto &arg = AddArg("", 0, "", &v);
200 1 : arg.SetDefault(5);
201 2 : std::vector<int> expected{5};
202 1 : EXPECT_EQ(arg.GetDefault<std::vector<int>>(), expected);
203 :
204 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
205 1 : CPLErrorReset();
206 1 : arg.SetDefault("invalid");
207 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
208 : }
209 :
210 : {
211 2 : std::vector<double> v;
212 1 : auto &arg = AddArg("", 0, "", &v);
213 1 : arg.SetDefault(4.5);
214 : {
215 2 : std::vector<double> expected{4.5};
216 1 : EXPECT_EQ(arg.GetDefault<std::vector<double>>(), expected);
217 : }
218 :
219 1 : arg.SetDefault(5);
220 : {
221 2 : std::vector<double> expected{5};
222 1 : EXPECT_EQ(arg.GetDefault<std::vector<double>>(), expected);
223 : }
224 :
225 1 : arg.SetDefault(2.5f);
226 : {
227 2 : std::vector<double> expected{2.5};
228 1 : EXPECT_EQ(arg.GetDefault<std::vector<double>>(), expected);
229 : }
230 :
231 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
232 1 : CPLErrorReset();
233 1 : arg.SetDefault("invalid");
234 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
235 : }
236 :
237 : {
238 2 : std::vector<std::string> v;
239 1 : auto &arg = AddArg("", 0, "", &v);
240 :
241 1 : arg.SetDefault("ab");
242 : {
243 5 : std::vector<std::string> expected{"ab"};
244 1 : EXPECT_EQ(arg.GetDefault<std::vector<std::string>>(),
245 : expected);
246 : }
247 :
248 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
249 1 : CPLErrorReset();
250 1 : arg.SetDefault(0);
251 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
252 : }
253 :
254 : {
255 2 : GDALArgDatasetValue v;
256 1 : auto &arg = AddArg("", 0, "", &v);
257 :
258 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
259 1 : CPLErrorReset();
260 1 : arg.SetDefault(0);
261 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
262 : }
263 :
264 : {
265 2 : std::vector<GDALArgDatasetValue> v;
266 1 : auto &arg = AddArg("", 0, "", &v);
267 :
268 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
269 1 : CPLErrorReset();
270 1 : arg.SetDefault(0);
271 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
272 : }
273 1 : }
274 : };
275 :
276 1 : MyAlgorithm alg;
277 1 : }
278 :
279 4 : TEST_F(test_gdal_algorithm, GDALAlgorithmArg_Set)
280 : {
281 : {
282 1 : bool val = false;
283 : auto arg = GDALAlgorithmArg(
284 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_BOOLEAN), &val);
285 1 : arg.Set(true);
286 1 : EXPECT_EQ(arg.Get<bool>(), true);
287 1 : EXPECT_EQ(val, true);
288 :
289 : {
290 1 : bool val2 = false;
291 : auto arg2 = GDALAlgorithmArg(
292 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_BOOLEAN), &val2);
293 1 : arg2.SetFrom(arg);
294 1 : EXPECT_EQ(arg2.Get<bool>(), true);
295 : }
296 :
297 1 : arg.Set(false);
298 1 : EXPECT_EQ(val, false);
299 :
300 1 : arg.Set(1);
301 1 : EXPECT_EQ(val, true);
302 :
303 1 : arg.Set(0);
304 1 : EXPECT_EQ(val, false);
305 :
306 1 : arg.Set("1");
307 1 : EXPECT_EQ(val, true);
308 :
309 1 : arg.Set("0");
310 1 : EXPECT_EQ(val, false);
311 :
312 1 : arg.Set("yes");
313 1 : EXPECT_EQ(val, true);
314 :
315 1 : arg.Set("no");
316 1 : EXPECT_EQ(val, false);
317 :
318 1 : arg.Set("true");
319 1 : EXPECT_EQ(val, true);
320 :
321 1 : arg.Set("false");
322 1 : EXPECT_EQ(val, false);
323 :
324 1 : arg.Set("on");
325 1 : EXPECT_EQ(val, true);
326 :
327 1 : arg.Set("off");
328 1 : EXPECT_EQ(val, false);
329 :
330 1 : arg = true;
331 1 : EXPECT_EQ(val, true);
332 :
333 1 : arg.Set(false);
334 : {
335 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
336 1 : CPLErrorReset();
337 1 : arg.Set(2);
338 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
339 1 : EXPECT_EQ(val, false);
340 :
341 1 : CPLErrorReset();
342 1 : arg.Set(1.5);
343 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
344 1 : EXPECT_EQ(val, false);
345 :
346 1 : CPLErrorReset();
347 1 : arg.Set("foo");
348 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
349 1 : EXPECT_EQ(val, false);
350 :
351 1 : CPLErrorReset();
352 1 : arg.Set(std::vector<std::string>());
353 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
354 1 : EXPECT_EQ(val, false);
355 :
356 1 : CPLErrorReset();
357 1 : arg.Set(std::vector<int>());
358 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
359 1 : EXPECT_EQ(val, false);
360 :
361 1 : CPLErrorReset();
362 1 : arg.Set(std::vector<double>());
363 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
364 1 : EXPECT_EQ(val, false);
365 :
366 1 : CPLErrorReset();
367 1 : arg.Set(std::vector<GDALArgDatasetValue>());
368 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
369 1 : EXPECT_EQ(val, false);
370 :
371 : auto poDS = std::unique_ptr<GDALDataset>(
372 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
373 2 : "", 1, 1, 1, GDT_Byte, nullptr));
374 1 : CPLErrorReset();
375 1 : arg.Set(std::move(poDS));
376 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
377 1 : EXPECT_EQ(val, false);
378 : }
379 :
380 : {
381 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
382 1 : CPLErrorReset();
383 1 : int val2 = 1;
384 : auto arg2 = GDALAlgorithmArg(
385 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER), &val2);
386 1 : arg2.SetFrom(arg);
387 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
388 1 : EXPECT_EQ(val2, 1);
389 : }
390 : }
391 : {
392 1 : int val = 0;
393 : auto arg = GDALAlgorithmArg(
394 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER), &val);
395 1 : arg.Set(1);
396 1 : EXPECT_EQ(arg.Get<int>(), 1);
397 1 : EXPECT_EQ(val, 1);
398 :
399 1 : int val2 = 0;
400 : auto arg2 = GDALAlgorithmArg(
401 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER), &val2);
402 1 : arg2.SetFrom(arg);
403 1 : EXPECT_EQ(arg2.Get<int>(), 1);
404 :
405 1 : arg.Set("2");
406 1 : EXPECT_EQ(val, 2);
407 :
408 1 : arg.Set(3.0);
409 1 : EXPECT_EQ(val, 3);
410 :
411 1 : arg.Set(std::vector<int>{1});
412 1 : EXPECT_EQ(val, 1);
413 :
414 1 : arg.Set(std::vector<double>{2.0});
415 1 : EXPECT_EQ(val, 2);
416 :
417 2 : arg.Set(std::vector<std::string>{"3"});
418 1 : EXPECT_EQ(val, 3);
419 :
420 1 : arg = 4;
421 1 : EXPECT_EQ(val, 4);
422 :
423 1 : arg.Set(0);
424 : {
425 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
426 1 : CPLErrorReset();
427 :
428 1 : arg.Set(true);
429 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
430 1 : EXPECT_EQ(val, 0);
431 :
432 1 : arg.Set(1.5);
433 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
434 1 : EXPECT_EQ(val, 0);
435 :
436 1 : arg.Set("12345679812346798123456");
437 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
438 1 : EXPECT_EQ(val, 0);
439 :
440 1 : arg.Set("foo");
441 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
442 1 : EXPECT_EQ(val, 0);
443 :
444 2 : arg.Set(std::vector<std::string>{"12345679812346798123456"});
445 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
446 1 : EXPECT_EQ(val, 0);
447 :
448 1 : arg.Set(std::vector<int>{1, 2});
449 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
450 1 : EXPECT_EQ(val, 0);
451 : }
452 : }
453 : {
454 1 : double val = 0;
455 : auto arg = GDALAlgorithmArg(
456 2 : GDALAlgorithmArgDecl("", 0, "", GAAT_REAL).SetDefault(-1), &val);
457 1 : arg.Set(1.5);
458 1 : EXPECT_EQ(arg.Get<double>(), 1.5);
459 1 : EXPECT_EQ(val, 1.5);
460 1 : arg.Set(1);
461 1 : EXPECT_EQ(arg.Get<double>(), 1);
462 :
463 1 : double val2 = 0;
464 : auto arg2 = GDALAlgorithmArg(
465 2 : GDALAlgorithmArgDecl("", 0, "", GAAT_REAL).SetDefault(-1.5), &val2);
466 1 : arg2.SetFrom(arg);
467 1 : EXPECT_EQ(val2, 1);
468 :
469 1 : arg.Set("2.5");
470 1 : EXPECT_EQ(val, 2.5);
471 :
472 1 : arg.Set(std::vector<int>{1});
473 1 : EXPECT_EQ(val, 1);
474 :
475 1 : arg.Set(std::vector<double>{2.5});
476 1 : EXPECT_EQ(val, 2.5);
477 :
478 2 : arg.Set(std::vector<std::string>{"3.5"});
479 1 : EXPECT_EQ(val, 3.5);
480 :
481 1 : arg = 4.5;
482 1 : EXPECT_EQ(val, 4.5);
483 :
484 1 : arg.Set(0);
485 : {
486 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
487 1 : CPLErrorReset();
488 :
489 1 : arg.Set(true);
490 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
491 1 : EXPECT_EQ(val, 0);
492 :
493 1 : arg.Set("foo");
494 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
495 1 : EXPECT_EQ(val, 0);
496 :
497 1 : arg.Set(std::vector<int>{1, 2});
498 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
499 1 : EXPECT_EQ(val, 0);
500 : }
501 : }
502 : {
503 2 : std::string val;
504 : auto arg = GDALAlgorithmArg(
505 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_STRING), &val);
506 1 : arg.Set("foo");
507 1 : EXPECT_STREQ(arg.Get<std::string>().c_str(), "foo");
508 1 : EXPECT_STREQ(val.c_str(), "foo");
509 :
510 2 : std::string val2;
511 : auto arg2 = GDALAlgorithmArg(
512 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_STRING), &val2);
513 1 : arg2.SetFrom(arg);
514 1 : EXPECT_STREQ(arg2.Get<std::string>().c_str(), "foo");
515 :
516 1 : arg.Set(1);
517 1 : EXPECT_STREQ(val.c_str(), "1");
518 :
519 1 : arg.Set(1.5);
520 1 : EXPECT_EQ(CPLAtof(val.c_str()), 1.5);
521 :
522 1 : arg.Set(std::vector<int>{1});
523 1 : EXPECT_STREQ(val.c_str(), "1");
524 :
525 1 : arg.Set(std::vector<double>{1.5});
526 1 : EXPECT_EQ(CPLAtof(val.c_str()), 1.5);
527 :
528 2 : arg.Set(std::vector<std::string>{"bar"});
529 1 : EXPECT_STREQ(val.c_str(), "bar");
530 :
531 1 : arg = "x";
532 1 : EXPECT_STREQ(val.c_str(), "x");
533 :
534 1 : arg = std::string("y");
535 1 : EXPECT_STREQ(val.c_str(), "y");
536 :
537 1 : arg = GDT_Byte;
538 1 : EXPECT_STREQ(val.c_str(), "Byte");
539 :
540 2 : OGRSpatialReference srs;
541 1 : srs.SetFromUserInput("WGS84");
542 1 : arg = srs;
543 1 : EXPECT_EQ(val.find("GEOGCRS["), 0U);
544 :
545 1 : arg.Set("foo");
546 : {
547 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
548 1 : CPLErrorReset();
549 1 : arg.Set(true);
550 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
551 1 : EXPECT_STREQ(val.c_str(), "foo");
552 : }
553 : {
554 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
555 1 : CPLErrorReset();
556 1 : arg.Set(static_cast<GDALDataset *>(nullptr));
557 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
558 1 : EXPECT_STREQ(val.c_str(), "foo");
559 : }
560 : {
561 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
562 1 : CPLErrorReset();
563 3 : arg.Set(std::vector<std::string>{"bar", "foo"});
564 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
565 1 : EXPECT_STREQ(val.c_str(), "foo");
566 : }
567 : {
568 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
569 1 : CPLErrorReset();
570 1 : arg.SetDatasetName("bar");
571 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
572 1 : EXPECT_STREQ(val.c_str(), "foo");
573 : }
574 : {
575 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
576 1 : CPLErrorReset();
577 2 : GDALArgDatasetValue dsValue;
578 1 : arg.SetFrom(dsValue);
579 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
580 1 : EXPECT_STREQ(val.c_str(), "foo");
581 : }
582 : }
583 : {
584 2 : std::string val;
585 2 : auto arg = GDALAlgorithmArg(GDALAlgorithmArgDecl("", 0, "", GAAT_STRING)
586 1 : .SetReadFromFileAtSyntaxAllowed()
587 1 : .SetRemoveSQLCommentsEnabled(),
588 2 : &val);
589 1 : EXPECT_TRUE(arg.Set("foo"));
590 1 : EXPECT_STREQ(val.c_str(), "foo");
591 : }
592 : {
593 2 : std::string osTmpFilename = VSIMemGenerateHiddenFilename("temp.sql");
594 1 : VSILFILE *fpTmp = VSIFOpenL(osTmpFilename.c_str(), "wb");
595 1 : VSIFPrintfL(fpTmp, "\xEF\xBB\xBF"); // UTF-8 BOM
596 1 : VSIFPrintfL(fpTmp, "-- this is a comment\n");
597 1 : VSIFPrintfL(fpTmp, "value");
598 1 : VSIFCloseL(fpTmp);
599 :
600 2 : std::string val;
601 2 : auto arg = GDALAlgorithmArg(GDALAlgorithmArgDecl("", 0, "", GAAT_STRING)
602 1 : .SetReadFromFileAtSyntaxAllowed()
603 1 : .SetRemoveSQLCommentsEnabled(),
604 2 : &val);
605 1 : EXPECT_TRUE(arg.Set(("@" + osTmpFilename).c_str()));
606 1 : EXPECT_STREQ(val.c_str(), "value");
607 1 : VSIUnlink(osTmpFilename.c_str());
608 : }
609 : {
610 2 : std::string val;
611 2 : auto arg = GDALAlgorithmArg(GDALAlgorithmArgDecl("", 0, "", GAAT_STRING)
612 1 : .SetReadFromFileAtSyntaxAllowed(),
613 2 : &val);
614 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
615 1 : EXPECT_FALSE(arg.Set("@i_do_not_exist"));
616 : }
617 : {
618 : auto poMEMDS = std::unique_ptr<GDALDataset>(
619 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
620 2 : "", 1, 1, 1, GDT_Byte, nullptr));
621 2 : GDALArgDatasetValue val;
622 : auto arg = GDALAlgorithmArg(
623 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_DATASET), &val);
624 1 : auto poMEMDSRaw = poMEMDS.get();
625 :
626 1 : arg.Set(poMEMDS.release());
627 1 : EXPECT_EQ(val.GetDatasetRef(), poMEMDSRaw);
628 :
629 1 : poMEMDS.reset(val.BorrowDataset());
630 1 : EXPECT_EQ(poMEMDS.get(), poMEMDSRaw);
631 1 : EXPECT_EQ(val.GetDatasetRef(), nullptr);
632 :
633 1 : EXPECT_TRUE(arg.Set(std::move(poMEMDS)));
634 1 : EXPECT_EQ(val.GetDatasetRef(), poMEMDSRaw);
635 :
636 1 : poMEMDSRaw->ReleaseRef();
637 :
638 1 : arg.SetDatasetName("foo");
639 1 : EXPECT_STREQ(val.GetName().c_str(), "foo");
640 :
641 2 : GDALArgDatasetValue val2;
642 1 : val2.Set("bar");
643 1 : arg.SetFrom(val2);
644 1 : EXPECT_STREQ(val.GetName().c_str(), "bar");
645 :
646 : auto arg2 = GDALAlgorithmArg(
647 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_DATASET), &val2);
648 1 : val2.Set("baz");
649 1 : arg.SetFrom(arg2);
650 1 : EXPECT_STREQ(val.GetName().c_str(), "baz");
651 : }
652 :
653 : {
654 2 : GDALArgDatasetValue val;
655 3 : auto decl = GDALAlgorithmArgDecl("", 0, "", GAAT_DATASET);
656 1 : decl.SetDatasetInputFlags(GADV_NAME);
657 1 : decl.SetDatasetOutputFlags(GADV_OBJECT);
658 2 : auto arg = GDALAlgorithmArg(decl, &val);
659 :
660 : {
661 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
662 1 : CPLErrorReset();
663 1 : arg.Set(static_cast<GDALDataset *>(nullptr));
664 1 : EXPECT_TRUE(strstr(
665 : CPLGetLastErrorMsg(),
666 : "is created by algorithm and cannot be set as an input"));
667 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
668 : }
669 :
670 : {
671 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
672 1 : CPLErrorReset();
673 1 : arg.Set(std::unique_ptr<GDALDataset>(nullptr));
674 1 : EXPECT_TRUE(strstr(
675 : CPLGetLastErrorMsg(),
676 : "is created by algorithm and cannot be set as an input"));
677 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
678 : }
679 :
680 : {
681 2 : GDALArgDatasetValue val2;
682 1 : val2.Set(std::unique_ptr<GDALDataset>(
683 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
684 : "", 1, 1, 1, GDT_Byte, nullptr)));
685 :
686 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
687 1 : CPLErrorReset();
688 1 : arg.SetFrom(val2);
689 1 : EXPECT_TRUE(strstr(
690 : CPLGetLastErrorMsg(),
691 : "is created by algorithm and cannot be set as an input"));
692 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
693 : }
694 : }
695 :
696 : {
697 2 : GDALArgDatasetValue val;
698 3 : auto decl = GDALAlgorithmArgDecl("", 0, "", GAAT_DATASET);
699 1 : decl.SetDatasetInputFlags(0);
700 1 : decl.SetDatasetOutputFlags(0);
701 2 : auto arg = GDALAlgorithmArg(decl, &val);
702 :
703 : {
704 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
705 1 : CPLErrorReset();
706 1 : arg.Set(static_cast<GDALDataset *>(nullptr));
707 1 : EXPECT_TRUE(
708 : strstr(CPLGetLastErrorMsg(),
709 : "A dataset cannot be set as an input argument of"));
710 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
711 : }
712 : }
713 :
714 : {
715 : class MyAlgorithm : public MyAlgorithmWithDummyRun
716 : {
717 : public:
718 1 : MyAlgorithm()
719 1 : {
720 2 : GDALArgDatasetValue val;
721 1 : AddArg("", 0, "", &val).SetDatasetInputFlags(0);
722 :
723 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
724 1 : CPLErrorReset();
725 :
726 1 : val.Set(std::unique_ptr<GDALDataset>(
727 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
728 : "", 1, 1, 1, GDT_Byte, nullptr)));
729 :
730 1 : Run();
731 :
732 1 : EXPECT_TRUE(
733 : strstr(CPLGetLastErrorMsg(),
734 : "A dataset cannot be set as an input argument of"));
735 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
736 1 : }
737 : };
738 :
739 1 : MyAlgorithm alg;
740 : }
741 :
742 : {
743 1 : std::vector<std::string> val;
744 : auto arg = GDALAlgorithmArg(
745 2 : GDALAlgorithmArgDecl("", 0, "", GAAT_STRING_LIST), &val);
746 : {
747 6 : const std::vector<std::string> expected{"foo", "bar"};
748 1 : arg.Set(expected);
749 1 : EXPECT_EQ(arg.Get<std::vector<std::string>>(), expected);
750 1 : EXPECT_EQ(val, expected);
751 :
752 2 : std::vector<std::string> val2;
753 : auto arg2 = GDALAlgorithmArg(
754 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_STRING_LIST), &val2);
755 1 : arg2.SetFrom(arg);
756 1 : EXPECT_EQ(arg2.Get<std::vector<std::string>>(), expected);
757 :
758 : {
759 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
760 1 : CPLErrorReset();
761 1 : arg.Set(true);
762 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
763 1 : EXPECT_EQ(val, expected);
764 : }
765 : }
766 :
767 : {
768 1 : arg.Set(1);
769 5 : const std::vector<std::string> expected{"1"};
770 1 : EXPECT_EQ(val, expected);
771 : }
772 :
773 : {
774 1 : arg.Set("1");
775 5 : const std::vector<std::string> expected{"1"};
776 1 : EXPECT_EQ(val, expected);
777 : }
778 :
779 : {
780 1 : arg.Set(std::vector<int>{1, 2});
781 6 : const std::vector<std::string> expected{"1", "2"};
782 1 : EXPECT_EQ(val, expected);
783 : }
784 :
785 : {
786 1 : arg.Set(3.5);
787 1 : ASSERT_EQ(val.size(), 1);
788 1 : EXPECT_EQ(CPLAtof(val[0].c_str()), 3.5);
789 : }
790 :
791 : {
792 1 : arg.Set(std::vector<double>{1.5, 2.5});
793 1 : ASSERT_EQ(val.size(), 2);
794 1 : EXPECT_EQ(CPLAtof(val[0].c_str()), 1.5);
795 1 : EXPECT_EQ(CPLAtof(val[1].c_str()), 2.5);
796 : }
797 :
798 : {
799 3 : arg = std::vector<std::string>{"foo", "bar"};
800 6 : const std::vector<std::string> expected{"foo", "bar"};
801 1 : EXPECT_EQ(val, expected);
802 : }
803 : }
804 : {
805 2 : std::vector<int> val;
806 : auto arg = GDALAlgorithmArg(
807 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER_LIST), &val);
808 : {
809 2 : const std::vector<int> expected{1, 2};
810 1 : arg.Set(expected);
811 1 : EXPECT_EQ(arg.Get<std::vector<int>>(), expected);
812 1 : EXPECT_EQ(val, expected);
813 :
814 2 : std::vector<int> val2;
815 : auto arg2 = GDALAlgorithmArg(
816 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER_LIST), &val2);
817 1 : arg2.SetFrom(arg);
818 1 : EXPECT_EQ(arg2.Get<std::vector<int>>(), expected);
819 :
820 : {
821 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
822 1 : CPLErrorReset();
823 1 : arg.Set(true);
824 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
825 1 : EXPECT_EQ(val, expected);
826 : }
827 : }
828 :
829 : {
830 1 : arg.Set(3);
831 2 : const std::vector<int> expected{3};
832 1 : EXPECT_EQ(val, expected);
833 : }
834 :
835 : {
836 1 : arg.Set(4.0);
837 2 : const std::vector<int> expected{4};
838 1 : EXPECT_EQ(val, expected);
839 : }
840 :
841 : {
842 1 : arg.Set("5");
843 2 : const std::vector<int> expected{5};
844 1 : EXPECT_EQ(val, expected);
845 : }
846 :
847 : {
848 1 : arg.Set(std::vector<double>{6.0});
849 2 : const std::vector<int> expected{6};
850 1 : EXPECT_EQ(val, expected);
851 : }
852 :
853 : {
854 2 : arg.Set(std::vector<std::string>{"7"});
855 2 : const std::vector<int> expected{7};
856 1 : EXPECT_EQ(val, expected);
857 : }
858 :
859 : {
860 1 : arg = std::vector<int>{4, 5};
861 2 : const std::vector<int> expected{4, 5};
862 1 : EXPECT_EQ(val, expected);
863 : }
864 :
865 : {
866 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
867 1 : CPLErrorReset();
868 :
869 1 : arg.Set(6.5);
870 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
871 : }
872 :
873 : {
874 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
875 1 : CPLErrorReset();
876 :
877 1 : arg.Set("foo");
878 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
879 : }
880 :
881 : {
882 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
883 1 : CPLErrorReset();
884 :
885 1 : arg.Set("12345679812346798123456");
886 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
887 : }
888 :
889 : {
890 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
891 1 : CPLErrorReset();
892 :
893 1 : arg.Set(std::vector<double>{6.5});
894 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
895 : }
896 :
897 : {
898 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
899 1 : CPLErrorReset();
900 :
901 2 : arg.Set(std::vector<std::string>{"foo"});
902 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
903 : }
904 :
905 : {
906 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
907 1 : CPLErrorReset();
908 :
909 2 : arg.Set(std::vector<std::string>{"12345679812346798123456"});
910 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
911 : }
912 : }
913 : {
914 2 : std::vector<double> val;
915 : auto arg = GDALAlgorithmArg(
916 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_REAL_LIST), &val);
917 : {
918 2 : const std::vector<double> expected{1.5, 2.5};
919 1 : arg.Set(expected);
920 1 : EXPECT_EQ(arg.Get<std::vector<double>>(), expected);
921 1 : EXPECT_EQ(val, expected);
922 :
923 2 : std::vector<double> val2;
924 : auto arg2 = GDALAlgorithmArg(
925 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_REAL_LIST), &val2);
926 1 : arg2.SetFrom(arg);
927 1 : EXPECT_EQ(arg2.Get<std::vector<double>>(), expected);
928 :
929 : {
930 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
931 1 : CPLErrorReset();
932 1 : arg.Set(true);
933 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
934 1 : EXPECT_EQ(arg.Get<std::vector<double>>(), expected);
935 : }
936 : }
937 :
938 : {
939 1 : arg.Set(3);
940 2 : const std::vector<double> expected{3.0};
941 1 : EXPECT_EQ(val, expected);
942 : }
943 :
944 : {
945 1 : arg.Set("4.5");
946 2 : const std::vector<double> expected{4.5};
947 1 : EXPECT_EQ(val, expected);
948 : }
949 :
950 : {
951 1 : arg.Set(std::vector<int>{5});
952 2 : const std::vector<double> expected{5.0};
953 1 : EXPECT_EQ(val, expected);
954 : }
955 :
956 : {
957 1 : arg.Set(std::vector<double>{6.5});
958 2 : const std::vector<double> expected{6.5};
959 1 : EXPECT_EQ(val, expected);
960 : }
961 :
962 : {
963 2 : arg.Set(std::vector<std::string>{"7.5"});
964 2 : const std::vector<double> expected{7.5};
965 1 : EXPECT_EQ(val, expected);
966 : }
967 :
968 : {
969 1 : arg = std::vector<double>{4, 5};
970 2 : const std::vector<double> expected{4, 5};
971 1 : EXPECT_EQ(val, expected);
972 : }
973 :
974 : {
975 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
976 1 : CPLErrorReset();
977 :
978 1 : arg.Set("foo");
979 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
980 : }
981 :
982 : {
983 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
984 1 : CPLErrorReset();
985 :
986 2 : arg.Set(std::vector<std::string>{"foo"});
987 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
988 : }
989 : }
990 : {
991 2 : std::vector<GDALArgDatasetValue> val;
992 : auto arg = GDALAlgorithmArg(
993 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_DATASET_LIST), &val);
994 : {
995 2 : std::vector<GDALArgDatasetValue> val2;
996 1 : val2.emplace_back(GDALArgDatasetValue("foo"));
997 1 : val2.emplace_back(GDALArgDatasetValue("bar"));
998 1 : arg.Set(std::move(val2));
999 1 : EXPECT_EQ(arg.Get<std::vector<GDALArgDatasetValue>>().size(), 2U);
1000 1 : EXPECT_EQ(val.size(), 2U);
1001 : }
1002 :
1003 2 : std::vector<GDALArgDatasetValue> val2;
1004 : auto arg2 = GDALAlgorithmArg(
1005 3 : GDALAlgorithmArgDecl("", 0, "", GAAT_DATASET_LIST), &val2);
1006 1 : arg2.SetFrom(arg);
1007 1 : EXPECT_EQ(arg2.Get<std::vector<GDALArgDatasetValue>>().size(), 2U);
1008 :
1009 : {
1010 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1011 1 : CPLErrorReset();
1012 1 : arg.Set(true);
1013 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1014 1 : EXPECT_EQ(arg.Get<std::vector<GDALArgDatasetValue>>().size(), 2U);
1015 : }
1016 : }
1017 : }
1018 :
1019 4 : TEST_F(test_gdal_algorithm, RunValidationActions)
1020 : {
1021 1 : int val = 0;
1022 : auto arg = GDALInConstructionAlgorithmArg(
1023 3 : nullptr, GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER), &val);
1024 3 : arg.AddValidationAction([&arg]() { return arg.Get<int>() == 1; });
1025 1 : EXPECT_TRUE(arg.Set(1));
1026 1 : EXPECT_FALSE(arg.Set(2));
1027 1 : }
1028 :
1029 4 : TEST_F(test_gdal_algorithm, SetIsCRSArg_wrong_type)
1030 : {
1031 1 : int val = 0;
1032 : auto arg = GDALInConstructionAlgorithmArg(
1033 3 : nullptr, GDALAlgorithmArgDecl("", 0, "", GAAT_INTEGER), &val);
1034 : {
1035 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1036 1 : CPLErrorReset();
1037 1 : arg.SetIsCRSArg();
1038 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1039 : }
1040 1 : }
1041 :
1042 4 : TEST_F(test_gdal_algorithm, wrong_long_name_dash)
1043 : {
1044 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1045 : {
1046 : public:
1047 : bool m_flag = false;
1048 :
1049 1 : MyAlgorithm()
1050 1 : {
1051 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1052 1 : CPLErrorReset();
1053 1 : AddArg("-", 0, "", &m_flag);
1054 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1055 1 : }
1056 : };
1057 :
1058 1 : MyAlgorithm alg;
1059 1 : CPL_IGNORE_RET_VAL(alg.Run());
1060 1 : }
1061 :
1062 4 : TEST_F(test_gdal_algorithm, wrong_long_name_contains_equal)
1063 : {
1064 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1065 : {
1066 : public:
1067 : bool m_flag = false;
1068 :
1069 1 : MyAlgorithm()
1070 1 : {
1071 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1072 1 : CPLErrorReset();
1073 1 : AddArg("foo=bar", 0, "", &m_flag);
1074 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1075 1 : }
1076 : };
1077 :
1078 1 : MyAlgorithm alg;
1079 1 : }
1080 :
1081 4 : TEST_F(test_gdal_algorithm, long_name_duplicated)
1082 : {
1083 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1084 : {
1085 : public:
1086 : bool m_flag = false;
1087 :
1088 1 : MyAlgorithm()
1089 1 : {
1090 1 : AddArg("foo", 0, "", &m_flag);
1091 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1092 1 : CPLErrorReset();
1093 1 : AddArg("foo", 0, "", &m_flag);
1094 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1095 1 : }
1096 : };
1097 :
1098 1 : MyAlgorithm alg;
1099 1 : }
1100 :
1101 4 : TEST_F(test_gdal_algorithm, wrong_short_name)
1102 : {
1103 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1104 : {
1105 : public:
1106 : bool m_flag = false;
1107 :
1108 1 : MyAlgorithm()
1109 1 : {
1110 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1111 1 : CPLErrorReset();
1112 1 : AddArg("", '-', "", &m_flag);
1113 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1114 1 : }
1115 : };
1116 :
1117 1 : MyAlgorithm alg;
1118 1 : }
1119 :
1120 4 : TEST_F(test_gdal_algorithm, short_name_duplicated)
1121 : {
1122 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1123 : {
1124 : public:
1125 : bool m_flag = false;
1126 :
1127 1 : MyAlgorithm()
1128 1 : {
1129 1 : AddArg("", 'x', "", &m_flag);
1130 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1131 1 : CPLErrorReset();
1132 1 : AddArg("", 'x', "", &m_flag);
1133 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1134 1 : }
1135 : };
1136 :
1137 1 : MyAlgorithm alg;
1138 1 : }
1139 :
1140 4 : TEST_F(test_gdal_algorithm, GDALInConstructionAlgorithmArg_AddAlias)
1141 : {
1142 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1143 : {
1144 : public:
1145 : bool m_flag = false;
1146 :
1147 1 : MyAlgorithm()
1148 1 : {
1149 1 : AddArg("flag", 'f', "boolean flag", &m_flag).AddAlias("alias");
1150 1 : }
1151 : };
1152 :
1153 2 : MyAlgorithm alg;
1154 1 : alg.GetUsageForCLI(false);
1155 1 : EXPECT_NE(alg.GetArg("flag"), nullptr);
1156 1 : EXPECT_NE(alg.GetArg("--flag"), nullptr);
1157 1 : EXPECT_NE(alg.GetArg("-f"), nullptr);
1158 1 : EXPECT_NE(alg.GetArg("f"), nullptr);
1159 1 : EXPECT_NE(alg.GetArg("alias"), nullptr);
1160 1 : EXPECT_EQ(alg.GetArg("invalid"), nullptr);
1161 1 : EXPECT_EQ(alg.GetArg("-"), nullptr);
1162 :
1163 2 : EXPECT_STREQ(alg["flag"].GetName().c_str(), "flag");
1164 :
1165 1 : alg["flag"] = true;
1166 1 : EXPECT_EQ(alg.m_flag, true);
1167 :
1168 2 : EXPECT_STREQ(const_cast<const MyAlgorithm &>(alg)["flag"].GetName().c_str(),
1169 : "flag");
1170 :
1171 : {
1172 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1173 1 : CPLErrorReset();
1174 2 : EXPECT_STREQ(alg["invalid"].GetName().c_str(), "dummy");
1175 1 : EXPECT_NE(CPLGetLastErrorType(), CE_None);
1176 : }
1177 : {
1178 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1179 1 : CPLErrorReset();
1180 2 : EXPECT_STREQ(
1181 : const_cast<const MyAlgorithm &>(alg)["invalid"].GetName().c_str(),
1182 : "dummy");
1183 1 : EXPECT_NE(CPLGetLastErrorType(), CE_None);
1184 : }
1185 :
1186 : {
1187 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1188 1 : CPLErrorReset();
1189 1 : EXPECT_EQ(alg.GetArg("flig", /* suggestionAllowed = */ true), nullptr);
1190 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
1191 : "Argument 'flig' is unknown. Do you mean 'flag'?");
1192 : }
1193 :
1194 : {
1195 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1196 1 : CPLErrorReset();
1197 1 : EXPECT_EQ(alg.GetArg("flga", /* suggestionAllowed = */ true), nullptr);
1198 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
1199 : "Argument 'flga' is unknown. Do you mean 'flag'?");
1200 : }
1201 1 : }
1202 :
1203 4 : TEST_F(test_gdal_algorithm, GDALInConstructionAlgorithmArg_AddAlias_redundant)
1204 : {
1205 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1206 : {
1207 : public:
1208 : bool m_flag = false;
1209 : bool m_flag2 = false;
1210 :
1211 1 : MyAlgorithm()
1212 1 : {
1213 1 : AddArg("flag", 'F', "boolean flag", &m_flag).AddAlias("alias");
1214 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1215 1 : CPLErrorReset();
1216 1 : AddArg("flag2", '9', "boolean flag2", &m_flag2).AddAlias("alias");
1217 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1218 1 : }
1219 : };
1220 :
1221 2 : MyAlgorithm alg;
1222 1 : EXPECT_NE(alg.GetArg("alias"), nullptr);
1223 1 : }
1224 :
1225 4 : TEST_F(test_gdal_algorithm, GDALInConstructionAlgorithmArg_AddHiddenAlias)
1226 : {
1227 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1228 : {
1229 : public:
1230 : bool m_flag = false;
1231 :
1232 1 : MyAlgorithm()
1233 1 : {
1234 2 : AddArg("flag", 'f', "boolean flag", &m_flag)
1235 1 : .AddHiddenAlias("hidden_alias");
1236 1 : }
1237 : };
1238 :
1239 2 : MyAlgorithm alg;
1240 1 : EXPECT_NE(alg.GetArg("hidden_alias"), nullptr);
1241 1 : }
1242 :
1243 4 : TEST_F(test_gdal_algorithm, GDALInConstructionAlgorithmArg_SetPositional)
1244 : {
1245 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1246 : {
1247 : public:
1248 : int m_val = 0;
1249 :
1250 1 : MyAlgorithm()
1251 1 : {
1252 1 : AddArg("option", 0, "option", &m_val).SetPositional();
1253 1 : }
1254 : };
1255 :
1256 2 : MyAlgorithm alg;
1257 1 : EXPECT_TRUE(alg.GetArg("option")->IsPositional());
1258 1 : }
1259 :
1260 4 : TEST_F(test_gdal_algorithm, GDALArgDatasetValue)
1261 : {
1262 : {
1263 : auto poDS = std::unique_ptr<GDALDataset>(
1264 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
1265 2 : "", 1, 1, 1, GDT_Byte, nullptr));
1266 1 : auto poDSRaw = poDS.get();
1267 2 : GDALArgDatasetValue value(poDS.release());
1268 1 : EXPECT_EQ(value.GetDatasetRef(), poDSRaw);
1269 1 : EXPECT_STREQ(value.GetName().c_str(), poDSRaw->GetDescription());
1270 :
1271 2 : GDALArgDatasetValue value2;
1272 1 : value2 = std::move(value);
1273 1 : EXPECT_STREQ(value2.GetName().c_str(), poDSRaw->GetDescription());
1274 :
1275 1 : poDSRaw->ReleaseRef();
1276 : }
1277 : {
1278 3 : GDALArgDatasetValue value("foo");
1279 1 : EXPECT_STREQ(value.GetName().c_str(), "foo");
1280 :
1281 2 : GDALArgDatasetValue value2;
1282 1 : value2 = std::move(value);
1283 1 : EXPECT_STREQ(value2.GetName().c_str(), "foo");
1284 : }
1285 1 : }
1286 :
1287 4 : TEST_F(test_gdal_algorithm, bool_flag)
1288 : {
1289 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1290 : {
1291 : public:
1292 : bool m_flag = false;
1293 : std::string m_dummy{};
1294 :
1295 14 : MyAlgorithm()
1296 14 : {
1297 14 : AddArg("flag", 'f', "boolean flag", &m_flag);
1298 14 : AddArg("of", 0, "", &m_dummy);
1299 14 : }
1300 : };
1301 :
1302 : {
1303 2 : MyAlgorithm alg;
1304 1 : alg.GetUsageForCLI(true);
1305 1 : alg.GetUsageForCLI(false);
1306 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
1307 1 : EXPECT_STREQ(alg.GetActualAlgorithm().GetName().c_str(), "test");
1308 : }
1309 :
1310 : {
1311 2 : MyAlgorithm alg;
1312 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--flag"}));
1313 1 : EXPECT_TRUE(alg.m_flag);
1314 : }
1315 :
1316 : {
1317 2 : MyAlgorithm alg;
1318 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--flag=true"}));
1319 1 : EXPECT_TRUE(alg.m_flag);
1320 : }
1321 :
1322 : {
1323 2 : MyAlgorithm alg;
1324 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--flag=false"}));
1325 1 : EXPECT_FALSE(alg.m_flag);
1326 : }
1327 :
1328 : {
1329 2 : MyAlgorithm alg;
1330 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1331 1 : CPLErrorReset();
1332 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--flag=invalid"}));
1333 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1334 : }
1335 :
1336 : {
1337 2 : MyAlgorithm alg;
1338 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1339 1 : CPLErrorReset();
1340 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--flag", "--flag"}));
1341 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1342 : }
1343 :
1344 : {
1345 2 : MyAlgorithm alg;
1346 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1347 1 : CPLErrorReset();
1348 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--flig=invalid"}));
1349 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1350 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "test: Option '--flig' is "
1351 : "unknown. Do you mean '--flag'?");
1352 : }
1353 :
1354 : {
1355 2 : MyAlgorithm alg;
1356 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1357 1 : CPLErrorReset();
1358 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"-x", "foo"}));
1359 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1360 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "test: Short name option 'x' is "
1361 : "unknown.");
1362 : }
1363 :
1364 : {
1365 2 : MyAlgorithm alg;
1366 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1367 1 : CPLErrorReset();
1368 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"-of", "foo"}));
1369 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1370 1 : EXPECT_STREQ(
1371 : CPLGetLastErrorMsg(),
1372 : "test: Short name option 'o' is "
1373 : "unknown. Do you mean '--of' (with leading double dash) ?");
1374 : }
1375 :
1376 : {
1377 2 : MyAlgorithm alg;
1378 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1379 1 : CPLErrorReset();
1380 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"-ofx", "foo"}));
1381 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1382 1 : EXPECT_STREQ(
1383 : CPLGetLastErrorMsg(),
1384 : "test: Short name option 'o' is "
1385 : "unknown. Do you mean '--of' (with leading double dash) ?");
1386 : }
1387 :
1388 : {
1389 2 : MyAlgorithm alg;
1390 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1391 1 : CPLErrorReset();
1392 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--invalid"}));
1393 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1394 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
1395 : "test: Option '--invalid' is unknown.");
1396 : }
1397 :
1398 : {
1399 2 : MyAlgorithm alg;
1400 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1401 1 : CPLErrorReset();
1402 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"-"}));
1403 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1404 : }
1405 :
1406 : {
1407 2 : MyAlgorithm alg;
1408 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1409 1 : CPLErrorReset();
1410 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"-x"}));
1411 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1412 : }
1413 :
1414 : {
1415 2 : MyAlgorithm alg;
1416 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
1417 1 : CPLErrorReset();
1418 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"-xy"}));
1419 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1420 : }
1421 1 : }
1422 :
1423 4 : TEST_F(test_gdal_algorithm, int)
1424 : {
1425 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1426 : {
1427 : public:
1428 : int m_val = 0;
1429 :
1430 5 : MyAlgorithm()
1431 5 : {
1432 5 : AddArg("val", 0, "", &m_val);
1433 5 : }
1434 : };
1435 :
1436 : {
1437 2 : MyAlgorithm alg;
1438 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=5"}));
1439 1 : EXPECT_EQ(alg.m_val, 5);
1440 : }
1441 :
1442 : {
1443 2 : MyAlgorithm alg;
1444 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1445 1 : CPLErrorReset();
1446 : // Missing value
1447 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val"}));
1448 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1449 1 : EXPECT_EQ(alg.m_val, 0);
1450 : }
1451 :
1452 : {
1453 2 : MyAlgorithm alg;
1454 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1455 1 : CPLErrorReset();
1456 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=invalid"}));
1457 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1458 1 : EXPECT_EQ(alg.m_val, 0);
1459 : }
1460 :
1461 : {
1462 2 : MyAlgorithm alg;
1463 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1464 1 : CPLErrorReset();
1465 3 : EXPECT_FALSE(
1466 : alg.ParseCommandLineArguments({"--val=12345679812346798123456"}));
1467 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1468 1 : EXPECT_EQ(alg.m_val, 0);
1469 : }
1470 :
1471 : {
1472 2 : MyAlgorithm alg;
1473 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1474 1 : CPLErrorReset();
1475 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=1.5"}));
1476 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1477 1 : EXPECT_EQ(alg.m_val, 0);
1478 : }
1479 1 : }
1480 :
1481 4 : TEST_F(test_gdal_algorithm, int_min_val_included)
1482 : {
1483 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1484 : {
1485 : public:
1486 : int m_val = 0;
1487 :
1488 2 : MyAlgorithm()
1489 2 : {
1490 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMinValueIncluded(0);
1491 2 : const auto [minVal, minValIncluded] = arg.GetMinValue();
1492 2 : EXPECT_EQ(minVal, 0);
1493 2 : EXPECT_TRUE(minValIncluded);
1494 2 : }
1495 : };
1496 :
1497 : {
1498 2 : MyAlgorithm alg;
1499 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=0"}));
1500 1 : EXPECT_EQ(alg.m_val, 0);
1501 : }
1502 :
1503 : {
1504 2 : MyAlgorithm alg;
1505 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1506 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=-1"}));
1507 : }
1508 1 : }
1509 :
1510 4 : TEST_F(test_gdal_algorithm, int_min_val_excluded)
1511 : {
1512 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1513 : {
1514 : public:
1515 : int m_val = 0;
1516 :
1517 2 : MyAlgorithm()
1518 2 : {
1519 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMinValueExcluded(0);
1520 2 : const auto [minVal, minValIncluded] = arg.GetMinValue();
1521 2 : EXPECT_EQ(minVal, 0);
1522 2 : EXPECT_FALSE(minValIncluded);
1523 2 : }
1524 : };
1525 :
1526 : {
1527 2 : MyAlgorithm alg;
1528 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=1"}));
1529 1 : EXPECT_EQ(alg.m_val, 1);
1530 : }
1531 :
1532 : {
1533 2 : MyAlgorithm alg;
1534 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1535 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=0"}));
1536 : }
1537 1 : }
1538 :
1539 4 : TEST_F(test_gdal_algorithm, int_max_val_included)
1540 : {
1541 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1542 : {
1543 : public:
1544 : int m_val = 0;
1545 :
1546 2 : MyAlgorithm()
1547 2 : {
1548 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMaxValueIncluded(5);
1549 2 : const auto [maxVal, maxValIncluded] = arg.GetMaxValue();
1550 2 : EXPECT_EQ(maxVal, 5);
1551 2 : EXPECT_TRUE(maxValIncluded);
1552 2 : }
1553 : };
1554 :
1555 : {
1556 2 : MyAlgorithm alg;
1557 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=5"}));
1558 1 : EXPECT_EQ(alg.m_val, 5);
1559 : }
1560 :
1561 : {
1562 2 : MyAlgorithm alg;
1563 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1564 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=6"}));
1565 : }
1566 1 : }
1567 :
1568 4 : TEST_F(test_gdal_algorithm, int_max_val_excluded)
1569 : {
1570 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1571 : {
1572 : public:
1573 : int m_val = 0;
1574 :
1575 2 : MyAlgorithm()
1576 2 : {
1577 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMaxValueExcluded(5);
1578 2 : const auto [maxVal, maxValIncluded] = arg.GetMaxValue();
1579 2 : EXPECT_EQ(maxVal, 5);
1580 2 : EXPECT_FALSE(maxValIncluded);
1581 2 : }
1582 : };
1583 :
1584 : {
1585 2 : MyAlgorithm alg;
1586 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=4"}));
1587 1 : EXPECT_EQ(alg.m_val, 4);
1588 : }
1589 :
1590 : {
1591 2 : MyAlgorithm alg;
1592 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1593 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=5"}));
1594 : }
1595 1 : }
1596 :
1597 4 : TEST_F(test_gdal_algorithm, double_min_val_included)
1598 : {
1599 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1600 : {
1601 : public:
1602 : double m_val = 0;
1603 :
1604 2 : MyAlgorithm()
1605 2 : {
1606 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMinValueIncluded(0);
1607 2 : const auto [minVal, minValIncluded] = arg.GetMinValue();
1608 2 : EXPECT_EQ(minVal, 0);
1609 2 : EXPECT_TRUE(minValIncluded);
1610 2 : }
1611 : };
1612 :
1613 : {
1614 2 : MyAlgorithm alg;
1615 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=0"}));
1616 1 : EXPECT_EQ(alg.m_val, 0);
1617 : }
1618 :
1619 : {
1620 2 : MyAlgorithm alg;
1621 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1622 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=-0.1"}));
1623 : }
1624 1 : }
1625 :
1626 4 : TEST_F(test_gdal_algorithm, double_min_val_excluded)
1627 : {
1628 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1629 : {
1630 : public:
1631 : double m_val = 0;
1632 :
1633 2 : MyAlgorithm()
1634 2 : {
1635 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMinValueExcluded(0);
1636 2 : const auto [minVal, minValIncluded] = arg.GetMinValue();
1637 2 : EXPECT_EQ(minVal, 0);
1638 2 : EXPECT_FALSE(minValIncluded);
1639 2 : }
1640 : };
1641 :
1642 : {
1643 2 : MyAlgorithm alg;
1644 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=0.1"}));
1645 1 : EXPECT_EQ(alg.m_val, 0.1);
1646 : }
1647 :
1648 : {
1649 2 : MyAlgorithm alg;
1650 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1651 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=0"}));
1652 : }
1653 1 : }
1654 :
1655 4 : TEST_F(test_gdal_algorithm, double_max_val_included)
1656 : {
1657 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1658 : {
1659 : public:
1660 : double m_val = 0;
1661 :
1662 2 : MyAlgorithm()
1663 2 : {
1664 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMaxValueIncluded(5);
1665 2 : const auto [maxVal, maxValIncluded] = arg.GetMaxValue();
1666 2 : EXPECT_EQ(maxVal, 5);
1667 2 : EXPECT_TRUE(maxValIncluded);
1668 2 : }
1669 : };
1670 :
1671 : {
1672 2 : MyAlgorithm alg;
1673 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=5"}));
1674 1 : EXPECT_EQ(alg.m_val, 5);
1675 : }
1676 :
1677 : {
1678 2 : MyAlgorithm alg;
1679 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1680 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=5.1"}));
1681 : }
1682 1 : }
1683 :
1684 4 : TEST_F(test_gdal_algorithm, double_max_val_excluded)
1685 : {
1686 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1687 : {
1688 : public:
1689 : double m_val = 0;
1690 :
1691 2 : MyAlgorithm()
1692 2 : {
1693 2 : auto &arg = AddArg("val", 0, "", &m_val).SetMaxValueExcluded(5);
1694 2 : const auto [maxVal, maxValIncluded] = arg.GetMaxValue();
1695 2 : EXPECT_EQ(maxVal, 5);
1696 2 : EXPECT_FALSE(maxValIncluded);
1697 2 : }
1698 : };
1699 :
1700 : {
1701 2 : MyAlgorithm alg;
1702 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=4.9"}));
1703 1 : EXPECT_EQ(alg.m_val, 4.9);
1704 : }
1705 :
1706 : {
1707 2 : MyAlgorithm alg;
1708 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1709 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=5"}));
1710 : }
1711 1 : }
1712 :
1713 4 : TEST_F(test_gdal_algorithm, string_min_char_count)
1714 : {
1715 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1716 : {
1717 : public:
1718 : std::string m_val{};
1719 :
1720 2 : MyAlgorithm()
1721 2 : {
1722 2 : AddArg("val", 0, "", &m_val).SetMinCharCount(2);
1723 2 : }
1724 : };
1725 :
1726 : {
1727 2 : MyAlgorithm alg;
1728 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=ab"}));
1729 1 : EXPECT_STREQ(alg.m_val.c_str(), "ab");
1730 : }
1731 :
1732 : {
1733 2 : MyAlgorithm alg;
1734 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1735 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=a"}));
1736 : }
1737 1 : }
1738 :
1739 4 : TEST_F(test_gdal_algorithm, string_vector_min_char_count)
1740 : {
1741 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1742 : {
1743 : public:
1744 : std::vector<std::string> m_val{};
1745 :
1746 2 : MyAlgorithm()
1747 2 : {
1748 2 : AddArg("val", 0, "", &m_val).SetMinCharCount(2);
1749 2 : }
1750 : };
1751 :
1752 : {
1753 2 : MyAlgorithm alg;
1754 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=ab"}));
1755 1 : EXPECT_STREQ(alg.m_val[0].c_str(), "ab");
1756 : }
1757 :
1758 : {
1759 2 : MyAlgorithm alg;
1760 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1761 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=a"}));
1762 : }
1763 1 : }
1764 :
1765 4 : TEST_F(test_gdal_algorithm, SetDisplayInJSONUsage)
1766 : {
1767 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1768 : {
1769 : public:
1770 1 : MyAlgorithm()
1771 1 : {
1772 1 : SetDisplayInJSONUsage(false);
1773 1 : }
1774 : };
1775 :
1776 : {
1777 1 : MyAlgorithm alg;
1778 1 : alg.GetUsageForCLI(false);
1779 1 : alg.GetUsageAsJSON();
1780 : }
1781 1 : }
1782 :
1783 4 : TEST_F(test_gdal_algorithm, int_with_default)
1784 : {
1785 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1786 : {
1787 : public:
1788 : int m_val = 0;
1789 :
1790 1 : MyAlgorithm()
1791 1 : {
1792 1 : AddArg("val", 0, "", &m_val).SetDefault(3);
1793 1 : }
1794 : };
1795 :
1796 : {
1797 2 : MyAlgorithm alg;
1798 1 : alg.GetUsageForCLI(false);
1799 1 : alg.GetUsageAsJSON();
1800 1 : EXPECT_TRUE(alg.ValidateArguments());
1801 1 : EXPECT_EQ(alg.m_val, 3);
1802 : }
1803 1 : }
1804 :
1805 4 : TEST_F(test_gdal_algorithm, double)
1806 : {
1807 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1808 : {
1809 : public:
1810 : double m_val = 0;
1811 :
1812 2 : MyAlgorithm()
1813 2 : {
1814 2 : AddArg("val", 0, "", &m_val);
1815 2 : }
1816 : };
1817 :
1818 : {
1819 2 : MyAlgorithm alg;
1820 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=1.5"}));
1821 1 : EXPECT_EQ(alg.m_val, 1.5);
1822 : }
1823 :
1824 : {
1825 2 : MyAlgorithm alg;
1826 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1827 1 : CPLErrorReset();
1828 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=invalid"}));
1829 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1830 1 : EXPECT_EQ(alg.m_val, 0);
1831 : }
1832 1 : }
1833 :
1834 4 : TEST_F(test_gdal_algorithm, double_with_default)
1835 : {
1836 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1837 : {
1838 : public:
1839 : double m_val = 0;
1840 :
1841 1 : MyAlgorithm()
1842 1 : {
1843 1 : AddArg("val", 0, "", &m_val).SetDefault(3.5);
1844 1 : }
1845 : };
1846 :
1847 : {
1848 2 : MyAlgorithm alg;
1849 1 : alg.GetUsageForCLI(false);
1850 1 : alg.GetUsageAsJSON();
1851 1 : EXPECT_TRUE(alg.ValidateArguments());
1852 1 : EXPECT_EQ(alg.m_val, 3.5);
1853 : }
1854 1 : }
1855 :
1856 4 : TEST_F(test_gdal_algorithm, string_with_default)
1857 : {
1858 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1859 : {
1860 : public:
1861 : std::string m_val{};
1862 :
1863 1 : MyAlgorithm()
1864 1 : {
1865 1 : AddArg("val", 0, "", &m_val).SetDefault("foo");
1866 1 : }
1867 : };
1868 :
1869 : {
1870 2 : MyAlgorithm alg;
1871 1 : alg.GetUsageForCLI(false);
1872 1 : alg.GetUsageAsJSON();
1873 1 : EXPECT_TRUE(alg.ValidateArguments());
1874 1 : EXPECT_STREQ(alg.m_val.c_str(), "foo");
1875 : }
1876 1 : }
1877 :
1878 4 : TEST_F(test_gdal_algorithm, dataset)
1879 : {
1880 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1881 : {
1882 : public:
1883 : GDALArgDatasetValue m_val{};
1884 :
1885 5 : MyAlgorithm()
1886 5 : {
1887 5 : AddArg("val", 0, "", &m_val).SetRequired();
1888 5 : }
1889 : };
1890 :
1891 : {
1892 2 : MyAlgorithm alg;
1893 3 : EXPECT_TRUE(alg.ParseCommandLineArguments(
1894 : {"--val=" GCORE_DATA_DIR "byte.tif"}));
1895 1 : EXPECT_NE(alg.m_val.GetDatasetRef(), nullptr);
1896 : }
1897 :
1898 : {
1899 2 : MyAlgorithm alg;
1900 : auto poDS = std::unique_ptr<GDALDataset>(
1901 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
1902 2 : "", 1, 1, 1, GDT_Byte, nullptr));
1903 1 : auto poDSRaw = poDS.get();
1904 1 : alg.GetArg("val")->Set(poDS.release());
1905 1 : EXPECT_EQ(alg.m_val.GetDatasetRef(), poDSRaw);
1906 1 : poDSRaw->ReleaseRef();
1907 : }
1908 :
1909 : {
1910 2 : MyAlgorithm alg;
1911 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1912 1 : CPLErrorReset();
1913 3 : EXPECT_FALSE(
1914 : alg.ParseCommandLineArguments({"--val=i_do_not_exist.tif"}));
1915 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1916 : }
1917 :
1918 : {
1919 2 : MyAlgorithm alg;
1920 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1921 1 : CPLErrorReset();
1922 1 : EXPECT_FALSE(alg.Run());
1923 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1924 : }
1925 :
1926 : {
1927 2 : MyAlgorithm alg;
1928 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1929 1 : CPLErrorReset();
1930 2 : GDALArgDatasetValue value;
1931 1 : alg.GetArg("val")->SetFrom(value);
1932 1 : EXPECT_FALSE(alg.Run());
1933 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
1934 : }
1935 1 : }
1936 :
1937 4 : TEST_F(test_gdal_algorithm, input_update)
1938 : {
1939 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1940 : {
1941 : public:
1942 : GDALArgDatasetValue m_input{};
1943 : GDALArgDatasetValue m_output{};
1944 : bool m_update = false;
1945 :
1946 1 : MyAlgorithm()
1947 1 : {
1948 1 : AddInputDatasetArg(&m_input);
1949 1 : AddUpdateArg(&m_update);
1950 1 : }
1951 : };
1952 :
1953 : {
1954 1 : auto poDriver = GetGDALDriverManager()->GetDriverByName("GPKG");
1955 1 : if (!poDriver)
1956 : {
1957 0 : GTEST_SKIP() << "GPKG support missing";
1958 : }
1959 : else
1960 : {
1961 : std::string osTmpFilename =
1962 1 : VSIMemGenerateHiddenFilename("temp.gpkg");
1963 : auto poDS = std::unique_ptr<GDALDataset>(poDriver->Create(
1964 1 : osTmpFilename.c_str(), 0, 0, 0, GDT_Unknown, nullptr));
1965 1 : poDS->CreateLayer("foo");
1966 1 : poDS.reset();
1967 :
1968 1 : MyAlgorithm alg;
1969 1 : EXPECT_TRUE(!alg.GetUsageAsJSON().empty());
1970 4 : EXPECT_TRUE(
1971 : alg.ParseCommandLineArguments({"--update", osTmpFilename}));
1972 1 : ASSERT_NE(alg.m_input.GetDatasetRef(), nullptr);
1973 1 : EXPECT_EQ(alg.m_input.GetDatasetRef()->GetAccess(), GA_Update);
1974 :
1975 1 : alg.Finalize();
1976 :
1977 1 : VSIUnlink(osTmpFilename.c_str());
1978 : }
1979 : }
1980 : }
1981 :
1982 4 : TEST_F(test_gdal_algorithm, same_input_output_dataset_sqlite)
1983 : {
1984 : class MyAlgorithm : public MyAlgorithmWithDummyRun
1985 : {
1986 : public:
1987 : GDALArgDatasetValue m_input{};
1988 : GDALArgDatasetValue m_output{};
1989 : bool m_update = false;
1990 :
1991 1 : MyAlgorithm()
1992 1 : {
1993 1 : AddInputDatasetArg(&m_input);
1994 1 : AddOutputDatasetArg(&m_output).SetDatasetInputFlags(GADV_NAME |
1995 1 : GADV_OBJECT);
1996 1 : AddUpdateArg(&m_update);
1997 1 : }
1998 : };
1999 :
2000 : {
2001 1 : auto poDriver = GetGDALDriverManager()->GetDriverByName("GPKG");
2002 1 : if (!poDriver)
2003 : {
2004 0 : GTEST_SKIP() << "GPKG support missing";
2005 : }
2006 : else
2007 : {
2008 : std::string osTmpFilename =
2009 1 : VSIMemGenerateHiddenFilename("temp.gpkg");
2010 : auto poDS = std::unique_ptr<GDALDataset>(poDriver->Create(
2011 1 : osTmpFilename.c_str(), 0, 0, 0, GDT_Unknown, nullptr));
2012 1 : poDS->CreateLayer("foo");
2013 1 : poDS.reset();
2014 :
2015 1 : MyAlgorithm alg;
2016 5 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2017 : {"--update", osTmpFilename, osTmpFilename}));
2018 1 : ASSERT_NE(alg.m_input.GetDatasetRef(), nullptr);
2019 1 : EXPECT_NE(alg.m_output.GetDatasetRef(), nullptr);
2020 1 : EXPECT_EQ(alg.m_input.GetDatasetRef(),
2021 : alg.m_output.GetDatasetRef());
2022 1 : EXPECT_EQ(alg.m_input.GetDatasetRef()->GetAccess(), GA_Update);
2023 :
2024 1 : alg.Finalize();
2025 :
2026 1 : VSIUnlink(osTmpFilename.c_str());
2027 : }
2028 : }
2029 : }
2030 :
2031 4 : TEST_F(test_gdal_algorithm, output_dataset_created_by_alg)
2032 : {
2033 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2034 : {
2035 : public:
2036 : GDALArgDatasetValue m_output{};
2037 :
2038 2 : MyAlgorithm()
2039 2 : {
2040 2 : AddOutputDatasetArg(&m_output)
2041 2 : .SetDatasetInputFlags(GADV_NAME)
2042 2 : .SetDatasetOutputFlags(GADV_OBJECT);
2043 2 : }
2044 : };
2045 :
2046 : {
2047 1 : MyAlgorithm alg;
2048 1 : alg.GetUsageForCLI(false);
2049 : }
2050 :
2051 : {
2052 2 : MyAlgorithm alg;
2053 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--output=-"}));
2054 1 : EXPECT_STREQ(alg.m_output.GetName().c_str(), "/vsistdout/");
2055 : }
2056 1 : }
2057 :
2058 4 : TEST_F(test_gdal_algorithm, string_choices)
2059 : {
2060 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2061 : {
2062 : public:
2063 : std::string m_val{};
2064 :
2065 4 : MyAlgorithm()
2066 4 : {
2067 8 : AddArg("val", 0, "", &m_val)
2068 4 : .SetChoices("foo", "bar")
2069 4 : .SetHiddenChoices("baz");
2070 4 : }
2071 : };
2072 :
2073 : {
2074 2 : MyAlgorithm alg;
2075 1 : alg.GetUsageForCLI(false);
2076 :
2077 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=foo"}));
2078 1 : EXPECT_STREQ(alg.m_val.c_str(), "foo");
2079 : }
2080 :
2081 : {
2082 2 : MyAlgorithm alg;
2083 1 : alg.GetUsageForCLI(false);
2084 :
2085 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=FOO"}));
2086 1 : EXPECT_STREQ(alg.m_val.c_str(), "foo");
2087 : }
2088 :
2089 : {
2090 2 : MyAlgorithm alg;
2091 1 : alg.GetUsageForCLI(false);
2092 :
2093 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=baz"}));
2094 1 : EXPECT_STREQ(alg.m_val.c_str(), "baz");
2095 : }
2096 :
2097 : {
2098 2 : MyAlgorithm alg;
2099 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2100 1 : CPLErrorReset();
2101 1 : EXPECT_FALSE(alg.GetArg("val")->Set("invalid"));
2102 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2103 : }
2104 1 : }
2105 :
2106 4 : TEST_F(test_gdal_algorithm, vector_int)
2107 : {
2108 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2109 : {
2110 : public:
2111 : std::vector<int> m_val{};
2112 :
2113 6 : MyAlgorithm()
2114 6 : {
2115 6 : AddArg("val", 0, "", &m_val);
2116 6 : }
2117 : };
2118 :
2119 : {
2120 2 : MyAlgorithm alg;
2121 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=5,6"}));
2122 2 : auto expected = std::vector<int>{5, 6};
2123 1 : EXPECT_EQ(alg.m_val, expected);
2124 : }
2125 :
2126 : {
2127 2 : MyAlgorithm alg;
2128 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2129 1 : CPLErrorReset();
2130 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=1,foo"}));
2131 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2132 1 : EXPECT_TRUE(alg.m_val.empty());
2133 : }
2134 :
2135 : {
2136 2 : MyAlgorithm alg;
2137 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2138 1 : CPLErrorReset();
2139 3 : EXPECT_FALSE(
2140 : alg.ParseCommandLineArguments({"--val=1,12345679812346798123456"}));
2141 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2142 1 : EXPECT_TRUE(alg.m_val.empty());
2143 : }
2144 :
2145 : {
2146 2 : MyAlgorithm alg;
2147 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2148 1 : CPLErrorReset();
2149 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=1", "--val=foo"}));
2150 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2151 1 : EXPECT_TRUE(alg.m_val.empty());
2152 : }
2153 :
2154 : {
2155 2 : MyAlgorithm alg;
2156 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2157 1 : CPLErrorReset();
2158 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=3, ,4"}));
2159 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2160 1 : EXPECT_TRUE(alg.m_val.empty());
2161 : }
2162 :
2163 : {
2164 2 : MyAlgorithm alg;
2165 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2166 1 : CPLErrorReset();
2167 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=3,,4"}));
2168 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2169 1 : EXPECT_TRUE(alg.m_val.empty());
2170 : }
2171 1 : }
2172 :
2173 4 : TEST_F(test_gdal_algorithm, vector_int_validation_fails)
2174 : {
2175 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2176 : {
2177 : public:
2178 : std::vector<int> m_val{};
2179 :
2180 1 : MyAlgorithm()
2181 1 : {
2182 2 : AddArg("val", 0, "", &m_val)
2183 : .AddValidationAction(
2184 1 : []()
2185 : {
2186 1 : CPLError(CE_Failure, CPLE_AppDefined,
2187 : "validation failed");
2188 1 : return false;
2189 1 : });
2190 1 : }
2191 : };
2192 :
2193 : {
2194 2 : MyAlgorithm alg;
2195 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2196 1 : CPLErrorReset();
2197 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=5", "--val=6"}));
2198 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "validation failed");
2199 : }
2200 1 : }
2201 :
2202 4 : TEST_F(test_gdal_algorithm, vector_double)
2203 : {
2204 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2205 : {
2206 : public:
2207 : std::vector<double> m_val{};
2208 :
2209 5 : MyAlgorithm()
2210 5 : {
2211 5 : AddArg("val", 0, "", &m_val);
2212 5 : }
2213 : };
2214 :
2215 : {
2216 2 : MyAlgorithm alg;
2217 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=1.5,2.5"}));
2218 2 : auto expected = std::vector<double>{1.5, 2.5};
2219 1 : EXPECT_EQ(alg.m_val, expected);
2220 : }
2221 :
2222 : {
2223 2 : MyAlgorithm alg;
2224 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2225 1 : CPLErrorReset();
2226 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=1,foo"}));
2227 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2228 1 : EXPECT_TRUE(alg.m_val.empty());
2229 : }
2230 :
2231 : {
2232 2 : MyAlgorithm alg;
2233 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2234 1 : CPLErrorReset();
2235 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=3, ,4"}));
2236 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2237 1 : EXPECT_TRUE(alg.m_val.empty());
2238 : }
2239 :
2240 : {
2241 2 : MyAlgorithm alg;
2242 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2243 1 : CPLErrorReset();
2244 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=3,,4"}));
2245 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2246 1 : EXPECT_TRUE(alg.m_val.empty());
2247 : }
2248 :
2249 : {
2250 2 : MyAlgorithm alg;
2251 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2252 1 : CPLErrorReset();
2253 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=1", "--val=foo"}));
2254 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2255 1 : EXPECT_TRUE(alg.m_val.empty());
2256 : }
2257 1 : }
2258 :
2259 4 : TEST_F(test_gdal_algorithm, vector_double_validation_fails)
2260 : {
2261 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2262 : {
2263 : public:
2264 : std::vector<double> m_val{};
2265 :
2266 1 : MyAlgorithm()
2267 1 : {
2268 2 : AddArg("val", 0, "", &m_val)
2269 : .AddValidationAction(
2270 1 : []()
2271 : {
2272 1 : CPLError(CE_Failure, CPLE_AppDefined,
2273 : "validation failed");
2274 1 : return false;
2275 1 : });
2276 1 : }
2277 : };
2278 :
2279 : {
2280 2 : MyAlgorithm alg;
2281 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2282 1 : CPLErrorReset();
2283 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=5", "--val=6"}));
2284 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "validation failed");
2285 : }
2286 1 : }
2287 :
2288 4 : TEST_F(test_gdal_algorithm, vector_string)
2289 : {
2290 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2291 : {
2292 : public:
2293 : std::vector<std::string> m_val{};
2294 :
2295 1 : MyAlgorithm()
2296 1 : {
2297 1 : AddArg("val", 0, "", &m_val);
2298 1 : }
2299 : };
2300 :
2301 : {
2302 2 : MyAlgorithm alg;
2303 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=foo,bar"}));
2304 6 : auto expected = std::vector<std::string>{"foo", "bar"};
2305 1 : EXPECT_EQ(alg.m_val, expected);
2306 : }
2307 1 : }
2308 :
2309 4 : TEST_F(test_gdal_algorithm, vector_string_validation_fails)
2310 : {
2311 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2312 : {
2313 : public:
2314 : std::vector<std::string> m_val{};
2315 :
2316 1 : MyAlgorithm()
2317 1 : {
2318 2 : AddArg("val", 0, "", &m_val)
2319 : .AddValidationAction(
2320 1 : []()
2321 : {
2322 1 : CPLError(CE_Failure, CPLE_AppDefined,
2323 : "validation failed");
2324 1 : return false;
2325 1 : });
2326 1 : }
2327 : };
2328 :
2329 : {
2330 2 : MyAlgorithm alg;
2331 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2332 1 : CPLErrorReset();
2333 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=foo", "--val=bar"}));
2334 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "validation failed");
2335 : }
2336 1 : }
2337 :
2338 4 : TEST_F(test_gdal_algorithm, vector_string_choices)
2339 : {
2340 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2341 : {
2342 : public:
2343 : std::vector<std::string> m_val{};
2344 :
2345 4 : MyAlgorithm()
2346 4 : {
2347 4 : AddArg("val", 0, "", &m_val).SetChoices("foo", "bar");
2348 4 : }
2349 : };
2350 :
2351 : {
2352 2 : MyAlgorithm alg;
2353 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=foo,bar"}));
2354 6 : auto expected = std::vector<std::string>{"foo", "bar"};
2355 1 : EXPECT_EQ(alg.m_val, expected);
2356 : }
2357 :
2358 : {
2359 2 : MyAlgorithm alg;
2360 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--val=FOO,BAR"}));
2361 6 : auto expected = std::vector<std::string>{"foo", "bar"};
2362 1 : EXPECT_EQ(alg.m_val, expected);
2363 : }
2364 :
2365 : {
2366 2 : MyAlgorithm alg;
2367 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2368 1 : CPLErrorReset();
2369 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=foo,invalid"}));
2370 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2371 : }
2372 :
2373 : {
2374 2 : MyAlgorithm alg;
2375 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2376 1 : CPLErrorReset();
2377 4 : EXPECT_FALSE(
2378 : alg.ParseCommandLineArguments({"--val=foo", "--val=invalid"}));
2379 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2380 : }
2381 1 : }
2382 :
2383 4 : TEST_F(test_gdal_algorithm, vector_dataset)
2384 : {
2385 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2386 : {
2387 : public:
2388 : std::vector<GDALArgDatasetValue> m_val{};
2389 :
2390 3 : MyAlgorithm()
2391 3 : {
2392 3 : AddArg("val", 0, "", &m_val);
2393 3 : }
2394 : };
2395 :
2396 : {
2397 1 : MyAlgorithm alg;
2398 3 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2399 : {"--val=" GCORE_DATA_DIR "byte.tif"}));
2400 1 : ASSERT_EQ(alg.m_val.size(), 1U);
2401 1 : EXPECT_NE(alg.m_val[0].GetDatasetRef(), nullptr);
2402 : }
2403 :
2404 : {
2405 1 : MyAlgorithm alg;
2406 1 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2407 1 : CPLErrorReset();
2408 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=non_existing.tif"}));
2409 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2410 1 : ASSERT_EQ(alg.m_val.size(), 1U);
2411 1 : EXPECT_EQ(alg.m_val[0].GetDatasetRef(), nullptr);
2412 : }
2413 :
2414 : {
2415 2 : MyAlgorithm alg;
2416 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2417 1 : CPLErrorReset();
2418 1 : alg.GetArg("val")->Set(std::vector<GDALArgDatasetValue>(1));
2419 1 : EXPECT_FALSE(alg.Run());
2420 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2421 : }
2422 : }
2423 :
2424 4 : TEST_F(test_gdal_algorithm, vector_dataset_validation_fails)
2425 : {
2426 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2427 : {
2428 : public:
2429 : std::vector<GDALArgDatasetValue> m_val{};
2430 :
2431 1 : MyAlgorithm()
2432 1 : {
2433 2 : AddArg("val", 0, "", &m_val)
2434 : .AddValidationAction(
2435 1 : []()
2436 : {
2437 1 : CPLError(CE_Failure, CPLE_AppDefined,
2438 : "validation failed");
2439 1 : return false;
2440 1 : });
2441 1 : }
2442 : };
2443 :
2444 : {
2445 2 : MyAlgorithm alg;
2446 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2447 1 : CPLErrorReset();
2448 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--val=foo", "--val=bar"}));
2449 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "validation failed");
2450 : }
2451 1 : }
2452 :
2453 4 : TEST_F(test_gdal_algorithm, vector_input)
2454 : {
2455 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2456 : {
2457 : public:
2458 : std::vector<GDALArgDatasetValue> m_input{};
2459 : std::vector<std::string> m_oo{};
2460 : std::vector<std::string> m_if{};
2461 : bool m_update = false;
2462 :
2463 1 : MyAlgorithm()
2464 1 : {
2465 1 : AddInputDatasetArg(&m_input);
2466 1 : AddOpenOptionsArg(&m_oo);
2467 1 : AddInputFormatsArg(&m_if);
2468 1 : AddUpdateArg(&m_update);
2469 1 : }
2470 : };
2471 :
2472 : {
2473 1 : auto poDriver = GetGDALDriverManager()->GetDriverByName("GPKG");
2474 1 : if (!poDriver)
2475 : {
2476 0 : GTEST_SKIP() << "GPKG support missing";
2477 : }
2478 : else
2479 : {
2480 : std::string osTmpFilename =
2481 1 : VSIMemGenerateHiddenFilename("temp.gpkg");
2482 : auto poDS = std::unique_ptr<GDALDataset>(poDriver->Create(
2483 1 : osTmpFilename.c_str(), 0, 0, 0, GDT_Unknown, nullptr));
2484 1 : poDS->CreateLayer("foo");
2485 1 : poDS.reset();
2486 :
2487 1 : MyAlgorithm alg;
2488 6 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2489 : {"--update", "--oo=LIST_ALL_TABLES=YES", "--if=GPKG",
2490 : osTmpFilename}));
2491 1 : ASSERT_EQ(alg.m_input.size(), 1U);
2492 1 : ASSERT_NE(alg.m_input[0].GetDatasetRef(), nullptr);
2493 1 : EXPECT_EQ(alg.m_input[0].GetDatasetRef()->GetAccess(), GA_Update);
2494 :
2495 1 : alg.Finalize();
2496 :
2497 1 : VSIUnlink(osTmpFilename.c_str());
2498 : }
2499 : }
2500 : }
2501 :
2502 4 : TEST_F(test_gdal_algorithm, several_values)
2503 : {
2504 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2505 : {
2506 : public:
2507 : std::vector<std::string> m_co{};
2508 :
2509 5 : MyAlgorithm()
2510 5 : {
2511 5 : AddArg("co", 0, "creation options", &m_co);
2512 5 : }
2513 : };
2514 :
2515 : {
2516 2 : MyAlgorithm alg;
2517 1 : alg.GetUsageForCLI(false);
2518 :
2519 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
2520 : }
2521 :
2522 : {
2523 2 : MyAlgorithm alg;
2524 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co", "FOO=BAR"}));
2525 4 : EXPECT_EQ(alg.m_co, std::vector<std::string>{"FOO=BAR"});
2526 : }
2527 :
2528 : {
2529 2 : MyAlgorithm alg;
2530 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co=FOO=BAR"}));
2531 4 : EXPECT_EQ(alg.m_co, std::vector<std::string>{"FOO=BAR"});
2532 : }
2533 :
2534 : {
2535 2 : MyAlgorithm alg;
2536 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co=FOO=BAR,BAR=BAZ"}));
2537 6 : auto expected = std::vector<std::string>{"FOO=BAR", "BAR=BAZ"};
2538 1 : EXPECT_EQ(alg.m_co, expected);
2539 : }
2540 :
2541 : {
2542 2 : MyAlgorithm alg;
2543 5 : EXPECT_TRUE(
2544 : alg.ParseCommandLineArguments({"--co=FOO=BAR", "--co", "BAR=BAZ"}));
2545 6 : auto expected = std::vector<std::string>{"FOO=BAR", "BAR=BAZ"};
2546 1 : EXPECT_EQ(alg.m_co, expected);
2547 : }
2548 1 : }
2549 :
2550 4 : TEST_F(test_gdal_algorithm, required_arg)
2551 : {
2552 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2553 : {
2554 : public:
2555 : std::string m_arg{};
2556 :
2557 2 : MyAlgorithm()
2558 2 : {
2559 2 : AddArg("arg", 0, "required arg", &m_arg).SetRequired();
2560 2 : }
2561 : };
2562 :
2563 : {
2564 2 : MyAlgorithm alg;
2565 1 : alg.GetUsageForCLI(false);
2566 :
2567 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2568 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
2569 : }
2570 :
2571 : {
2572 2 : MyAlgorithm alg;
2573 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--arg", "foo"}));
2574 1 : EXPECT_STREQ(alg.m_arg.c_str(), "foo");
2575 : }
2576 1 : }
2577 :
2578 4 : TEST_F(test_gdal_algorithm, single_positional_arg)
2579 : {
2580 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2581 : {
2582 : public:
2583 : std::string m_value{};
2584 :
2585 4 : MyAlgorithm()
2586 4 : {
2587 4 : AddArg("input", 0, "input value", &m_value).SetPositional();
2588 4 : }
2589 : };
2590 :
2591 : {
2592 2 : MyAlgorithm alg;
2593 1 : alg.GetUsageForCLI(false);
2594 :
2595 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
2596 : }
2597 :
2598 : {
2599 2 : MyAlgorithm alg;
2600 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"my_input"}));
2601 1 : EXPECT_TRUE(alg.GetArg("input")->IsExplicitlySet());
2602 2 : EXPECT_STREQ(alg.GetArg("input")->Get<std::string>().c_str(),
2603 : "my_input");
2604 : }
2605 :
2606 : {
2607 2 : MyAlgorithm alg;
2608 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--input", "my_input"}));
2609 1 : EXPECT_STREQ(alg.m_value.c_str(), "my_input");
2610 : }
2611 :
2612 : {
2613 2 : MyAlgorithm alg;
2614 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--input=my_input"}));
2615 1 : EXPECT_STREQ(alg.m_value.c_str(), "my_input");
2616 : }
2617 1 : }
2618 :
2619 4 : TEST_F(test_gdal_algorithm, single_positional_arg_required)
2620 : {
2621 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2622 : {
2623 : public:
2624 : std::string m_value{};
2625 :
2626 2 : MyAlgorithm()
2627 2 : {
2628 4 : AddArg("input", 0, "input value", &m_value)
2629 2 : .SetPositional()
2630 2 : .SetRequired();
2631 2 : }
2632 : };
2633 :
2634 : {
2635 2 : MyAlgorithm alg;
2636 1 : alg.GetUsageForCLI(false);
2637 :
2638 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2639 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
2640 : }
2641 :
2642 : {
2643 2 : MyAlgorithm alg;
2644 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--input=my_input"}));
2645 1 : EXPECT_STREQ(alg.m_value.c_str(), "my_input");
2646 : }
2647 1 : }
2648 :
2649 4 : TEST_F(test_gdal_algorithm, two_positional_arg)
2650 : {
2651 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2652 : {
2653 : public:
2654 : std::string m_input_value{};
2655 : std::string m_output_value{};
2656 :
2657 12 : MyAlgorithm()
2658 12 : {
2659 12 : AddArg("input", 'i', "input value", &m_input_value).SetPositional();
2660 24 : AddArg("output", 'o', "output value", &m_output_value)
2661 12 : .SetPositional();
2662 12 : }
2663 : };
2664 :
2665 : {
2666 2 : MyAlgorithm alg;
2667 1 : alg.GetUsageForCLI(false);
2668 :
2669 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
2670 : }
2671 :
2672 : {
2673 2 : MyAlgorithm alg;
2674 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"my_input"}));
2675 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2676 : }
2677 :
2678 : {
2679 2 : MyAlgorithm alg;
2680 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"-i", "my_input"}));
2681 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2682 : }
2683 :
2684 : {
2685 2 : MyAlgorithm alg;
2686 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"my_input", "my_output"}));
2687 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2688 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2689 : }
2690 :
2691 : {
2692 2 : MyAlgorithm alg;
2693 6 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2694 : {"--input", "my_input", "-o", "my_output"}));
2695 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2696 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2697 : }
2698 :
2699 : {
2700 2 : MyAlgorithm alg;
2701 6 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2702 : {"-o", "my_output", "--input", "my_input"}));
2703 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2704 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2705 : }
2706 :
2707 : {
2708 2 : MyAlgorithm alg;
2709 5 : EXPECT_TRUE(
2710 : alg.ParseCommandLineArguments({"-o", "my_output", "my_input"}));
2711 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2712 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2713 : }
2714 :
2715 : {
2716 2 : MyAlgorithm alg;
2717 5 : EXPECT_TRUE(
2718 : alg.ParseCommandLineArguments({"my_input", "-o", "my_output"}));
2719 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2720 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2721 : }
2722 :
2723 : {
2724 2 : MyAlgorithm alg;
2725 1 : alg.GetArg("input")->Set("my_input");
2726 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"my_output"}));
2727 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2728 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2729 : }
2730 :
2731 : {
2732 2 : MyAlgorithm alg;
2733 1 : alg.GetArg("input")->Set("my_input");
2734 1 : alg.GetArg("output")->Set("my_output");
2735 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
2736 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2737 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2738 : }
2739 :
2740 : {
2741 2 : MyAlgorithm alg;
2742 1 : alg.GetArg("input")->Set("my_input");
2743 1 : alg.GetArg("output")->Set("my_output");
2744 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2745 1 : CPLErrorReset();
2746 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"unexpected"}));
2747 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2748 : }
2749 :
2750 : {
2751 2 : MyAlgorithm alg;
2752 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2753 1 : CPLErrorReset();
2754 5 : EXPECT_FALSE(alg.ParseCommandLineArguments({"foo", "bar", "baz"}));
2755 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2756 : }
2757 1 : }
2758 :
2759 4 : TEST_F(test_gdal_algorithm, two_positional_arg_first_two_values)
2760 : {
2761 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2762 : {
2763 : public:
2764 : std::vector<int> m_input_value{};
2765 : std::string m_output_value{};
2766 :
2767 3 : MyAlgorithm()
2768 3 : {
2769 6 : AddArg("input", 'i', "input value", &m_input_value)
2770 3 : .SetPositional()
2771 3 : .SetMinCount(2)
2772 3 : .SetMaxCount(2)
2773 3 : .SetDisplayHintAboutRepetition(false);
2774 6 : AddArg("output", 'o', "output value", &m_output_value)
2775 3 : .SetPositional();
2776 3 : }
2777 : };
2778 :
2779 : {
2780 2 : MyAlgorithm alg;
2781 1 : alg.GetUsageForCLI(false);
2782 :
2783 5 : EXPECT_TRUE(alg.ParseCommandLineArguments({"1", "2", "baz"}));
2784 2 : auto expected = std::vector<int>{1, 2};
2785 1 : EXPECT_EQ(alg.m_input_value, expected);
2786 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "baz");
2787 : }
2788 :
2789 : {
2790 2 : MyAlgorithm alg;
2791 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2792 1 : CPLErrorReset();
2793 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"1"}));
2794 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2795 : }
2796 :
2797 : {
2798 2 : MyAlgorithm alg;
2799 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2800 1 : CPLErrorReset();
2801 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"1", "foo"}));
2802 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
2803 : }
2804 1 : }
2805 :
2806 4 : TEST_F(test_gdal_algorithm, unlimited_input_single_output)
2807 : {
2808 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2809 : {
2810 : public:
2811 : std::vector<std::string> m_input_values{};
2812 : std::string m_output_value{};
2813 :
2814 2 : MyAlgorithm()
2815 2 : {
2816 4 : AddArg("input", 'i', "input value", &m_input_values)
2817 2 : .SetPositional();
2818 4 : AddArg("output", 'o', "output value", &m_output_value)
2819 2 : .SetPositional()
2820 2 : .SetRequired();
2821 2 : }
2822 : };
2823 :
2824 : {
2825 2 : MyAlgorithm alg;
2826 1 : alg.GetUsageForCLI(false);
2827 :
2828 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2829 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
2830 : }
2831 :
2832 : {
2833 2 : MyAlgorithm alg;
2834 5 : EXPECT_TRUE(
2835 : alg.ParseCommandLineArguments({"input1", "input2", "my_output"}));
2836 6 : auto expected = std::vector<std::string>{"input1", "input2"};
2837 1 : EXPECT_EQ(alg.m_input_values, expected);
2838 1 : EXPECT_STREQ(alg.m_output_value.c_str(), "my_output");
2839 : }
2840 1 : }
2841 :
2842 4 : TEST_F(test_gdal_algorithm, single_input_unlimited_outputs)
2843 : {
2844 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2845 : {
2846 : public:
2847 : std::string m_input_value{};
2848 : std::vector<std::string> m_output_values{};
2849 :
2850 2 : MyAlgorithm()
2851 2 : {
2852 4 : AddArg("input", 'i', "input value", &m_input_value)
2853 2 : .SetPositional()
2854 2 : .SetRequired();
2855 4 : AddArg("output", 'o', "output value", &m_output_values)
2856 2 : .SetPositional();
2857 2 : }
2858 : };
2859 :
2860 : {
2861 2 : MyAlgorithm alg;
2862 1 : alg.GetUsageForCLI(false);
2863 :
2864 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2865 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
2866 : }
2867 :
2868 : {
2869 2 : MyAlgorithm alg;
2870 5 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2871 : {"my_input", "my_output1", "my_output2"}));
2872 1 : EXPECT_STREQ(alg.m_input_value.c_str(), "my_input");
2873 6 : auto expected = std::vector<std::string>{"my_output1", "my_output2"};
2874 1 : EXPECT_EQ(alg.m_output_values, expected);
2875 : }
2876 1 : }
2877 :
2878 4 : TEST_F(test_gdal_algorithm, min_max_count)
2879 : {
2880 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2881 : {
2882 : public:
2883 : std::vector<std::string> m_arg{};
2884 :
2885 5 : MyAlgorithm()
2886 5 : {
2887 10 : AddArg("arg", 0, "arg", &m_arg)
2888 5 : .SetRequired()
2889 5 : .SetMinCount(2)
2890 5 : .SetMaxCount(3);
2891 5 : }
2892 : };
2893 :
2894 : {
2895 2 : MyAlgorithm alg;
2896 1 : alg.GetUsageForCLI(false);
2897 :
2898 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2899 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
2900 : }
2901 :
2902 : {
2903 2 : MyAlgorithm alg;
2904 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2905 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--arg=foo"}));
2906 : }
2907 :
2908 : {
2909 2 : MyAlgorithm alg;
2910 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2911 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--arg=1,2,3,4"}));
2912 : }
2913 :
2914 : {
2915 2 : MyAlgorithm alg;
2916 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--arg=foo,bar"}));
2917 6 : auto expected = std::vector<std::string>{"foo", "bar"};
2918 1 : EXPECT_EQ(alg.m_arg, expected);
2919 : }
2920 :
2921 : {
2922 2 : MyAlgorithm alg;
2923 8 : EXPECT_TRUE(alg.ParseCommandLineArguments(
2924 : {"--arg", "foo", "--arg", "bar", "--arg", "baz"}));
2925 7 : auto expected = std::vector<std::string>{"foo", "bar", "baz"};
2926 1 : EXPECT_EQ(alg.m_arg, expected);
2927 : }
2928 1 : }
2929 :
2930 4 : TEST_F(test_gdal_algorithm, min_max_count_equal)
2931 : {
2932 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2933 : {
2934 : public:
2935 : std::vector<std::string> m_arg{};
2936 :
2937 2 : MyAlgorithm()
2938 2 : {
2939 4 : AddArg("arg", 0, "arg", &m_arg)
2940 2 : .SetRequired()
2941 2 : .SetMinCount(2)
2942 2 : .SetMaxCount(2);
2943 2 : }
2944 : };
2945 :
2946 : {
2947 2 : MyAlgorithm alg;
2948 1 : alg.GetUsageForCLI(false);
2949 :
2950 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2951 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
2952 : }
2953 :
2954 : {
2955 2 : MyAlgorithm alg;
2956 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
2957 3 : EXPECT_FALSE(alg.GetArg("arg")->Set(std::vector<std::string>{"foo"}));
2958 1 : EXPECT_FALSE(alg.ValidateArguments());
2959 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
2960 : "test: 1 value has been specified for argument 'arg', "
2961 : "whereas exactly 2 were expected.");
2962 : }
2963 1 : }
2964 :
2965 4 : TEST_F(test_gdal_algorithm, repeated_arg_allowed_false)
2966 : {
2967 : class MyAlgorithm : public MyAlgorithmWithDummyRun
2968 : {
2969 : public:
2970 : std::vector<std::string> m_arg{};
2971 :
2972 3 : MyAlgorithm()
2973 3 : {
2974 6 : AddArg("arg", 0, "arg", &m_arg)
2975 3 : .SetRepeatedArgAllowed(false)
2976 3 : .SetMinCount(2)
2977 3 : .SetMaxCount(3);
2978 3 : }
2979 : };
2980 :
2981 : {
2982 2 : MyAlgorithm alg;
2983 1 : alg.GetUsageForCLI(false);
2984 :
2985 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
2986 : }
2987 :
2988 : {
2989 2 : MyAlgorithm alg;
2990 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--arg=foo,bar"}));
2991 6 : auto expected = std::vector<std::string>{"foo", "bar"};
2992 1 : EXPECT_EQ(alg.m_arg, expected);
2993 : }
2994 :
2995 : {
2996 2 : MyAlgorithm alg;
2997 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
2998 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--arg=foo", "--arg=bar"}));
2999 : }
3000 1 : }
3001 :
3002 4 : TEST_F(test_gdal_algorithm, ambiguous_positional_unlimited_and_then_varying)
3003 : {
3004 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3005 : {
3006 : public:
3007 : std::vector<std::string> m_input_values{};
3008 : std::vector<std::string> m_output_values{};
3009 :
3010 1 : MyAlgorithm()
3011 1 : {
3012 2 : AddArg("input", 'i', "input value", &m_input_values)
3013 1 : .SetPositional();
3014 2 : AddArg("output", 'o', "output value", &m_output_values)
3015 1 : .SetPositional()
3016 1 : .SetMinCount(2)
3017 1 : .SetMaxCount(3);
3018 1 : }
3019 : };
3020 :
3021 : {
3022 2 : MyAlgorithm alg;
3023 1 : alg.GetUsageForCLI(false);
3024 :
3025 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3026 1 : CPLErrorReset();
3027 5 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3028 : {"my_input", "my_output1", "my_output2"}));
3029 1 : EXPECT_STREQ(
3030 : CPLGetLastErrorMsg(),
3031 : "test: Ambiguity in definition of positional argument 'output' "
3032 : "given it has a varying number of values, but follows argument "
3033 : "'input' which also has a varying number of values");
3034 : }
3035 1 : }
3036 :
3037 4 : TEST_F(test_gdal_algorithm,
3038 : ambiguous_positional_unlimited_and_then_non_required)
3039 : {
3040 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3041 : {
3042 : public:
3043 : std::vector<std::string> m_input_values{};
3044 : std::string m_output_value{};
3045 :
3046 1 : MyAlgorithm()
3047 1 : {
3048 2 : AddArg("input", 'i', "input value", &m_input_values)
3049 1 : .SetPositional();
3050 2 : AddArg("output", 'o', "output value", &m_output_value)
3051 1 : .SetPositional();
3052 1 : }
3053 : };
3054 :
3055 : {
3056 2 : MyAlgorithm alg;
3057 1 : alg.GetUsageForCLI(false);
3058 :
3059 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3060 1 : CPLErrorReset();
3061 5 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3062 : {"my_input1", "my_input2", "my_output"}));
3063 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3064 : "test: Ambiguity in definition of positional argument "
3065 : "'output', given it is not required but follows argument "
3066 : "'input' which has a varying number of values");
3067 : }
3068 1 : }
3069 :
3070 4 : TEST_F(test_gdal_algorithm,
3071 : ambiguous_positional_fixed_then_unlimited_then_fixed)
3072 : {
3073 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3074 : {
3075 : public:
3076 : std::string m_input_value{};
3077 : std::vector<std::string> m_something{};
3078 : std::string m_output_value{};
3079 :
3080 1 : MyAlgorithm()
3081 1 : {
3082 1 : AddArg("input", 'i', "input value", &m_input_value).SetPositional();
3083 1 : AddArg("something", 0, "something", &m_something).SetPositional();
3084 2 : AddArg("output", 'o', "output value", &m_output_value)
3085 1 : .SetPositional();
3086 1 : }
3087 : };
3088 :
3089 : {
3090 2 : MyAlgorithm alg;
3091 1 : alg.GetUsageForCLI(false);
3092 :
3093 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3094 1 : CPLErrorReset();
3095 5 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3096 : {"my_input", "something", "my_output"}));
3097 : // Actually this is not ambiguous here, but our parser does not support
3098 : // that for now
3099 1 : EXPECT_STREQ(
3100 : CPLGetLastErrorMsg(),
3101 : "test: Ambiguity in definition of positional arguments: arguments "
3102 : "with varying number of values must be first or last one.");
3103 : }
3104 1 : }
3105 :
3106 4 : TEST_F(test_gdal_algorithm, positional_unlimited_and_then_2)
3107 : {
3108 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3109 : {
3110 : public:
3111 : std::vector<std::string> m_input_values{};
3112 : std::vector<std::string> m_output_values{};
3113 :
3114 2 : MyAlgorithm()
3115 2 : {
3116 4 : AddArg("input", 'i', "input value", &m_input_values)
3117 2 : .SetPositional();
3118 4 : AddArg("output", 'o', "output value", &m_output_values)
3119 2 : .SetPositional()
3120 2 : .SetMinCount(2)
3121 2 : .SetMaxCount(2);
3122 2 : }
3123 : };
3124 :
3125 : {
3126 2 : MyAlgorithm alg;
3127 1 : alg.GetUsageForCLI(false);
3128 :
3129 7 : EXPECT_TRUE(alg.ParseCommandLineArguments({"my_input1", "my_input2",
3130 : "my_input3", "my_output1",
3131 : "my_output2"}));
3132 1 : EXPECT_EQ(alg.m_input_values.size(), 3U);
3133 1 : EXPECT_EQ(alg.m_output_values.size(), 2U);
3134 : }
3135 :
3136 : {
3137 2 : MyAlgorithm alg;
3138 :
3139 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3140 1 : CPLErrorReset();
3141 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"my_output1"}));
3142 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3143 : "test: Not enough positional values.");
3144 : }
3145 1 : }
3146 :
3147 4 : TEST_F(test_gdal_algorithm, positional_unlimited_validation_error_and_then_2)
3148 : {
3149 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3150 : {
3151 : public:
3152 : std::vector<std::string> m_input_values{};
3153 : std::vector<std::string> m_output_values{};
3154 :
3155 1 : MyAlgorithm()
3156 1 : {
3157 2 : AddArg("input", 'i', "input value", &m_input_values)
3158 1 : .SetPositional()
3159 : .AddValidationAction(
3160 1 : []()
3161 : {
3162 1 : CPLError(CE_Failure, CPLE_AppDefined,
3163 : "validation failed");
3164 1 : return false;
3165 1 : });
3166 2 : AddArg("output", 'o', "output value", &m_output_values)
3167 1 : .SetPositional()
3168 1 : .SetMinCount(2)
3169 1 : .SetMaxCount(2);
3170 1 : }
3171 : };
3172 :
3173 : {
3174 2 : MyAlgorithm alg;
3175 :
3176 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3177 1 : CPLErrorReset();
3178 7 : EXPECT_FALSE(alg.ParseCommandLineArguments({"my_input1", "my_input2",
3179 : "my_input3", "my_output1",
3180 : "my_output2"}));
3181 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "validation failed");
3182 : }
3183 1 : }
3184 :
3185 4 : TEST_F(test_gdal_algorithm,
3186 : positional_unlimited_validation_error_and_then_required)
3187 : {
3188 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3189 : {
3190 : public:
3191 : std::vector<std::string> m_input_values{};
3192 : std::string m_output_value{};
3193 :
3194 1 : MyAlgorithm()
3195 1 : {
3196 2 : AddArg("input", 'i', "input value", &m_input_values)
3197 1 : .SetPositional()
3198 1 : .SetChoices("foo");
3199 2 : AddArg("output", 'o', "output value", &m_output_value)
3200 1 : .SetPositional()
3201 1 : .SetRequired();
3202 1 : }
3203 : };
3204 :
3205 : {
3206 2 : MyAlgorithm alg;
3207 :
3208 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3209 1 : CPLErrorReset();
3210 5 : EXPECT_FALSE(
3211 : alg.ParseCommandLineArguments({"foo", "bar", "my_output"}));
3212 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3213 : "Invalid value 'bar' for string argument 'input'. "
3214 : "Should be one among 'foo'.");
3215 : }
3216 1 : }
3217 :
3218 4 : TEST_F(test_gdal_algorithm,
3219 : positional_required_and_then_unlimited_validation_error)
3220 : {
3221 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3222 : {
3223 : public:
3224 : std::string m_input_value{};
3225 : std::vector<std::string> m_output_values{};
3226 :
3227 1 : MyAlgorithm()
3228 1 : {
3229 2 : AddArg("input", 'i', "input value", &m_input_value)
3230 1 : .SetPositional()
3231 1 : .SetRequired();
3232 2 : AddArg("output", 'o', "output values", &m_output_values)
3233 1 : .SetPositional()
3234 1 : .SetChoices("foo");
3235 1 : }
3236 : };
3237 :
3238 : {
3239 2 : MyAlgorithm alg;
3240 :
3241 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3242 1 : CPLErrorReset();
3243 5 : EXPECT_FALSE(
3244 : alg.ParseCommandLineArguments({"something", "foo", "bar"}));
3245 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3246 : "Invalid value 'bar' for string argument 'output'. "
3247 : "Should be one among 'foo'.");
3248 : }
3249 1 : }
3250 :
3251 4 : TEST_F(test_gdal_algorithm,
3252 : positional_required_then_unlimited_required_then_positional_required)
3253 : {
3254 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3255 : {
3256 : public:
3257 : std::string m_input_value{};
3258 : std::vector<std::string> m_something{};
3259 : std::string m_output_value{};
3260 :
3261 7 : MyAlgorithm()
3262 7 : {
3263 14 : AddArg("input", 'i', "input value", &m_input_value)
3264 7 : .SetMinCharCount(2)
3265 7 : .SetPositional()
3266 7 : .SetRequired();
3267 14 : AddArg("something", 0, "something", &m_something)
3268 7 : .SetMinCharCount(2)
3269 7 : .SetPositional()
3270 7 : .SetMinCount(1);
3271 14 : AddArg("output", 'o', "output value", &m_output_value)
3272 7 : .SetMinCharCount(2)
3273 7 : .SetMaxCharCount(20)
3274 7 : .SetPositional()
3275 7 : .SetRequired();
3276 7 : }
3277 : };
3278 :
3279 : {
3280 2 : MyAlgorithm alg;
3281 :
3282 5 : EXPECT_TRUE(alg.ParseCommandLineArguments(
3283 : {"my_input", "something", "my_output"}));
3284 : }
3285 :
3286 : {
3287 2 : MyAlgorithm alg;
3288 :
3289 6 : EXPECT_TRUE(alg.ParseCommandLineArguments(
3290 : {"my_input", "something", "else", "my_output"}));
3291 : }
3292 :
3293 : {
3294 2 : MyAlgorithm alg;
3295 :
3296 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3297 1 : CPLErrorReset();
3298 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"input", "output"}));
3299 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3300 : "test: Not enough positional values.");
3301 : }
3302 :
3303 : {
3304 2 : MyAlgorithm alg;
3305 :
3306 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3307 1 : CPLErrorReset();
3308 5 : EXPECT_FALSE(
3309 : alg.ParseCommandLineArguments({"x", "something", "output"}));
3310 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3311 : "Value of argument 'input' is 'x', but should have at "
3312 : "least 2 characters");
3313 : }
3314 :
3315 : {
3316 2 : MyAlgorithm alg;
3317 :
3318 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3319 1 : CPLErrorReset();
3320 5 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3321 : {"input", "something", "output_waaaaaaaay_too_long"}));
3322 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3323 : "Value of argument 'output' is "
3324 : "'output_waaaaaaaay_too_long', but should have no "
3325 : "more than 20 characters");
3326 : }
3327 :
3328 : {
3329 2 : MyAlgorithm alg;
3330 :
3331 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3332 1 : CPLErrorReset();
3333 5 : EXPECT_FALSE(alg.ParseCommandLineArguments({"input", "x", "output"}));
3334 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3335 : "Value of argument 'something' is 'x', but should have at "
3336 : "least 2 characters");
3337 : }
3338 :
3339 : {
3340 2 : MyAlgorithm alg;
3341 :
3342 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3343 1 : CPLErrorReset();
3344 5 : EXPECT_FALSE(
3345 : alg.ParseCommandLineArguments({"input", "something", "x"}));
3346 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
3347 : "Value of argument 'output' is 'x', but should have at "
3348 : "least 2 characters");
3349 : }
3350 1 : }
3351 :
3352 4 : TEST_F(test_gdal_algorithm, packed_values_allowed_false)
3353 : {
3354 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3355 : {
3356 : public:
3357 : std::vector<std::string> m_arg{};
3358 :
3359 3 : MyAlgorithm()
3360 3 : {
3361 6 : AddArg("arg", 0, "arg", &m_arg)
3362 3 : .SetPackedValuesAllowed(false)
3363 3 : .SetMinCount(2)
3364 3 : .SetMaxCount(3);
3365 3 : }
3366 : };
3367 :
3368 : {
3369 2 : MyAlgorithm alg;
3370 1 : alg.GetUsageForCLI(false);
3371 :
3372 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
3373 : }
3374 :
3375 : {
3376 2 : MyAlgorithm alg;
3377 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--arg=foo", "--arg=bar"}));
3378 6 : auto expected = std::vector<std::string>{"foo", "bar"};
3379 1 : EXPECT_EQ(alg.m_arg, expected);
3380 :
3381 2 : std::string serialized;
3382 1 : EXPECT_TRUE(alg.GetArg("arg")->Serialize(serialized));
3383 1 : EXPECT_STREQ(serialized.c_str(), "--arg foo --arg bar");
3384 : }
3385 :
3386 : {
3387 2 : MyAlgorithm alg;
3388 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3389 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--arg=foo,bar"}));
3390 : }
3391 1 : }
3392 :
3393 4 : TEST_F(test_gdal_algorithm, actions)
3394 : {
3395 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3396 : {
3397 : public:
3398 : bool m_flag = false;
3399 : bool m_flagSpecified = false;
3400 :
3401 1 : MyAlgorithm()
3402 1 : {
3403 2 : AddArg("flag", 'f', "boolean flag", &m_flag)
3404 1 : .AddAction([this]() { m_flagSpecified = true; });
3405 1 : }
3406 : };
3407 :
3408 : {
3409 2 : MyAlgorithm alg;
3410 1 : alg.GetUsageForCLI(false);
3411 :
3412 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--flag"}));
3413 1 : EXPECT_TRUE(alg.m_flag);
3414 1 : EXPECT_TRUE(alg.m_flagSpecified);
3415 : }
3416 1 : }
3417 :
3418 4 : TEST_F(test_gdal_algorithm, various)
3419 : {
3420 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3421 : {
3422 : public:
3423 : bool m_flag = false;
3424 :
3425 6 : MyAlgorithm()
3426 6 : {
3427 6 : AddProgressArg();
3428 6 : }
3429 : };
3430 :
3431 : {
3432 2 : MyAlgorithm alg;
3433 1 : alg.GetUsageForCLI(false);
3434 :
3435 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
3436 : // Parse again
3437 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3438 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
3439 : }
3440 :
3441 : {
3442 2 : MyAlgorithm alg;
3443 1 : alg.SetCalledFromCommandLine();
3444 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"-h"}));
3445 1 : EXPECT_TRUE(alg.IsHelpRequested());
3446 : }
3447 :
3448 : {
3449 2 : MyAlgorithm alg;
3450 1 : alg.SetCalledFromCommandLine();
3451 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--help"}));
3452 1 : EXPECT_TRUE(alg.IsHelpRequested());
3453 : }
3454 :
3455 : {
3456 2 : MyAlgorithm alg;
3457 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"help"}));
3458 1 : EXPECT_TRUE(alg.IsHelpRequested());
3459 : }
3460 :
3461 : {
3462 2 : MyAlgorithm alg;
3463 1 : alg.SetCalledFromCommandLine();
3464 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--json-usage"}));
3465 1 : EXPECT_TRUE(alg.IsJSONUsageRequested());
3466 : }
3467 :
3468 : {
3469 2 : MyAlgorithm alg;
3470 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--progress"}));
3471 1 : EXPECT_TRUE(alg.IsProgressBarRequested());
3472 : }
3473 1 : }
3474 :
3475 4 : TEST_F(test_gdal_algorithm, mutually_exclusive)
3476 : {
3477 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3478 : {
3479 : public:
3480 : bool m_flag1 = false;
3481 : bool m_flag2 = false;
3482 : bool m_flag3 = false;
3483 :
3484 4 : MyAlgorithm()
3485 4 : {
3486 8 : AddArg("flag1", 0, "", &m_flag1)
3487 4 : .SetMutualExclusionGroup("my_group");
3488 8 : AddArg("flag2", 0, "", &m_flag2)
3489 4 : .SetMutualExclusionGroup("my_group");
3490 8 : AddArg("flag3", 0, "", &m_flag3)
3491 4 : .SetMutualExclusionGroup("my_group");
3492 4 : }
3493 : };
3494 :
3495 : {
3496 2 : MyAlgorithm alg;
3497 1 : alg.GetUsageForCLI(false);
3498 :
3499 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
3500 : }
3501 :
3502 : {
3503 2 : MyAlgorithm alg;
3504 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--flag1"}));
3505 : }
3506 :
3507 : {
3508 2 : MyAlgorithm alg;
3509 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--flag2"}));
3510 : }
3511 :
3512 : {
3513 2 : MyAlgorithm alg;
3514 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3515 1 : CPLErrorReset();
3516 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--flag1", "--flag2"}));
3517 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3518 : }
3519 1 : }
3520 :
3521 4 : TEST_F(test_gdal_algorithm, invalid_input_format)
3522 : {
3523 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3524 : {
3525 : public:
3526 : std::vector<std::string> m_if{};
3527 :
3528 2 : MyAlgorithm()
3529 2 : {
3530 2 : AddInputFormatsArg(&m_if).AddMetadataItem(
3531 4 : GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR});
3532 2 : }
3533 : };
3534 :
3535 : {
3536 2 : MyAlgorithm alg;
3537 1 : alg.GetUsageForCLI(false);
3538 :
3539 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3540 1 : CPLErrorReset();
3541 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--if=I_DO_NOT_EXIST"}));
3542 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3543 : }
3544 :
3545 : {
3546 2 : MyAlgorithm alg;
3547 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
3548 1 : CPLErrorReset();
3549 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--if=GTIFF"}));
3550 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3551 : }
3552 1 : }
3553 :
3554 4 : TEST_F(test_gdal_algorithm, arg_layer_name_single)
3555 : {
3556 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3557 : {
3558 : public:
3559 : std::string m_layerName{};
3560 :
3561 1 : MyAlgorithm()
3562 1 : {
3563 1 : AddLayerNameArg(&m_layerName);
3564 1 : }
3565 : };
3566 :
3567 : {
3568 2 : MyAlgorithm alg;
3569 1 : alg.GetUsageForCLI(false);
3570 :
3571 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"-l", "foo"}));
3572 1 : EXPECT_STREQ(alg.m_layerName.c_str(), "foo");
3573 : }
3574 1 : }
3575 :
3576 4 : TEST_F(test_gdal_algorithm, arg_layer_name_multiple)
3577 : {
3578 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3579 : {
3580 : public:
3581 : std::vector<std::string> m_layerNames{};
3582 :
3583 1 : MyAlgorithm()
3584 1 : {
3585 1 : AddLayerNameArg(&m_layerNames);
3586 1 : }
3587 : };
3588 :
3589 : {
3590 2 : MyAlgorithm alg;
3591 6 : EXPECT_TRUE(alg.ParseCommandLineArguments({"-l", "foo", "-l", "bar"}));
3592 1 : EXPECT_EQ(alg.m_layerNames.size(), 2U);
3593 : }
3594 1 : }
3595 :
3596 4 : TEST_F(test_gdal_algorithm, arg_co)
3597 : {
3598 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3599 : {
3600 : public:
3601 : std::vector<std::string> m_co{};
3602 :
3603 7 : MyAlgorithm()
3604 7 : {
3605 7 : AddCreationOptionsArg(&m_co);
3606 7 : }
3607 : };
3608 :
3609 : {
3610 2 : MyAlgorithm alg;
3611 1 : alg.GetUsageForCLI(false);
3612 :
3613 6 : EXPECT_TRUE(alg.ParseCommandLineArguments(
3614 : {"--co", "foo=bar", "--co", "bar=baz"}));
3615 6 : const std::vector<std::string> expected{"foo=bar", "bar=baz"};
3616 1 : EXPECT_EQ(alg.m_co, expected);
3617 : }
3618 :
3619 : {
3620 2 : MyAlgorithm alg;
3621 1 : alg.GetUsageForCLI(false);
3622 :
3623 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co", "foo=bar,bar=baz"}));
3624 6 : const std::vector<std::string> expected{"foo=bar", "bar=baz"};
3625 1 : EXPECT_EQ(alg.m_co, expected);
3626 : }
3627 :
3628 : {
3629 2 : MyAlgorithm alg;
3630 1 : alg.GetUsageForCLI(false);
3631 :
3632 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co", "foo=bar,baz"}));
3633 5 : const std::vector<std::string> expected{"foo=bar,baz"};
3634 1 : EXPECT_EQ(alg.m_co, expected);
3635 : }
3636 :
3637 : {
3638 2 : MyAlgorithm alg;
3639 1 : alg.GetUsageForCLI(false);
3640 :
3641 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co", "foo=bar=,a"}));
3642 5 : const std::vector<std::string> expected{"foo=bar=,a"};
3643 1 : EXPECT_EQ(alg.m_co, expected);
3644 : }
3645 :
3646 : {
3647 2 : MyAlgorithm alg;
3648 1 : alg.GetUsageForCLI(false);
3649 :
3650 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--co", "foo=bar,,"}));
3651 5 : const std::vector<std::string> expected{"foo=bar,,"};
3652 1 : EXPECT_EQ(alg.m_co, expected);
3653 : }
3654 :
3655 : {
3656 2 : MyAlgorithm alg;
3657 1 : alg.GetUsageForCLI(false);
3658 :
3659 4 : EXPECT_TRUE(
3660 : alg.ParseCommandLineArguments({"--co", "foo=bar,\"foo=baz\""}));
3661 5 : const std::vector<std::string> expected{"foo=bar,\"foo=baz\""};
3662 1 : EXPECT_EQ(alg.m_co, expected);
3663 : }
3664 :
3665 : {
3666 2 : MyAlgorithm alg;
3667 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3668 1 : CPLErrorReset();
3669 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--co", "foo"}));
3670 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3671 : }
3672 1 : }
3673 :
3674 4 : TEST_F(test_gdal_algorithm, arg_lco)
3675 : {
3676 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3677 : {
3678 : public:
3679 : std::vector<std::string> m_lco{};
3680 :
3681 2 : MyAlgorithm()
3682 2 : {
3683 2 : AddLayerCreationOptionsArg(&m_lco);
3684 2 : }
3685 : };
3686 :
3687 : {
3688 2 : MyAlgorithm alg;
3689 1 : alg.GetUsageForCLI(false);
3690 :
3691 6 : EXPECT_TRUE(alg.ParseCommandLineArguments(
3692 : {"--lco", "foo=bar", "--lco", "bar=baz"}));
3693 1 : EXPECT_EQ(alg.m_lco.size(), 2U);
3694 : }
3695 :
3696 : {
3697 2 : MyAlgorithm alg;
3698 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3699 1 : CPLErrorReset();
3700 4 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--lco", "foo"}));
3701 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3702 : }
3703 1 : }
3704 :
3705 4 : TEST_F(test_gdal_algorithm, arg_band)
3706 : {
3707 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3708 : {
3709 : public:
3710 : int m_band{};
3711 :
3712 2 : MyAlgorithm()
3713 2 : {
3714 2 : AddBandArg(&m_band);
3715 2 : }
3716 : };
3717 :
3718 : {
3719 2 : MyAlgorithm alg;
3720 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--band=1"}));
3721 1 : EXPECT_EQ(alg.m_band, 1);
3722 : }
3723 :
3724 : {
3725 2 : MyAlgorithm alg;
3726 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3727 1 : CPLErrorReset();
3728 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--band=0"}));
3729 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3730 : }
3731 1 : }
3732 :
3733 4 : TEST_F(test_gdal_algorithm, arg_band_with_input_dataset)
3734 : {
3735 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3736 : {
3737 : public:
3738 : GDALArgDatasetValue m_input{};
3739 : int m_band{};
3740 :
3741 3 : MyAlgorithm()
3742 3 : {
3743 3 : AddInputDatasetArg(&m_input, GDAL_OF_RASTER, false);
3744 3 : AddBandArg(&m_band);
3745 3 : }
3746 : };
3747 :
3748 : {
3749 2 : MyAlgorithm alg;
3750 4 : EXPECT_TRUE(alg.ParseCommandLineArguments(
3751 : {std::string("--input=")
3752 : .append(tut::common::data_basedir)
3753 : .append(SEP)
3754 : .append("byte.tif"),
3755 : "--band=1"}));
3756 1 : EXPECT_EQ(alg.m_band, 1);
3757 : }
3758 :
3759 : {
3760 2 : MyAlgorithm alg;
3761 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3762 4 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3763 : {std::string("--input=")
3764 : .append(tut::common::data_basedir)
3765 : .append(SEP)
3766 : .append("byte.tif"),
3767 : "--band=2"}));
3768 : }
3769 :
3770 : {
3771 2 : MyAlgorithm alg;
3772 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3773 4 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3774 : {"--input=i_do_not_exist", "--band=1"}));
3775 : }
3776 1 : }
3777 :
3778 4 : TEST_F(test_gdal_algorithm, AddInputDatasetArg_single)
3779 : {
3780 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3781 : {
3782 : public:
3783 : GDALArgDatasetValue m_input{};
3784 :
3785 1 : MyAlgorithm()
3786 1 : {
3787 1 : AddInputDatasetArg(&m_input, GDAL_OF_RASTER, false)
3788 1 : .SetAutoOpenDataset(false);
3789 1 : }
3790 : };
3791 :
3792 : {
3793 2 : MyAlgorithm alg;
3794 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--input=-"}));
3795 1 : EXPECT_STREQ(alg.m_input.GetName().c_str(), "/vsistdin/");
3796 : }
3797 1 : }
3798 :
3799 4 : TEST_F(test_gdal_algorithm, AddInputDatasetArg_several)
3800 : {
3801 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3802 : {
3803 : public:
3804 : std::vector<GDALArgDatasetValue> m_input{};
3805 :
3806 1 : MyAlgorithm()
3807 1 : {
3808 1 : AddInputDatasetArg(&m_input, GDAL_OF_RASTER, false)
3809 1 : .SetAutoOpenDataset(false);
3810 1 : }
3811 : };
3812 :
3813 : {
3814 1 : MyAlgorithm alg;
3815 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--input=-"}));
3816 1 : ASSERT_EQ(alg.m_input.size(), 1);
3817 1 : EXPECT_STREQ(alg.m_input[0].GetName().c_str(), "/vsistdin/");
3818 : }
3819 : }
3820 :
3821 4 : TEST_F(test_gdal_algorithm, arg_band_vector)
3822 : {
3823 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3824 : {
3825 : public:
3826 : std::vector<int> m_band{};
3827 :
3828 2 : MyAlgorithm()
3829 2 : {
3830 2 : AddBandArg(&m_band);
3831 2 : }
3832 : };
3833 :
3834 : {
3835 2 : MyAlgorithm alg;
3836 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--band=1,2"}));
3837 2 : const std::vector<int> expected{1, 2};
3838 1 : EXPECT_EQ(alg.m_band, expected);
3839 : }
3840 :
3841 : {
3842 2 : MyAlgorithm alg;
3843 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3844 1 : CPLErrorReset();
3845 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--band=1,0"}));
3846 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3847 : }
3848 1 : }
3849 :
3850 4 : TEST_F(test_gdal_algorithm, arg_band_vector_with_input_dataset)
3851 : {
3852 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3853 : {
3854 : public:
3855 : GDALArgDatasetValue m_input{};
3856 : std::vector<int> m_band{};
3857 :
3858 3 : MyAlgorithm()
3859 3 : {
3860 3 : AddInputDatasetArg(&m_input, GDAL_OF_RASTER, false);
3861 3 : AddBandArg(&m_band);
3862 3 : }
3863 : };
3864 :
3865 : {
3866 2 : MyAlgorithm alg;
3867 4 : EXPECT_TRUE(alg.ParseCommandLineArguments(
3868 : {std::string("--input=")
3869 : .append(tut::common::data_basedir)
3870 : .append(SEP)
3871 : .append("byte.tif"),
3872 : "--band=1"}));
3873 2 : const std::vector<int> expected{1};
3874 1 : EXPECT_EQ(alg.m_band, expected);
3875 : }
3876 :
3877 : {
3878 2 : MyAlgorithm alg;
3879 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3880 4 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3881 : {std::string("--input=")
3882 : .append(tut::common::data_basedir)
3883 : .append(SEP)
3884 : .append("byte.tif"),
3885 : "--band=2"}));
3886 : }
3887 :
3888 : {
3889 2 : MyAlgorithm alg;
3890 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3891 4 : EXPECT_FALSE(alg.ParseCommandLineArguments(
3892 : {"--input=i_do_not_exist", "--band=1"}));
3893 : }
3894 1 : }
3895 :
3896 4 : TEST_F(test_gdal_algorithm, SetHidden)
3897 : {
3898 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3899 : {
3900 : public:
3901 : bool m_b = false;
3902 :
3903 1 : MyAlgorithm()
3904 1 : {
3905 1 : AddArg("flag", 0, "", &m_b).SetHidden().SetCategory(GAAC_ESOTERIC);
3906 1 : }
3907 : };
3908 :
3909 1 : MyAlgorithm alg;
3910 1 : EXPECT_TRUE(alg.GetArg("flag")->IsHiddenForCLI());
3911 1 : EXPECT_TRUE(alg.GetArg("flag")->IsHiddenForAPI());
3912 1 : EXPECT_TRUE(alg.GetArg("flag")->IsHidden());
3913 1 : alg.GetUsageForCLI(false);
3914 1 : }
3915 :
3916 4 : TEST_F(test_gdal_algorithm, SetHiddenForCLI)
3917 : {
3918 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3919 : {
3920 : public:
3921 : bool m_b = false;
3922 :
3923 1 : MyAlgorithm()
3924 1 : {
3925 2 : AddArg("flag", 0, "", &m_b)
3926 1 : .SetHiddenForCLI()
3927 1 : .SetCategory(GAAC_ESOTERIC);
3928 1 : }
3929 : };
3930 :
3931 1 : MyAlgorithm alg;
3932 1 : EXPECT_TRUE(alg.GetArg("flag")->IsHiddenForCLI());
3933 1 : EXPECT_FALSE(alg.GetArg("flag")->IsHiddenForAPI());
3934 1 : EXPECT_FALSE(alg.GetArg("flag")->IsHidden());
3935 1 : alg.GetUsageForCLI(false);
3936 1 : }
3937 :
3938 4 : TEST_F(test_gdal_algorithm, SetHiddenForAPI)
3939 : {
3940 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3941 : {
3942 : public:
3943 : bool m_b = false;
3944 :
3945 1 : MyAlgorithm()
3946 1 : {
3947 2 : AddArg("flag", 0, "", &m_b)
3948 1 : .SetHiddenForAPI()
3949 1 : .SetCategory("my category");
3950 1 : m_longDescription = "long description";
3951 1 : }
3952 : };
3953 :
3954 1 : MyAlgorithm alg;
3955 1 : EXPECT_TRUE(alg.GetArg("flag")->IsHiddenForAPI());
3956 1 : EXPECT_FALSE(alg.GetArg("flag")->IsHiddenForCLI());
3957 1 : EXPECT_FALSE(alg.GetArg("flag")->IsHidden());
3958 1 : alg.GetUsageForCLI(false);
3959 1 : }
3960 :
3961 4 : TEST_F(test_gdal_algorithm, SetSkipIfAlreadySet)
3962 : {
3963 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3964 : {
3965 : public:
3966 : int m_val = 0;
3967 :
3968 2 : MyAlgorithm()
3969 2 : {
3970 2 : AddArg("option", 0, "option", &m_val).SetPositional();
3971 2 : }
3972 : };
3973 :
3974 : {
3975 2 : MyAlgorithm alg;
3976 1 : alg.GetArg("option")->Set(1);
3977 1 : alg.GetArg("option")->SetSkipIfAlreadySet();
3978 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--option=1"}));
3979 : }
3980 :
3981 : {
3982 2 : MyAlgorithm alg;
3983 1 : alg.GetArg("option")->Set(1);
3984 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
3985 1 : CPLErrorReset();
3986 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"--option=1"}));
3987 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
3988 : }
3989 1 : }
3990 :
3991 4 : TEST_F(test_gdal_algorithm, alg_with_aliases)
3992 : {
3993 : class MyAlgorithm : public MyAlgorithmWithDummyRun
3994 : {
3995 : public:
3996 : int m_val = 0;
3997 :
3998 1 : MyAlgorithm()
3999 1 : {
4000 1 : m_aliases.push_back("one_alias");
4001 1 : m_aliases.push_back(GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR);
4002 1 : m_aliases.push_back("hidden_alias");
4003 1 : }
4004 : };
4005 :
4006 2 : MyAlgorithm alg;
4007 1 : alg.GetUsageForCLI(false);
4008 1 : EXPECT_EQ(alg.GetAliases().size(), 3U);
4009 1 : }
4010 :
4011 4 : TEST_F(test_gdal_algorithm, subalgorithms)
4012 : {
4013 1 : bool hasRun = false;
4014 :
4015 : class SubAlgorithm : public GDALAlgorithm
4016 : {
4017 : public:
4018 : bool &m_bHasRun;
4019 : bool m_flag = false;
4020 :
4021 4 : SubAlgorithm(bool &lHasRun)
4022 4 : : GDALAlgorithm("subalg", "", "https://example.com"),
4023 4 : m_bHasRun(lHasRun)
4024 : {
4025 4 : AddProgressArg();
4026 4 : m_aliases.push_back("one_alias");
4027 4 : m_aliases.push_back(GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR);
4028 4 : m_aliases.push_back("hidden_alias");
4029 4 : }
4030 :
4031 1 : bool RunImpl(GDALProgressFunc, void *) override
4032 : {
4033 1 : m_bHasRun = true;
4034 1 : return true;
4035 : }
4036 : };
4037 :
4038 : class MyAlgorithm : public MyAlgorithmWithDummyRun
4039 : {
4040 : public:
4041 5 : MyAlgorithm(bool &lHasRun)
4042 5 : {
4043 10 : GDALAlgorithmRegistry::AlgInfo info;
4044 5 : info.m_name = "subalg";
4045 4 : info.m_creationFunc = [&lHasRun]()
4046 9 : { return std::make_unique<SubAlgorithm>(lHasRun); };
4047 5 : RegisterSubAlgorithm(info);
4048 : // RegisterSubAlgorithm(SubAlgorithm);
4049 5 : }
4050 : };
4051 :
4052 : {
4053 2 : MyAlgorithm alg(hasRun);
4054 1 : alg.GetUsageForCLI(false);
4055 :
4056 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4057 1 : CPLErrorReset();
4058 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
4059 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4060 : }
4061 :
4062 : {
4063 2 : MyAlgorithm alg(hasRun);
4064 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4065 1 : CPLErrorReset();
4066 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"invalid_subcommand"}));
4067 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4068 : }
4069 :
4070 : {
4071 1 : MyAlgorithm alg(hasRun);
4072 2 : alg.SetCallPath(std::vector<std::string>{"main"});
4073 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"subalg"}));
4074 1 : EXPECT_STREQ(alg.GetActualAlgorithm().GetName().c_str(), "subalg");
4075 1 : EXPECT_TRUE(alg.ValidateArguments());
4076 1 : EXPECT_TRUE(alg.Run());
4077 1 : EXPECT_TRUE(hasRun);
4078 1 : EXPECT_TRUE(alg.Finalize());
4079 1 : alg.GetUsageForCLI(false);
4080 : }
4081 :
4082 : {
4083 1 : MyAlgorithm alg(hasRun);
4084 1 : alg.SetCalledFromCommandLine();
4085 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"subalg", "-h"}));
4086 1 : EXPECT_TRUE(alg.IsHelpRequested());
4087 1 : EXPECT_TRUE(alg.ValidateArguments());
4088 1 : alg.GetUsageForCLI(false);
4089 : }
4090 :
4091 : {
4092 1 : MyAlgorithm alg(hasRun);
4093 4 : EXPECT_TRUE(alg.ParseCommandLineArguments({"subalg", "--progress"}));
4094 1 : EXPECT_TRUE(alg.IsProgressBarRequested());
4095 1 : EXPECT_TRUE(alg.ValidateArguments());
4096 1 : alg.GetUsageForCLI(false);
4097 : }
4098 1 : }
4099 :
4100 : class MyRedundantRasterAlgorithm : public MyAlgorithmWithDummyRun
4101 : {
4102 : public:
4103 : static constexpr const char *NAME = "raster";
4104 : static constexpr const char *DESCRIPTION =
4105 : "redundant with existing raster!!!";
4106 : static constexpr const char *HELP_URL = "";
4107 : };
4108 :
4109 : class MyAlgorithmWithAlias : public MyAlgorithmWithDummyRun
4110 : {
4111 : public:
4112 : static constexpr const char *NAME = "MyAlgorithmWithAlias";
4113 : static constexpr const char *DESCRIPTION = "";
4114 : static constexpr const char *HELP_URL = "";
4115 :
4116 1 : static std::vector<std::string> GetAliasesStatic()
4117 : {
4118 : return {"alias", GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR,
4119 4 : "hidden_alias"};
4120 : }
4121 : };
4122 :
4123 : class MyAlgorithmWithRedundantAlias : public MyAlgorithmWithDummyRun
4124 : {
4125 : public:
4126 : static constexpr const char *NAME = "MyAlgorithmWithRedundantAlias";
4127 : static constexpr const char *DESCRIPTION = "";
4128 : static constexpr const char *HELP_URL = "";
4129 :
4130 1 : static std::vector<std::string> GetAliasesStatic()
4131 : {
4132 2 : return {"alias"};
4133 : }
4134 : };
4135 :
4136 : class MyAlgorithmWithRedundantHiddenAlias : public MyAlgorithmWithDummyRun
4137 : {
4138 : public:
4139 : static constexpr const char *NAME = "MyAlgorithmWithRedundantHiddenAlias";
4140 : static constexpr const char *DESCRIPTION = "";
4141 : static constexpr const char *HELP_URL = "";
4142 :
4143 1 : static std::vector<std::string> GetAliasesStatic()
4144 : {
4145 3 : return {GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR, "hidden_alias"};
4146 : }
4147 : };
4148 :
4149 4 : TEST_F(test_gdal_algorithm, GDALGlobalAlgorithmRegistry)
4150 : {
4151 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4152 1 : EXPECT_NE(singleton.GetInfo("raster"), nullptr);
4153 1 : EXPECT_EQ(singleton.GetInfo("not_existing"), nullptr);
4154 2 : auto alg = singleton.Instantiate("raster");
4155 1 : ASSERT_NE(alg, nullptr);
4156 1 : EXPECT_TRUE(!alg->GetUsageAsJSON().empty());
4157 :
4158 : {
4159 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4160 1 : EXPECT_FALSE(singleton.Register<MyRedundantRasterAlgorithm>());
4161 : }
4162 :
4163 1 : EXPECT_TRUE(singleton.Register<MyAlgorithmWithAlias>());
4164 : {
4165 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4166 1 : EXPECT_FALSE(singleton.Register<MyAlgorithmWithRedundantAlias>());
4167 : }
4168 : {
4169 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4170 1 : EXPECT_FALSE(singleton.Register<MyAlgorithmWithRedundantHiddenAlias>());
4171 : }
4172 : }
4173 :
4174 4 : TEST_F(test_gdal_algorithm, registry)
4175 : {
4176 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4177 2 : EXPECT_EQ(singleton.Instantiate(std::vector<std::string>()), nullptr);
4178 2 : EXPECT_EQ(singleton.Instantiate("vector", "not_existing"), nullptr);
4179 1 : }
4180 :
4181 4 : TEST_F(test_gdal_algorithm, vector_pipeline_GetUsageForCLI)
4182 : {
4183 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4184 2 : auto pipeline = singleton.Instantiate("vector", "pipeline");
4185 1 : ASSERT_NE(pipeline, nullptr);
4186 1 : pipeline->GetUsageForCLI(false);
4187 1 : pipeline->GetUsageForCLI(true);
4188 : }
4189 :
4190 4 : TEST_F(test_gdal_algorithm, raster_pipeline_GetUsageForCLI)
4191 : {
4192 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4193 2 : auto raster = singleton.Instantiate("raster");
4194 1 : ASSERT_NE(raster, nullptr);
4195 2 : auto pipeline = raster->InstantiateSubAlgorithm("pipeline");
4196 1 : ASSERT_NE(pipeline, nullptr);
4197 1 : pipeline->GetUsageForCLI(false);
4198 1 : pipeline->GetUsageForCLI(true);
4199 :
4200 : {
4201 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4202 1 : CPLErrorReset();
4203 2 : EXPECT_EQ(raster->InstantiateSubAlgorithm("pipline"), nullptr);
4204 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
4205 : "Algorithm 'pipline' is unknown. Do you mean 'pipeline'?");
4206 : }
4207 :
4208 : {
4209 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4210 1 : CPLErrorReset();
4211 2 : EXPECT_EQ(raster->InstantiateSubAlgorithm("pipleine"), nullptr);
4212 1 : EXPECT_STREQ(
4213 : CPLGetLastErrorMsg(),
4214 : "Algorithm 'pipleine' is unknown. Do you mean 'pipeline'?");
4215 : }
4216 : }
4217 :
4218 4 : TEST_F(test_gdal_algorithm, registry_c_api)
4219 : {
4220 1 : auto reg = GDALGetGlobalAlgorithmRegistry();
4221 1 : ASSERT_NE(reg, nullptr);
4222 1 : char **names = GDALAlgorithmRegistryGetAlgNames(reg);
4223 1 : EXPECT_GE(CSLCount(names), 2);
4224 1 : CSLDestroy(names);
4225 : {
4226 1 : auto alg = GDALAlgorithmRegistryInstantiateAlg(reg, "raster");
4227 1 : ASSERT_NE(alg, nullptr);
4228 1 : EXPECT_EQ(GDALAlgorithmRegistryInstantiateAlg(reg, "not_existing"),
4229 : nullptr);
4230 1 : GDALAlgorithmRelease(alg);
4231 : }
4232 : {
4233 1 : const char *const apszPath[] = {"raster", "reproject", nullptr};
4234 1 : auto alg = GDALAlgorithmRegistryInstantiateAlgFromPath(reg, apszPath);
4235 1 : ASSERT_NE(alg, nullptr);
4236 1 : GDALAlgorithmRelease(alg);
4237 : }
4238 1 : GDALAlgorithmRegistryRelease(reg);
4239 : }
4240 :
4241 4 : TEST_F(test_gdal_algorithm, algorithm_c_api)
4242 : {
4243 : class MyAlgorithm : public GDALAlgorithm
4244 : {
4245 : public:
4246 : bool m_flag = false;
4247 : std::string m_str{};
4248 : int m_int = 0;
4249 : double m_double = 0;
4250 : std::vector<std::string> m_strlist{};
4251 : std::vector<int> m_intlist{};
4252 : std::vector<double> m_doublelist{};
4253 : GDALArgDatasetValue m_dsValue{};
4254 :
4255 : bool m_hasParsedCommandLinearguments = false;
4256 : bool m_hasRun = false;
4257 : bool m_hasFinalized = false;
4258 :
4259 1 : MyAlgorithm()
4260 1 : : GDALAlgorithm("test", "description", "http://example.com")
4261 : {
4262 1 : m_longDescription = "long description";
4263 1 : AddArg("flag", 'f', "boolean flag", &m_flag).SetDefault(true);
4264 1 : AddArg("str", 0, "str", &m_str).SetDefault("default");
4265 1 : AddArg("int", 0, "int", &m_int).SetDefault(1);
4266 1 : AddArg("double", 0, "double", &m_double).SetDefault(1.5);
4267 2 : AddArg("strlist", 0, "strlist", &m_strlist)
4268 3 : .SetDefault(std::vector<std::string>{"one", "two"});
4269 2 : AddArg("doublelist", 0, "doublelist", &m_doublelist)
4270 1 : .SetDefault(std::vector<double>{1.5, 2.5});
4271 2 : AddArg("intlist", 0, "intlist", &m_intlist)
4272 1 : .SetDefault(std::vector<int>{1, 2});
4273 1 : AddArg("dataset", 0, "dataset", &m_dsValue);
4274 1 : }
4275 :
4276 : bool
4277 1 : ParseCommandLineArguments(const std::vector<std::string> &args) override
4278 : {
4279 1 : m_hasParsedCommandLinearguments = true;
4280 1 : return GDALAlgorithm::ParseCommandLineArguments(args);
4281 : }
4282 :
4283 1 : bool RunImpl(GDALProgressFunc, void *) override
4284 : {
4285 1 : m_hasRun = true;
4286 1 : return true;
4287 : }
4288 :
4289 1 : bool Finalize() override
4290 : {
4291 1 : m_hasFinalized = true;
4292 1 : return GDALAlgorithm::Finalize();
4293 : }
4294 : };
4295 :
4296 : auto hAlg =
4297 1 : std::make_unique<GDALAlgorithmHS>(std::make_unique<MyAlgorithm>());
4298 1 : MyAlgorithm *pAlg = cpl::down_cast<MyAlgorithm *>(hAlg->ptr);
4299 1 : EXPECT_STREQ(GDALAlgorithmGetName(hAlg.get()), "test");
4300 1 : EXPECT_STREQ(GDALAlgorithmGetDescription(hAlg.get()), "description");
4301 1 : EXPECT_STREQ(GDALAlgorithmGetLongDescription(hAlg.get()),
4302 : "long description");
4303 1 : EXPECT_STREQ(GDALAlgorithmGetHelpFullURL(hAlg.get()), "http://example.com");
4304 1 : EXPECT_FALSE(GDALAlgorithmHasSubAlgorithms(hAlg.get()));
4305 1 : EXPECT_EQ(GDALAlgorithmGetSubAlgorithmNames(hAlg.get()), nullptr);
4306 1 : EXPECT_EQ(GDALAlgorithmInstantiateSubAlgorithm(hAlg.get(), "not_existing"),
4307 : nullptr);
4308 3 : EXPECT_TRUE(GDALAlgorithmParseCommandLineArguments(
4309 : hAlg.get(), CPLStringList(std::vector<std::string>({"-f"})).List()));
4310 1 : EXPECT_TRUE(pAlg->m_hasParsedCommandLinearguments);
4311 1 : EXPECT_TRUE(GDALAlgorithmRun(hAlg.get(), nullptr, nullptr));
4312 1 : EXPECT_TRUE(pAlg->m_hasRun);
4313 1 : EXPECT_TRUE(GDALAlgorithmFinalize(hAlg.get()));
4314 1 : EXPECT_TRUE(pAlg->m_hasFinalized);
4315 1 : char *jsonUsage = GDALAlgorithmGetUsageAsJSON(hAlg.get());
4316 1 : EXPECT_NE(jsonUsage, nullptr);
4317 1 : CPLFree(jsonUsage);
4318 :
4319 1 : char **argNames = GDALAlgorithmGetArgNames(hAlg.get());
4320 1 : ASSERT_NE(argNames, nullptr);
4321 1 : EXPECT_EQ(CSLCount(argNames), 12);
4322 1 : CSLDestroy(argNames);
4323 :
4324 1 : EXPECT_EQ(GDALAlgorithmGetArg(hAlg.get(), "non_existing"), nullptr);
4325 : {
4326 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "flag");
4327 1 : ASSERT_NE(hArg, nullptr);
4328 1 : EXPECT_TRUE(GDALAlgorithmArgHasDefaultValue(hArg));
4329 : {
4330 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4331 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsString(hArg), nullptr);
4332 : }
4333 1 : EXPECT_TRUE(GDALAlgorithmArgGetDefaultAsBoolean(hArg));
4334 1 : GDALAlgorithmArgSetAsBoolean(hArg, true);
4335 1 : EXPECT_TRUE(GDALAlgorithmArgGetAsBoolean(hArg));
4336 1 : GDALAlgorithmArgRelease(hArg);
4337 : }
4338 : {
4339 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "str");
4340 1 : ASSERT_NE(hArg, nullptr);
4341 : {
4342 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4343 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsInteger(hArg), 0);
4344 : }
4345 1 : EXPECT_STREQ(GDALAlgorithmArgGetDefaultAsString(hArg), "default");
4346 1 : GDALAlgorithmArgSetAsString(hArg, "foo");
4347 1 : EXPECT_STREQ(GDALAlgorithmArgGetAsString(hArg), "foo");
4348 1 : GDALAlgorithmArgRelease(hArg);
4349 : }
4350 : {
4351 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "int");
4352 1 : ASSERT_NE(hArg, nullptr);
4353 : {
4354 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4355 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsDouble(hArg), 0);
4356 : }
4357 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsInteger(hArg), 1);
4358 1 : GDALAlgorithmArgSetAsInteger(hArg, 2);
4359 1 : EXPECT_EQ(GDALAlgorithmArgGetAsInteger(hArg), 2);
4360 1 : GDALAlgorithmArgRelease(hArg);
4361 : }
4362 : {
4363 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "double");
4364 1 : ASSERT_NE(hArg, nullptr);
4365 : {
4366 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4367 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsStringList(hArg), nullptr);
4368 : }
4369 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsDouble(hArg), 1.5);
4370 1 : GDALAlgorithmArgSetAsDouble(hArg, 2.5);
4371 1 : EXPECT_EQ(GDALAlgorithmArgGetAsDouble(hArg), 2.5);
4372 1 : GDALAlgorithmArgRelease(hArg);
4373 : }
4374 : {
4375 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "strlist");
4376 1 : ASSERT_NE(hArg, nullptr);
4377 : {
4378 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4379 : size_t nCount;
4380 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsIntegerList(hArg, &nCount),
4381 : nullptr);
4382 : }
4383 : {
4384 1 : char **ret = GDALAlgorithmArgGetDefaultAsStringList(hArg);
4385 1 : EXPECT_EQ(CSLCount(ret), 2);
4386 1 : if (CSLCount(ret) == 2)
4387 : {
4388 1 : EXPECT_STREQ(ret[0], "one");
4389 1 : EXPECT_STREQ(ret[1], "two");
4390 : }
4391 1 : CSLDestroy(ret);
4392 : }
4393 6 : const CPLStringList list(std::vector<std::string>({"foo", "bar"}));
4394 1 : GDALAlgorithmArgSetAsStringList(hArg, list.List());
4395 1 : char **ret = GDALAlgorithmArgGetAsStringList(hArg);
4396 1 : EXPECT_EQ(CSLCount(ret), 2);
4397 1 : if (CSLCount(ret) == 2)
4398 : {
4399 1 : EXPECT_STREQ(ret[0], "foo");
4400 1 : EXPECT_STREQ(ret[1], "bar");
4401 : }
4402 1 : CSLDestroy(ret);
4403 1 : GDALAlgorithmArgRelease(hArg);
4404 : }
4405 : {
4406 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "intlist");
4407 1 : ASSERT_NE(hArg, nullptr);
4408 : {
4409 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4410 : size_t nCount;
4411 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsDoubleList(hArg, &nCount),
4412 : nullptr);
4413 : }
4414 : {
4415 1 : size_t nCount = 0;
4416 : const int *ret =
4417 1 : GDALAlgorithmArgGetDefaultAsIntegerList(hArg, &nCount);
4418 1 : ASSERT_EQ(nCount, 2);
4419 1 : ASSERT_NE(ret, nullptr);
4420 1 : EXPECT_EQ(ret[0], 1);
4421 1 : EXPECT_EQ(ret[1], 2);
4422 : }
4423 1 : std::vector<int> vals{2, 3};
4424 1 : GDALAlgorithmArgSetAsIntegerList(hArg, vals.size(), vals.data());
4425 1 : size_t nCount = 0;
4426 1 : const int *ret = GDALAlgorithmArgGetAsIntegerList(hArg, &nCount);
4427 1 : ASSERT_EQ(nCount, 2);
4428 1 : ASSERT_NE(ret, nullptr);
4429 1 : EXPECT_EQ(ret[0], 2);
4430 1 : EXPECT_EQ(ret[1], 3);
4431 1 : GDALAlgorithmArgRelease(hArg);
4432 : }
4433 : {
4434 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "doublelist");
4435 1 : ASSERT_NE(hArg, nullptr);
4436 : {
4437 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4438 1 : EXPECT_EQ(GDALAlgorithmArgGetDefaultAsBoolean(hArg), false);
4439 : }
4440 : {
4441 1 : size_t nCount = 0;
4442 : const double *ret =
4443 1 : GDALAlgorithmArgGetDefaultAsDoubleList(hArg, &nCount);
4444 1 : ASSERT_EQ(nCount, 2);
4445 1 : ASSERT_NE(ret, nullptr);
4446 1 : EXPECT_EQ(ret[0], 1.5);
4447 1 : EXPECT_EQ(ret[1], 2.5);
4448 : }
4449 1 : std::vector<double> vals{2.5, 3.5};
4450 1 : GDALAlgorithmArgSetAsDoubleList(hArg, vals.size(), vals.data());
4451 1 : size_t nCount = 0;
4452 1 : const double *ret = GDALAlgorithmArgGetAsDoubleList(hArg, &nCount);
4453 1 : ASSERT_EQ(nCount, 2);
4454 1 : ASSERT_NE(ret, nullptr);
4455 1 : EXPECT_EQ(ret[0], 2.5);
4456 1 : EXPECT_EQ(ret[1], 3.5);
4457 1 : GDALAlgorithmArgRelease(hArg);
4458 : }
4459 : {
4460 1 : auto hArg = GDALAlgorithmGetArg(hAlg.get(), "dataset");
4461 1 : ASSERT_NE(hArg, nullptr);
4462 1 : EXPECT_EQ(GDALAlgorithmArgGetDatasetType(hArg),
4463 : GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER);
4464 1 : EXPECT_EQ(GDALAlgorithmArgGetDatasetInputFlags(hArg),
4465 : GADV_NAME | GADV_OBJECT);
4466 1 : EXPECT_EQ(GDALAlgorithmArgGetDatasetOutputFlags(hArg), GADV_OBJECT);
4467 1 : GDALArgDatasetValueH hVal = GDALArgDatasetValueCreate();
4468 1 : GDALArgDatasetValueSetName(hVal, "foo");
4469 :
4470 : {
4471 : auto poDS = std::unique_ptr<GDALDataset>(
4472 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
4473 2 : "", 1, 1, 1, GDT_Byte, nullptr));
4474 1 : GDALArgDatasetValueSetDataset(hVal, poDS.release());
4475 : }
4476 :
4477 1 : GDALAlgorithmArgSetAsDatasetValue(hArg, hVal);
4478 1 : GDALArgDatasetValueRelease(hVal);
4479 :
4480 1 : hVal = GDALAlgorithmArgGetAsDatasetValue(hArg);
4481 1 : ASSERT_NE(hVal, nullptr);
4482 1 : auto hDS = GDALArgDatasetValueGetDatasetRef(hVal);
4483 1 : EXPECT_NE(hDS, nullptr);
4484 : {
4485 1 : auto hDS2 = GDALArgDatasetValueGetDatasetIncreaseRefCount(hVal);
4486 1 : EXPECT_EQ(hDS2, hDS);
4487 1 : GDALReleaseDataset(hDS2);
4488 : }
4489 1 : GDALArgDatasetValueRelease(hVal);
4490 :
4491 1 : GDALAlgorithmArgSetDataset(hArg, nullptr);
4492 :
4493 1 : hVal = GDALAlgorithmArgGetAsDatasetValue(hArg);
4494 1 : ASSERT_NE(hVal, nullptr);
4495 1 : EXPECT_EQ(GDALArgDatasetValueGetDatasetRef(hVal), nullptr);
4496 1 : GDALArgDatasetValueRelease(hVal);
4497 :
4498 : {
4499 : auto poDS = std::unique_ptr<GDALDataset>(
4500 : GetGDALDriverManager()->GetDriverByName("MEM")->Create(
4501 2 : "", 1, 1, 1, GDT_Byte, nullptr));
4502 1 : GDALAlgorithmArgSetDataset(hArg, poDS.release());
4503 : }
4504 :
4505 1 : hVal = GDALAlgorithmArgGetAsDatasetValue(hArg);
4506 1 : ASSERT_NE(hVal, nullptr);
4507 1 : EXPECT_NE(GDALArgDatasetValueGetDatasetRef(hVal), nullptr);
4508 1 : GDALArgDatasetValueRelease(hVal);
4509 :
4510 1 : GDALAlgorithmArgRelease(hArg);
4511 : }
4512 : }
4513 :
4514 4 : TEST_F(test_gdal_algorithm, DispatcherGetUsageForCLI)
4515 : {
4516 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4517 : {
4518 2 : auto info = singleton.Instantiate("info");
4519 1 : info->GetUsageForCLI(false);
4520 : }
4521 : {
4522 2 : auto info = singleton.Instantiate("info");
4523 3 : EXPECT_TRUE(info->ParseCommandLineArguments(
4524 : std::vector<std::string>{GCORE_DATA_DIR "byte.tif"}));
4525 1 : info->GetUsageForCLI(false);
4526 : }
4527 : {
4528 1 : auto poDriver = GetGDALDriverManager()->GetDriverByName("GPKG");
4529 1 : if (!poDriver)
4530 : {
4531 0 : GTEST_SKIP() << "GPKG support missing";
4532 : }
4533 : else
4534 : {
4535 : std::string osTmpFilename =
4536 2 : VSIMemGenerateHiddenFilename("temp.gpkg");
4537 : auto poDS = std::unique_ptr<GDALDataset>(poDriver->Create(
4538 2 : osTmpFilename.c_str(), 1, 1, 1, GDT_Byte, nullptr));
4539 1 : double adfGT[] = {1, 1, 0, 1, 0, -1};
4540 1 : poDS->SetGeoTransform(adfGT);
4541 1 : poDS->CreateLayer("foo");
4542 1 : poDS.reset();
4543 :
4544 3 : auto info = singleton.Instantiate("info");
4545 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4546 3 : EXPECT_FALSE(info->ParseCommandLineArguments(
4547 : std::vector<std::string>{osTmpFilename.c_str()}));
4548 1 : info->GetUsageForCLI(false);
4549 :
4550 1 : VSIUnlink(osTmpFilename.c_str());
4551 : }
4552 : }
4553 : }
4554 :
4555 4 : TEST_F(test_gdal_algorithm, raster_edit_failures_dataset_0_0)
4556 : {
4557 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4558 2 : auto raster = singleton.Instantiate("raster");
4559 1 : ASSERT_NE(raster, nullptr);
4560 2 : auto edit = raster->InstantiateSubAlgorithm("edit");
4561 1 : ASSERT_NE(edit, nullptr);
4562 :
4563 : class MyDataset : public GDALDataset
4564 : {
4565 : public:
4566 1 : MyDataset()
4567 1 : {
4568 1 : nRasterXSize = 0;
4569 1 : nRasterYSize = 0;
4570 1 : eAccess = GA_Update;
4571 1 : }
4572 : };
4573 :
4574 1 : auto datasetArg = edit->GetArg("dataset");
4575 1 : ASSERT_NE(datasetArg, nullptr);
4576 1 : datasetArg->Get<GDALArgDatasetValue>().Set(std::make_unique<MyDataset>());
4577 :
4578 1 : auto extentArg = edit->GetArg("bbox");
4579 1 : ASSERT_NE(extentArg, nullptr);
4580 1 : extentArg->Set(std::vector<double>{2, 49, 3, 50});
4581 :
4582 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4583 1 : CPLErrorReset();
4584 1 : EXPECT_FALSE(edit->Run());
4585 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4586 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "edit: Cannot set extent because one of "
4587 : "dataset height or width is null");
4588 : }
4589 :
4590 4 : TEST_F(test_gdal_algorithm, raster_edit_failures_set_spatial_ref_none)
4591 : {
4592 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4593 2 : auto raster = singleton.Instantiate("raster");
4594 1 : ASSERT_NE(raster, nullptr);
4595 2 : auto edit = raster->InstantiateSubAlgorithm("edit");
4596 1 : ASSERT_NE(edit, nullptr);
4597 :
4598 : class MyDataset : public GDALDataset
4599 : {
4600 : public:
4601 1 : MyDataset()
4602 1 : {
4603 1 : eAccess = GA_Update;
4604 1 : }
4605 :
4606 1 : CPLErr SetSpatialRef(const OGRSpatialReference *) override
4607 : {
4608 1 : return CE_Failure;
4609 : }
4610 : };
4611 :
4612 1 : auto datasetArg = edit->GetArg("dataset");
4613 1 : ASSERT_NE(datasetArg, nullptr);
4614 1 : datasetArg->Get<GDALArgDatasetValue>().Set(std::make_unique<MyDataset>());
4615 :
4616 1 : auto crsArg = edit->GetArg("crs");
4617 1 : ASSERT_NE(crsArg, nullptr);
4618 1 : crsArg->Set("none");
4619 :
4620 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4621 1 : CPLErrorReset();
4622 1 : EXPECT_FALSE(edit->Run());
4623 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4624 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "edit: SetSpatialRef(none) failed");
4625 : }
4626 :
4627 4 : TEST_F(test_gdal_algorithm, raster_edit_failures_set_spatial_ref_regular)
4628 : {
4629 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4630 2 : auto raster = singleton.Instantiate("raster");
4631 1 : ASSERT_NE(raster, nullptr);
4632 2 : auto edit = raster->InstantiateSubAlgorithm("edit");
4633 1 : ASSERT_NE(edit, nullptr);
4634 :
4635 : class MyDataset : public GDALDataset
4636 : {
4637 : public:
4638 1 : MyDataset()
4639 1 : {
4640 1 : eAccess = GA_Update;
4641 1 : }
4642 :
4643 1 : CPLErr SetSpatialRef(const OGRSpatialReference *) override
4644 : {
4645 1 : return CE_Failure;
4646 : }
4647 : };
4648 :
4649 1 : auto datasetArg = edit->GetArg("dataset");
4650 1 : ASSERT_NE(datasetArg, nullptr);
4651 1 : datasetArg->Get<GDALArgDatasetValue>().Set(std::make_unique<MyDataset>());
4652 :
4653 1 : auto crsArg = edit->GetArg("crs");
4654 1 : ASSERT_NE(crsArg, nullptr);
4655 1 : crsArg->Set("EPSG:32632");
4656 :
4657 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4658 1 : CPLErrorReset();
4659 1 : EXPECT_FALSE(edit->Run());
4660 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4661 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
4662 : "edit: SetSpatialRef(EPSG:32632) failed");
4663 : }
4664 :
4665 4 : TEST_F(test_gdal_algorithm, raster_edit_failures_set_geo_transform)
4666 : {
4667 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4668 2 : auto raster = singleton.Instantiate("raster");
4669 1 : ASSERT_NE(raster, nullptr);
4670 2 : auto edit = raster->InstantiateSubAlgorithm("edit");
4671 1 : ASSERT_NE(edit, nullptr);
4672 :
4673 : class MyDataset : public GDALDataset
4674 : {
4675 : public:
4676 1 : MyDataset()
4677 1 : {
4678 1 : eAccess = GA_Update;
4679 1 : }
4680 :
4681 1 : CPLErr SetGeoTransform(const GDALGeoTransform &) override
4682 : {
4683 1 : return CE_Failure;
4684 : }
4685 : };
4686 :
4687 1 : auto datasetArg = edit->GetArg("dataset");
4688 1 : ASSERT_NE(datasetArg, nullptr);
4689 1 : datasetArg->Get<GDALArgDatasetValue>().Set(std::make_unique<MyDataset>());
4690 :
4691 1 : auto extentArg = edit->GetArg("bbox");
4692 1 : ASSERT_NE(extentArg, nullptr);
4693 1 : extentArg->Set(std::vector<double>{2, 49, 3, 50});
4694 :
4695 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4696 1 : CPLErrorReset();
4697 1 : EXPECT_FALSE(edit->Run());
4698 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4699 1 : EXPECT_STREQ(CPLGetLastErrorMsg(), "edit: Setting extent failed");
4700 : }
4701 :
4702 4 : TEST_F(test_gdal_algorithm, raster_edit_failures_set_metadata)
4703 : {
4704 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4705 2 : auto raster = singleton.Instantiate("raster");
4706 1 : ASSERT_NE(raster, nullptr);
4707 2 : auto edit = raster->InstantiateSubAlgorithm("edit");
4708 1 : ASSERT_NE(edit, nullptr);
4709 :
4710 : class MyDataset : public GDALDataset
4711 : {
4712 : public:
4713 1 : MyDataset()
4714 1 : {
4715 1 : eAccess = GA_Update;
4716 1 : }
4717 :
4718 1 : CPLErr SetMetadataItem(const char *, const char *,
4719 : const char *) override
4720 : {
4721 1 : return CE_Failure;
4722 : }
4723 : };
4724 :
4725 1 : auto datasetArg = edit->GetArg("dataset");
4726 1 : ASSERT_NE(datasetArg, nullptr);
4727 1 : datasetArg->Get<GDALArgDatasetValue>().Set(std::make_unique<MyDataset>());
4728 :
4729 1 : auto extentArg = edit->GetArg("metadata");
4730 1 : ASSERT_NE(extentArg, nullptr);
4731 2 : extentArg->Set(std::vector<std::string>{"foo=bar"});
4732 :
4733 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4734 1 : CPLErrorReset();
4735 1 : EXPECT_FALSE(edit->Run());
4736 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4737 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
4738 : "edit: SetMetadataItem('foo', 'bar') failed");
4739 : }
4740 :
4741 4 : TEST_F(test_gdal_algorithm, raster_edit_failures_unset_metadata)
4742 : {
4743 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4744 2 : auto raster = singleton.Instantiate("raster");
4745 1 : ASSERT_NE(raster, nullptr);
4746 2 : auto edit = raster->InstantiateSubAlgorithm("edit");
4747 1 : ASSERT_NE(edit, nullptr);
4748 :
4749 : class MyDataset : public GDALDataset
4750 : {
4751 : public:
4752 1 : MyDataset()
4753 1 : {
4754 1 : eAccess = GA_Update;
4755 1 : }
4756 :
4757 1 : CPLErr SetMetadataItem(const char *, const char *,
4758 : const char *) override
4759 : {
4760 1 : return CE_Failure;
4761 : }
4762 : };
4763 :
4764 1 : auto datasetArg = edit->GetArg("dataset");
4765 1 : ASSERT_NE(datasetArg, nullptr);
4766 1 : datasetArg->Get<GDALArgDatasetValue>().Set(std::make_unique<MyDataset>());
4767 :
4768 1 : auto extentArg = edit->GetArg("unset-metadata");
4769 1 : ASSERT_NE(extentArg, nullptr);
4770 2 : extentArg->Set(std::vector<std::string>{"foo"});
4771 :
4772 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4773 1 : CPLErrorReset();
4774 1 : EXPECT_FALSE(edit->Run());
4775 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4776 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
4777 : "edit: SetMetadataItem('foo', NULL) failed");
4778 : }
4779 :
4780 4 : TEST_F(test_gdal_algorithm, register_plugin_algorithms)
4781 : {
4782 1 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
4783 1 : bool flag = false;
4784 3 : singleton.DeclareAlgorithm(
4785 : {"foo", "bar"},
4786 5 : [&flag]() -> std::unique_ptr<GDALAlgorithm>
4787 : {
4788 5 : flag = true;
4789 5 : return std::make_unique<GDALContainerAlgorithm>("dummy");
4790 2 : });
4791 :
4792 : {
4793 2 : EXPECT_NE(singleton.Instantiate("foo"), nullptr);
4794 1 : EXPECT_FALSE(flag);
4795 : }
4796 :
4797 : {
4798 5 : auto got = singleton.GetDeclaredSubAlgorithmNames({"gdal"});
4799 1 : EXPECT_TRUE(std::find(got.begin(), got.end(), "foo") != got.end());
4800 1 : EXPECT_FALSE(flag);
4801 : }
4802 :
4803 : {
4804 5 : auto got = singleton.GetDeclaredSubAlgorithmNames({"gdal", "foo"});
4805 1 : EXPECT_TRUE(std::find(got.begin(), got.end(), "bar") != got.end());
4806 1 : EXPECT_TRUE(flag);
4807 1 : flag = false;
4808 : }
4809 :
4810 : {
4811 : auto got =
4812 7 : singleton.GetDeclaredSubAlgorithmNames({"gdal", "foo", "bar"});
4813 1 : EXPECT_TRUE(got.empty());
4814 1 : EXPECT_FALSE(flag);
4815 : }
4816 :
4817 : {
4818 6 : auto got = singleton.GetDeclaredSubAlgorithmNames({"gdal", "bar"});
4819 1 : EXPECT_TRUE(got.empty());
4820 1 : EXPECT_FALSE(flag);
4821 : }
4822 :
4823 : {
4824 5 : auto alg = singleton.InstantiateDeclaredSubAlgorithm({"gdal", "foo"});
4825 1 : ASSERT_NE(alg, nullptr);
4826 1 : EXPECT_TRUE(alg->HasSubAlgorithms());
4827 1 : EXPECT_EQ(alg->GetSubAlgorithmNames().size(), 1);
4828 1 : EXPECT_TRUE(flag);
4829 1 : flag = false;
4830 : }
4831 :
4832 : {
4833 : auto alg =
4834 6 : singleton.InstantiateDeclaredSubAlgorithm({"gdal", "foo", "bar"});
4835 1 : ASSERT_NE(alg, nullptr);
4836 1 : EXPECT_TRUE(flag);
4837 1 : flag = false;
4838 : }
4839 :
4840 : {
4841 2 : auto alg = singleton.Instantiate("foo")->InstantiateSubAlgorithm("bar");
4842 1 : ASSERT_NE(alg, nullptr);
4843 1 : EXPECT_TRUE(flag);
4844 : }
4845 :
4846 : {
4847 5 : auto alg = singleton.InstantiateDeclaredSubAlgorithm({"gdal", "bar"});
4848 1 : ASSERT_EQ(alg, nullptr);
4849 : }
4850 :
4851 3 : singleton.DeclareAlgorithm({"foo", "bar"},
4852 0 : []() -> std::unique_ptr<GDALAlgorithm>
4853 2 : { return nullptr; });
4854 : }
4855 :
4856 4 : TEST_F(test_gdal_algorithm, AddNumThreadsArg)
4857 : {
4858 : class MyAlgorithm : public MyAlgorithmWithDummyRun
4859 : {
4860 : public:
4861 : int m_numThreads = 0;
4862 : std::string m_numThreadsStr{"ALL_CPUS"};
4863 :
4864 9 : MyAlgorithm()
4865 9 : {
4866 9 : AddNumThreadsArg(&m_numThreads, &m_numThreadsStr);
4867 9 : }
4868 : };
4869 :
4870 : {
4871 2 : MyAlgorithm alg;
4872 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
4873 1 : EXPECT_EQ(alg.m_numThreads, CPLGetNumCPUs());
4874 : }
4875 :
4876 : {
4877 2 : CPLConfigOptionSetter oSetter("GDAL_NUM_THREADS", "1", false);
4878 2 : MyAlgorithm alg;
4879 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
4880 1 : EXPECT_EQ(alg.m_numThreads, 1);
4881 : }
4882 :
4883 : {
4884 2 : CPLConfigOptionSetter oSetter("GDAL_NUM_THREADS", "ALL_CPUS", false);
4885 2 : MyAlgorithm alg;
4886 1 : EXPECT_TRUE(alg.ParseCommandLineArguments({}));
4887 1 : EXPECT_EQ(alg.m_numThreads, CPLGetNumCPUs());
4888 : }
4889 :
4890 : {
4891 2 : MyAlgorithm alg;
4892 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--num-threads=1"}));
4893 1 : EXPECT_EQ(alg.m_numThreads, 1);
4894 : }
4895 :
4896 : {
4897 2 : MyAlgorithm alg;
4898 3 : EXPECT_TRUE(
4899 : alg.ParseCommandLineArguments({"--num-threads=2147483647"}));
4900 1 : EXPECT_EQ(alg.m_numThreads, CPLGetNumCPUs());
4901 : }
4902 :
4903 : {
4904 2 : MyAlgorithm alg;
4905 3 : EXPECT_TRUE(alg.ParseCommandLineArguments({"--num-threads=ALL_CPUS"}));
4906 1 : EXPECT_EQ(alg.m_numThreads, CPLGetNumCPUs());
4907 : }
4908 :
4909 : {
4910 2 : MyAlgorithm alg;
4911 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
4912 1 : CPLErrorReset();
4913 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"num-threads=invalid"}));
4914 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4915 : }
4916 :
4917 : {
4918 2 : MyAlgorithm alg;
4919 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
4920 1 : CPLErrorReset();
4921 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"num-threads=-1"}));
4922 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4923 : }
4924 :
4925 : {
4926 2 : MyAlgorithm alg;
4927 2 : CPLErrorStateBackuper oErrorHandler(CPLQuietErrorHandler);
4928 1 : CPLErrorReset();
4929 3 : EXPECT_FALSE(alg.ParseCommandLineArguments({"num-threads=2147483648"}));
4930 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_Failure);
4931 : }
4932 1 : }
4933 :
4934 4 : TEST_F(test_gdal_algorithm, AddAppendLayerArg_without_update)
4935 : {
4936 : class MyAlgorithm : public MyAlgorithmWithDummyRun
4937 : {
4938 : public:
4939 : bool m_boolean = false;
4940 :
4941 1 : MyAlgorithm()
4942 1 : {
4943 1 : AddAppendLayerArg(&m_boolean);
4944 1 : }
4945 : };
4946 :
4947 : {
4948 2 : MyAlgorithm alg;
4949 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4950 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
4951 1 : EXPECT_STREQ(
4952 : CPLGetLastErrorMsg(),
4953 : "test: --update argument must exist for --append, even if hidden");
4954 : }
4955 1 : }
4956 :
4957 4 : TEST_F(test_gdal_algorithm, AddOverwriteLayerArg_without_update)
4958 : {
4959 : class MyAlgorithm : public MyAlgorithmWithDummyRun
4960 : {
4961 : public:
4962 : bool m_boolean = false;
4963 :
4964 1 : MyAlgorithm()
4965 1 : {
4966 1 : AddOverwriteLayerArg(&m_boolean);
4967 1 : }
4968 : };
4969 :
4970 : {
4971 2 : MyAlgorithm alg;
4972 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
4973 1 : EXPECT_FALSE(alg.ParseCommandLineArguments({}));
4974 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
4975 : "test: --update argument must exist for "
4976 : "--overwrite-layer, even if hidden");
4977 : }
4978 1 : }
4979 :
4980 : } // namespace test_gdal_algorithm
4981 :
4982 : #if defined(__clang__)
4983 : #pragma clang diagnostic pop
4984 : #endif
|