Home | History | Annotate | Download | only in tests
      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 "config.h"
     31 
     32 #include <glib.h>
     33 #include <stdio.h>
     34 #include <string.h>
     35 #include <stdlib.h>
     36 
     37 typedef struct
     38 {
     39   char *filename;
     40   char *hostname;
     41   char *expected_result;
     42   GConvertError expected_error; /* If failed */
     43 }  ToUriTest;
     44 
     45 ToUriTest
     46 to_uri_tests[] = {
     47   { "/etc", NULL, "file:///etc"},
     48   { "/etc", "", "file:///etc"},
     49   { "/etc", "otherhost", "file://otherhost/etc"},
     50 #ifdef G_OS_WIN32
     51   { "/etc", "localhost", "file:///etc"},
     52   { "c:\\windows", NULL, "file:///c:/windows"},
     53   { "c:\\windows", "localhost", "file:///c:/windows"},
     54   { "c:\\windows", "otherhost", "file://otherhost/c:/windows"},
     55   { "\\\\server\\share\\dir", NULL, "file:////server/share/dir"},
     56   { "\\\\server\\share\\dir", "localhost", "file:////server/share/dir"},
     57 #else
     58   { "/etc", "localhost", "file://localhost/etc"},
     59   { "c:\\windows", NULL, NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH}, /* it's important to get this error on Unix */
     60   { "c:\\windows", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     61   { "c:\\windows", "otherhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     62 #endif
     63   { "etc", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     64 #ifndef G_PLATFORM_WIN32
     65   { "/etc/\xE5\xE4\xF6", NULL, "file:///etc/%E5%E4%F6" },
     66   { "/etc/\xC3\xB6\xC3\xA4\xC3\xA5", NULL, "file:///etc/%C3%B6%C3%A4%C3%A5"},
     67 #endif
     68   { "/etc", "\xC3\xB6\xC3\xA4\xC3\xA5", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     69   { "/etc", "\xE5\xE4\xF6", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     70   { "/etc/file with #%", NULL, "file:///etc/file%20with%20%23%25"},
     71   { "", NULL, NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     72   { "", "", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     73   { "", "localhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     74   { "", "otherhost", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH},
     75   { "/0123456789", NULL, "file:///0123456789"},
     76   { "/ABCDEFGHIJKLMNOPQRSTUVWXYZ", NULL, "file:///ABCDEFGHIJKLMNOPQRSTUVWXYZ"},
     77   { "/abcdefghijklmnopqrstuvwxyz", NULL, "file:///abcdefghijklmnopqrstuvwxyz"},
     78   { "/-_.!~*'()", NULL, "file:///-_.!~*'()"},
     79 #ifdef G_OS_WIN32
     80   /* As '\\' is a path separator on Win32, it gets turned into '/' in the URI */
     81   { "/\"#%<>[\\]^`{|}\x7F", NULL, "file:///%22%23%25%3C%3E%5B/%5D%5E%60%7B%7C%7D%7F"},
     82 #else
     83   /* On Unix, '\\' is a normal character in the file name */
     84   { "/\"#%<>[\\]^`{|}\x7F", NULL, "file:///%22%23%25%3C%3E%5B%5C%5D%5E%60%7B%7C%7D%7F"},
     85 #endif
     86   { "/;@+$,", NULL, "file:///%3B@+$,"},
     87   /* This and some of the following are of course as such illegal file names on Windows,
     88    * and would not occur in real life.
     89    */
     90   { "/:", NULL, "file:///:"},
     91   { "/?&=", NULL, "file:///%3F&="},
     92   { "/", "0123456789-", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     93   { "/", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "file://ABCDEFGHIJKLMNOPQRSTUVWXYZ/"},
     94   { "/", "abcdefghijklmnopqrstuvwxyz", "file://abcdefghijklmnopqrstuvwxyz/"},
     95   { "/", "_.!~*'()", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     96   { "/", "\"#%<>[\\]^`{|}\x7F", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     97   { "/", ";?&=+$,", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     98   { "/", "/", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
     99   { "/", "@:", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
    100   { "/", "\x80\xFF", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
    101   { "/", "\xC3\x80\xC3\xBF", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE},
    102 };
    103 
    104 
    105 typedef struct
    106 {
    107   char *uri;
    108   char *expected_filename;
    109   char *expected_hostname;
    110   GConvertError expected_error; /* If failed */
    111 }  FromUriTest;
    112 
    113 FromUriTest
    114 from_uri_tests[] = {
    115   { "file:///etc", "/etc"},
    116   { "file:/etc", "/etc"},
    117 #ifdef G_OS_WIN32
    118   /* On Win32 we don't return "localhost" hostames, just in case
    119    * it isn't recognized anyway.
    120    */
    121   { "file://localhost/etc", "/etc", NULL},
    122   { "file://localhost/etc/%23%25%20file", "/etc/#% file", NULL},
    123   { "file://localhost/\xE5\xE4\xF6", "/\xe5\xe4\xf6", NULL},
    124   { "file://localhost/%E5%E4%F6", "/\xe5\xe4\xf6", NULL},
    125 #else
    126   { "file://localhost/etc", "/etc", "localhost"},
    127   { "file://localhost/etc/%23%25%20file", "/etc/#% file", "localhost"},
    128   { "file://localhost/\xE5\xE4\xF6", "/\xe5\xe4\xf6", "localhost"},
    129   { "file://localhost/%E5%E4%F6", "/\xe5\xe4\xf6", "localhost"},
    130 #endif
    131   { "file://otherhost/etc", "/etc", "otherhost"},
    132   { "file://otherhost/etc/%23%25%20file", "/etc/#% file", "otherhost"},
    133   { "file://%C3%B6%C3%A4%C3%A5/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    134   { "file:////etc/%C3%B6%C3%C3%C3%A5", "//etc/\xc3\xb6\xc3\xc3\xc3\xa5", NULL},
    135   { "file://\xE5\xE4\xF6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    136   { "file://%E5%E4%F6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    137   { "file:///some/file#bad", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    138   { "file://some", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    139   { "", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    140   { "file:test", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    141   { "http://www.yahoo.com/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    142   { "file:////etc", "//etc"},
    143   { "file://///etc", "///etc"},
    144 #ifdef G_OS_WIN32
    145   /* URIs with backslashes come from some nonstandard application, but accept them anyhow */
    146   { "file:///c:\\foo", "c:\\foo"},
    147   { "file:///c:/foo\\bar", "c:\\foo\\bar"},
    148   /* Accept also the old Netscape drive-letter-and-vertical bar convention */
    149   { "file:///c|/foo", "c:\\foo"},
    150   { "file:////server/share/dir", "\\\\server\\share\\dir"},
    151   { "file://localhost//server/share/foo", "\\\\server\\share\\foo"},
    152   { "file://otherhost//server/share/foo", "\\\\server\\share\\foo", "otherhost"},
    153 #else
    154   { "file:///c:\\foo", "/c:\\foo"},
    155   { "file:///c:/foo", "/c:/foo"},
    156   { "file:////c:/foo", "//c:/foo"},
    157 #endif
    158   { "file://0123456789/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    159   { "file://ABCDEFGHIJKLMNOPQRSTUVWXYZ/", "/", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"},
    160   { "file://abcdefghijklmnopqrstuvwxyz/", "/", "abcdefghijklmnopqrstuvwxyz"},
    161   { "file://-_.!~*'()/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    162   { "file://\"<>[\\]^`{|}\x7F/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    163   { "file://;?&=+$,/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    164   { "file://%C3%80%C3%BF/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    165   { "file://@/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    166   { "file://:/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    167   { "file://#/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    168   { "file://%23/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    169   { "file://%2F/", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
    170 };
    171 
    172 
    173 static gboolean any_failed = FALSE;
    174 
    175 static void
    176 run_to_uri_tests (void)
    177 {
    178   int i;
    179   gchar *res;
    180   GError *error;
    181 
    182   for (i = 0; i < G_N_ELEMENTS (to_uri_tests); i++)
    183     {
    184       error = NULL;
    185       res = g_filename_to_uri (to_uri_tests[i].filename,
    186 			       to_uri_tests[i].hostname,
    187 			       &error);
    188 
    189       if (to_uri_tests[i].expected_result == NULL)
    190 	{
    191 	  if (res != NULL)
    192 	    {
    193 	      g_print ("\ng_filename_to_uri() test %d failed, expected to return NULL, actual result: %s\n", i, res);
    194 	      any_failed = TRUE;
    195 	    }
    196 	  else
    197 	    {
    198 	      if (error == NULL)
    199 		{
    200 		  g_print ("\ng_filename_to_uri() test %d failed, returned NULL, but didn't set error\n", i);
    201 		  any_failed = TRUE;
    202 		}
    203 	      else if (error->domain != G_CONVERT_ERROR)
    204 		{
    205 		  g_print ("\ng_filename_to_uri() test %d failed, returned NULL, set non G_CONVERT_ERROR error\n", i);
    206 		  any_failed = TRUE;
    207 		}
    208 	      else if (error->code != to_uri_tests[i].expected_error)
    209 		{
    210 		  g_print ("\ng_filename_to_uri() test %d failed as expected, but set wrong errorcode %d instead of expected %d \n",
    211 			   i, error->code, to_uri_tests[i].expected_error);
    212 		  any_failed = TRUE;
    213 		}
    214 	    }
    215 	}
    216       else if (res == NULL || strcmp (res, to_uri_tests[i].expected_result) != 0)
    217 	{
    218 	  g_print ("\ng_filename_to_uri() test %d failed, expected result: %s, actual result: %s\n",
    219 		   i, to_uri_tests[i].expected_result, (res) ? res : "NULL");
    220 	  if (error)
    221 	    g_print ("Error message: %s\n", error->message);
    222 	  any_failed = TRUE;
    223 	}
    224       g_free (res);
    225     }
    226 }
    227 
    228 static void
    229 run_from_uri_tests (void)
    230 {
    231   int i;
    232   gchar *res;
    233   gchar *hostname;
    234   GError *error;
    235 
    236   for (i = 0; i < G_N_ELEMENTS (from_uri_tests); i++)
    237     {
    238       error = NULL;
    239       res = g_filename_from_uri (from_uri_tests[i].uri,
    240 				 &hostname,
    241 				 &error);
    242 
    243       if (from_uri_tests[i].expected_filename == NULL)
    244 	{
    245 	  if (res != NULL)
    246 	    {
    247 	      g_print ("\ng_filename_from_uri() test %d failed, expected to return NULL, actual result: %s\n", i, res);
    248 	      any_failed = TRUE;
    249 	    }
    250 	  else
    251 	    {
    252 	      if (error == NULL)
    253 		{
    254 		  g_print ("\ng_filename_from_uri() test %d failed, returned NULL, but didn't set error\n", i);
    255 		  any_failed = TRUE;
    256 		}
    257 	      else if (error->domain != G_CONVERT_ERROR)
    258 		{
    259 		  g_print ("\ng_filename_from_uri() test %d failed, returned NULL, set non G_CONVERT_ERROR error\n", i);
    260 		  any_failed = TRUE;
    261 		}
    262 	      else if (error->code != from_uri_tests[i].expected_error)
    263 		{
    264 		  g_print ("\ng_filename_from_uri() test %d failed as expected, but set wrong errorcode %d instead of expected %d \n",
    265 			   i, error->code, from_uri_tests[i].expected_error);
    266 		  any_failed = TRUE;
    267 		}
    268 	    }
    269 	}
    270       else
    271 	{
    272 #ifdef G_OS_WIN32
    273 	  gchar *slash, *p;
    274 
    275 	  p = from_uri_tests[i].expected_filename = g_strdup (from_uri_tests[i].expected_filename);
    276 	  while ((slash = strchr (p, '/')) != NULL)
    277 	    {
    278 	      *slash = '\\';
    279 	      p = slash + 1;
    280 	    }
    281 #endif
    282 	  if (res == NULL || strcmp (res, from_uri_tests[i].expected_filename) != 0)
    283 	    {
    284 	      g_print ("\ng_filename_from_uri() test %d failed, expected result: %s, actual result: %s\n",
    285 		       i, from_uri_tests[i].expected_filename, (res) ? res : "NULL");
    286 	      any_failed = TRUE;
    287 	    }
    288 
    289 	  if (from_uri_tests[i].expected_hostname == NULL)
    290 	    {
    291 	      if (hostname != NULL)
    292 		{
    293 		  g_print ("\ng_filename_from_uri() test %d failed, expected no hostname, got: %s\n",
    294 			   i, hostname);
    295 		  any_failed = TRUE;
    296 		}
    297 	    }
    298 	  else if (hostname == NULL ||
    299 		   strcmp (hostname, from_uri_tests[i].expected_hostname) != 0)
    300 	    {
    301 	      g_print ("\ng_filename_from_uri() test %d failed, expected hostname: %s, actual result: %s\n",
    302 		       i, from_uri_tests[i].expected_hostname, (hostname) ? hostname : "NULL");
    303 	      any_failed = TRUE;
    304 	    }
    305 	}
    306     }
    307 }
    308 
    309 static gint
    310 safe_strcmp (const gchar *a, const gchar *b)
    311 {
    312   return strcmp (a ? a : "", b ? b : "");
    313 }
    314 
    315 static gint
    316 safe_strcmp_filename (const gchar *a, const gchar *b)
    317 {
    318 #ifndef G_OS_WIN32
    319   return safe_strcmp (a, b);
    320 #else
    321   if (!a || !b)
    322     return safe_strcmp (a, b);
    323   else
    324     {
    325       while (*a && *b)
    326 	{
    327 	  if ((G_IS_DIR_SEPARATOR (*a) && G_IS_DIR_SEPARATOR (*b)) ||
    328 	      *a == *b)
    329 	    a++, b++;
    330 	  else
    331 	    return (*a - *b);
    332 	}
    333       return (*a - *b);
    334     }
    335 #endif
    336 }
    337 
    338 static gint
    339 safe_strcmp_hostname (const gchar *a, const gchar *b)
    340 {
    341 #ifndef G_OS_WIN32
    342   return safe_strcmp (a, b);
    343 #else
    344   if (safe_strcmp (a, "localhost") == 0 && b == NULL)
    345     return 0;
    346   else
    347     return safe_strcmp (a, b);
    348 #endif
    349 }
    350 
    351 static void
    352 run_roundtrip_tests (void)
    353 {
    354   int i;
    355   gchar *uri, *hostname, *res;
    356   GError *error;
    357 
    358   for (i = 0; i < G_N_ELEMENTS (to_uri_tests); i++)
    359     {
    360       if (to_uri_tests[i].expected_error != 0)
    361 	continue;
    362 
    363       error = NULL;
    364       uri = g_filename_to_uri (to_uri_tests[i].filename,
    365 			       to_uri_tests[i].hostname,
    366 			       &error);
    367 
    368       if (error != NULL)
    369 	{
    370 	  g_print ("g_filename_to_uri failed unexpectedly: %s\n",
    371 		   error->message);
    372 	  any_failed = TRUE;
    373 	  continue;
    374 	}
    375 
    376       error = NULL;
    377       res = g_filename_from_uri (uri, &hostname, &error);
    378       if (error != NULL)
    379 	{
    380 	  g_print ("g_filename_from_uri failed unexpectedly: %s\n",
    381 		   error->message);
    382 	  any_failed = TRUE;
    383 	  continue;
    384 	}
    385 
    386       if (safe_strcmp_filename (to_uri_tests[i].filename, res))
    387 	{
    388 	  g_print ("roundtrip test %d failed, filename modified: "
    389 		   " expected \"%s\", but got \"%s\"\n",
    390 		   i, to_uri_tests[i].filename, res);
    391 	  any_failed = TRUE;
    392 	}
    393 
    394       if (safe_strcmp_hostname (to_uri_tests[i].hostname, hostname))
    395 	{
    396 	  g_print ("roundtrip test %d failed, hostname modified: "
    397 		     " expected \"%s\", but got \"%s\"\n",
    398 		   i, to_uri_tests[i].hostname, hostname);
    399 	  any_failed = TRUE;
    400 	}
    401     }
    402 }
    403 
    404 static void
    405 run_uri_list_tests (void)
    406 {
    407   /* straight from the RFC */
    408   gchar *list =
    409     "# urn:isbn:0-201-08372-8\r\n"
    410     "http://www.huh.org/books/foo.html\r\n"
    411     "http://www.huh.org/books/foo.pdf   \r\n"
    412     "   ftp://ftp.foo.org/books/foo.txt\r\n";
    413   gchar *expected_uris[] = {
    414     "http://www.huh.org/books/foo.html",
    415     "http://www.huh.org/books/foo.pdf",
    416     "ftp://ftp.foo.org/books/foo.txt"
    417   };
    418 
    419   gchar **uris;
    420   gint j;
    421 
    422   uris = g_uri_list_extract_uris (list);
    423 
    424   if (g_strv_length (uris) != 3)
    425     {
    426       g_print ("uri list test failed: "
    427 	       " expected %d uris, but got %d\n",
    428 	       3, g_strv_length (uris));
    429       any_failed = TRUE;
    430     }
    431 
    432   for (j = 0; j < 3; j++)
    433     {
    434       if (safe_strcmp (uris[j], expected_uris[j]))
    435 	{
    436 	  g_print ("uri list test failed: "
    437 		   " expected \"%s\", but got \"%s\"\n",
    438 		   expected_uris[j], uris[j]);
    439 	  any_failed = TRUE;
    440 	}
    441     }
    442 
    443   g_strfreev (uris);
    444 
    445   uris = g_uri_list_extract_uris ("# just hot air\r\n# more hot air");
    446   if (g_strv_length (uris) != 0)
    447     {
    448       g_print ("uri list test 2 failed: "
    449 	       " expected %d uris, but got %d (first is \"%s\")\n",
    450 	       0, g_strv_length (uris), uris[0]);
    451       any_failed = TRUE;
    452     }
    453 
    454 }
    455 
    456 int
    457 main (int   argc,
    458       char *argv[])
    459 {
    460 #ifdef G_OS_UNIX
    461 #  ifdef HAVE_UNSETENV
    462   unsetenv ("G_BROKEN_FILENAMES");
    463 #  else
    464   /* putenv with no = isn't standard, but works to unset the variable
    465    * on some systems
    466    */
    467   putenv ("G_BROKEN_FILENAMES");
    468 #  endif
    469 #endif
    470 
    471   run_to_uri_tests ();
    472   run_from_uri_tests ();
    473   run_roundtrip_tests ();
    474   run_uri_list_tests ();
    475 
    476   return any_failed ? 1 : 0;
    477 }
    478