openMSX
StringOp_test.cc
Go to the documentation of this file.
1 #include "catch.hpp"
2 #include "StringOp.hh"
3 #include <type_traits>
4 
5 using namespace StringOp;
6 using std::string;
7 using std::string_view;
8 using std::vector;
9 
10 static void testStringToInt(const string& s, bool ok, int expected)
11 {
12  int result;
13  bool success = stringToInt(s, result);
14  REQUIRE(success == ok);
15  if (ok) {
16  CHECK(result == expected);
17  CHECK(stringToInt(s) == expected);
18  }
19 }
20 
21 static void checkTrimRight(const string& s, char c, const string& expected)
22 {
23  string test = s;
24  trimRight(test, c);
25  CHECK(test == expected);
26 
27  string_view ref = s;
28  trimRight(ref, c);
29  CHECK(ref == expected);
30 }
31 static void checkTrimRight(const string& s, const char* chars, const string& expected)
32 {
33  string test = s;
34  trimRight(test, chars);
35  CHECK(test == expected);
36 
37  string_view ref = s;
38  trimRight(ref, chars);
39  CHECK(ref == expected);
40 }
41 
42 static void checkTrimLeft(const string& s, char c, const string& expected)
43 {
44  string test = s;
45  trimLeft(test, c);
46  CHECK(test == expected);
47 
48  string_view ref = s;
49  trimLeft(ref, c);
50  CHECK(ref == expected);
51 }
52 static void checkTrimLeft(const string& s, const char* chars, const string& expected)
53 {
54  string test = s;
55  trimLeft(test, chars);
56  CHECK(test == expected);
57 
58  string_view ref = s;
59  trimLeft(ref, chars);
60  CHECK(ref == expected);
61 }
62 
63 static void checkSplitOnFirst(const string& s, const string& first, const string& last)
64 {
65  auto [f1, l1] = splitOnFirst(s, '-');
66  auto [f2, l2] = splitOnFirst(s, " -+");
67  static_assert(std::is_same_v<decltype(f1), std::string_view>);
68  static_assert(std::is_same_v<decltype(f2), std::string_view>);
69  static_assert(std::is_same_v<decltype(l1), std::string_view>);
70  static_assert(std::is_same_v<decltype(l2), std::string_view>);
71  CHECK(f1 == first);
72  CHECK(f2 == first);
73  CHECK(l1 == last);
74  CHECK(l2 == last);
75 }
76 
77 static void checkSplitOnLast(const string& s, const string& first, const string& last)
78 {
79  auto [f1, l1] = splitOnLast(s, '-');
80  auto [f2, l2] = splitOnLast(s, " -+");
81  static_assert(std::is_same_v<decltype(f1), std::string_view>);
82  static_assert(std::is_same_v<decltype(f2), std::string_view>);
83  static_assert(std::is_same_v<decltype(l1), std::string_view>);
84  static_assert(std::is_same_v<decltype(l2), std::string_view>);
85  CHECK(f1 == first);
86  CHECK(f2 == first);
87  CHECK(l1 == last);
88  CHECK(l2 == last);
89 }
90 
91 static void checkSplit(const string& s, const vector<string_view> expected)
92 {
93  CHECK(split(s, '-') == expected);
94 }
95 
96 static void checkParseRange(const string& s, const vector<unsigned>& expected)
97 {
98  CHECK(parseRange(s, 0, 99) == expected);
99 }
100 
101 TEST_CASE("StringOp")
102 {
103  SECTION("stringToXXX") {
104  testStringToInt("", true, 0);
105  testStringToInt("0", true, 0);
106  testStringToInt("1234", true, 1234);
107  testStringToInt("-1234", true, -1234);
108  testStringToInt("0xabcd", true, 43981);
109  testStringToInt("0x7fffffff", true, 2147483647);
110  testStringToInt("-0x80000000", true, -2147483648);
111  testStringToInt("bla", false, 0);
112  //testStringToInt("0x80000000", true, 0); not detected correctly
113 
114  // TODO stringToUint
115  // TODO stringToUint64
116 
117  CHECK(stringToBool("0") == false);
118  CHECK(stringToBool("1") == true);
119  CHECK(stringToBool("Yes") == true);
120  CHECK(stringToBool("yes") == true);
121  CHECK(stringToBool("YES") == true);
122  CHECK(stringToBool("No") == false);
123  CHECK(stringToBool("no") == false);
124  CHECK(stringToBool("NO") == false);
125  CHECK(stringToBool("True") == true);
126  CHECK(stringToBool("true") == true);
127  CHECK(stringToBool("TRUE") == true);
128  CHECK(stringToBool("False") == false);
129  CHECK(stringToBool("false") == false);
130  CHECK(stringToBool("FALSE") == false);
131  // These two behave different as Tcl
132  CHECK(stringToBool("2") == false); // is true in Tcl
133  CHECK(stringToBool("foobar") == false); // is error in Tcl
134 
135  // TODO stringToDouble
136  }
137  SECTION("toLower") {
138  CHECK(toLower("") == "");
139  CHECK(toLower("foo") == "foo");
140  CHECK(toLower("FOO") == "foo");
141  CHECK(toLower("fOo") == "foo");
142  CHECK(toLower(string("FoO")) == "foo");
143  }
144  SECTION("startsWith") {
145  CHECK (startsWith("foobar", "foo"));
146  CHECK_FALSE(startsWith("foobar", "bar"));
147  CHECK_FALSE(startsWith("ba", "bar"));
148  CHECK (startsWith("", ""));
149  CHECK_FALSE(startsWith("", "bar"));
150  CHECK (startsWith("foobar", ""));
151 
152  CHECK (startsWith("foobar", 'f'));
153  CHECK_FALSE(startsWith("foobar", 'b'));
154  CHECK_FALSE(startsWith("", 'b'));
155  }
156  SECTION("endsWith") {
157  CHECK (endsWith("foobar", "bar"));
158  CHECK_FALSE(endsWith("foobar", "foo"));
159  CHECK_FALSE(endsWith("ba", "bar"));
160  CHECK_FALSE(endsWith("ba", "baba"));
161  CHECK (endsWith("", ""));
162  CHECK_FALSE(endsWith("", "bar"));
163  CHECK (endsWith("foobar", ""));
164 
165  CHECK (endsWith("foobar", 'r'));
166  CHECK_FALSE(endsWith("foobar", 'o'));
167  CHECK_FALSE(endsWith("", 'b'));
168  }
169  SECTION("trimRight") {
170  checkTrimRight("", ' ', "");
171  checkTrimRight(" ", ' ', "");
172  checkTrimRight("foo", ' ', "foo");
173  checkTrimRight(" foo", ' ', " foo");
174  checkTrimRight("foo ", ' ', "foo");
175 
176  checkTrimRight("", "o ", "");
177  checkTrimRight(" o ", "o ", "");
178  checkTrimRight("foobar", "o ", "foobar");
179  checkTrimRight(" foobar", "o ", " foobar");
180  checkTrimRight("foo ", "o ", "f");
181  }
182  SECTION("trimLeft") {
183  checkTrimLeft("", ' ', "");
184  checkTrimLeft(" ", ' ', "");
185  checkTrimLeft("foo", ' ', "foo");
186  checkTrimLeft("foo ", ' ', "foo ");
187  checkTrimLeft(" foo", ' ', "foo");
188 
189  checkTrimLeft("", "f ", "");
190  checkTrimLeft(" f ", "f ", "");
191  checkTrimLeft("foo", "f ", "oo");
192  checkTrimLeft("barfoo ", "f ", "barfoo ");
193  checkTrimLeft(" foo", "f ", "oo");
194  }
195  SECTION("splitOnFirst") {
196  checkSplitOnFirst("", "", "");
197  checkSplitOnFirst("-", "", "");
198  checkSplitOnFirst("foo-", "foo", "");
199  checkSplitOnFirst("-foo", "", "foo");
200  checkSplitOnFirst("foo-bar", "foo", "bar");
201  checkSplitOnFirst("foo-bar-qux", "foo", "bar-qux");
202  checkSplitOnFirst("-bar-qux", "", "bar-qux");
203  checkSplitOnFirst("foo-bar-", "foo", "bar-");
204  }
205  SECTION("splitOnLast") {
206  checkSplitOnLast("", "", "");
207  checkSplitOnLast("-", "", "");
208  checkSplitOnLast("foo-", "foo", "");
209  checkSplitOnLast("-foo", "", "foo");
210  checkSplitOnLast("foo-bar", "foo", "bar");
211  checkSplitOnLast("foo-bar-qux", "foo-bar", "qux");
212  checkSplitOnLast("-bar-qux", "-bar", "qux");
213  checkSplitOnLast("foo-bar-", "foo-bar", "");
214  }
215  SECTION("split") {
216  checkSplit("", {});
217  checkSplit("-", {""});
218  checkSplit("foo-", {"foo"});
219  checkSplit("-foo", {"", "foo"});
220  checkSplit("foo-bar", {"foo", "bar"});
221  checkSplit("foo-bar-qux", {"foo", "bar", "qux"});
222  checkSplit("-bar-qux", {"", "bar", "qux"});
223  checkSplit("foo-bar-", {"foo", "bar"});
224  }
225  SECTION("parseRange") {
226  checkParseRange("", {});
227  checkParseRange("5", {5});
228  checkParseRange("5,8", {5,8});
229  checkParseRange("5,5", {5});
230  checkParseRange("5-7", {5,6,7});
231  checkParseRange("7-5", {5,6,7});
232  checkParseRange("5-7,19", {5,6,7,19});
233  checkParseRange("15,5-7", {5,6,7,15});
234  checkParseRange("6,5-7", {5,6,7});
235  checkParseRange("5-8,10-12", {5,6,7,8,10,11,12});
236  checkParseRange("5-9,6-10", {5,6,7,8,9,10});
237 
238  CHECK_THROWS (parseRange( "4", 5, 10));
239  CHECK_NOTHROW(parseRange( "5", 5, 10));
240  CHECK_NOTHROW(parseRange("10", 5, 10));
241  CHECK_THROWS (parseRange("11", 5, 10));
242  }
243  SECTION("caseless") {
244  caseless op;
245  CHECK( op("abc", "xyz"));
246  CHECK(!op("xyz", "abc"));
247  CHECK(!op("abc", "abc"));
248  CHECK( op("ABC", "xyz"));
249  CHECK(!op("xyz", "ABC"));
250  CHECK(!op("ABC", "abc"));
251  CHECK( op("aBC", "Xyz"));
252  CHECK(!op("xYz", "AbC"));
253  CHECK(!op("ABc", "abC"));
254 
255  CHECK( op("abc", "ABCdef"));
256  CHECK(!op("AbcDef", "AbC"));
257  }
258  SECTION("casecmp") {
259  casecmp op;
260  CHECK( op("abc", "abc"));
261  CHECK( op("abc", "ABC"));
262  CHECK(!op("abc", "xyz"));
263  CHECK(!op("ab", "abc"));
264  CHECK(!op("ab", "ABC"));
265  CHECK(!op("abc", "ab"));
266  CHECK(!op("abc", "AB"));
267  }
268 }
StringOp::splitOnLast
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
Definition: StringOp.cc:174
StringOp::startsWith
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:71
StringOp::caseless
Definition: StringOp.hh:61
StringOp::trimLeft
void trimLeft(string &str, const char *chars)
Definition: StringOp.cc:122
StringOp
Definition: StringOp.cc:14
CHECK
CHECK(m3==m3)
StringOp::casecmp
Definition: StringOp.hh:68
StringOp::toLower
string toLower(string_view str)
Definition: StringOp.cc:64
TEST_CASE
TEST_CASE("StringOp")
Definition: StringOp_test.cc:101
StringOp::endsWith
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:81
StringOp::stringToBool
bool stringToBool(string_view str)
Definition: StringOp.cc:43
StringOp::trimRight
void trimRight(string &str, const char *chars)
Definition: StringOp.cc:91
StringOp::stringToInt
int stringToInt(const string &str)
Definition: StringOp.cc:16
StringOp::split
vector< string_view > split(string_view str, char chars)
Definition: StringOp.cc:193
StringOp::splitOnFirst
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
Definition: StringOp.cc:155
StringOp.hh
StringOp::parseRange
vector< unsigned > parseRange(string_view str, unsigned min, unsigned max)
Definition: StringOp.cc:250