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