1 #include "catch.hpp"
2 #include <vector>
3 #include <list>
4 #include <functional>
5 #include <cstring>
6 #include <locale.h>
7 
8 #include "stringutil.h"
9 
10 // Test plain arrays, vectors, and lists (not random-access), with const variants of both
11 TEMPLATE_TEST_CASE( "comma_separated_*", "[single-file]",
12                     const char *[], string[], const string[],
13                     vector<const char *>, const vector<string>,
14                     list<const char *>, const list<const char *> )
15 {
16     TestType several = { "foo", "bar", "baz" };
17     TestType two = { "foo", "bar" };
18     TestType one = { "foo" };
19 
20     CHECK(comma_separated_line(begin(several), end(several)) == "foo, bar and baz");
21     CHECK(comma_separated_line(begin(two), end(two)) == "foo and bar");
22     CHECK(comma_separated_line(begin(one), end(one)) == *begin(one));
23     // N.b. begin() twice is intentional, to get an empty range (likewise below)
24     CHECK(comma_separated_line(begin(one), begin(one)) == "");
25 
26     CHECK(comma_separated_line(begin(several), end(several), "&", "+") == "foo+bar&baz");
27     CHECK(comma_separated_line(begin(two), end(two), "&", "+") == "foo&bar");
28     CHECK(comma_separated_line(begin(one), end(one), "&", "+") == *begin(one));
29     CHECK(comma_separated_line(begin(one), begin(one), "&", "+") == "");
30 
31     CHECK(join_strings(begin(several), end(several)) == "foo bar baz");
32     CHECK(join_strings(begin(two), end(two)) == "foo bar");
33     CHECK(join_strings(begin(one), end(one)) == *begin(one));
34     CHECK(join_strings(begin(one), begin(one)) == "");
35 
36     CHECK(comma_separated_fn(begin(several), end(several), uppercase_string)
37             == "FOO, BAR and BAZ");
38     CHECK(comma_separated_fn(begin(two), end(two), uppercase_string) == "FOO and BAR");
39     CHECK(comma_separated_fn(begin(one), end(one), uppercase_string)
40             == uppercase_string(*begin(one)));
41     CHECK(comma_separated_fn(begin(one), begin(one), uppercase_string) == "");
42 
43     CHECK(comma_separated_fn(begin(several), end(several), uppercase_string, "&", "+")
44             == "FOO+BAR&BAZ");
45     CHECK(comma_separated_fn(begin(two), end(two), uppercase_string, "&", "+") == "FOO&BAR");
46     CHECK(comma_separated_fn(begin(one), end(one), uppercase_string, "&", "+")
47             == uppercase_string(*begin(one)));
48     CHECK(comma_separated_fn(begin(one), begin(one), uppercase_string, "&", "+") == "");
49 
50 }
51 
52 TEST_CASE( "comma_separated_fn with a non-string", "[single-file]")
53 {
54     int numlist[] = { 1, 2, 3, 4 };
55     // Select a specific overload of std::to_string.
56     string (*fn)(int) = to_string;
57     // Also with a std::function
58     function<string(int)> fn_func{fn};
59 
60     CHECK(comma_separated_fn(begin(numlist), end(numlist), fn) == "1, 2, 3 and 4");
61     CHECK(comma_separated_fn(begin(numlist), end(numlist), fn_func) == "1, 2, 3 and 4");
62 }
63 
64 TEST_CASE( "uppercase and lowercase", "[single-file]")
65 {
66     for (int i = 0; i < 2; ++i) {
67         // Also try with a Turkish locale, where tolower("I") is not "i". Our uppercase
68         // and lowercase functions should ignore the locale for ASCII characters, because
69         // they are also used for things that aren't exactly "text".
70         if (i > 0)
71             setlocale(LC_ALL, "tr_TR");
72 
73         // N.b. includes a capital I
74         const char orig[] = "mIxEdCaSe";
75         string in_s(orig);
76         const string in_cs(orig);
77         const char *in = in_s.c_str();
78 
79         // First, the non-mutating versions.
80         CHECK(lowercase_string(in) == "mixedcase");
81         CHECK(lowercase_string(in_s) == "mixedcase");
82         CHECK(lowercase_string(in_cs) == "mixedcase");
83 
84         // Ensure they didn't mutate the input, and abort the test case if they did.
85         REQUIRE(in_s == orig);
86         REQUIRE(strcmp(in, orig) == 0);
87 
88         // Again for uppercasing
89         CHECK(uppercase_string(in) == "MIXEDCASE");
90         CHECK(uppercase_string(in_s) == "MIXEDCASE");
91         CHECK(uppercase_string(in_cs) == "MIXEDCASE");
92 
93         REQUIRE(in_s == orig);
94         REQUIRE(strcmp(in, orig) == 0);
95 
96         // Again for title-casing
97         CHECK(uppercase_first(in) == "MIxEdCaSe");
98         CHECK(uppercase_first(in_s) == "MIxEdCaSe");
99         CHECK(uppercase_first(in_cs) == "MIxEdCaSe");
100 
101         REQUIRE(in_s == orig);
102         REQUIRE(strcmp(in, orig) == 0);
103 
104         // Now the mutating versions
105         string s1(orig);
106         string &result = uppercase(s1);
107         CHECK(result == "MIXEDCASE");
108         // Verify identity
109         CHECK(&result == &s1);
110 
111         string &result2 = lowercase(result);
112         CHECK(result2 == "mixedcase");
113         // Verify identity
114         CHECK(&result2 == &s1);
115     }
116 }
117