Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/kyua/utils/text/operations_test.cpp
48180 views
1
// Copyright 2012 The Kyua Authors.
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
6
// met:
7
//
8
// * Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// * Redistributions in binary form must reproduce the above copyright
11
// notice, this list of conditions and the following disclaimer in the
12
// documentation and/or other materials provided with the distribution.
13
// * Neither the name of Google Inc. nor the names of its contributors
14
// may be used to endorse or promote products derived from this software
15
// without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
#include "utils/text/operations.ipp"
30
31
#include <iostream>
32
#include <set>
33
#include <string>
34
#include <vector>
35
36
#include <atf-c++.hpp>
37
38
#include "utils/text/exceptions.hpp"
39
40
namespace text = utils::text;
41
42
43
namespace {
44
45
46
/// Tests text::refill() on an input string with a range of widths.
47
///
48
/// \param expected The expected refilled paragraph.
49
/// \param input The input paragraph to be refilled.
50
/// \param first_width The first width to validate.
51
/// \param last_width The last width to validate (inclusive).
52
static void
53
refill_test(const char* expected, const char* input,
54
const std::size_t first_width, const std::size_t last_width)
55
{
56
for (std::size_t width = first_width; width <= last_width; ++width) {
57
const std::vector< std::string > lines = text::split(expected, '\n');
58
std::cout << "Breaking at width " << width << '\n';
59
ATF_REQUIRE_EQ(expected, text::refill_as_string(input, width));
60
ATF_REQUIRE(lines == text::refill(input, width));
61
}
62
}
63
64
65
} // anonymous namespace
66
67
68
ATF_TEST_CASE_WITHOUT_HEAD(escape_xml__empty);
69
ATF_TEST_CASE_BODY(escape_xml__empty)
70
{
71
ATF_REQUIRE_EQ("", text::escape_xml(""));
72
}
73
74
75
ATF_TEST_CASE_WITHOUT_HEAD(escape_xml__no_escaping);
76
ATF_TEST_CASE_BODY(escape_xml__no_escaping)
77
{
78
ATF_REQUIRE_EQ("a", text::escape_xml("a"));
79
ATF_REQUIRE_EQ("Some text!", text::escape_xml("Some text!"));
80
ATF_REQUIRE_EQ("\n\t\r", text::escape_xml("\n\t\r"));
81
}
82
83
84
ATF_TEST_CASE_WITHOUT_HEAD(escape_xml__some_escaping);
85
ATF_TEST_CASE_BODY(escape_xml__some_escaping)
86
{
87
ATF_REQUIRE_EQ("&apos;", text::escape_xml("'"));
88
89
ATF_REQUIRE_EQ("foo &quot;bar&amp; &lt;tag&gt; yay&apos; baz",
90
text::escape_xml("foo \"bar& <tag> yay' baz"));
91
92
ATF_REQUIRE_EQ("&quot;&amp;&lt;&gt;&apos;", text::escape_xml("\"&<>'"));
93
ATF_REQUIRE_EQ("&amp;&amp;&amp;", text::escape_xml("&&&"));
94
ATF_REQUIRE_EQ("&amp;#8;&amp;#11;", text::escape_xml("\b\v"));
95
ATF_REQUIRE_EQ("\t&amp;#127;BAR&amp;", text::escape_xml("\t\x7f""BAR&"));
96
}
97
98
99
ATF_TEST_CASE_WITHOUT_HEAD(quote__empty);
100
ATF_TEST_CASE_BODY(quote__empty)
101
{
102
ATF_REQUIRE_EQ("''", text::quote("", '\''));
103
ATF_REQUIRE_EQ("##", text::quote("", '#'));
104
}
105
106
107
ATF_TEST_CASE_WITHOUT_HEAD(quote__no_escaping);
108
ATF_TEST_CASE_BODY(quote__no_escaping)
109
{
110
ATF_REQUIRE_EQ("'Some text\"'", text::quote("Some text\"", '\''));
111
ATF_REQUIRE_EQ("#Another'string#", text::quote("Another'string", '#'));
112
}
113
114
115
ATF_TEST_CASE_WITHOUT_HEAD(quote__some_escaping);
116
ATF_TEST_CASE_BODY(quote__some_escaping)
117
{
118
ATF_REQUIRE_EQ("'Some\\'text'", text::quote("Some'text", '\''));
119
ATF_REQUIRE_EQ("#Some\\#text#", text::quote("Some#text", '#'));
120
121
ATF_REQUIRE_EQ("'More than one\\' quote\\''",
122
text::quote("More than one' quote'", '\''));
123
ATF_REQUIRE_EQ("'Multiple quotes \\'\\'\\' together'",
124
text::quote("Multiple quotes ''' together", '\''));
125
126
ATF_REQUIRE_EQ("'\\'escape at the beginning'",
127
text::quote("'escape at the beginning", '\''));
128
ATF_REQUIRE_EQ("'escape at the end\\''",
129
text::quote("escape at the end'", '\''));
130
}
131
132
133
ATF_TEST_CASE_WITHOUT_HEAD(refill__empty);
134
ATF_TEST_CASE_BODY(refill__empty)
135
{
136
ATF_REQUIRE_EQ(1, text::refill("", 0).size());
137
ATF_REQUIRE(text::refill("", 0)[0].empty());
138
ATF_REQUIRE_EQ("", text::refill_as_string("", 0));
139
140
ATF_REQUIRE_EQ(1, text::refill("", 10).size());
141
ATF_REQUIRE(text::refill("", 10)[0].empty());
142
ATF_REQUIRE_EQ("", text::refill_as_string("", 10));
143
}
144
145
146
ATF_TEST_CASE_WITHOUT_HEAD(refill__no_changes);
147
ATF_TEST_CASE_BODY(refill__no_changes)
148
{
149
std::vector< std::string > exp_lines;
150
exp_lines.push_back("foo bar\nbaz");
151
152
ATF_REQUIRE(exp_lines == text::refill("foo bar\nbaz", 12));
153
ATF_REQUIRE_EQ("foo bar\nbaz", text::refill_as_string("foo bar\nbaz", 12));
154
155
ATF_REQUIRE(exp_lines == text::refill("foo bar\nbaz", 18));
156
ATF_REQUIRE_EQ("foo bar\nbaz", text::refill_as_string("foo bar\nbaz", 80));
157
}
158
159
160
ATF_TEST_CASE_WITHOUT_HEAD(refill__break_one);
161
ATF_TEST_CASE_BODY(refill__break_one)
162
{
163
refill_test("only break the\nfirst line", "only break the first line",
164
14, 19);
165
}
166
167
168
ATF_TEST_CASE_WITHOUT_HEAD(refill__break_one__not_first_word);
169
ATF_TEST_CASE_BODY(refill__break_one__not_first_word)
170
{
171
refill_test("first-long-word\nother\nwords", "first-long-word other words",
172
6, 10);
173
refill_test("first-long-word\nother words", "first-long-word other words",
174
11, 20);
175
refill_test("first-long-word other\nwords", "first-long-word other words",
176
21, 26);
177
refill_test("first-long-word other words", "first-long-word other words",
178
27, 28);
179
}
180
181
182
ATF_TEST_CASE_WITHOUT_HEAD(refill__break_many);
183
ATF_TEST_CASE_BODY(refill__break_many)
184
{
185
refill_test("this is a long\nparagraph to be\nsplit into\npieces",
186
"this is a long paragraph to be split into pieces",
187
15, 15);
188
}
189
190
191
ATF_TEST_CASE_WITHOUT_HEAD(refill__cannot_break);
192
ATF_TEST_CASE_BODY(refill__cannot_break)
193
{
194
refill_test("this-is-a-long-string", "this-is-a-long-string", 5, 5);
195
196
refill_test("this is\na-string-with-long-words",
197
"this is a-string-with-long-words", 10, 10);
198
}
199
200
201
ATF_TEST_CASE_WITHOUT_HEAD(refill__preserve_whitespace);
202
ATF_TEST_CASE_BODY(refill__preserve_whitespace)
203
{
204
refill_test("foo bar baz ", "foo bar baz ", 80, 80);
205
refill_test("foo \n bar", "foo bar", 5, 5);
206
207
std::vector< std::string > exp_lines;
208
exp_lines.push_back("foo \n");
209
exp_lines.push_back(" bar");
210
ATF_REQUIRE(exp_lines == text::refill("foo \n bar", 5));
211
ATF_REQUIRE_EQ("foo \n\n bar", text::refill_as_string("foo \n bar", 5));
212
}
213
214
215
ATF_TEST_CASE_WITHOUT_HEAD(join__empty);
216
ATF_TEST_CASE_BODY(join__empty)
217
{
218
std::vector< std::string > lines;
219
ATF_REQUIRE_EQ("", text::join(lines, " "));
220
}
221
222
223
ATF_TEST_CASE_WITHOUT_HEAD(join__one);
224
ATF_TEST_CASE_BODY(join__one)
225
{
226
std::vector< std::string > lines;
227
lines.push_back("first line");
228
ATF_REQUIRE_EQ("first line", text::join(lines, "*"));
229
}
230
231
232
ATF_TEST_CASE_WITHOUT_HEAD(join__several);
233
ATF_TEST_CASE_BODY(join__several)
234
{
235
std::vector< std::string > lines;
236
lines.push_back("first abc");
237
lines.push_back("second");
238
lines.push_back("and last line");
239
ATF_REQUIRE_EQ("first abc second and last line", text::join(lines, " "));
240
ATF_REQUIRE_EQ("first abc***second***and last line",
241
text::join(lines, "***"));
242
}
243
244
245
ATF_TEST_CASE_WITHOUT_HEAD(join__unordered);
246
ATF_TEST_CASE_BODY(join__unordered)
247
{
248
std::set< std::string > lines;
249
lines.insert("first");
250
lines.insert("second");
251
const std::string joined = text::join(lines, " ");
252
ATF_REQUIRE(joined == "first second" || joined == "second first");
253
}
254
255
256
ATF_TEST_CASE_WITHOUT_HEAD(split__empty);
257
ATF_TEST_CASE_BODY(split__empty)
258
{
259
std::vector< std::string > words = text::split("", ' ');
260
std::vector< std::string > exp_words;
261
ATF_REQUIRE(exp_words == words);
262
}
263
264
265
ATF_TEST_CASE_WITHOUT_HEAD(split__one);
266
ATF_TEST_CASE_BODY(split__one)
267
{
268
std::vector< std::string > words = text::split("foo", ' ');
269
std::vector< std::string > exp_words;
270
exp_words.push_back("foo");
271
ATF_REQUIRE(exp_words == words);
272
}
273
274
275
ATF_TEST_CASE_WITHOUT_HEAD(split__several__simple);
276
ATF_TEST_CASE_BODY(split__several__simple)
277
{
278
std::vector< std::string > words = text::split("foo bar baz", ' ');
279
std::vector< std::string > exp_words;
280
exp_words.push_back("foo");
281
exp_words.push_back("bar");
282
exp_words.push_back("baz");
283
ATF_REQUIRE(exp_words == words);
284
}
285
286
287
ATF_TEST_CASE_WITHOUT_HEAD(split__several__delimiters);
288
ATF_TEST_CASE_BODY(split__several__delimiters)
289
{
290
std::vector< std::string > words = text::split("XfooXXbarXXXbazXX", 'X');
291
std::vector< std::string > exp_words;
292
exp_words.push_back("");
293
exp_words.push_back("foo");
294
exp_words.push_back("");
295
exp_words.push_back("bar");
296
exp_words.push_back("");
297
exp_words.push_back("");
298
exp_words.push_back("baz");
299
exp_words.push_back("");
300
exp_words.push_back("");
301
ATF_REQUIRE(exp_words == words);
302
}
303
304
305
ATF_TEST_CASE_WITHOUT_HEAD(replace_all__empty);
306
ATF_TEST_CASE_BODY(replace_all__empty)
307
{
308
ATF_REQUIRE_EQ("", text::replace_all("", "search", "replacement"));
309
}
310
311
312
ATF_TEST_CASE_WITHOUT_HEAD(replace_all__none);
313
ATF_TEST_CASE_BODY(replace_all__none)
314
{
315
ATF_REQUIRE_EQ("string without matches",
316
text::replace_all("string without matches",
317
"WITHOUT", "replacement"));
318
}
319
320
321
ATF_TEST_CASE_WITHOUT_HEAD(replace_all__one);
322
ATF_TEST_CASE_BODY(replace_all__one)
323
{
324
ATF_REQUIRE_EQ("string replacement matches",
325
text::replace_all("string without matches",
326
"without", "replacement"));
327
}
328
329
330
ATF_TEST_CASE_WITHOUT_HEAD(replace_all__several);
331
ATF_TEST_CASE_BODY(replace_all__several)
332
{
333
ATF_REQUIRE_EQ("OO fOO bar OOf baz OO",
334
text::replace_all("oo foo bar oof baz oo",
335
"oo", "OO"));
336
}
337
338
339
ATF_TEST_CASE_WITHOUT_HEAD(to_type__ok__bool);
340
ATF_TEST_CASE_BODY(to_type__ok__bool)
341
{
342
ATF_REQUIRE( text::to_type< bool >("true"));
343
ATF_REQUIRE(!text::to_type< bool >("false"));
344
}
345
346
347
ATF_TEST_CASE_WITHOUT_HEAD(to_type__ok__numerical);
348
ATF_TEST_CASE_BODY(to_type__ok__numerical)
349
{
350
ATF_REQUIRE_EQ(12, text::to_type< int >("12"));
351
ATF_REQUIRE_EQ(18745, text::to_type< int >("18745"));
352
ATF_REQUIRE_EQ(-12345, text::to_type< int >("-12345"));
353
354
ATF_REQUIRE_EQ(12.0, text::to_type< double >("12"));
355
ATF_REQUIRE_EQ(12.5, text::to_type< double >("12.5"));
356
}
357
358
359
ATF_TEST_CASE_WITHOUT_HEAD(to_type__ok__string);
360
ATF_TEST_CASE_BODY(to_type__ok__string)
361
{
362
// While this seems redundant, having this particular specialization that
363
// does nothing allows callers to delegate work to to_type without worrying
364
// about the particular type being converted.
365
ATF_REQUIRE_EQ("", text::to_type< std::string >(""));
366
ATF_REQUIRE_EQ(" abcd ", text::to_type< std::string >(" abcd "));
367
}
368
369
370
ATF_TEST_CASE_WITHOUT_HEAD(to_type__empty);
371
ATF_TEST_CASE_BODY(to_type__empty)
372
{
373
ATF_REQUIRE_THROW(text::value_error, text::to_type< int >(""));
374
}
375
376
377
ATF_TEST_CASE_WITHOUT_HEAD(to_type__invalid__bool);
378
ATF_TEST_CASE_BODY(to_type__invalid__bool)
379
{
380
ATF_REQUIRE_THROW(text::value_error, text::to_type< bool >(""));
381
ATF_REQUIRE_THROW(text::value_error, text::to_type< bool >("true "));
382
ATF_REQUIRE_THROW(text::value_error, text::to_type< bool >("foo"));
383
}
384
385
386
ATF_TEST_CASE_WITHOUT_HEAD(to_type__invalid__numerical);
387
ATF_TEST_CASE_BODY(to_type__invalid__numerical)
388
{
389
ATF_REQUIRE_THROW(text::value_error, text::to_type< int >(" 3"));
390
ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("3 "));
391
ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("3a"));
392
ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("a3"));
393
}
394
395
396
ATF_INIT_TEST_CASES(tcs)
397
{
398
ATF_ADD_TEST_CASE(tcs, escape_xml__empty);
399
ATF_ADD_TEST_CASE(tcs, escape_xml__no_escaping);
400
ATF_ADD_TEST_CASE(tcs, escape_xml__some_escaping);
401
402
ATF_ADD_TEST_CASE(tcs, quote__empty);
403
ATF_ADD_TEST_CASE(tcs, quote__no_escaping);
404
ATF_ADD_TEST_CASE(tcs, quote__some_escaping);
405
406
ATF_ADD_TEST_CASE(tcs, refill__empty);
407
ATF_ADD_TEST_CASE(tcs, refill__no_changes);
408
ATF_ADD_TEST_CASE(tcs, refill__break_one);
409
ATF_ADD_TEST_CASE(tcs, refill__break_one__not_first_word);
410
ATF_ADD_TEST_CASE(tcs, refill__break_many);
411
ATF_ADD_TEST_CASE(tcs, refill__cannot_break);
412
ATF_ADD_TEST_CASE(tcs, refill__preserve_whitespace);
413
414
ATF_ADD_TEST_CASE(tcs, join__empty);
415
ATF_ADD_TEST_CASE(tcs, join__one);
416
ATF_ADD_TEST_CASE(tcs, join__several);
417
ATF_ADD_TEST_CASE(tcs, join__unordered);
418
419
ATF_ADD_TEST_CASE(tcs, split__empty);
420
ATF_ADD_TEST_CASE(tcs, split__one);
421
ATF_ADD_TEST_CASE(tcs, split__several__simple);
422
ATF_ADD_TEST_CASE(tcs, split__several__delimiters);
423
424
ATF_ADD_TEST_CASE(tcs, replace_all__empty);
425
ATF_ADD_TEST_CASE(tcs, replace_all__none);
426
ATF_ADD_TEST_CASE(tcs, replace_all__one);
427
ATF_ADD_TEST_CASE(tcs, replace_all__several);
428
429
ATF_ADD_TEST_CASE(tcs, to_type__ok__bool);
430
ATF_ADD_TEST_CASE(tcs, to_type__ok__numerical);
431
ATF_ADD_TEST_CASE(tcs, to_type__ok__string);
432
ATF_ADD_TEST_CASE(tcs, to_type__empty);
433
ATF_ADD_TEST_CASE(tcs, to_type__invalid__bool);
434
ATF_ADD_TEST_CASE(tcs, to_type__invalid__numerical);
435
}
436
437