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