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