1 /* GLIB - Library of useful routines for C programming 2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20 /* 21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS 22 * file for a list of people on the GLib Team. See the ChangeLog 23 * files for a list of changes. These files are distributed with 24 * GLib at ftp://ftp.gtk.org/pub/gtk/. 25 */ 26 27 #undef G_DISABLE_ASSERT 28 #undef G_LOG_DOMAIN 29 30 #include <glib.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <stdlib.h> 34 35 36 typedef struct _TestResult TestResult; 37 38 struct _TestResult 39 { 40 gint argc; 41 const gchar **argv; 42 }; 43 44 static const gchar * 45 test_command_lines[] = 46 { 47 /* 0 */ "foo bar", 48 /* 1 */ "foo 'bar'", 49 /* 2 */ "foo \"bar\"", 50 /* 3 */ "foo '' 'bar'", 51 /* 4 */ "foo \"bar\"'baz'blah'foo'\\''blah'\"boo\"", 52 /* 5 */ "foo \t \tblah\tfoo\t\tbar baz", 53 /* 6 */ "foo ' spaces more spaces lots of spaces in this ' \t", 54 /* 7 */ "foo \\\nbar", 55 /* 8 */ "foo '' ''", 56 /* 9 */ "foo \\\" la la la", 57 /* 10 */ "foo \\ foo woo woo\\ ", 58 /* 11 */ "foo \"yada yada \\$\\\"\"", 59 /* 12 */ "foo \"c:\\\\\"", 60 NULL 61 }; 62 63 static const gchar *result0[] = { "foo", "bar", NULL }; 64 static const gchar *result1[] = { "foo", "bar", NULL }; 65 static const gchar *result2[] = { "foo", "bar", NULL }; 66 static const gchar *result3[] = { "foo", "", "bar", NULL }; 67 static const gchar *result4[] = { "foo", "barbazblahfoo'blahboo", NULL }; 68 static const gchar *result5[] = { "foo", "blah", "foo", "bar", "baz", NULL }; 69 static const gchar *result6[] = { "foo", " spaces more spaces lots of spaces in this ", NULL }; 70 static const gchar *result7[] = { "foo", "bar", NULL }; 71 static const gchar *result8[] = { "foo", "", "", NULL }; 72 static const gchar *result9[] = { "foo", "\"", "la", "la", "la", NULL }; 73 static const gchar *result10[] = { "foo", " foo", "woo", "woo ", NULL }; 74 static const gchar *result11[] = { "foo", "yada yada $\"", NULL }; 75 static const gchar *result12[] = { "foo", "c:\\", NULL }; 76 77 static const TestResult 78 correct_results[] = 79 { 80 { G_N_ELEMENTS (result0) - 1, result0 }, 81 { G_N_ELEMENTS (result1) - 1, result1 }, 82 { G_N_ELEMENTS (result2) - 1, result2 }, 83 { G_N_ELEMENTS (result3) - 1, result3 }, 84 { G_N_ELEMENTS (result4) - 1, result4 }, 85 { G_N_ELEMENTS (result5) - 1, result5 }, 86 { G_N_ELEMENTS (result6) - 1, result6 }, 87 { G_N_ELEMENTS (result7) - 1, result7 }, 88 { G_N_ELEMENTS (result8) - 1, result8 }, 89 { G_N_ELEMENTS (result9) - 1, result9 }, 90 { G_N_ELEMENTS (result10) - 1, result10 }, 91 { G_N_ELEMENTS (result11) - 1, result11 }, 92 { G_N_ELEMENTS (result12) - 1, result12 } 93 }; 94 95 static void 96 print_test (const gchar *cmdline, gint argc, gchar **argv, 97 const TestResult *result) 98 { 99 gint i; 100 101 fprintf (stderr, "Command line was: '%s'\n", cmdline); 102 103 fprintf (stderr, "Expected result (%d args):\n", result->argc); 104 105 i = 0; 106 while (result->argv[i]) 107 { 108 fprintf (stderr, " %3d '%s'\n", i, result->argv[i]); 109 ++i; 110 } 111 112 fprintf (stderr, "Actual result (%d args):\n", argc); 113 114 i = 0; 115 while (argv[i]) 116 { 117 fprintf (stderr, " %3d '%s'\n", i, argv[i]); 118 ++i; 119 } 120 } 121 122 static void 123 do_argv_test (const gchar *cmdline, const TestResult *result) 124 { 125 gint argc; 126 gchar **argv; 127 GError *err; 128 gint i; 129 130 err = NULL; 131 if (!g_shell_parse_argv (cmdline, &argc, &argv, &err)) 132 { 133 fprintf (stderr, "Error parsing command line that should work fine: %s\n", 134 err->message); 135 136 exit (1); 137 } 138 139 if (argc != result->argc) 140 { 141 fprintf (stderr, "Expected and actual argc don't match\n"); 142 print_test (cmdline, argc, argv, result); 143 exit (1); 144 } 145 146 i = 0; 147 while (argv[i]) 148 { 149 if (strcmp (argv[i], result->argv[i]) != 0) 150 { 151 fprintf (stderr, "Expected and actual arg %d do not match\n", i); 152 print_test (cmdline, argc, argv, result); 153 exit (1); 154 } 155 156 ++i; 157 } 158 159 if (argv[i] != NULL) 160 { 161 fprintf (stderr, "argv didn't get NULL-terminated\n"); 162 exit (1); 163 } 164 g_strfreev (argv); 165 } 166 167 static void 168 run_tests (void) 169 { 170 gint i; 171 172 i = 0; 173 while (test_command_lines[i]) 174 { 175 do_argv_test (test_command_lines[i], &correct_results[i]); 176 ++i; 177 } 178 } 179 180 static gboolean any_test_failed = FALSE; 181 182 #define CHECK_STRING_RESULT(expression, expected_value) \ 183 check_string_result (#expression, __FILE__, __LINE__, expression, expected_value) 184 185 static void 186 check_string_result (const char *expression, 187 const char *file_name, 188 int line_number, 189 char *result, 190 const char *expected) 191 { 192 gboolean match; 193 194 if (expected == NULL) 195 match = result == NULL; 196 else 197 match = result != NULL && strcmp (result, expected) == 0; 198 199 if (!match) 200 { 201 if (!any_test_failed) 202 fprintf (stderr, "\n"); 203 204 fprintf (stderr, "FAIL: check failed in %s, line %d\n", file_name, line_number); 205 fprintf (stderr, " evaluated: %s\n", expression); 206 fprintf (stderr, " expected: %s\n", expected == NULL ? "NULL" : expected); 207 fprintf (stderr, " got: %s\n", result == NULL ? "NULL" : result); 208 209 any_test_failed = TRUE; 210 } 211 212 g_free (result); 213 } 214 215 static char * 216 test_shell_unquote (const char *str) 217 { 218 char *result; 219 GError *error; 220 221 error = NULL; 222 result = g_shell_unquote (str, &error); 223 if (error == NULL) 224 return result; 225 226 /* Leaks the error, which is no big deal and easy to fix if we 227 * decide it matters. 228 */ 229 230 if (error->domain != G_SHELL_ERROR) 231 return g_strdup ("error in domain other than G_SHELL_ERROR"); 232 233 /* It would be nice to check the error message too, but that's 234 * localized, so it's too much of a pain. 235 */ 236 switch (error->code) 237 { 238 case G_SHELL_ERROR_BAD_QUOTING: 239 return g_strdup ("G_SHELL_ERROR_BAD_QUOTING"); 240 case G_SHELL_ERROR_EMPTY_STRING: 241 return g_strdup ("G_SHELL_ERROR_EMPTY_STRING"); 242 case G_SHELL_ERROR_FAILED: 243 return g_strdup ("G_SHELL_ERROR_FAILED"); 244 default: 245 return g_strdup ("bad error code in G_SHELL_ERROR domain"); 246 } 247 } 248 249 int 250 main (int argc, 251 char *argv[]) 252 { 253 run_tests (); 254 255 CHECK_STRING_RESULT (g_shell_quote (""), "''"); 256 CHECK_STRING_RESULT (g_shell_quote ("a"), "'a'"); 257 CHECK_STRING_RESULT (g_shell_quote ("("), "'('"); 258 CHECK_STRING_RESULT (g_shell_quote ("'"), "''\\'''"); 259 CHECK_STRING_RESULT (g_shell_quote ("'a"), "''\\''a'"); 260 CHECK_STRING_RESULT (g_shell_quote ("a'"), "'a'\\'''"); 261 CHECK_STRING_RESULT (g_shell_quote ("a'a"), "'a'\\''a'"); 262 263 CHECK_STRING_RESULT (test_shell_unquote (""), ""); 264 CHECK_STRING_RESULT (test_shell_unquote ("a"), "a"); 265 CHECK_STRING_RESULT (test_shell_unquote ("'a'"), "a"); 266 CHECK_STRING_RESULT (test_shell_unquote ("'('"), "("); 267 CHECK_STRING_RESULT (test_shell_unquote ("''\\'''"), "'"); 268 CHECK_STRING_RESULT (test_shell_unquote ("''\\''a'"), "'a"); 269 CHECK_STRING_RESULT (test_shell_unquote ("'a'\\'''"), "a'"); 270 CHECK_STRING_RESULT (test_shell_unquote ("'a'\\''a'"), "a'a"); 271 272 CHECK_STRING_RESULT (test_shell_unquote ("\\\\"), "\\"); 273 CHECK_STRING_RESULT (test_shell_unquote ("\\\n"), ""); 274 275 CHECK_STRING_RESULT (test_shell_unquote ("'\\''"), "G_SHELL_ERROR_BAD_QUOTING"); 276 277 #if defined (_MSC_VER) && (_MSC_VER <= 1200) 278 /* using \x22 instead of \" to work around a msvc 5.0, 6.0 compiler bug */ 279 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\\x22\""), "\""); 280 #else 281 CHECK_STRING_RESULT (test_shell_unquote ("\"\\\"\""), "\""); 282 #endif 283 284 CHECK_STRING_RESULT (test_shell_unquote ("\""), "G_SHELL_ERROR_BAD_QUOTING"); 285 CHECK_STRING_RESULT (test_shell_unquote ("'"), "G_SHELL_ERROR_BAD_QUOTING"); 286 287 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\\\\""), "\\"); 288 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\`\""), "`"); 289 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\$\""), "$"); 290 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\\n\""), "\n"); 291 292 CHECK_STRING_RESULT (test_shell_unquote ("\"\\'\""), "\\'"); 293 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\\r\""), "\\\r"); 294 CHECK_STRING_RESULT (test_shell_unquote ("\x22\\n\""), "\\n"); 295 296 return any_test_failed ? 1 : 0; 297 } 298