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