1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2023 LoRd_MuldeR <MuldeR2@GMX.de>
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.
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"
25 #include <MUtils/OSSupport.h>
30 //===========================================================================
32 //===========================================================================
34 class GlobalTest
: public Testbed
41 virtual void TearDown()
46 //===========================================================================
48 //===========================================================================
50 //-----------------------------------------------------------------
52 //-----------------------------------------------------------------
54 #define TEST_RANDOM_MAX 29989
55 #define TEST_RANDOM(X,Y) do \
58 for (size_t retry = 0; retry < 8; ++retry) \
61 for (size_t i = 0; i < TEST_RANDOM_MAX; ++i) \
63 test.insert(MUtils::next_rand_##Y()); \
65 if(test.count() == TEST_RANDOM_MAX) \
70 ASSERT_EQ(test.count(), TEST_RANDOM_MAX); \
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
);
92 //-----------------------------------------------------------------
94 //-----------------------------------------------------------------
96 #define TEST_TRIM_STR(X,Y,Z) do \
100 MUtils::trim_##X(test); \
101 ASSERT_QSTR(test, (Z)); \
104 const QString test((Y)); \
105 ASSERT_QSTR(MUtils::trim_##X(test), (Z)); \
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 !");
130 //-----------------------------------------------------------------
132 //-----------------------------------------------------------------
134 #define TEST_CLEAN_FILE(X,Y,Z) do \
136 ASSERT_QSTR(MUtils::clean_file_##X((Y), false), (Z)); \
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 //-----------------------------------------------------------------
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); \
201 ASSERT_TRUE(file.open(QIODevice::ReadWrite)); \
202 ASSERT_GE(file.write(TEST_STRING), strlen(TEST_STRING)); \
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 //-----------------------------------------------------------------
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); \
272 #define MAKE_SUB_DIR(X,Y) do \
274 ASSERT_TRUE((X).mkpath((Y))); \
275 ASSERT_TRUE((X).cd((Y))); \
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
));
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
++)
301 MAKE_SUB_DIR(dir
, QLatin1String(DIR_NAMES
[i
]));
302 for (size_t j
= 0; DIR_NAMES
[j
]; j
++)
305 MAKE_SUB_DIR(subdir
, QLatin1String(DIR_NAMES
[j
]));
306 QFile
test(subdir
.filePath("example.txt"));
307 MAKE_TEST_FILE(test
);
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));
317 ASSERT_TRUE(dir
.exists());
318 ASSERT_TRUE(MUtils::remove_directory(dir
.absolutePath(), true));
320 ASSERT_FALSE(dir
.exists());
324 #undef MAKE_TEST_FILE
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",
342 for (size_t i
= 0; TEST
[i
]; i
++)
344 test
<< QLatin1String(TEST
[i
]);
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 //-----------------------------------------------------------------
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]); \
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