3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "util/numeric.h"
24 #include "util/string.h"
26 class TestUtilities : public TestBase {
28 TestUtilities() { TestManager::registerTestModule(this); }
29 const char *getName() { return "TestUtilities"; }
31 void runTests(IGameDef *gamedef);
33 void testAngleWrapAround();
34 void testWrapDegrees_0_360_v3f();
38 void testRemoveStringEnd();
42 void testStartsWith();
44 void testStringTrim();
45 void testStrToIntConversion();
46 void testStringReplace();
47 void testStringAllowed();
48 void testAsciiPrintableHelper();
50 void testRemoveEscapes();
53 void testIsPowerOfTwo();
55 void testStringJoin();
58 static TestUtilities g_test_instance;
60 void TestUtilities::runTests(IGameDef *gamedef)
62 TEST(testAngleWrapAround);
63 TEST(testWrapDegrees_0_360_v3f);
67 TEST(testRemoveStringEnd);
74 TEST(testStrToIntConversion);
75 TEST(testStringReplace);
76 TEST(testStringAllowed);
77 TEST(testAsciiPrintableHelper);
79 TEST(testRemoveEscapes);
82 TEST(testIsPowerOfTwo);
87 ////////////////////////////////////////////////////////////////////////////////
89 inline float ref_WrapDegrees180(float f)
91 // This is a slower alternative to the wrapDegrees_180() function;
92 // used as a reference for testing
93 float value = fmodf(f + 180, 360);
100 inline float ref_WrapDegrees_0_360(float f)
102 // This is a slower alternative to the wrapDegrees_0_360() function;
103 // used as a reference for testing
104 float value = fmodf(f, 360);
107 return value < 0 ? value + 360 : value;
111 void TestUtilities::testAngleWrapAround() {
112 UASSERT(fabs(modulo360f(100.0) - 100.0) < 0.001);
113 UASSERT(fabs(modulo360f(720.5) - 0.5) < 0.001);
114 UASSERT(fabs(modulo360f(-0.5) - (-0.5)) < 0.001);
115 UASSERT(fabs(modulo360f(-365.5) - (-5.5)) < 0.001);
117 for (float f = -720; f <= -360; f += 0.25) {
118 UASSERT(std::fabs(modulo360f(f) - modulo360f(f + 360)) < 0.001);
121 for (float f = -1440; f <= 1440; f += 0.25) {
122 UASSERT(std::fabs(modulo360f(f) - fmodf(f, 360)) < 0.001);
123 UASSERT(std::fabs(wrapDegrees_180(f) - ref_WrapDegrees180(f)) < 0.001);
124 UASSERT(std::fabs(wrapDegrees_0_360(f) - ref_WrapDegrees_0_360(f)) < 0.001);
125 UASSERT(wrapDegrees_0_360(
126 std::fabs(wrapDegrees_180(f) - wrapDegrees_0_360(f))) < 0.001);
131 void TestUtilities::testWrapDegrees_0_360_v3f()
133 // only x test with little step
134 for (float x = -720.f; x <= 720; x += 0.05) {
135 v3f r = wrapDegrees_0_360_v3f(v3f(x, 0, 0));
136 UASSERT(r.X >= 0.0f && r.X < 360.0f)
141 // only y test with little step
142 for (float y = -720.f; y <= 720; y += 0.05) {
143 v3f r = wrapDegrees_0_360_v3f(v3f(0, y, 0));
145 UASSERT(r.Y >= 0.0f && r.Y < 360.0f)
149 // only z test with little step
150 for (float z = -720.f; z <= 720; z += 0.05) {
151 v3f r = wrapDegrees_0_360_v3f(v3f(0, 0, z));
154 UASSERT(r.Z >= 0.0f && r.Z < 360.0f)
157 // test the whole coordinate translation
158 for (float x = -720.f; x <= 720; x += 2.5) {
159 for (float y = -720.f; y <= 720; y += 2.5) {
160 for (float z = -720.f; z <= 720; z += 2.5) {
161 v3f r = wrapDegrees_0_360_v3f(v3f(x, y, z));
162 UASSERT(r.X >= 0.0f && r.X < 360.0f)
163 UASSERT(r.Y >= 0.0f && r.Y < 360.0f)
164 UASSERT(r.Z >= 0.0f && r.Z < 360.0f)
171 void TestUtilities::testLowercase()
173 UASSERT(lowercase("Foo bAR") == "foo bar");
177 void TestUtilities::testTrim()
179 UASSERT(trim("") == "");
180 UASSERT(trim("dirt_with_grass") == "dirt_with_grass");
181 UASSERT(trim("\n \t\r Foo bAR \r\n\t\t ") == "Foo bAR");
182 UASSERT(trim("\n \t\r \r\n\t\t ") == "");
186 void TestUtilities::testIsYes()
188 UASSERT(is_yes("YeS") == true);
189 UASSERT(is_yes("") == false);
190 UASSERT(is_yes("FAlse") == false);
191 UASSERT(is_yes("-1") == true);
192 UASSERT(is_yes("0") == false);
193 UASSERT(is_yes("1") == true);
194 UASSERT(is_yes("2") == true);
198 void TestUtilities::testRemoveStringEnd()
200 const char *ends[] = {"abc", "c", "bc", "", NULL};
201 UASSERT(removeStringEnd("abc", ends) == "");
202 UASSERT(removeStringEnd("bc", ends) == "b");
203 UASSERT(removeStringEnd("12c", ends) == "12");
204 UASSERT(removeStringEnd("foo", ends) == "");
208 void TestUtilities::testUrlEncode()
210 UASSERT(urlencode("\"Aardvarks lurk, OK?\"")
211 == "%22Aardvarks%20lurk%2C%20OK%3F%22");
215 void TestUtilities::testUrlDecode()
217 UASSERT(urldecode("%22Aardvarks%20lurk%2C%20OK%3F%22")
218 == "\"Aardvarks lurk, OK?\"");
222 void TestUtilities::testPadString()
224 UASSERT(padStringRight("hello", 8) == "hello ");
227 void TestUtilities::testStartsWith()
229 UASSERT(str_starts_with(std::string(), std::string()) == true);
230 UASSERT(str_starts_with(std::string("the sharp pickaxe"),
231 std::string()) == true);
232 UASSERT(str_starts_with(std::string("the sharp pickaxe"),
233 std::string("the")) == true);
234 UASSERT(str_starts_with(std::string("the sharp pickaxe"),
235 std::string("The")) == false);
236 UASSERT(str_starts_with(std::string("the sharp pickaxe"),
237 std::string("The"), true) == true);
238 UASSERT(str_starts_with(std::string("T"), std::string("The")) == false);
241 void TestUtilities::testStrEqual()
243 UASSERT(str_equal(narrow_to_wide("abc"), narrow_to_wide("abc")));
244 UASSERT(str_equal(narrow_to_wide("ABC"), narrow_to_wide("abc"), true));
248 void TestUtilities::testStringTrim()
250 UASSERT(trim(" a") == "a");
251 UASSERT(trim(" a ") == "a");
252 UASSERT(trim("a ") == "a");
253 UASSERT(trim("") == "");
257 void TestUtilities::testStrToIntConversion()
259 UASSERT(mystoi("123", 0, 1000) == 123);
260 UASSERT(mystoi("123", 0, 10) == 10);
264 void TestUtilities::testStringReplace()
266 std::string test_str;
267 test_str = "Hello there";
268 str_replace(test_str, "there", "world");
269 UASSERT(test_str == "Hello world");
270 test_str = "ThisAisAaAtest";
271 str_replace(test_str, 'A', ' ');
272 UASSERT(test_str == "This is a test");
276 void TestUtilities::testStringAllowed()
278 UASSERT(string_allowed("hello", "abcdefghijklmno") == true);
279 UASSERT(string_allowed("123", "abcdefghijklmno") == false);
280 UASSERT(string_allowed_blacklist("hello", "123") == true);
281 UASSERT(string_allowed_blacklist("hello123", "123") == false);
284 void TestUtilities::testAsciiPrintableHelper()
286 UASSERT(IS_ASCII_PRINTABLE_CHAR('e') == true);
287 UASSERT(IS_ASCII_PRINTABLE_CHAR('\0') == false);
289 // Ensures that there is no cutting off going on...
290 // If there were, 331 would be cut to 75 in this example
291 // and 73 is a valid ASCII char.
293 UASSERT(IS_ASCII_PRINTABLE_CHAR(ch) == false);
296 void TestUtilities::testUTF8()
298 UASSERT(wide_to_utf8(utf8_to_wide("")) == "");
299 UASSERT(wide_to_utf8(utf8_to_wide("the shovel dug a crumbly node!"))
300 == "the shovel dug a crumbly node!");
303 void TestUtilities::testRemoveEscapes()
305 UASSERT(unescape_enriched<wchar_t>(
306 L"abc\x1bXdef") == L"abcdef");
307 UASSERT(unescape_enriched<wchar_t>(
308 L"abc\x1b(escaped)def") == L"abcdef");
309 UASSERT(unescape_enriched<wchar_t>(
310 L"abc\x1b((escaped with parenthesis\\))def") == L"abcdef");
311 UASSERT(unescape_enriched<wchar_t>(
312 L"abc\x1b(incomplete") == L"abc");
313 UASSERT(unescape_enriched<wchar_t>(
314 L"escape at the end\x1b") == L"escape at the end");
315 // Nested escapes not supported
316 UASSERT(unescape_enriched<wchar_t>(
317 L"abc\x1b(outer \x1b(inner escape)escape)def") == L"abcescape)def");
320 void TestUtilities::testWrapRows()
322 UASSERT(wrap_rows("12345678",4) == "1234\n5678");
323 // test that wrap_rows doesn't wrap inside multibyte sequences
325 const unsigned char s[] = {
326 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x72, 0x61, 0x70, 0x74, 0x6f,
327 0x72, 0x2f, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0x2f,
328 0x6d, 0x69, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x62, 0x69,
329 0x6e, 0x2f, 0x2e, 0x2e, 0};
330 std::string str((char *)s);
331 UASSERT(utf8_to_wide(wrap_rows(str, 20)) != L"<invalid UTF-8 string>");
334 const unsigned char s[] = {
335 0x74, 0x65, 0x73, 0x74, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81,
336 0xd1, 0x82, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82,
337 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0};
338 std::string str((char *)s);
339 UASSERT(utf8_to_wide(wrap_rows(str, 8)) != L"<invalid UTF-8 string>");
344 void TestUtilities::testIsNumber()
346 UASSERT(is_number("123") == true);
347 UASSERT(is_number("") == false);
348 UASSERT(is_number("123a") == false);
352 void TestUtilities::testIsPowerOfTwo()
354 UASSERT(is_power_of_two(0) == false);
355 UASSERT(is_power_of_two(1) == true);
356 UASSERT(is_power_of_two(2) == true);
357 UASSERT(is_power_of_two(3) == false);
358 for (int exponent = 2; exponent <= 31; ++exponent) {
359 UASSERT(is_power_of_two((1 << exponent) - 1) == false);
360 UASSERT(is_power_of_two((1 << exponent)) == true);
361 UASSERT(is_power_of_two((1 << exponent) + 1) == false);
363 UASSERT(is_power_of_two(U32_MAX) == false);
366 void TestUtilities::testMyround()
368 UASSERT(myround(4.6f) == 5);
369 UASSERT(myround(1.2f) == 1);
370 UASSERT(myround(-3.1f) == -3);
371 UASSERT(myround(-6.5f) == -7);
374 void TestUtilities::testStringJoin()
376 std::vector<std::string> input;
377 UASSERT(str_join(input, ",") == "");
379 input.emplace_back("one");
380 UASSERT(str_join(input, ",") == "one");
382 input.emplace_back("two");
383 UASSERT(str_join(input, ",") == "one,two");
385 input.emplace_back("three");
386 UASSERT(str_join(input, ",") == "one,two,three");
389 UASSERT(str_join(input, ",") == "one,,three");
392 UASSERT(str_join(input, " and ") == "one and two and three");