OXYGENHUB
◆ main openmsx / src / unittest / strCat.cc
8.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "catch.hpp"
2
#include "strCat.hh"
3
4
#include <array>
5
6
static std::string rValue()
7
{
8
	return "bar";
9
}
10
11
TEST_CASE("strCat")
12
{
13
	std::string str = "abc";
14
	std::string_view sr = "xyz";
15
	const char* literal = "foo";
16
	std::array<char, 100> buf; buf[0] = 'q'; buf[1] = 'u'; buf[2] = 'x'; buf[3] = '\0';
17
	char c = '-';
18
	unsigned char uc = 222;
19
	int m = -31;
20
	int i = 123456;
21
	float f = 6.28f;
22
	double d = -1.234;
23
24
	SECTION("zero") {
25
		CHECK(strCat() == "");
26
	}
27
	SECTION("one") {
28
		CHECK(strCat(rValue()) == "bar");
29
		CHECK(strCat(str) == "abc");
30
		CHECK(strCat(sr) == "xyz");
31
		CHECK(strCat(literal) == "foo");
32
		CHECK(strCat(buf.data()) == "qux");
33
		CHECK(strCat(c) == "-");
34
		CHECK(strCat(uc) == "222");
35
		CHECK(strCat(m) == "-31");
36
		CHECK(strCat(i) == "123456");
37
		CHECK(strCat(f) == "6.280000");
38
		CHECK(strCat(d) == "-1.234000");
39
		CHECK(strCat(hex_string<8>(i)) == "0001e240");
40
		CHECK(strCat(hex_string<4>(i)) == "e240");
41
		CHECK(strCat(hex_string<4, HexCase::upper>(i)) == "E240");
42
		CHECK(strCat(hex_string(Digits{5}, i)) == "1e240");
43
		CHECK(strCat(hex_string<HexCase::upper>(Digits{5}, i)) == "1E240");
44
		CHECK(strCat(hex_string(Digits{3}, i)) == "240");
45
		CHECK(strCat(bin_string<16>(i)) == "1110001001000000");
46
		CHECK(strCat(bin_string<8>(i)) == "01000000");
47
		CHECK(strCat(bin_string(uint8_t(0))) == "0");
48
		CHECK(strCat(bin_string(uint8_t(11))) == "1011");
49
		CHECK(strCat(bin_string(uint8_t(131))) == "10000011");
50
		CHECK(strCat(bin_string(int8_t(11))) == "1011");
51
		CHECK(strCat(bin_string(int8_t(-11))) == "11110101");
52
		CHECK(strCat(bin_string(1234)) == "10011010010");
53
		CHECK(strCat(bin_string(uint64_t(123))) == "1111011");
54
		CHECK(strCat(bin_string(int64_t(-123))) == "1111111111111111111111111111111111111111111111111111111110000101");
55
		CHECK(strCat(dec_string<8>(i)) == "  123456");
56
		CHECK(strCat(dec_string<6>(i)) == "123456");
57
		CHECK(strCat(dec_string<4>(i)) == "3456");
58
		CHECK(strCat(spaces(5)) == "     ");
59
	}
60
	SECTION("two") {
61
		CHECK(strCat(str, i) == "abc123456");
62
		CHECK(strCat(str, m) == "abc-31");
63
		CHECK(strCat(str, uc) == "abc222");
64
		CHECK(strCat(i, str) == "123456abc");
65
		CHECK(strCat(m, str) == "-31abc");
66
		CHECK(strCat(uc, str) == "222abc");
67
		CHECK(strCat(buf.data(), i) == "qux123456");
68
		CHECK(strCat(literal, m) == "foo-31");
69
		CHECK(strCat(i, m) == "123456-31");
70
		CHECK(strCat(c, m) == "--31");
71
		CHECK(strCat(i, rValue()) == "123456bar");
72
		CHECK(strCat(spaces(4), i) == "    123456");
73
		CHECK(strCat(hex_string<3>(i), i) == "240123456");
74
		CHECK(strCat(c, hex_string<1>(i)) == "-0");
75
		CHECK(strCat(rValue(), uc) == "bar222");
76
77
		// these have special overloads
78
		CHECK(strCat(str, str) == "abcabc");
79
		CHECK(strCat(literal, str) == "fooabc");
80
		CHECK(strCat(c, str) == "-abc");
81
		CHECK(strCat(str, literal) == "abcfoo");
82
		CHECK(strCat(str, c) == "abc-");
83
		CHECK(strCat(rValue(), str) == "barabc");
84
		CHECK(strCat(str, rValue()) == "abcbar");
85
		CHECK(strCat(rValue(), rValue()) == "barbar");
86
		CHECK(strCat(literal, rValue()) == "foobar");
87
		CHECK(strCat(c, rValue()) == "-bar");
88
		CHECK(strCat(rValue(), literal) == "barfoo");
89
		CHECK(strCat(rValue(), c) == "bar-");
90
		CHECK(strCat(rValue(), sr) == "barxyz");
91
	}
92
	SECTION("three") {
93
		CHECK(strCat(str, str, str) == "abcabcabc");
94
		CHECK(strCat(i, m, c) == "123456-31-");
95
		CHECK(strCat(literal, buf.data(), rValue()) == "fooquxbar");
96
97
		// 1st an r-value is a special case
98
		CHECK(strCat(rValue(), i, literal) == "bar123456foo");
99
		CHECK(strCat(rValue(), uc, buf.data()) == "bar222qux");
100
	}
101
	SECTION("many") {
102
		CHECK(strCat(str, sr, literal, buf.data(), c, uc, m, i, rValue(), spaces(2), hex_string<2>(255)) ==
103
		      "abcxyzfooqux-222-31123456bar  ff");
104
		CHECK(strCat(rValue(), uc, buf.data(), c, spaces(2), str, i, hex_string<3>(9999), sr, literal, m) ==
105
		      "bar222qux-  abc12345670fxyzfoo-31");
106
	}
107
}
108
109
template<typename... Args>
110
static void testAppend(const std::string& expected, Args&& ...args)
111
{
112
	std::string s1;
113
	strAppend(s1, std::forward<Args>(args)...);
114
	CHECK(s1 == expected);
115
116
	std::string s2 = "abcdefghijklmnopqrstuvwxyz";
117
	strAppend(s2, std::forward<Args>(args)...);
118
	CHECK(s2 == ("abcdefghijklmnopqrstuvwxyz" + expected));
119
}
120
121
TEST_CASE("strAppend")
122
{
123
	std::string str = "mno";
124
	std::string_view sr = "rst";
125
	const char* literal = "ijklmn";
126
	std::array<char, 100> buf; buf[0] = 'd'; buf[1] = 'e'; buf[2] = '\0'; buf[3] = 'f';
127
	char c = '+';
128
	unsigned u = 4294967295u;
129
	long long ll = -876;
130
131
	SECTION("zero") {
132
		testAppend("");
133
	}
134
	SECTION("one") {
135
		testAppend("bar", rValue());
136
		testAppend("mno", str);
137
		testAppend("rst", sr);
138
		testAppend("ijklmn", literal);
139
		testAppend("de", buf.data());
140
		testAppend("+", c);
141
		testAppend("4294967295", u);
142
		testAppend("-876", ll);
143
		testAppend("          ", spaces(10));
144
		testAppend("fffffffc94", hex_string<10>(ll));
145
	}
146
	SECTION("many") {
147
		std::string s = "bla";
148
		strAppend(s, str, sr, literal, spaces(3));
149
		strAppend(s, buf.data(), c, u, ll, rValue());
150
		CHECK(s == "blamnorstijklmn   de+4294967295-876bar");
151
	}
152
}
153
154
TEST_CASE("strCat_if")
155
{
156
	SECTION("if only") {
157
		CHECK(strCat("foo", strCat_if(true, "bla", 42, ' ')) == "foobla42 ");
158
		CHECK(strCat("foo", strCat_if(false, "bla", 42, ' ')) == "foo");
159
	}
160
161
	SECTION("if else") {
162
		CHECK(strCat("x", strCat_if(true, "a").else_("b"), "y") == "xay");
163
		CHECK(strCat("x", strCat_if(false, "a").else_("b"), "y") == "xby");
164
		CHECK(strCat("x", strCat_if(false, "a").else_("b", 7, ' '), "y") == "xb7 y");
165
	}
166
167
	SECTION("if else_if else chain") {
168
		CHECK(strCat("bla", strCat_if(true, ' ').else_if(true, "t").else_("xyz"), "\n") == "bla \n");
169
		CHECK(strCat("bla", strCat_if(false, ' ').else_if(true, "t").else_("xyz"), "\n") == "blat\n");
170
		CHECK(strCat("bla", strCat_if(false, ' ').else_if(false, "t").else_("xyz"), "\n") == "blaxyz\n");
171
		CHECK(strCat("x", strCat_if(false, "a").else_if(true, "b", 7, ' ').else_("z"), "y") == "xb7 y");
172
	}
173
174
	SECTION("if else_if without else") {
175
		CHECK(strCat("x", strCat_if(false, "a").else_if(false, "b"), "y") == "xy");
176
		CHECK(strCat("x", strCat_if(false, "a").else_if(true, "b"), "y") == "xby");
177
	}
178
179
	SECTION("zero-arg branches are allowed") {
180
		CHECK(strCat("x", strCat_if(true), "y") == "xy");
181
		CHECK(strCat("x", strCat_if(false), "y") == "xy");
182
		CHECK(strCat("x", strCat_if(false, "a").else_if(true), "y") == "xy");
183
		CHECK(strCat("x", strCat_if(false, "a").else_if(false).else_(), "y") == "xy");
184
	}
185
}
186
187
TEST_CASE("lazy")
188
{
189
	SECTION("basic usage in strCat") {
190
		CHECK(strCat("a", strCat_lazy([&]{ return std::string("b"); }), "c") == "abc");
191
		CHECK(strCat("x", strCat_lazy([&]{ return 42; }), "y") == "x42y");
192
		CHECK(strCat(strCat_lazy([&]{ return "foo"; })) == "foo");
193
	}
194
195
	SECTION("lazy with strCat_if - condition true, lambda invoked") {
196
		int callCount = 0;
197
		CHECK(strCat("pre", strCat_if(true, strCat_lazy([&]{
198
			++callCount;
199
			return "mid";
200
		})), "suf") == "premidsuf");
201
		CHECK(callCount == 1);
202
	}
203
204
	SECTION("lazy with strCat_if - condition false, lambda not invoked") {
205
		int callCount = 0;
206
		CHECK(strCat("pre", strCat_if(false, strCat_lazy([&]{
207
			++callCount;
208
			return "mid";
209
		})), "suf") == "presuf");
210
		CHECK(callCount == 0);
211
	}
212
213
	SECTION("lazy with else_ - condition false, lambda invoked for else") {
214
		int callCount = 0;
215
		CHECK(strCat("x", strCat_if(false, "a").else_(strCat_lazy([&]{
216
			++callCount;
217
			return "b";
218
		})), "y") == "xby");
219
		CHECK(callCount == 1);
220
	}
221
222
	SECTION("lazy with else_ - condition true, else lambda not invoked") {
223
		int callCount = 0;
224
		CHECK(strCat("x", strCat_if(true, "a").else_(strCat_lazy([&]{
225
			++callCount;
226
			return "b";
227
		})), "y") == "xay");
228
		CHECK(callCount == 0);
229
	}
230
231
	SECTION("lazy with else_if - only invoked when that branch is taken") {
232
		int callCount = 0;
233
		CHECK(strCat("x", strCat_if(false, "a").else_if(true, strCat_lazy([&]{
234
			++callCount;
235
			return "b";
236
		})), "y") == "xby");
237
		CHECK(callCount == 1);
238
		callCount = 0;
239
		CHECK(strCat("x", strCat_if(true, "a").else_if(true, strCat_lazy([&]{
240
			++callCount;
241
			return "b";
242
		})), "y") == "xay");
243
		CHECK(callCount == 0);
244
	}
245
246
	SECTION("compare with/without lazy") {
247
		int i = 0;
248
		CHECK(strCat("a", strCat_if(false, STRCAT_LAZY(++i)), "z") == "az");
249
		CHECK(i == 0);
250
		CHECK(strCat("a", strCat_if(false, ++i), "z") == "az");
251
		CHECK(i == 1);
252
	}
253
}
254
255
256
#if 0
257
258
// Not part of the actual unittest. Can be used to (manually) inspect the
259
// quality of the generated code.
260
261
auto test1(int i) { return strCat(i); }
262
auto test1b(int i) { return std::to_string(i); }
263
auto test2(const char* s) { return strCat(s); }
264
auto test3(std::string_view s) { return strCat(s); }
265
auto test4(const std::string& s) { return strCat(s); }
266
auto test5() { return strCat("bla"); }
267
auto test6() { return strCat('a'); }
268
auto test7(char i) { return strCat('a', i, "bla"); }
269
auto test8(int i, unsigned u) { return strCat(i, u); }
270
271
auto testA1(const std::string& s1, const std::string& s2) { return strCat(s1, s2); }
272
auto testA2(const std::string& s1, const std::string& s2) { return s1 + s2; }
273
274
#endif