Added support for VS2022 Update-10.
[MUtilities.git] / test / src / GlobalTest.cpp
blob1b980d85ab0cc18da1bbf8267a39fb0d5dabd0f7
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2023 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
22 #include "MUtilsTest.h"
24 //MUtils
25 #include <MUtils/OSSupport.h>
27 //Qt
28 #include <QSet>
30 //===========================================================================
31 // TESTBED CLASS
32 //===========================================================================
34 class GlobalTest : public Testbed
36 protected:
37 virtual void SetUp()
41 virtual void TearDown()
46 //===========================================================================
47 // TEST METHODS
48 //===========================================================================
50 //-----------------------------------------------------------------
51 // Random
52 //-----------------------------------------------------------------
54 #define TEST_RANDOM_MAX 29989
55 #define TEST_RANDOM(X,Y) do \
56 { \
57 QSet<X> test; \
58 for (size_t retry = 0; retry < 8; ++retry) \
59 { \
60 test.clear(); \
61 for (size_t i = 0; i < TEST_RANDOM_MAX; ++i) \
62 { \
63 test.insert(MUtils::next_rand_##Y()); \
64 } \
65 if(test.count() == TEST_RANDOM_MAX) \
66 { \
67 break; \
68 } \
69 } \
70 ASSERT_EQ(test.count(), TEST_RANDOM_MAX); \
71 } \
72 while(0)
74 TEST_F(GlobalTest, RandomU32)
76 TEST_RANDOM(quint32, u32);
79 TEST_F(GlobalTest, RandomU64)
81 TEST_RANDOM(quint64, u64);
84 TEST_F(GlobalTest, RandomStr)
86 TEST_RANDOM(QString, str);
89 #undef TEST_RANDOM
90 #undef RND_LIMIT
92 //-----------------------------------------------------------------
93 // Trim String
94 //-----------------------------------------------------------------
96 #define TEST_TRIM_STR(X,Y,Z) do \
97 { \
98 { \
99 QString test((Y)); \
100 MUtils::trim_##X(test); \
101 ASSERT_QSTR(test, (Z)); \
104 const QString test((Y)); \
105 ASSERT_QSTR(MUtils::trim_##X(test), (Z)); \
108 while(0)
110 TEST_F(GlobalTest, TrimStringLeft)
112 TEST_TRIM_STR(left, "", "");
113 TEST_TRIM_STR(left, " ", "");
114 TEST_TRIM_STR(left, "! test !", "! test !");
115 TEST_TRIM_STR(left, " test ", "test ");
116 TEST_TRIM_STR(left, " ! test ! ", "! test ! ");
119 TEST_F(GlobalTest, TrimStringRight)
121 TEST_TRIM_STR(right, "", "");
122 TEST_TRIM_STR(right, " ", "");
123 TEST_TRIM_STR(right, "! test !", "! test !");
124 TEST_TRIM_STR(right, " test ", " test");
125 TEST_TRIM_STR(right, " ! test ! ", " ! test !");
128 #undef TEST_TRIM_STR
130 //-----------------------------------------------------------------
131 // Clean File Path
132 //-----------------------------------------------------------------
134 #define TEST_CLEAN_FILE(X,Y,Z) do \
136 ASSERT_QSTR(MUtils::clean_file_##X((Y), false), (Z)); \
138 while(0)
140 static const char *const VALID_FILENAME_CHARS = "!#$%&'()+,-.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~";
142 TEST_F(GlobalTest, CleanFileName)
144 TEST_CLEAN_FILE(name, "", "");
145 TEST_CLEAN_FILE(name, VALID_FILENAME_CHARS, VALID_FILENAME_CHARS);
146 TEST_CLEAN_FILE(name, "example.txt", "example.txt");
147 TEST_CLEAN_FILE(name, " example.txt", " example.txt");
148 TEST_CLEAN_FILE(name, "example.txt ", "example.txt");
149 TEST_CLEAN_FILE(name, ".example.txt", ".example.txt");
150 TEST_CLEAN_FILE(name, "example.txt.", "example.txt");
151 TEST_CLEAN_FILE(name, "foo<>:\"/\\|?*\t\r\nbar", "foo____________bar");
152 TEST_CLEAN_FILE(name, "NUL", "___");
153 TEST_CLEAN_FILE(name, "xNUL", "xNUL");
154 TEST_CLEAN_FILE(name, "NULx", "NULx");
155 TEST_CLEAN_FILE(name, "NUL.txt", "___.txt");
156 TEST_CLEAN_FILE(name, "NULx.txt", "NULx.txt");
157 TEST_CLEAN_FILE(name, "xNUL.txt", "xNUL.txt");
160 TEST_F(GlobalTest, CleanFilePath)
162 TEST_CLEAN_FILE(path, "", "");
163 TEST_CLEAN_FILE(path, VALID_FILENAME_CHARS, VALID_FILENAME_CHARS);
164 TEST_CLEAN_FILE(path, "c:\\foo\\bar\\example.txt", "c:/foo/bar/example.txt");
165 TEST_CLEAN_FILE(path, "c:/foo/bar/example.txt", "c:/foo/bar/example.txt");
166 TEST_CLEAN_FILE(path, "foo\\bar\\example.txt", "foo/bar/example.txt");
167 TEST_CLEAN_FILE(path, "\\foo\\bar\\example.txt", "/foo/bar/example.txt");
168 TEST_CLEAN_FILE(path, "\\\\hostname\\share\\example.txt", "//hostname/share/example.txt");
169 TEST_CLEAN_FILE(path, "\\\\?\\c:\\very long path", "//?/c:/very long path");
170 TEST_CLEAN_FILE(path, "c:\\foo<>:\"|?*\t\r\nbar\\example.txt", "c:/foo__________bar/example.txt");
171 TEST_CLEAN_FILE(path, "c:\\example\\foo<>:\"|?*\t\r\nbar.txt", "c:/example/foo__________bar.txt");
172 TEST_CLEAN_FILE(path, "c:\\ foo\\ bar\\ example.txt", "c:/ foo/ bar/ example.txt");
173 TEST_CLEAN_FILE(path, "c:\\foo \\bar \\example.txt ", "c:/foo/bar/example.txt");
174 TEST_CLEAN_FILE(path, "c:\\foo bar\\exa mple.txt", "c:/foo bar/exa mple.txt");
175 TEST_CLEAN_FILE(path, "c:\\example\\NUL", "c:/example/___");
176 TEST_CLEAN_FILE(path, "c:\\example\\xNUL", "c:/example/xNUL");
177 TEST_CLEAN_FILE(path, "c:\\example\\NULx", "c:/example/NULx");
178 TEST_CLEAN_FILE(path, "c:\\example\\NUL.txt", "c:/example/___.txt");
179 TEST_CLEAN_FILE(path, "c:\\example\\xNUL.txt", "c:/example/xNUL.txt");
180 TEST_CLEAN_FILE(path, "c:\\example\\NULx.txt", "c:/example/NULx.txt");
183 //-----------------------------------------------------------------
184 // File Names
185 //-----------------------------------------------------------------
187 #define TEST_FILE_NAME(X, Y, ...) \
189 const QString workDir = makeTempFolder(__FUNCTION__); \
190 ASSERT_FALSE(workDir.isEmpty()); \
191 QSet<QString> test; \
192 const QRegExp pattern((Y)); \
193 for (int i = 0; i < 997; ++i) \
195 const QString name = MUtils::make_##X##_file(workDir, __VA_ARGS__); \
196 ASSERT_FALSE(name.isEmpty()); \
197 ASSERT_FALSE(test.contains(name)); \
198 ASSERT_GE(pattern.indexIn(name), 0); \
199 test.insert(name); \
200 QFile file(name); \
201 ASSERT_TRUE(file.open(QIODevice::ReadWrite)); \
202 ASSERT_GE(file.write(TEST_STRING), strlen(TEST_STRING)); \
203 file.close(); \
205 for (QSet<QString>::const_iterator iter = test.constBegin(); iter != test.constEnd(); iter++) \
207 ASSERT_TRUE(QFile::exists(*iter)); \
208 QFile::remove(*iter); \
212 TEST_F(GlobalTest, TempFileName)
214 TEST_FILE_NAME(temp, "/\\w+\\.txt$", "txt", true);
217 TEST_F(GlobalTest, UniqFileName)
219 TEST_FILE_NAME(unique, "/example.\\w+\\.txt$", "example", "txt");
222 #undef TEST_FILE_NAME
224 //-----------------------------------------------------------------
225 // Parity
226 //-----------------------------------------------------------------
228 TEST_F(GlobalTest, Parity)
230 ASSERT_EQ(MUtils::parity(0x00000000), false);
231 ASSERT_EQ(MUtils::parity(0x11111111), false);
232 ASSERT_EQ(MUtils::parity(0xFFFFFFFF), false);
233 ASSERT_EQ(MUtils::parity(0x00000001), true );
234 ASSERT_EQ(MUtils::parity(0x00000010), true );
235 ASSERT_EQ(MUtils::parity(0x00000100), true );
236 ASSERT_EQ(MUtils::parity(0x00001000), true );
237 ASSERT_EQ(MUtils::parity(0x00010000), true );
238 ASSERT_EQ(MUtils::parity(0x00100000), true );
239 ASSERT_EQ(MUtils::parity(0x01000000), true );
240 ASSERT_EQ(MUtils::parity(0x10000000), true );
241 ASSERT_EQ(MUtils::parity(0xEFFFFFFF), true );
242 ASSERT_EQ(MUtils::parity(0xFEFFFFFF), true );
243 ASSERT_EQ(MUtils::parity(0xFFEFFFFF), true );
244 ASSERT_EQ(MUtils::parity(0xFFFEFFFF), true );
245 ASSERT_EQ(MUtils::parity(0xFFFFEFFF), true );
246 ASSERT_EQ(MUtils::parity(0xFFFFFEFF), true );
247 ASSERT_EQ(MUtils::parity(0xFFFFFFEF), true );
248 ASSERT_EQ(MUtils::parity(0xFFFFFFFE), true );
249 ASSERT_EQ(MUtils::parity(0x10101010), false);
250 ASSERT_EQ(MUtils::parity(0x01010101), false);
251 ASSERT_EQ(MUtils::parity(0xC8A2CC96), false);
252 ASSERT_EQ(MUtils::parity(0x504928DD), true );
253 ASSERT_EQ(MUtils::parity(0x38BFB9EC), false);
254 ASSERT_EQ(MUtils::parity(0x73F42695), true );
255 ASSERT_EQ(MUtils::parity(0x9161E326), false);
256 ASSERT_EQ(MUtils::parity(0xB1C93AC2), true );
257 ASSERT_EQ(MUtils::parity(0xCA4B1193), false);
260 //-----------------------------------------------------------------
261 // Remove File/Dirrectory
262 //-----------------------------------------------------------------
264 #define MAKE_TEST_FILE(X) do \
266 ASSERT_TRUE((X).open(QIODevice::ReadWrite)); \
267 ASSERT_GE((X).write(TEST_STRING), strlen(TEST_STRING)); \
268 (X).setPermissions(QFile::ReadOwner|QFile::ExeOwner|QFile::ReadGroup|QFile::ExeGroup|QFile::ReadOther|QFile::ExeOther); \
270 while(0)
272 #define MAKE_SUB_DIR(X,Y) do \
274 ASSERT_TRUE((X).mkpath((Y))); \
275 ASSERT_TRUE((X).cd((Y))); \
277 while (0)
279 TEST_F(GlobalTest, RemoveFile)
281 const QString workDir = makeTempFolder(__FUNCTION__);
282 ASSERT_FALSE(workDir.isEmpty());
283 const QString fileName = QString("%1/example.txt").arg(workDir);
284 QFile test(fileName);
285 MAKE_TEST_FILE(test);
286 ASSERT_FALSE(MUtils::remove_file(fileName));
287 test.close();
288 ASSERT_TRUE(QFileInfo(fileName).exists());
289 ASSERT_TRUE(MUtils::remove_file(fileName));
290 ASSERT_FALSE(QFileInfo(fileName).exists());
293 TEST_F(GlobalTest, Directory)
295 const QString workDir = makeTempFolder(__FUNCTION__);
296 ASSERT_FALSE(workDir.isEmpty());
297 static const char *const DIR_NAMES[] = { "foo", "bar", NULL };
298 for (size_t i = 0; DIR_NAMES[i]; i++)
300 QDir dir(workDir);
301 MAKE_SUB_DIR(dir, QLatin1String(DIR_NAMES[i]));
302 for (size_t j = 0; DIR_NAMES[j]; j++)
304 QDir subdir(dir);
305 MAKE_SUB_DIR(subdir, QLatin1String(DIR_NAMES[j]));
306 QFile test(subdir.filePath("example.txt"));
307 MAKE_TEST_FILE(test);
308 test.close();
311 for (size_t i = 0; DIR_NAMES[i]; i++)
313 QDir dir(QString("%1/%2").arg(workDir, QLatin1String(DIR_NAMES[i])));
314 ASSERT_TRUE(dir.exists());
315 ASSERT_FALSE(MUtils::remove_directory(dir.absolutePath(), false));
316 dir.refresh();
317 ASSERT_TRUE(dir.exists());
318 ASSERT_TRUE(MUtils::remove_directory(dir.absolutePath(), true));
319 dir.refresh();
320 ASSERT_FALSE(dir.exists());
324 #undef MAKE_TEST_FILE
325 #undef MAKE_SUB_DIR
327 //-----------------------------------------------------------------
328 // Natural String Sort
329 //-----------------------------------------------------------------
331 TEST_F(GlobalTest, NaturalStrSort)
333 static const char *const TEST[] =
335 "z0.txt", "z1.txt", "z2.txt", "z3.txt", "z4.txt", "z5.txt", "z6.txt", "z7.txt", "z8.txt", "z9.txt",
336 "z10.txt", "z11.txt", "z12.txt", "z13.txt", "z14.txt", "z15.txt", "z16.txt", "z17.txt", "z18.txt", "z19.txt",
337 "z100.txt", "z101.txt", "z102.txt", "z103.txt", "z104.txt", "z105.txt", "z106.txt", "z107.txt", "z108.txt", "z109.txt",
338 NULL
341 QStringList test;
342 for (size_t i = 0; TEST[i]; i++)
344 test << QLatin1String(TEST[i]);
347 qsrand(time(NULL));
348 for (size_t q = 0; q < 97; q++)
350 for (size_t k = 0; k < 997; k++)
352 const size_t len = size_t(test.count());
353 for (size_t i = 0; i < len; i++)
355 test.swap(i, qrand() % len);
358 MUtils::natural_string_sort(test, true);
359 for (size_t i = 0; TEST[i]; i++)
361 ASSERT_QSTR(test[i], TEST[i]);
366 //-----------------------------------------------------------------
367 // RegExp Parser
368 //-----------------------------------------------------------------
370 #define TEST_REGEX_U32(X,Y,Z,...) do \
372 const QRegExp test(QLatin1String((X))); \
373 ASSERT_GE(test.indexIn(QLatin1String((Y))), 0); \
374 quint32 result[(Z)]; \
375 ASSERT_TRUE(MUtils::regexp_parse_uint32(test, result, (Z))); \
376 const quint32 expected[] = { __VA_ARGS__ }; \
377 for(size_t i = 0; i < (Z); i++) \
379 ASSERT_EQ(result[i], expected[i]); \
382 while(0)
384 TEST_F(GlobalTest, ParseRegExp)
386 TEST_REGEX_U32("(\\d+)", "42", 1, 42);
387 TEST_REGEX_U32("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)", "4 8 15 16 23 42", 6, 4, 8, 15, 16, 23, 42);
388 TEST_REGEX_U32("x264\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\s+\\w+", "x264 0.148.2744 b97ae06", 3, 0, 148, 2744);
389 TEST_REGEX_U32("HEVC\\s+encoder\\s+version\\s+(\\d+)\\.(\\d+)\\+(\\d+)-\\w+", "HEVC encoder version 2.1+70-78e1e1354a25", 3, 2, 1, 70);
392 #undef TEST_REGEX_U32