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