1 // Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
2 // under NSF AWARD 1414736 and by the respective contributors.
3 // All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6
7 #include "app_helper.hpp"
8
9 #include <array>
10 #include <atomic>
11 #include <complex>
12 #include <cstdint>
13 #include <cstdio>
14 #include <fstream>
15 #include <limits>
16 #include <map>
17 #include <string>
18 #include <tuple>
19 #include <unordered_map>
20 #include <utility>
21
22 class NotStreamable {};
23
24 class Streamable {};
25
operator <<(std::ostream & out,const Streamable &)26 std::ostream &operator<<(std::ostream &out, const Streamable &) { return out << "Streamable"; }
27
28 TEST_CASE("TypeTools: Streaming", "[helpers]") {
29
30 CHECK("" == CLI::detail::to_string(NotStreamable{}));
31
32 CHECK("Streamable" == CLI::detail::to_string(Streamable{}));
33
34 CHECK("5" == CLI::detail::to_string(5));
35
36 CHECK(std::string("string") == CLI::detail::to_string("string"));
37 CHECK(std::string("string") == CLI::detail::to_string(std::string("string")));
38 }
39
40 TEST_CASE("TypeTools: tuple", "[helpers]") {
41 CHECK_FALSE(CLI::detail::is_tuple_like<int>::value);
42 CHECK_FALSE(CLI::detail::is_tuple_like<std::vector<double>>::value);
43 auto v = CLI::detail::is_tuple_like<std::tuple<double, int>>::value;
44 CHECK(v);
45 v = CLI::detail::is_tuple_like<std::tuple<double, double, double>>::value;
46 CHECK(v);
47 }
48
49 TEST_CASE("TypeTools: type_size", "[helpers]") {
50 auto V = CLI::detail::type_count<int>::value;
51 CHECK(1 == V);
52 V = CLI::detail::type_count<void>::value;
53 CHECK(0 == V);
54 V = CLI::detail::type_count<std::vector<double>>::value;
55 CHECK(1 == V);
56 V = CLI::detail::type_count<std::tuple<double, int>>::value;
57 CHECK(2 == V);
58 V = CLI::detail::type_count<std::tuple<std::string, double, int>>::value;
59 CHECK(3 == V);
60 V = CLI::detail::type_count<std::array<std::string, 5>>::value;
61 CHECK(5 == V);
62 V = CLI::detail::type_count<std::vector<std::pair<std::string, double>>>::value;
63 CHECK(2 == V);
64 V = CLI::detail::type_count<std::tuple<std::pair<std::string, double>>>::value;
65 CHECK(2 == V);
66 V = CLI::detail::type_count<std::tuple<int, std::pair<std::string, double>>>::value;
67 CHECK(3 == V);
68 V = CLI::detail::type_count<std::tuple<std::pair<int, double>, std::pair<std::string, double>>>::value;
69 CHECK(4 == V);
70 // maps
71 V = CLI::detail::type_count<std::map<int, std::pair<int, double>>>::value;
72 CHECK(3 == V);
73 // three level tuples
74 V = CLI::detail::type_count<std::tuple<int, std::pair<int, std::tuple<int, double, std::string>>>>::value;
75 CHECK(5 == V);
76 V = CLI::detail::type_count<std::pair<int, std::vector<int>>>::value;
77 CHECK(CLI::detail::expected_max_vector_size <= V);
78 V = CLI::detail::type_count<std::vector<std::vector<int>>>::value;
79 CHECK(CLI::detail::expected_max_vector_size == V);
80 }
81
82 TEST_CASE("TypeTools: type_size_min", "[helpers]") {
83 auto V = CLI::detail::type_count_min<int>::value;
84 CHECK(1 == V);
85 V = CLI::detail::type_count_min<void>::value;
86 CHECK(0 == V);
87 V = CLI::detail::type_count_min<std::vector<double>>::value;
88 CHECK(1 == V);
89 V = CLI::detail::type_count_min<std::tuple<double, int>>::value;
90 CHECK(2 == V);
91 V = CLI::detail::type_count_min<std::tuple<std::string, double, int>>::value;
92 CHECK(3 == V);
93 V = CLI::detail::type_count_min<std::array<std::string, 5>>::value;
94 CHECK(5 == V);
95 V = CLI::detail::type_count_min<std::vector<std::pair<std::string, double>>>::value;
96 CHECK(2 == V);
97 V = CLI::detail::type_count_min<std::tuple<std::pair<std::string, double>>>::value;
98 CHECK(2 == V);
99 V = CLI::detail::type_count_min<std::tuple<int, std::pair<std::string, double>>>::value;
100 CHECK(3 == V);
101 V = CLI::detail::type_count_min<std::tuple<std::pair<int, double>, std::pair<std::string, double>>>::value;
102 CHECK(4 == V);
103 // maps
104 V = CLI::detail::type_count_min<std::map<int, std::pair<int, double>>>::value;
105 CHECK(3 == V);
106 // three level tuples
107 V = CLI::detail::type_count_min<std::tuple<int, std::pair<int, std::tuple<int, double, std::string>>>>::value;
108 CHECK(5 == V);
109 V = CLI::detail::type_count_min<std::pair<int, std::vector<int>>>::value;
110 CHECK(2 == V);
111 V = CLI::detail::type_count_min<std::vector<std::vector<int>>>::value;
112 CHECK(1 == V);
113 V = CLI::detail::type_count_min<std::vector<std::vector<std::pair<int, int>>>>::value;
114 CHECK(2 == V);
115 }
116
117 TEST_CASE("TypeTools: expected_count", "[helpers]") {
118 auto V = CLI::detail::expected_count<int>::value;
119 CHECK(1 == V);
120 V = CLI::detail::expected_count<void>::value;
121 CHECK(0 == V);
122 V = CLI::detail::expected_count<std::vector<double>>::value;
123 CHECK(CLI::detail::expected_max_vector_size == V);
124 V = CLI::detail::expected_count<std::tuple<double, int>>::value;
125 CHECK(1 == V);
126 V = CLI::detail::expected_count<std::tuple<std::string, double, int>>::value;
127 CHECK(1 == V);
128 V = CLI::detail::expected_count<std::array<std::string, 5>>::value;
129 CHECK(1 == V);
130 V = CLI::detail::expected_count<std::vector<std::pair<std::string, double>>>::value;
131 CHECK(CLI::detail::expected_max_vector_size == V);
132 }
133
134 TEST_CASE("Split: SimpleByToken", "[helpers]") {
135 auto out = CLI::detail::split("one.two.three", '.');
136 REQUIRE(out.size() == 3u);
137 CHECK(out.at(0) == "one");
138 CHECK(out.at(1) == "two");
139 CHECK(out.at(2) == "three");
140 }
141
142 TEST_CASE("Split: Single", "[helpers]") {
143 auto out = CLI::detail::split("one", '.');
144 REQUIRE(out.size() == 1u);
145 CHECK(out.at(0) == "one");
146 }
147
148 TEST_CASE("Split: Empty", "[helpers]") {
149 auto out = CLI::detail::split("", '.');
150 REQUIRE(out.size() == 1u);
151 CHECK(out.at(0) == "");
152 }
153
154 TEST_CASE("String: InvalidName", "[helpers]") {
155 CHECK(CLI::detail::valid_name_string("valid"));
156 CHECK_FALSE(CLI::detail::valid_name_string("-invalid"));
157 CHECK(CLI::detail::valid_name_string("va-li-d"));
158 CHECK_FALSE(CLI::detail::valid_name_string("valid{}"));
159 CHECK(CLI::detail::valid_name_string("_valid"));
160 CHECK(CLI::detail::valid_name_string("/valid"));
161 CHECK(CLI::detail::valid_name_string("vali?d"));
162 CHECK(CLI::detail::valid_name_string("@@@@"));
163 CHECK(CLI::detail::valid_name_string("b@d2?"));
164 CHECK(CLI::detail::valid_name_string("2vali?d"));
165 CHECK_FALSE(CLI::detail::valid_name_string("!valid"));
166 }
167
168 TEST_CASE("StringTools: Modify", "[helpers]") {
169 int cnt{0};
__anon26387f5f0102(std::string &str, std::size_t index) 170 std::string newString = CLI::detail::find_and_modify("======", "=", [&cnt](std::string &str, std::size_t index) {
171 if((++cnt) % 2 == 0) {
172 str[index] = ':';
173 }
174 return index + 1;
175 });
176 CHECK("=:=:=:" == newString);
177 }
178
179 TEST_CASE("StringTools: Modify2", "[helpers]") {
180 std::string newString =
__anon26387f5f0202(std::string &str, std::size_t index) 181 CLI::detail::find_and_modify("this is a string test", "is", [](std::string &str, std::size_t index) {
182 if((index > 1) && (str[index - 1] != ' ')) {
183 str[index] = 'a';
184 str[index + 1] = 't';
185 }
186 return index + 1;
187 });
188 CHECK("that is a string test" == newString);
189 }
190
191 TEST_CASE("StringTools: Modify3", "[helpers]") {
192 // this picks up 3 sets of 3 after the 'b' then collapses the new first set
__anon26387f5f0302(std::string &str, std::size_t index) 193 std::string newString = CLI::detail::find_and_modify("baaaaaaaaaa", "aaa", [](std::string &str, std::size_t index) {
194 str.erase(index, 3);
195 str.insert(str.begin(), 'a');
196 return 0u;
197 });
198 CHECK("aba" == newString);
199 }
200
201 TEST_CASE("StringTools: flagValues", "[helpers]") {
202 CHECK(-1 == CLI::detail::to_flag_value("0"));
203 CHECK(1 == CLI::detail::to_flag_value("t"));
204 CHECK(1 == CLI::detail::to_flag_value("1"));
205 CHECK(6 == CLI::detail::to_flag_value("6"));
206 CHECK(-6 == CLI::detail::to_flag_value("-6"));
207 CHECK(-1 == CLI::detail::to_flag_value("false"));
208 CHECK(1 == CLI::detail::to_flag_value("YES"));
209 CHECK_THROWS_AS(CLI::detail::to_flag_value("frog"), std::invalid_argument);
210 CHECK_THROWS_AS(CLI::detail::to_flag_value("q"), std::invalid_argument);
211 CHECK(-1 == CLI::detail::to_flag_value("NO"));
212 CHECK(475555233 == CLI::detail::to_flag_value("475555233"));
213 }
214
215 TEST_CASE("StringTools: Validation", "[helpers]") {
216 CHECK(CLI::detail::isalpha(""));
217 CHECK(CLI::detail::isalpha("a"));
218 CHECK(CLI::detail::isalpha("abcd"));
219 CHECK_FALSE(CLI::detail::isalpha("_"));
220 CHECK_FALSE(CLI::detail::isalpha("2"));
221 CHECK_FALSE(CLI::detail::isalpha("test test"));
222 CHECK_FALSE(CLI::detail::isalpha("test "));
223 CHECK_FALSE(CLI::detail::isalpha(" test"));
224 CHECK_FALSE(CLI::detail::isalpha("test2"));
225 }
226
227 TEST_CASE("Trim: Various", "[helpers]") {
228 std::string s1{" sdlfkj sdflk sd s "};
229 std::string a1{"sdlfkj sdflk sd s"};
230 CLI::detail::trim(s1);
231 CHECK(s1 == a1);
232
233 std::string s2{" a \t"};
234 CLI::detail::trim(s2);
235 CHECK(s2 == "a");
236
237 std::string s3{" a \n"};
238 CLI::detail::trim(s3);
239 CHECK(s3 == "a");
240
241 std::string s4{" a b "};
242 CHECK(CLI::detail::trim(s4) == "a b");
243 }
244
245 TEST_CASE("Trim: VariousFilters", "[helpers]") {
246 std::string s1{" sdlfkj sdflk sd s "};
247 std::string a1{"sdlfkj sdflk sd s"};
248 CLI::detail::trim(s1, " ");
249 CHECK(s1 == a1);
250
251 std::string s2{" a \t"};
252 CLI::detail::trim(s2, " ");
253 CHECK(s2 == "a \t");
254
255 std::string s3{"abdavda"};
256 CLI::detail::trim(s3, "a");
257 CHECK(s3 == "bdavd");
258
259 std::string s4{"abcabcabc"};
260 CHECK(CLI::detail::trim(s4, "ab") == "cabcabc");
261 }
262
263 TEST_CASE("Trim: TrimCopy", "[helpers]") {
264 std::string orig{" cabc "};
265 std::string trimmed = CLI::detail::trim_copy(orig);
266 CHECK(trimmed == "cabc");
267 CHECK(trimmed != orig);
268 CLI::detail::trim(orig);
269 CHECK(orig == trimmed);
270
271 orig = "abcabcabc";
272 trimmed = CLI::detail::trim_copy(orig, "ab");
273 CHECK(trimmed == "cabcabc");
274 CHECK(trimmed != orig);
275 CLI::detail::trim(orig, "ab");
276 CHECK(orig == trimmed);
277 }
278
279 TEST_CASE("Validators: FileExists", "[helpers]") {
280 std::string myfile{"TestFileNotUsed.txt"};
281 CHECK_FALSE(CLI::ExistingFile(myfile).empty());
282 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
283 CHECK(ok);
284 CHECK(CLI::ExistingFile(myfile).empty());
285
286 std::remove(myfile.c_str());
287 CHECK_FALSE(CLI::ExistingFile(myfile).empty());
288 }
289
290 TEST_CASE("Validators: FileNotExists", "[helpers]") {
291 std::string myfile{"TestFileNotUsed.txt"};
292 CHECK(CLI::NonexistentPath(myfile).empty());
293 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
294 CHECK(ok);
295 CHECK_FALSE(CLI::NonexistentPath(myfile).empty());
296
297 std::remove(myfile.c_str());
298 CHECK(CLI::NonexistentPath(myfile).empty());
299 }
300
301 TEST_CASE("Validators: FileIsDir", "[helpers]") {
302 std::string mydir{"../tests"};
303 CHECK("" != CLI::ExistingFile(mydir));
304 }
305
306 TEST_CASE("Validators: DirectoryExists", "[helpers]") {
307 std::string mydir{"../tests"};
308 CHECK("" == CLI::ExistingDirectory(mydir));
309 }
310
311 TEST_CASE("Validators: DirectoryNotExists", "[helpers]") {
312 std::string mydir{"nondirectory"};
313 CHECK("" != CLI::ExistingDirectory(mydir));
314 }
315
316 TEST_CASE("Validators: DirectoryIsFile", "[helpers]") {
317 std::string myfile{"TestFileNotUsed.txt"};
318 CHECK(CLI::NonexistentPath(myfile).empty());
319 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
320 CHECK(ok);
321 CHECK_FALSE(CLI::ExistingDirectory(myfile).empty());
322
323 std::remove(myfile.c_str());
324 CHECK(CLI::NonexistentPath(myfile).empty());
325 }
326
327 TEST_CASE("Validators: PathExistsDir", "[helpers]") {
328 std::string mydir{"../tests"};
329 CHECK("" == CLI::ExistingPath(mydir));
330 }
331
332 TEST_CASE("Validators: PathExistsFile", "[helpers]") {
333 std::string myfile{"TestFileNotUsed.txt"};
334 CHECK_FALSE(CLI::ExistingPath(myfile).empty());
335 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
336 CHECK(ok);
337 CHECK(CLI::ExistingPath(myfile).empty());
338
339 std::remove(myfile.c_str());
340 CHECK_FALSE(CLI::ExistingPath(myfile).empty());
341 }
342
343 TEST_CASE("Validators: PathNotExistsDir", "[helpers]") {
344 std::string mydir{"nonpath"};
345 CHECK("" != CLI::ExistingPath(mydir));
346 }
347
348 TEST_CASE("Validators: IPValidate1", "[helpers]") {
349 std::string ip = "1.1.1.1";
350 CHECK(CLI::ValidIPV4(ip).empty());
351 ip = "224.255.0.1";
352 CHECK(CLI::ValidIPV4(ip).empty());
353 ip = "-1.255.0.1";
354 CHECK_FALSE(CLI::ValidIPV4(ip).empty());
355 ip = "1.256.0.1";
356 CHECK_FALSE(CLI::ValidIPV4(ip).empty());
357 ip = "1.256.0.1";
358 CHECK_FALSE(CLI::ValidIPV4(ip).empty());
359 ip = "aaa";
360 CHECK_FALSE(CLI::ValidIPV4(ip).empty());
361 ip = "1.2.3.abc";
362 CHECK_FALSE(CLI::ValidIPV4(ip).empty());
363 ip = "11.22";
364 CHECK_FALSE(CLI::ValidIPV4(ip).empty());
365 }
366
367 TEST_CASE("Validators: PositiveValidator", "[helpers]") {
368 std::string num = "1.1.1.1";
369 CHECK_FALSE(CLI::PositiveNumber(num).empty());
370 num = "1";
371 CHECK(CLI::PositiveNumber(num).empty());
372 num = "10000";
373 CHECK(CLI::PositiveNumber(num).empty());
374 num = "0";
375 CHECK_FALSE(CLI::PositiveNumber(num).empty());
376 num = "+0.5";
377 CHECK(CLI::PositiveNumber(num).empty());
378 num = "-1";
379 CHECK_FALSE(CLI::PositiveNumber(num).empty());
380 num = "-1.5";
381 CHECK_FALSE(CLI::PositiveNumber(num).empty());
382 num = "a";
383 CHECK_FALSE(CLI::PositiveNumber(num).empty());
384 }
385
386 TEST_CASE("Validators: NonNegativeValidator", "[helpers]") {
387 std::string num = "1.1.1.1";
388 CHECK_FALSE(CLI::NonNegativeNumber(num).empty());
389 num = "1";
390 CHECK(CLI::NonNegativeNumber(num).empty());
391 num = "10000";
392 CHECK(CLI::NonNegativeNumber(num).empty());
393 num = "0";
394 CHECK(CLI::NonNegativeNumber(num).empty());
395 num = "+0.5";
396 CHECK(CLI::NonNegativeNumber(num).empty());
397 num = "-1";
398 CHECK_FALSE(CLI::NonNegativeNumber(num).empty());
399 num = "-1.5";
400 CHECK_FALSE(CLI::NonNegativeNumber(num).empty());
401 num = "a";
402 CHECK_FALSE(CLI::NonNegativeNumber(num).empty());
403 }
404
405 TEST_CASE("Validators: NumberValidator", "[helpers]") {
406 std::string num = "1.1.1.1";
407 CHECK_FALSE(CLI::Number(num).empty());
408 num = "1.7";
409 CHECK(CLI::Number(num).empty());
410 num = "10000";
411 CHECK(CLI::Number(num).empty());
412 num = "-0.000";
413 CHECK(CLI::Number(num).empty());
414 num = "+1.55";
415 CHECK(CLI::Number(num).empty());
416 num = "a";
417 CHECK_FALSE(CLI::Number(num).empty());
418 }
419
420 TEST_CASE("Validators: CombinedAndRange", "[helpers]") {
421 auto crange = CLI::Range(0, 12) & CLI::Range(4, 16);
422 CHECK(crange("4").empty());
423 CHECK(crange("12").empty());
424 CHECK(crange("7").empty());
425
426 CHECK_FALSE(crange("-2").empty());
427 CHECK_FALSE(crange("2").empty());
428 CHECK_FALSE(crange("15").empty());
429 CHECK_FALSE(crange("16").empty());
430 CHECK_FALSE(crange("18").empty());
431 }
432
433 TEST_CASE("Validators: CombinedOrRange", "[helpers]") {
434 auto crange = CLI::Range(0, 4) | CLI::Range(8, 12);
435
436 CHECK_FALSE(crange("-2").empty());
437 CHECK(crange("2").empty());
438 CHECK_FALSE(crange("5").empty());
439 CHECK(crange("8").empty());
440 CHECK(crange("12").empty());
441 CHECK_FALSE(crange("16").empty());
442 }
443
444 TEST_CASE("Validators: CombinedPaths", "[helpers]") {
445 std::string myfile{"TestFileNotUsed.txt"};
446 CHECK_FALSE(CLI::ExistingFile(myfile).empty());
447 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
448 CHECK(ok);
449
450 std::string dir{"../tests"};
451 std::string notpath{"nondirectory"};
452
453 auto path_or_dir = CLI::ExistingPath | CLI::ExistingDirectory;
454 CHECK(path_or_dir(dir).empty());
455 CHECK(path_or_dir(myfile).empty());
456 CHECK_FALSE(path_or_dir(notpath).empty());
457
458 auto file_or_dir = CLI::ExistingFile | CLI::ExistingDirectory;
459 CHECK(file_or_dir(dir).empty());
460 CHECK(file_or_dir(myfile).empty());
461 CHECK_FALSE(file_or_dir(notpath).empty());
462
463 auto path_and_dir = CLI::ExistingPath & CLI::ExistingDirectory;
464 CHECK(path_and_dir(dir).empty());
465 CHECK_FALSE(path_and_dir(myfile).empty());
466 CHECK_FALSE(path_and_dir(notpath).empty());
467
468 auto path_and_file = CLI::ExistingFile & CLI::ExistingDirectory;
469 CHECK_FALSE(path_and_file(dir).empty());
470 CHECK_FALSE(path_and_file(myfile).empty());
471 CHECK_FALSE(path_and_file(notpath).empty());
472
473 std::remove(myfile.c_str());
474 CHECK_FALSE(CLI::ExistingFile(myfile).empty());
475 }
476
477 TEST_CASE("Validators: ProgramNameSplit", "[helpers]") {
478 TempFile myfile{"program_name1.exe"};
479 {
480 std::ofstream out{myfile};
481 out << "useless string doesn't matter" << std::endl;
482 }
483 auto res =
484 CLI::detail::split_program_name(std::string("./") + std::string(myfile) + " this is a bunch of extra stuff ");
485 CHECK(std::string("./") + std::string(myfile) == res.first);
486 CHECK("this is a bunch of extra stuff" == res.second);
487
488 TempFile myfile2{"program name1.exe"};
489 {
490 std::ofstream out{myfile2};
491 out << "useless string doesn't matter" << std::endl;
492 }
493 res = CLI::detail::split_program_name(std::string(" ") + std::string("./") + std::string(myfile2) +
494 " this is a bunch of extra stuff ");
495 CHECK(std::string("./") + std::string(myfile2) == res.first);
496 CHECK("this is a bunch of extra stuff" == res.second);
497
498 res = CLI::detail::split_program_name("./program_name this is a bunch of extra stuff ");
499 CHECK("./program_name" == res.first);
500 CHECK("this is a bunch of extra stuff" == res.second);
501
502 res = CLI::detail::split_program_name(std::string(" ./") + std::string(myfile) + " ");
503 CHECK(std::string("./") + std::string(myfile) == res.first);
504 CHECK(res.second.empty());
505 }
506
507 TEST_CASE("CheckedMultiply: Int", "[helpers]") {
508 int a{10};
509 int b{-20};
510 REQUIRE(CLI::detail::checked_multiply(a, b));
511 REQUIRE(-200 == a);
512
513 a = 0;
514 b = -20;
515 REQUIRE(CLI::detail::checked_multiply(a, b));
516 REQUIRE(0 == a);
517
518 a = 20;
519 b = 0;
520 REQUIRE(CLI::detail::checked_multiply(a, b));
521 REQUIRE(0 == a);
522
523 a = std::numeric_limits<int>::max();
524 b = 1;
525 REQUIRE(CLI::detail::checked_multiply(a, b));
526 REQUIRE(std::numeric_limits<int>::max() == a);
527
528 a = std::numeric_limits<int>::max();
529 b = 2;
530 REQUIRE(!CLI::detail::checked_multiply(a, b));
531 REQUIRE(std::numeric_limits<int>::max() == a);
532
533 a = std::numeric_limits<int>::max();
534 b = -1;
535 REQUIRE(CLI::detail::checked_multiply(a, b));
536 REQUIRE(-std::numeric_limits<int>::max() == a);
537
538 a = std::numeric_limits<int>::max();
539 b = std::numeric_limits<int>::max();
540 REQUIRE(!CLI::detail::checked_multiply(a, b));
541 REQUIRE(std::numeric_limits<int>::max() == a);
542
543 a = std::numeric_limits<int>::min();
544 b = std::numeric_limits<int>::max();
545 REQUIRE(!CLI::detail::checked_multiply(a, b));
546 REQUIRE(std::numeric_limits<int>::min() == a);
547
548 a = std::numeric_limits<int>::min();
549 b = 1;
550 REQUIRE(CLI::detail::checked_multiply(a, b));
551 REQUIRE(std::numeric_limits<int>::min() == a);
552
553 a = std::numeric_limits<int>::min();
554 b = -1;
555 REQUIRE(!CLI::detail::checked_multiply(a, b));
556 REQUIRE(std::numeric_limits<int>::min() == a);
557
558 b = std::numeric_limits<int>::min();
559 a = -1;
560 REQUIRE(!CLI::detail::checked_multiply(a, b));
561 REQUIRE(-1 == a);
562
563 a = std::numeric_limits<int>::min() / 100;
564 b = 99;
565 REQUIRE(CLI::detail::checked_multiply(a, b));
566 REQUIRE(std::numeric_limits<int>::min() / 100 * 99 == a);
567
568 a = std::numeric_limits<int>::min() / 100;
569 b = -101;
570 REQUIRE(!CLI::detail::checked_multiply(a, b));
571 REQUIRE(std::numeric_limits<int>::min() / 100 == a);
572 a = 2;
573 b = std::numeric_limits<int>::min() / 2;
574 REQUIRE(CLI::detail::checked_multiply(a, b));
575 a = std::numeric_limits<int>::min() / 2;
576 b = 2;
577 REQUIRE(CLI::detail::checked_multiply(a, b));
578
579 a = 4;
580 b = std::numeric_limits<int>::min() / 4;
581 REQUIRE(CLI::detail::checked_multiply(a, b));
582
583 a = 48;
584 b = std::numeric_limits<int>::min() / 48;
585 REQUIRE(CLI::detail::checked_multiply(a, b));
586 }
587
588 TEST_CASE("CheckedMultiply: SizeT", "[helpers]") {
589 std::size_t a = 10;
590 std::size_t b = 20;
591 REQUIRE(CLI::detail::checked_multiply(a, b));
592 REQUIRE(200u == a);
593
594 a = 0u;
595 b = 20u;
596 REQUIRE(CLI::detail::checked_multiply(a, b));
597 REQUIRE(0u == a);
598
599 a = 20u;
600 b = 0u;
601 REQUIRE(CLI::detail::checked_multiply(a, b));
602 REQUIRE(0u == a);
603
604 a = std::numeric_limits<std::size_t>::max();
605 b = 1u;
606 REQUIRE(CLI::detail::checked_multiply(a, b));
607 REQUIRE(std::numeric_limits<std::size_t>::max() == a);
608
609 a = std::numeric_limits<std::size_t>::max();
610 b = 2u;
611 REQUIRE(!CLI::detail::checked_multiply(a, b));
612 REQUIRE(std::numeric_limits<std::size_t>::max() == a);
613
614 a = std::numeric_limits<std::size_t>::max();
615 b = std::numeric_limits<std::size_t>::max();
616 REQUIRE(!CLI::detail::checked_multiply(a, b));
617 REQUIRE(std::numeric_limits<std::size_t>::max() == a);
618
619 a = std::numeric_limits<std::size_t>::max() / 100;
620 b = 99u;
621 REQUIRE(CLI::detail::checked_multiply(a, b));
622 REQUIRE(std::numeric_limits<std::size_t>::max() / 100u * 99u == a);
623 }
624
625 TEST_CASE("CheckedMultiply: Float", "[helpers]") {
626 float a{10.0F};
627 float b{20.0F};
628 REQUIRE(CLI::detail::checked_multiply(a, b));
629 REQUIRE(200 == Approx(a));
630
631 a = 0.0F;
632 b = 20.0F;
633 REQUIRE(CLI::detail::checked_multiply(a, b));
634 REQUIRE(0 == Approx(a));
635
636 a = INFINITY;
637 b = 20.0F;
638 REQUIRE(CLI::detail::checked_multiply(a, b));
639 REQUIRE(INFINITY == Approx(a));
640
641 a = 2.0F;
642 b = -INFINITY;
643 REQUIRE(CLI::detail::checked_multiply(a, b));
644 REQUIRE(-INFINITY == Approx(a));
645
646 a = std::numeric_limits<float>::max() / 100.0F;
647 b = 1.0F;
648 REQUIRE(CLI::detail::checked_multiply(a, b));
649 REQUIRE(std::numeric_limits<float>::max() / 100.0F == Approx(a));
650
651 a = std::numeric_limits<float>::max() / 100.0F;
652 b = 99.0F;
653 REQUIRE(CLI::detail::checked_multiply(a, b));
654 REQUIRE(std::numeric_limits<float>::max() / 100.0F * 99.0F == Approx(a));
655
656 a = std::numeric_limits<float>::max() / 100.0F;
657 b = 101;
658 REQUIRE(!CLI::detail::checked_multiply(a, b));
659 REQUIRE(std::numeric_limits<float>::max() / 100.0F == Approx(a));
660
661 a = std::numeric_limits<float>::max() / 100.0F;
662 b = -99;
663 REQUIRE(CLI::detail::checked_multiply(a, b));
664 REQUIRE(std::numeric_limits<float>::max() / 100.0F * -99.0F == Approx(a));
665
666 a = std::numeric_limits<float>::max() / 100.0F;
667 b = -101;
668 REQUIRE(!CLI::detail::checked_multiply(a, b));
669 REQUIRE(std::numeric_limits<float>::max() / 100.0F == Approx(a));
670 }
671
672 TEST_CASE("CheckedMultiply: Double", "[helpers]") {
673 double a{10.0F};
674 double b{20.0F};
675 REQUIRE(CLI::detail::checked_multiply(a, b));
676 REQUIRE(200 == Approx(a));
677
678 a = 0;
679 b = 20;
680 REQUIRE(CLI::detail::checked_multiply(a, b));
681 REQUIRE(0 == Approx(a));
682
683 a = INFINITY;
684 b = 20;
685 REQUIRE(CLI::detail::checked_multiply(a, b));
686 REQUIRE(INFINITY == Approx(a));
687
688 a = 2;
689 b = -INFINITY;
690 REQUIRE(CLI::detail::checked_multiply(a, b));
691 REQUIRE(-INFINITY == Approx(a));
692
693 a = std::numeric_limits<double>::max() / 100;
694 b = 1;
695 REQUIRE(CLI::detail::checked_multiply(a, b));
696 REQUIRE(std::numeric_limits<double>::max() / 100 == Approx(a));
697
698 a = std::numeric_limits<double>::max() / 100;
699 b = 99;
700 REQUIRE(CLI::detail::checked_multiply(a, b));
701 REQUIRE(std::numeric_limits<double>::max() / 100 * 99 == Approx(a));
702
703 a = std::numeric_limits<double>::max() / 100;
704 b = 101;
705 REQUIRE(!CLI::detail::checked_multiply(a, b));
706 REQUIRE(std::numeric_limits<double>::max() / 100 == Approx(a));
707
708 a = std::numeric_limits<double>::max() / 100;
709 b = -99;
710 REQUIRE(CLI::detail::checked_multiply(a, b));
711 REQUIRE(std::numeric_limits<double>::max() / 100 * -99 == Approx(a));
712
713 a = std::numeric_limits<double>::max() / 100;
714 b = -101;
715 REQUIRE(!CLI::detail::checked_multiply(a, b));
716 REQUIRE(std::numeric_limits<double>::max() / 100 == Approx(a));
717 }
718
719 // Yes, this is testing an app_helper :)
720 TEST_CASE("AppHelper: TempfileCreated", "[helpers]") {
721 std::string name = "TestFileNotUsed.txt";
722 {
723 TempFile myfile{name};
724
725 CHECK_FALSE(CLI::ExistingFile(myfile).empty());
726
727 bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
728 CHECK(ok);
729 CHECK(CLI::ExistingFile(name).empty());
__anon26387f5f0402() 730 CHECK_THROWS_AS([&]() { TempFile otherfile(name); }(), std::runtime_error);
731 }
732 CHECK_FALSE(CLI::ExistingFile(name).empty());
733 }
734
735 TEST_CASE("AppHelper: TempfileNotCreated", "[helpers]") {
736 std::string name = "TestFileNotUsed.txt";
737 {
738 TempFile myfile{name};
739
740 CHECK_FALSE(CLI::ExistingFile(myfile).empty());
741 }
742 CHECK_FALSE(CLI::ExistingFile(name).empty());
743 }
744
745 TEST_CASE("AppHelper: Ofstream", "[helpers]") {
746
747 std::string name = "TestFileNotUsed.txt";
748 {
749 TempFile myfile(name);
750
751 {
752 std::ofstream out{myfile};
753 out << "this is output" << std::endl;
754 }
755
756 CHECK(CLI::ExistingFile(myfile).empty());
757 }
758 CHECK_FALSE(CLI::ExistingFile(name).empty());
759 }
760
761 TEST_CASE("Split: StringList", "[helpers]") {
762
763 std::vector<std::string> results{"a", "long", "--lone", "-q"};
764 CHECK(CLI::detail::split_names("a,long,--lone,-q") == results);
765 CHECK(CLI::detail::split_names(" a, long, --lone, -q") == results);
766 CHECK(CLI::detail::split_names(" a , long , --lone , -q ") == results);
767 CHECK(CLI::detail::split_names(" a , long , --lone , -q ") == results);
768
769 CHECK(CLI::detail::split_names("one") == std::vector<std::string>({"one"}));
770 }
771
772 TEST_CASE("RegEx: Shorts", "[helpers]") {
773 std::string name, value;
774
775 CHECK(CLI::detail::split_short("-a", name, value));
776 CHECK(name == "a");
777 CHECK(value == "");
778
779 CHECK(CLI::detail::split_short("-B", name, value));
780 CHECK(name == "B");
781 CHECK(value == "");
782
783 CHECK(CLI::detail::split_short("-cc", name, value));
784 CHECK(name == "c");
785 CHECK(value == "c");
786
787 CHECK(CLI::detail::split_short("-simple", name, value));
788 CHECK(name == "s");
789 CHECK(value == "imple");
790
791 CHECK_FALSE(CLI::detail::split_short("--a", name, value));
792 CHECK_FALSE(CLI::detail::split_short("--thing", name, value));
793 CHECK_FALSE(CLI::detail::split_short("--", name, value));
794 CHECK_FALSE(CLI::detail::split_short("something", name, value));
795 CHECK_FALSE(CLI::detail::split_short("s", name, value));
796 }
797
798 TEST_CASE("RegEx: Longs", "[helpers]") {
799 std::string name, value;
800
801 CHECK(CLI::detail::split_long("--a", name, value));
802 CHECK(name == "a");
803 CHECK(value == "");
804
805 CHECK(CLI::detail::split_long("--thing", name, value));
806 CHECK(name == "thing");
807 CHECK(value == "");
808
809 CHECK(CLI::detail::split_long("--some=thing", name, value));
810 CHECK(name == "some");
811 CHECK(value == "thing");
812
813 CHECK_FALSE(CLI::detail::split_long("-a", name, value));
814 CHECK_FALSE(CLI::detail::split_long("-things", name, value));
815 CHECK_FALSE(CLI::detail::split_long("Q", name, value));
816 CHECK_FALSE(CLI::detail::split_long("--", name, value));
817 }
818
819 TEST_CASE("RegEx: SplittingNew", "[helpers]") {
820
821 std::vector<std::string> shorts;
822 std::vector<std::string> longs;
823 std::string pname;
824
825 CHECK_NOTHROW(std::tie(shorts, longs, pname) = CLI::detail::get_names({"--long", "-s", "-q", "--also-long"}));
826 CHECK(longs == std::vector<std::string>({"long", "also-long"}));
827 CHECK(shorts == std::vector<std::string>({"s", "q"}));
828 CHECK(pname == "");
829
830 std::tie(shorts, longs, pname) = CLI::detail::get_names({"--long", "", "-s", "-q", "", "--also-long"});
831 CHECK(longs == std::vector<std::string>({"long", "also-long"}));
832 CHECK(shorts == std::vector<std::string>({"s", "q"}));
833
__anon26387f5f0502() 834 CHECK_THROWS_AS([&]() { std::tie(shorts, longs, pname) = CLI::detail::get_names({"-"}); }(), CLI::BadNameString);
__anon26387f5f0602() 835 CHECK_THROWS_AS([&]() { std::tie(shorts, longs, pname) = CLI::detail::get_names({"--"}); }(), CLI::BadNameString);
__anon26387f5f0702() 836 CHECK_THROWS_AS([&]() { std::tie(shorts, longs, pname) = CLI::detail::get_names({"-hi"}); }(), CLI::BadNameString);
__anon26387f5f0802() 837 CHECK_THROWS_AS([&]() { std::tie(shorts, longs, pname) = CLI::detail::get_names({"---hi"}); }(),
838 CLI::BadNameString);
839 CHECK_THROWS_AS(
__anon26387f5f0902() 840 [&]() {
841 std::tie(shorts, longs, pname) = CLI::detail::get_names({"one", "two"});
842 }(),
843 CLI::BadNameString);
844 }
845
846 TEST_CASE("String: ToLower", "[helpers]") { CHECK("one and two" == CLI::detail::to_lower("one And TWO")); }
847
848 TEST_CASE("Join: Forward", "[helpers]") {
849 std::vector<std::string> val{{"one", "two", "three"}};
850 CHECK(CLI::detail::join(val) == "one,two,three");
851 CHECK(CLI::detail::join(val, ";") == "one;two;three");
852 }
853
854 TEST_CASE("Join: Backward", "[helpers]") {
855 std::vector<std::string> val{{"three", "two", "one"}};
856 CHECK(CLI::detail::rjoin(val) == "one,two,three");
857 CHECK(CLI::detail::rjoin(val, ";") == "one;two;three");
858 }
859
860 TEST_CASE("SplitUp: Simple", "[helpers]") {
861 std::vector<std::string> oput = {"one", "two three"};
862 std::string orig{R"(one "two three")"};
863 std::vector<std::string> result = CLI::detail::split_up(orig);
864 CHECK(result == oput);
865 }
866
867 TEST_CASE("SplitUp: SimpleDifferentQuotes", "[helpers]") {
868 std::vector<std::string> oput = {"one", "two three"};
869 std::string orig{R"(one `two three`)"};
870 std::vector<std::string> result = CLI::detail::split_up(orig);
871 CHECK(result == oput);
872 }
873
874 TEST_CASE("SplitUp: SimpleDifferentQuotes2", "[helpers]") {
875 std::vector<std::string> oput = {"one", "two three"};
876 std::string orig{R"(one 'two three')"};
877 std::vector<std::string> result = CLI::detail::split_up(orig);
878 CHECK(result == oput);
879 }
880
881 TEST_CASE("SplitUp: Layered", "[helpers]") {
882 std::vector<std::string> output = {R"(one 'two three')"};
883 std::string orig{R"("one 'two three'")"};
884 std::vector<std::string> result = CLI::detail::split_up(orig);
885 CHECK(result == output);
886 }
887
888 TEST_CASE("SplitUp: Spaces", "[helpers]") {
889 std::vector<std::string> oput = {"one", " two three"};
890 std::string orig{R"( one " two three" )"};
891 std::vector<std::string> result = CLI::detail::split_up(orig);
892 CHECK(result == oput);
893 }
894
895 TEST_CASE("SplitUp: BadStrings", "[helpers]") {
896 std::vector<std::string> oput = {"one", " two three"};
897 std::string orig{R"( one " two three )"};
898 std::vector<std::string> result = CLI::detail::split_up(orig);
899 CHECK(result == oput);
900
901 oput = {"one", " two three"};
902 orig = R"( one ' two three )";
903 result = CLI::detail::split_up(orig);
904 CHECK(result == oput);
905 }
906
907 TEST_CASE("Types: TypeName", "[helpers]") {
908 std::string int_name = CLI::detail::type_name<int>();
909 CHECK(int_name == "INT");
910
911 std::string int2_name = CLI::detail::type_name<std::int16_t>();
912 CHECK(int2_name == "INT");
913
914 std::string uint_name = CLI::detail::type_name<unsigned char>();
915 CHECK(uint_name == "UINT");
916
917 std::string float_name = CLI::detail::type_name<double>();
918 CHECK(float_name == "FLOAT");
919
920 std::string char_name = CLI::detail::type_name<char>();
921 CHECK(char_name == "CHAR");
922
923 std::string vector_name = CLI::detail::type_name<std::vector<int>>();
924 CHECK(vector_name == "INT");
925
926 vector_name = CLI::detail::type_name<std::vector<double>>();
927 CHECK(vector_name == "FLOAT");
928
929 static_assert(CLI::detail::classify_object<std::pair<int, std::string>>::value ==
930 CLI::detail::object_category::tuple_value,
931 "pair<int,string> does not read like a tuple");
932
933 static_assert(CLI::detail::classify_object<std::tuple<std::string, double>>::value ==
934 CLI::detail::object_category::tuple_value,
935 "tuple<string,double> does not read like a tuple");
936
937 std::string pair_name = CLI::detail::type_name<std::vector<std::pair<int, std::string>>>();
938 CHECK(pair_name == "[INT,TEXT]");
939
940 vector_name = CLI::detail::type_name<std::vector<std::vector<unsigned char>>>();
941 CHECK(vector_name == "UINT");
942
943 auto vclass = CLI::detail::classify_object<std::vector<std::vector<unsigned char>>>::value;
944 CHECK(CLI::detail::object_category::container_value == vclass);
945
946 auto tclass = CLI::detail::classify_object<std::tuple<double>>::value;
947 CHECK(CLI::detail::object_category::number_constructible == tclass);
948
949 std::string tuple_name = CLI::detail::type_name<std::tuple<double>>();
950 CHECK(tuple_name == "FLOAT");
951
952 static_assert(CLI::detail::classify_object<std::tuple<int, std::string>>::value ==
953 CLI::detail::object_category::tuple_value,
954 "tuple<int,string> does not read like a tuple");
955 tuple_name = CLI::detail::type_name<std::tuple<int, std::string>>();
956 CHECK(tuple_name == "[INT,TEXT]");
957
958 tuple_name = CLI::detail::type_name<std::tuple<const int, std::string>>();
959 CHECK(tuple_name == "[INT,TEXT]");
960
961 tuple_name = CLI::detail::type_name<const std::tuple<int, std::string>>();
962 CHECK(tuple_name == "[INT,TEXT]");
963
964 tuple_name = CLI::detail::type_name<std::tuple<std::string, double>>();
965 CHECK(tuple_name == "[TEXT,FLOAT]");
966
967 tuple_name = CLI::detail::type_name<const std::tuple<std::string, double>>();
968 CHECK(tuple_name == "[TEXT,FLOAT]");
969
970 tuple_name = CLI::detail::type_name<std::tuple<int, std::string, double>>();
971 CHECK(tuple_name == "[INT,TEXT,FLOAT]");
972
973 tuple_name = CLI::detail::type_name<std::tuple<int, std::string, double, unsigned int>>();
974 CHECK(tuple_name == "[INT,TEXT,FLOAT,UINT]");
975
976 tuple_name = CLI::detail::type_name<std::tuple<int, std::string, double, unsigned int, std::string>>();
977 CHECK(tuple_name == "[INT,TEXT,FLOAT,UINT,TEXT]");
978
979 tuple_name = CLI::detail::type_name<std::array<int, 10>>();
980 CHECK(tuple_name == "[INT,INT,INT,INT,INT,INT,INT,INT,INT,INT]");
981
982 std::string text_name = CLI::detail::type_name<std::string>();
983 CHECK(text_name == "TEXT");
984
985 std::string text2_name = CLI::detail::type_name<char *>();
986 CHECK(text2_name == "TEXT");
987
988 enum class test { test1, test2, test3 };
989 std::string enum_name = CLI::detail::type_name<test>();
990 CHECK(enum_name == "ENUM");
991
992 vclass = CLI::detail::classify_object<std::tuple<test>>::value;
993 CHECK(CLI::detail::object_category::tuple_value == vclass);
994 static_assert(CLI::detail::classify_object<std::tuple<test>>::value == CLI::detail::object_category::tuple_value,
995 "tuple<test> does not classify as a tuple");
996 std::string enum_name2 = CLI::detail::type_name<std::tuple<test>>();
997 CHECK(enum_name2 == "ENUM");
998 std::string umapName = CLI::detail::type_name<std::unordered_map<int, std::tuple<std::string, double>>>();
999 CHECK(umapName == "[INT,[TEXT,FLOAT]]");
1000
1001 // On older compilers, this may show up as other/TEXT
1002 vclass = CLI::detail::classify_object<std::atomic<int>>::value;
1003 CHECK((CLI::detail::object_category::wrapper_value == vclass || CLI::detail::object_category::other == vclass));
1004
1005 std::string atomic_name = CLI::detail::type_name<std::atomic<int>>();
1006 CHECK((atomic_name == "INT" || atomic_name == "TEXT"));
1007 }
1008
1009 TEST_CASE("Types: OverflowSmall", "[helpers]") {
1010 signed char x;
1011 auto strmax = std::to_string(std::numeric_limits<signed char>::max() + 1);
1012 CHECK_FALSE(CLI::detail::lexical_cast(strmax, x));
1013
1014 unsigned char y;
1015 strmax = std::to_string(std::numeric_limits<unsigned char>::max() + 1);
1016 CHECK_FALSE(CLI::detail::lexical_cast(strmax, y));
1017 }
1018
1019 TEST_CASE("Types: LexicalCastInt", "[helpers]") {
1020 std::string signed_input = "-912";
1021 int x_signed;
1022 CHECK(CLI::detail::lexical_cast(signed_input, x_signed));
1023 CHECK(x_signed == -912);
1024
1025 std::string unsigned_input = "912";
1026 unsigned int x_unsigned;
1027 CHECK(CLI::detail::lexical_cast(unsigned_input, x_unsigned));
1028 CHECK(x_unsigned == (unsigned int)912);
1029
1030 CHECK_FALSE(CLI::detail::lexical_cast(signed_input, x_unsigned));
1031
1032 unsigned char y;
1033 std::string overflow_input = std::to_string(std::numeric_limits<uint64_t>::max()) + "0";
1034 CHECK_FALSE(CLI::detail::lexical_cast(overflow_input, y));
1035
1036 char y_signed;
1037 CHECK_FALSE(CLI::detail::lexical_cast(overflow_input, y_signed));
1038
1039 std::string bad_input = "hello";
1040 CHECK_FALSE(CLI::detail::lexical_cast(bad_input, y));
1041
1042 std::string extra_input = "912i";
1043 CHECK_FALSE(CLI::detail::lexical_cast(extra_input, y));
1044
1045 std::string empty_input{};
1046 CHECK_FALSE(CLI::detail::lexical_cast(empty_input, x_signed));
1047 CHECK_FALSE(CLI::detail::lexical_cast(empty_input, x_unsigned));
1048 CHECK_FALSE(CLI::detail::lexical_cast(empty_input, y_signed));
1049 }
1050
1051 TEST_CASE("Types: LexicalCastDouble", "[helpers]") {
1052 std::string input = "9.12";
1053 long double x;
1054 CHECK(CLI::detail::lexical_cast(input, x));
1055 CHECK((float)x == Approx((float)9.12));
1056
1057 std::string bad_input = "hello";
1058 CHECK_FALSE(CLI::detail::lexical_cast(bad_input, x));
1059
1060 std::string overflow_input = "1" + std::to_string(std::numeric_limits<long double>::max());
1061 CHECK(CLI::detail::lexical_cast(overflow_input, x));
1062 CHECK_FALSE(std::isfinite(x));
1063
1064 std::string extra_input = "9.12i";
1065 CHECK_FALSE(CLI::detail::lexical_cast(extra_input, x));
1066
1067 std::string empty_input{};
1068 CHECK_FALSE(CLI::detail::lexical_cast(empty_input, x));
1069 }
1070
1071 TEST_CASE("Types: LexicalCastBool", "[helpers]") {
1072 std::string input = "false";
1073 bool x;
1074 CHECK(CLI::detail::lexical_cast(input, x));
1075 CHECK_FALSE(x);
1076
1077 std::string bad_input = "happy";
1078 CHECK_FALSE(CLI::detail::lexical_cast(bad_input, x));
1079
1080 std::string input_true = "EnaBLE";
1081 CHECK(CLI::detail::lexical_cast(input_true, x));
1082 CHECK(x);
1083 }
1084
1085 TEST_CASE("Types: LexicalCastString", "[helpers]") {
1086 std::string input = "one";
1087 std::string output;
1088 CLI::detail::lexical_cast(input, output);
1089 CHECK(output == input);
1090 }
1091
1092 TEST_CASE("Types: LexicalCastParsable", "[helpers]") {
1093 std::string input = "(4.2,7.3)";
1094 std::string fail_input = "4.2,7.3";
1095 std::string extra_input = "(4.2,7.3)e";
1096
1097 std::complex<double> output;
1098 CHECK(CLI::detail::lexical_cast(input, output));
1099 CHECK(4.2 == Approx(output.real()));
1100 CHECK(7.3 == Approx(output.imag()));
1101
1102 CHECK(CLI::detail::lexical_cast("2.456", output));
1103 CHECK(2.456 == Approx(output.real()));
1104 CHECK(0.0 == Approx(output.imag()));
1105
1106 CHECK_FALSE(CLI::detail::lexical_cast(fail_input, output));
1107 CHECK_FALSE(CLI::detail::lexical_cast(extra_input, output));
1108 }
1109
1110 TEST_CASE("Types: LexicalCastEnum", "[helpers]") {
1111 enum t1 : signed char { v1 = 5, v3 = 7, v5 = -9 };
1112
1113 t1 output;
1114 CHECK(CLI::detail::lexical_cast("-9", output));
1115 CHECK(v5 == output);
1116
1117 CHECK_FALSE(CLI::detail::lexical_cast("invalid", output));
1118 enum class t2 : std::uint64_t { enum1 = 65, enum2 = 45667, enum3 = 9999999999999 };
1119 t2 output2{t2::enum2};
1120 CHECK(CLI::detail::lexical_cast("65", output2));
1121 CHECK(t2::enum1 == output2);
1122
1123 CHECK_FALSE(CLI::detail::lexical_cast("invalid", output2));
1124
1125 CHECK(CLI::detail::lexical_cast("9999999999999", output2));
1126 CHECK(t2::enum3 == output2);
1127 }
1128
1129 TEST_CASE("Types: LexicalConversionDouble", "[helpers]") {
1130 CLI::results_t input = {"9.12"};
1131 long double x{0.0};
1132 bool res = CLI::detail::lexical_conversion<long double, double>(input, x);
1133 CHECK(res);
1134 CHECK((float)x == Approx((float)9.12));
1135
1136 CLI::results_t bad_input = {"hello"};
1137 res = CLI::detail::lexical_conversion<long double, double>(bad_input, x);
1138 CHECK_FALSE(res);
1139 }
1140
1141 TEST_CASE("Types: LexicalConversionDoubleTuple", "[helpers]") {
1142 CLI::results_t input = {"9.12"};
1143 std::tuple<double> x{0.0};
1144 bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1145 CHECK(res);
1146 CHECK(std::get<0>(x) == Approx(9.12));
1147
1148 CLI::results_t bad_input = {"hello"};
1149 res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(bad_input, x);
1150 CHECK_FALSE(res);
1151 }
1152
1153 TEST_CASE("Types: LexicalConversionVectorDouble", "[helpers]") {
1154 CLI::results_t input = {"9.12", "10.79", "-3.54"};
1155 std::vector<double> x;
1156 bool res = CLI::detail::lexical_conversion<std::vector<double>, double>(input, x);
1157 CHECK(res);
1158 CHECK(3u == x.size());
1159 CHECK(-3.54 == Approx(x[2]));
1160
1161 res = CLI::detail::lexical_conversion<std::vector<double>, std::vector<double>>(input, x);
1162 CHECK(res);
1163 CHECK(3u == x.size());
1164 CHECK(-3.54 == Approx(x[2]));
1165 }
1166
1167 static_assert(!CLI::detail::is_tuple_like<std::vector<double>>::value, "vector should not be like a tuple");
1168 static_assert(CLI::detail::is_tuple_like<std::pair<double, double>>::value, "pair of double should be like a tuple");
1169 static_assert(CLI::detail::is_tuple_like<std::array<double, 4>>::value, "std::array<double,4> should be like a tuple");
1170 static_assert(CLI::detail::is_tuple_like<std::array<int, 10>>::value, "std::array<int,10> should be like a tuple");
1171 static_assert(!CLI::detail::is_tuple_like<std::string>::value, "std::string should not be like a tuple");
1172 static_assert(!CLI::detail::is_tuple_like<double>::value, "double should not be like a tuple");
1173 static_assert(CLI::detail::is_tuple_like<std::tuple<double, int, double>>::value, "tuple should look like a tuple");
1174
1175 TEST_CASE("Types: LexicalConversionTuple2", "[helpers]") {
1176 CLI::results_t input = {"9.12", "19"};
1177
1178 std::tuple<double, int> x{0.0, 0};
1179 static_assert(CLI::detail::is_tuple_like<decltype(x)>::value,
1180 "tuple type must have is_tuple_like trait to be true");
1181 bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1182 CHECK(res);
1183 CHECK(19 == std::get<1>(x));
1184 CHECK(9.12 == Approx(std::get<0>(x)));
1185
1186 input = {"19", "9.12"};
1187 res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1188 CHECK_FALSE(res);
1189 }
1190
1191 TEST_CASE("Types: LexicalConversionTuple3", "[helpers]") {
1192 CLI::results_t input = {"9.12", "19", "hippo"};
1193 std::tuple<double, int, std::string> x;
1194 bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1195 CHECK(res);
1196 CHECK(19 == std::get<1>(x));
1197 CHECK(9.12 == Approx(std::get<0>(x)));
1198 CHECK("hippo" == std::get<2>(x));
1199
1200 input = {"19", "9.12"};
1201 res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1202 CHECK_FALSE(res);
1203 }
1204
1205 TEST_CASE("Types: LexicalConversionTuple4", "[helpers]") {
1206 CLI::results_t input = {"9.12", "19", "18.6", "5.87"};
1207 std::array<double, 4> x;
1208 bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1209 CHECK(res);
1210 CHECK(19 == Approx(std::get<1>(x)));
1211 CHECK(9.12 == Approx(x[0]));
1212 CHECK(18.6 == Approx(x[2]));
1213 CHECK(5.87 == Approx(x[3]));
1214
1215 input = {"19", "9.12", "hippo"};
1216 res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1217 CHECK_FALSE(res);
1218 }
1219
1220 TEST_CASE("Types: LexicalConversionTuple5", "[helpers]") {
1221 CLI::results_t input = {"9", "19", "18", "5", "235235"};
1222 std::array<unsigned int, 5> x;
1223 bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1224 CHECK(res);
1225 CHECK(19u == std::get<1>(x));
1226 CHECK(9u == x[0]);
1227 CHECK(18u == x[2]);
1228 CHECK(5u == x[3]);
1229 CHECK(235235u == x[4]);
1230
1231 input = {"19", "9.12", "hippo"};
1232 res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1233 CHECK_FALSE(res);
1234 }
1235
1236 TEST_CASE("Types: LexicalConversionTuple10", "[helpers]") {
1237 CLI::results_t input = {"9", "19", "18", "5", "235235", "9", "19", "18", "5", "235235"};
1238 std::array<unsigned int, 10> x;
1239 bool res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1240 CHECK(res);
1241 CHECK(19u == std::get<1>(x));
1242 CHECK(9u == x[0]);
1243 CHECK(18u == x[2]);
1244 CHECK(5u == x[3]);
1245 CHECK(235235u == x[4]);
1246 CHECK(235235u == x[9]);
1247 input[3] = "hippo";
1248 res = CLI::detail::lexical_conversion<decltype(x), decltype(x)>(input, x);
1249 CHECK_FALSE(res);
1250 }
1251
1252 TEST_CASE("Types: LexicalConversionTuple10XC", "[helpers]") {
1253 CLI::results_t input = {"9", "19", "18", "5", "235235", "9", "19", "18", "5", "235235"};
1254 std::array<double, 10> x;
1255 bool res = CLI::detail::lexical_conversion<decltype(x), std::array<unsigned int, 10>>(input, x);
1256
1257 CHECK(res);
1258 CHECK(19.0 == std::get<1>(x));
1259 CHECK(9.0 == x[0]);
1260 CHECK(18.0 == x[2]);
1261 CHECK(5.0 == x[3]);
1262 CHECK(235235.0 == x[4]);
1263 CHECK(235235.0 == x[9]);
1264 input[3] = "19.7";
1265 res = CLI::detail::lexical_conversion<decltype(x), std::array<unsigned int, 10>>(input, x);
1266 CHECK_FALSE(res);
1267 }
1268
1269 TEST_CASE("Types: LexicalConversionComplex", "[helpers]") {
1270 CLI::results_t input = {"5.1", "3.5"};
1271 std::complex<double> x;
1272 bool res = CLI::detail::lexical_conversion<std::complex<double>, std::array<double, 2>>(input, x);
1273 CHECK(res);
1274 CHECK(5.1 == x.real());
1275 CHECK(3.5 == x.imag());
1276 }
1277
1278 static_assert(CLI::detail::is_wrapper<std::vector<double>>::value, "vector double should be a wrapper");
1279 static_assert(CLI::detail::is_wrapper<std::vector<std::string>>::value, "vector string should be a wrapper");
1280 static_assert(CLI::detail::is_wrapper<std::string>::value, "string should be a wrapper");
1281 static_assert(!CLI::detail::is_wrapper<double>::value, "double should not be a wrapper");
1282
1283 static_assert(CLI::detail::is_mutable_container<std::vector<double>>::value, "vector class should be a container");
1284 static_assert(CLI::detail::is_mutable_container<std::vector<std::string>>::value, "vector class should be a container");
1285 static_assert(!CLI::detail::is_mutable_container<std::string>::value, "string should be a container");
1286 static_assert(!CLI::detail::is_mutable_container<double>::value, "double should not be a container");
1287 static_assert(!CLI::detail::is_mutable_container<std::array<double, 5>>::value, "array should not be a container");
1288
1289 static_assert(CLI::detail::is_mutable_container<std::vector<int>>::value, "vector int should be a container");
1290
1291 static_assert(CLI::detail::is_readable_container<std::vector<int> &>::value,
1292 "vector int & should be a readable container");
1293 static_assert(CLI::detail::is_readable_container<const std::vector<int>>::value,
1294 "const vector int should be a readable container");
1295 static_assert(CLI::detail::is_readable_container<const std::vector<int> &>::value,
1296 "const vector int & should be a readable container");
1297
1298 TEST_CASE("FixNewLines: BasicCheck", "[helpers]") {
1299 std::string input = "one\ntwo";
1300 std::string output = "one\n; two";
1301 std::string result = CLI::detail::fix_newlines("; ", input);
1302 CHECK(output == result);
1303 }
1304
1305 TEST_CASE("FixNewLines: EdgesCheck", "[helpers]") {
1306 std::string input = "\none\ntwo\n";
1307 std::string output = "\n; one\n; two\n; ";
1308 std::string result = CLI::detail::fix_newlines("; ", input);
1309 CHECK(output == result);
1310 }
1311