Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : * Copyright (C) 2019 Руслан Ижбулатов <lrn1986@gmail.com>
3 : : *
4 : : * SPDX-License-Identifier: LicenseRef-old-glib-tests
5 : : *
6 : : * This work is provided "as is"; redistribution and modification
7 : : * in whole or in part, in any medium, physical or electronic is
8 : : * permitted without restriction.
9 : : *
10 : : * This work 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.
13 : : *
14 : : * In no event shall the authors or contributors be liable for any
15 : : * direct, indirect, incidental, special, exemplary, or consequential
16 : : * damages (including, but not limited to, procurement of substitute
17 : : * goods or services; loss of use, data, or profits; or business
18 : : * interruption) however caused and on any theory of liability, whether
19 : : * in contract, strict liability, or tort (including negligence or
20 : : * otherwise) arising in any way out of the use of this software, even
21 : : * if advised of the possibility of such damage.
22 : : */
23 : :
24 : : #include <glib/glib.h>
25 : : #include <gio/gio.h>
26 : : #include <stdlib.h>
27 : :
28 : : #include "../giowin32-private.c"
29 : :
30 : : static int
31 : 17 : g_utf16_cmp0 (const gunichar2 *str1,
32 : : const gunichar2 *str2)
33 : : {
34 : 17 : if (!str1)
35 : 0 : return -(str1 != str2);
36 : 17 : if (!str2)
37 : 0 : return str1 != str2;
38 : :
39 : : while (TRUE)
40 : : {
41 : 1010 : if (str1[0] > str2[0])
42 : 0 : return 1;
43 : 1010 : else if (str1[0] < str2[0])
44 : 0 : return -1;
45 : 1010 : else if (str1[0] == 0 && str2[0] == 0)
46 : 17 : return 0;
47 : :
48 : 993 : str1++;
49 : 993 : str2++;
50 : : }
51 : : }
52 : :
53 : : #define g_assert_cmputf16(s1, cmp, s2, s1u8, s2u8) \
54 : : G_STMT_START { \
55 : : const gunichar2 *__s1 = (s1), *__s2 = (s2); \
56 : : if (g_utf16_cmp0 (__s1, __s2) cmp 0) ; else \
57 : : g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
58 : : #s1u8 " " #cmp " " #s2u8, s1u8, #cmp, s2u8); \
59 : : } G_STMT_END
60 : :
61 : : static void
62 : 1 : test_utf16_strfuncs (void)
63 : : {
64 : : gsize i;
65 : :
66 : : struct {
67 : : gsize len;
68 : : const gunichar2 utf16[10];
69 : : const gchar *utf8;
70 : : const gchar *utf8_folded;
71 : 1 : } string_cases[] = {
72 : : {
73 : : 0,
74 : : { 0x0000 },
75 : : "",
76 : : "",
77 : : },
78 : : {
79 : : 1,
80 : : { 0x0020, 0x0000 },
81 : : " ",
82 : : " ",
83 : : },
84 : : {
85 : : 2,
86 : : { 0x0020, 0xd800, 0x0000 },
87 : : NULL,
88 : : NULL,
89 : : },
90 : : };
91 : :
92 : 4 : for (i = 0; i < G_N_ELEMENTS (string_cases); i++)
93 : : {
94 : : gsize len;
95 : : gunichar2 *str;
96 : : gboolean success;
97 : : gchar *utf8;
98 : : gchar *utf8_folded;
99 : :
100 : 3 : len = g_utf16_len (string_cases[i].utf16);
101 : 3 : g_assert_cmpuint (len, ==, string_cases[i].len);
102 : :
103 : 3 : str = (gunichar2 *) g_utf16_find_basename (string_cases[i].utf16, -1);
104 : : /* This only works because all testcases lack separators */
105 : 3 : g_assert_true (string_cases[i].utf16 == str);
106 : :
107 : 3 : str = g_wcsdup (string_cases[i].utf16, string_cases[i].len);
108 : 3 : g_assert_cmpmem (string_cases[i].utf16, len, str, len);
109 : 3 : g_free (str);
110 : :
111 : 3 : str = g_wcsdup (string_cases[i].utf16, -1);
112 : 3 : g_assert_cmpmem (string_cases[i].utf16, len, str, len);
113 : 3 : g_free (str);
114 : :
115 : 3 : success = g_utf16_to_utf8_and_fold (string_cases[i].utf16, -1, NULL, NULL);
116 : :
117 : 3 : if (string_cases[i].utf8 == NULL)
118 : 1 : g_assert_false (success);
119 : : else
120 : 2 : g_assert_true (success);
121 : :
122 : 3 : utf8 = NULL;
123 : 3 : success = g_utf16_to_utf8_and_fold (string_cases[i].utf16, -1, &utf8, NULL);
124 : :
125 : 3 : if (string_cases[i].utf8 != NULL)
126 : : {
127 : 2 : g_assert_true (success);
128 : 2 : g_assert_cmpstr (string_cases[i].utf8, ==, utf8);
129 : : /* This only works because all testcases lack separators */
130 : 2 : g_assert_true (utf8 == g_utf8_find_basename (utf8, len));
131 : : }
132 : :
133 : 3 : g_free (utf8);
134 : :
135 : 3 : utf8 = NULL;
136 : 3 : utf8_folded = NULL;
137 : 3 : success = g_utf16_to_utf8_and_fold (string_cases[i].utf16, -1, &utf8, &utf8_folded);
138 : :
139 : 3 : if (string_cases[i].utf8 != NULL)
140 : : {
141 : 2 : g_assert_true (success);
142 : 2 : g_assert_cmpstr (string_cases[i].utf8_folded, ==, utf8_folded);
143 : : }
144 : :
145 : 3 : g_free (utf8);
146 : 3 : g_free (utf8_folded);
147 : : }
148 : 1 : }
149 : :
150 : : struct {
151 : : const char *orig;
152 : : const char *executable;
153 : : const char *executable_basename;
154 : : gboolean is_rundll32;
155 : : const char *fixed;
156 : : } rundll32_commandlines[] = {
157 : : {
158 : : "%SystemRoot%\\System32\\rundll32.exe \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\", ImageView_Fullscreen %1",
159 : : "%SystemRoot%\\System32\\rundll32.exe",
160 : : "rundll32.exe",
161 : : TRUE,
162 : : "%SystemRoot%\\System32\\rundll32.exe \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\" ImageView_Fullscreen %1",
163 : : },
164 : : {
165 : : "%SystemRoot%/System32/rundll32.exe \"%ProgramFiles%/Windows Photo Viewer/PhotoViewer.dll\", ImageView_Fullscreen %1",
166 : : "%SystemRoot%/System32/rundll32.exe",
167 : : "rundll32.exe",
168 : : TRUE,
169 : : "%SystemRoot%/System32/rundll32.exe \"%ProgramFiles%/Windows Photo Viewer/PhotoViewer.dll\" ImageView_Fullscreen %1",
170 : : },
171 : : {
172 : : "%SystemRoot%\\System32/rundll32.exe \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\", ImageView_Fullscreen %1",
173 : : "%SystemRoot%\\System32/rundll32.exe",
174 : : "rundll32.exe",
175 : : TRUE,
176 : : "%SystemRoot%\\System32/rundll32.exe \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\" ImageView_Fullscreen %1",
177 : : },
178 : : {
179 : : "\"some path with spaces\\rundll32.exe\" \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\", ImageView_Fullscreen %1",
180 : : "some path with spaces\\rundll32.exe",
181 : : "rundll32.exe",
182 : : TRUE,
183 : : "\"some path with spaces\\rundll32.exe\" \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\" ImageView_Fullscreen %1",
184 : : },
185 : : {
186 : : " \"some path with spaces\\rundll32.exe\"\"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\",ImageView_Fullscreen %1",
187 : : "some path with spaces\\rundll32.exe",
188 : : "rundll32.exe",
189 : : TRUE,
190 : : " \"some path with spaces\\rundll32.exe\"\"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll\" ImageView_Fullscreen %1",
191 : : },
192 : : {
193 : : "rundll32.exe foo.bar,baz",
194 : : "rundll32.exe",
195 : : "rundll32.exe",
196 : : TRUE,
197 : : "rundll32.exe foo.bar baz",
198 : : },
199 : : {
200 : : " rundll32.exe foo.bar,baz",
201 : : "rundll32.exe",
202 : : "rundll32.exe",
203 : : TRUE,
204 : : " rundll32.exe foo.bar baz",
205 : : },
206 : : {
207 : : "rundll32.exe",
208 : : "rundll32.exe",
209 : : "rundll32.exe",
210 : : FALSE,
211 : : NULL,
212 : : },
213 : : {
214 : : "rundll32.exe ,foobar",
215 : : "rundll32.exe",
216 : : "rundll32.exe",
217 : : FALSE,
218 : : NULL,
219 : : },
220 : : {
221 : : "rundll32.exe ,foobar",
222 : : "rundll32.exe",
223 : : "rundll32.exe",
224 : : FALSE,
225 : : NULL,
226 : : },
227 : : {
228 : : "rundll32.exe foo.dll",
229 : : "rundll32.exe",
230 : : "rundll32.exe",
231 : : FALSE,
232 : : NULL,
233 : : },
234 : : {
235 : : "rundll32.exe \"foo bar\",baz",
236 : : "rundll32.exe",
237 : : "rundll32.exe",
238 : : TRUE,
239 : : "rundll32.exe \"foo bar\" baz",
240 : : },
241 : : {
242 : : "\"rundll32.exe\" \"foo bar\",baz",
243 : : "rundll32.exe",
244 : : "rundll32.exe",
245 : : TRUE,
246 : : "\"rundll32.exe\" \"foo bar\" baz",
247 : : },
248 : : {
249 : : "\"rundll32.exe\" \"foo bar\",, , ,,, , ,,baz",
250 : : "rundll32.exe",
251 : : "rundll32.exe",
252 : : TRUE,
253 : : "\"rundll32.exe\" \"foo bar\" , , ,,, , ,,baz",
254 : : },
255 : : {
256 : : "\"rundll32.exe\" foo.bar,,,,,,,,,baz",
257 : : "rundll32.exe",
258 : : "rundll32.exe",
259 : : TRUE,
260 : : "\"rundll32.exe\" foo.bar ,,,,,,,,baz",
261 : : },
262 : : {
263 : : "\"rundll32.exe\" foo.bar baz",
264 : : "rundll32.exe",
265 : : "rundll32.exe",
266 : : TRUE,
267 : : "\"rundll32.exe\" foo.bar baz",
268 : : },
269 : : {
270 : : "\"RuNdlL32.exe\" foo.bar baz",
271 : : "RuNdlL32.exe",
272 : : "RuNdlL32.exe",
273 : : TRUE,
274 : : "\"RuNdlL32.exe\" foo.bar baz",
275 : : },
276 : : {
277 : : "%SystemRoot%\\System32\\rundll32.exe \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll,\" ImageView_Fullscreen %1",
278 : : "%SystemRoot%\\System32\\rundll32.exe",
279 : : "rundll32.exe",
280 : : TRUE,
281 : : "%SystemRoot%\\System32\\rundll32.exe \"%ProgramFiles%\\Windows Photo Viewer\\PhotoViewer.dll,\" ImageView_Fullscreen %1",
282 : : },
283 : : {
284 : : "\"rundll32.exe\" \"foo bar,\"baz",
285 : : "rundll32.exe",
286 : : "rundll32.exe",
287 : : TRUE,
288 : : "\"rundll32.exe\" \"foo bar,\"baz",
289 : : },
290 : : {
291 : : "\"rundll32.exe\" some,thing",
292 : : "rundll32.exe",
293 : : "rundll32.exe",
294 : : TRUE,
295 : : "\"rundll32.exe\" some thing",
296 : : },
297 : : {
298 : : "\"rundll32.exe\" some,",
299 : : "rundll32.exe",
300 : : "rundll32.exe",
301 : : FALSE,
302 : : "\"rundll32.exe\" some,",
303 : : },
304 : : /* These filenames are not allowed on Windows, but our function doesn't care about that */
305 : : {
306 : : "run\"dll32.exe foo\".bar,baz",
307 : : "run\"dll32.exe",
308 : : "run\"dll32.exe",
309 : : FALSE,
310 : : NULL,
311 : : },
312 : : {
313 : : "run,dll32.exe foo.bar,baz",
314 : : "run,dll32.exe",
315 : : "run,dll32.exe",
316 : : FALSE,
317 : : NULL,
318 : : },
319 : : {
320 : : "\"rundll32.exe\" some, thing",
321 : : "rundll32.exe",
322 : : "rundll32.exe",
323 : : TRUE,
324 : : "\"rundll32.exe\" some thing",
325 : : },
326 : : /* Commands with "rundll32" (without the .exe suffix) do exist,
327 : : * but GLib currently does not recognize them, so there's no point
328 : : * in testing these.
329 : : */
330 : : };
331 : :
332 : : static void
333 : 1 : test_win32_rundll32_fixup (void)
334 : : {
335 : : gsize i;
336 : :
337 : 25 : for (i = 0; i < G_N_ELEMENTS (rundll32_commandlines); i++)
338 : : {
339 : : gunichar2 *argument;
340 : : gunichar2 *expected;
341 : :
342 : 24 : if (!rundll32_commandlines[i].is_rundll32)
343 : 7 : continue;
344 : :
345 : 17 : argument = g_utf8_to_utf16 (rundll32_commandlines[i].orig, -1, NULL, NULL, NULL);
346 : 17 : expected = g_utf8_to_utf16 (rundll32_commandlines[i].fixed, -1, NULL, NULL, NULL);
347 : :
348 : 17 : g_assert_nonnull (argument);
349 : 17 : g_assert_nonnull (expected);
350 : 17 : _g_win32_fixup_broken_microsoft_rundll_commandline (argument);
351 : :
352 : 17 : g_assert_cmputf16 (argument, ==, expected, rundll32_commandlines[i].orig, rundll32_commandlines[i].fixed);
353 : :
354 : 17 : g_free (argument);
355 : 17 : g_free (expected);
356 : : }
357 : 1 : }
358 : :
359 : : static void
360 : 1 : test_win32_extract_executable (void)
361 : : {
362 : : gsize i;
363 : :
364 : 25 : for (i = 0; i < G_N_ELEMENTS (rundll32_commandlines); i++)
365 : : {
366 : : gunichar2 *argument;
367 : : gchar *dll_function;
368 : : gchar *executable;
369 : : gchar *executable_basename;
370 : : gchar *executable_folded;
371 : : gchar *executable_folded_basename;
372 : :
373 : 24 : argument = g_utf8_to_utf16 (rundll32_commandlines[i].orig, -1, NULL, NULL, NULL);
374 : :
375 : 24 : _g_win32_extract_executable (argument, NULL, NULL, NULL, NULL, &dll_function);
376 : :
377 : 24 : if (rundll32_commandlines[i].is_rundll32)
378 : 17 : g_assert_nonnull (dll_function);
379 : : else
380 : 7 : g_assert_null (dll_function);
381 : :
382 : 24 : g_free (dll_function);
383 : :
384 : 24 : executable = NULL;
385 : 24 : executable_basename = NULL;
386 : 24 : executable_folded = NULL;
387 : 24 : executable_folded_basename = NULL;
388 : 24 : _g_win32_extract_executable (argument, &executable, &executable_basename, &executable_folded, &executable_folded_basename, NULL);
389 : :
390 : 24 : g_assert_cmpstr (rundll32_commandlines[i].executable, ==, executable);
391 : 24 : g_assert_cmpstr (rundll32_commandlines[i].executable_basename, ==, executable_basename);
392 : 24 : g_assert_nonnull (executable_folded);
393 : :
394 : 24 : g_free (executable);
395 : 24 : g_free (executable_folded);
396 : :
397 : : /* Check the corner-case where we don't want to know where basename is */
398 : 24 : executable = NULL;
399 : 24 : executable_folded = NULL;
400 : 24 : _g_win32_extract_executable (argument, &executable, NULL, &executable_folded, NULL, NULL);
401 : :
402 : 24 : g_assert_cmpstr (rundll32_commandlines[i].executable, ==, executable);
403 : 24 : g_assert_nonnull (executable_folded);
404 : :
405 : 24 : g_free (executable);
406 : 24 : g_free (executable_folded);
407 : :
408 : 24 : g_free (argument);
409 : : }
410 : 1 : }
411 : :
412 : : static void
413 : 1 : test_win32_parse_filename (void)
414 : : {
415 : : gsize i;
416 : :
417 : 25 : for (i = 0; i < G_N_ELEMENTS (rundll32_commandlines); i++)
418 : : {
419 : : gunichar2 *argument;
420 : 24 : argument = g_utf8_to_utf16 (rundll32_commandlines[i].orig, -1, NULL, NULL, NULL);
421 : : /* Just checking that it doesn't blow up on various (sometimes incorrect) strings */
422 : 24 : _g_win32_parse_filename (argument, FALSE, NULL, NULL, NULL, NULL);
423 : 24 : g_free (argument);
424 : : }
425 : 1 : }
426 : :
427 : : static void
428 : 0 : do_fail_on_broken_utf16_1 (void)
429 : : {
430 : 0 : const gunichar2 utf16[] = { 0xd800, 0x0000 };
431 : 0 : _g_win32_extract_executable (utf16, NULL, NULL, NULL, NULL, NULL);
432 : 0 : }
433 : :
434 : : static void
435 : 0 : do_fail_on_broken_utf16_2 (void)
436 : : {
437 : : /* "rundll32.exe <invalid utf16> r" */
438 : : gchar *dll_function;
439 : 0 : const gunichar2 utf16[] = { 0x0072, 0x0075, 0x006E, 0x0064, 0x006C, 0x006C, 0x0033, 0x0032,
440 : : 0x002E, 0x0065, 0x0078, 0x0065, 0x0020, 0xd800, 0x0020, 0x0072, 0x0000 };
441 : 0 : _g_win32_extract_executable (utf16, NULL, NULL, NULL, NULL, &dll_function);
442 : 0 : }
443 : :
444 : : static void
445 : 1 : test_fail_on_broken_utf16 (void)
446 : : {
447 : 1 : g_test_trap_subprocess ("/appinfo/subprocess/win32-assert-broken-utf16_1", 0,
448 : : G_TEST_SUBPROCESS_DEFAULT);
449 : 1 : g_test_trap_assert_failed ();
450 : 1 : g_test_trap_assert_stderr ("*GLib-GIO:ERROR:*giowin32-private.c:*:_g_win32_extract_executable: assertion failed: (folded)*");
451 : 1 : g_test_trap_subprocess ("/appinfo/subprocess/win32-assert-broken-utf16_2", 0,
452 : : G_TEST_SUBPROCESS_DEFAULT);
453 : 1 : g_test_trap_assert_failed ();
454 : 1 : g_test_trap_assert_stderr ("*GLib-GIO:ERROR:*giowin32-private.c:*:_g_win32_extract_executable: assertion failed: (folded)*");
455 : 1 : }
456 : :
457 : : int
458 : 1 : main (int argc,
459 : : char *argv[])
460 : : {
461 : 1 : g_test_init (&argc, &argv, NULL);
462 : :
463 : 1 : g_test_add_func ("/appinfo/utf16-strfuncs", test_utf16_strfuncs);
464 : 1 : g_test_add_func ("/appinfo/win32-extract-executable", test_win32_extract_executable);
465 : 1 : g_test_add_func ("/appinfo/win32-rundll32-fixup", test_win32_rundll32_fixup);
466 : 1 : g_test_add_func ("/appinfo/win32-parse-filename", test_win32_parse_filename);
467 : 1 : g_test_add_func ("/appinfo/win32-utf16-conversion-fail", test_fail_on_broken_utf16);
468 : :
469 : 1 : g_test_add_func ("/appinfo/subprocess/win32-assert-broken-utf16_1", do_fail_on_broken_utf16_1);
470 : 1 : g_test_add_func ("/appinfo/subprocess/win32-assert-broken-utf16_2", do_fail_on_broken_utf16_2);
471 : :
472 : 1 : return g_test_run ();
473 : : }
|