LCOV - code coverage report
Current view: top level - glib/glib/tests - unicode-encoding.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 165 170 97.1 %
Date: 2024-03-26 05:16:46 Functions: 6 6 100.0 %
Branches: 62 81 76.5 %

           Branch data     Line data    Source code
       1                 :            : #include <stdarg.h>
       2                 :            : #include <stdio.h>
       3                 :            : #include <stdlib.h>
       4                 :            : #include <string.h>
       5                 :            : #include <glib.h>
       6                 :            : 
       7                 :            : typedef enum
       8                 :            : {
       9                 :            :   VALID,
      10                 :            :   INCOMPLETE,
      11                 :            :   NOTUNICODE,
      12                 :            :   OVERLONG,
      13                 :            :   MALFORMED
      14                 :            : } Status;
      15                 :            : 
      16                 :            : static gboolean
      17                 :         47 : ucs4_equal (gunichar *a, gunichar *b)
      18                 :            : {
      19   [ +  +  +  -  :        118 :   while (*a && *b && (*a == *b))
                   +  - ]
      20                 :            :     {
      21                 :         71 :       a++;
      22                 :         71 :       b++;
      23                 :            :     }
      24                 :            : 
      25                 :         47 :   return (*a == *b);
      26                 :            : }
      27                 :            : 
      28                 :            : static gboolean
      29                 :         26 : utf16_equal (gunichar2 *a, gunichar2 *b)
      30                 :            : {
      31   [ +  +  +  -  :         78 :   while (*a && *b && (*a == *b))
                   +  - ]
      32                 :            :     {
      33                 :         52 :       a++;
      34                 :         52 :       b++;
      35                 :            :     }
      36                 :            : 
      37                 :         26 :   return (*a == *b);
      38                 :            : }
      39                 :            : 
      40                 :            : static gint
      41                 :         52 : utf16_count (gunichar2 *a)
      42                 :            : {
      43                 :         52 :   gint result = 0;
      44                 :            : 
      45         [ +  + ]:        156 :   while (a[result])
      46                 :        104 :     result++;
      47                 :            : 
      48                 :         52 :   return result;
      49                 :            : }
      50                 :            : 
      51                 :            : static void
      52                 :         77 : process (gint      line,
      53                 :            :          gchar    *utf8,
      54                 :            :          Status    status,
      55                 :            :          gunichar *ucs4,
      56                 :            :          gint      ucs4_len)
      57                 :            : {
      58                 :            :   const gchar *end;
      59                 :         77 :   gboolean is_valid = g_utf8_validate (utf8, -1, &end);
      60                 :         77 :   GError *error = NULL;
      61                 :            :   glong items_read, items_written;
      62                 :            : 
      63      [ +  +  - ]:         77 :   switch (status)
      64                 :            :     {
      65                 :         13 :     case VALID:
      66                 :         13 :       g_assert_true (is_valid);
      67                 :         13 :       break;
      68                 :            : 
      69                 :         64 :     case NOTUNICODE:
      70                 :            :     case INCOMPLETE:
      71                 :            :     case OVERLONG:
      72                 :            :     case MALFORMED:
      73                 :         64 :       g_assert_false (is_valid);
      74                 :         64 :       break;
      75                 :            :     }
      76                 :            : 
      77         [ +  + ]:         77 :   if (status == INCOMPLETE)
      78                 :            :     {
      79                 :            :       gunichar *ucs4_result;
      80                 :            : 
      81                 :         10 :       ucs4_result = g_utf8_to_ucs4 (utf8, -1, NULL, NULL, &error);
      82                 :            : 
      83                 :         10 :       g_assert_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT);
      84                 :            : 
      85                 :         10 :       g_clear_error (&error);
      86                 :            : 
      87                 :         10 :       ucs4_result = g_utf8_to_ucs4 (utf8, -1, &items_read, NULL, &error);
      88                 :         10 :       g_assert_no_error (error);
      89                 :         10 :       g_assert_nonnull (ucs4_result);
      90                 :         10 :       g_assert_cmpint (items_read, !=, strlen (utf8));
      91                 :            : 
      92                 :         10 :       g_free (ucs4_result);
      93                 :            :     }
      94                 :            : 
      95   [ +  +  +  + ]:         77 :   if (status == VALID || status == NOTUNICODE)
      96                 :            :     {
      97                 :            :       gunichar *ucs4_result;
      98                 :            : 
      99                 :         34 :       ucs4_result = g_utf8_to_ucs4 (utf8, -1, &items_read, &items_written, &error);
     100                 :         34 :       g_assert_no_error (error);
     101                 :         34 :       g_assert_nonnull (ucs4_result);
     102                 :            : 
     103                 :         34 :       g_assert_true (ucs4_equal (ucs4_result, ucs4));
     104                 :         34 :       g_assert_cmpint (items_read, ==, strlen (utf8));
     105                 :         34 :       g_assert_cmpint (items_written, ==, ucs4_len);
     106                 :            : 
     107                 :         34 :       g_free (ucs4_result);
     108                 :            :     }
     109                 :            : 
     110         [ +  + ]:         77 :   if (status == VALID)
     111                 :            :      {
     112                 :            :       gunichar *ucs4_result;
     113                 :            :       gchar *utf8_result;
     114                 :            : 
     115                 :         13 :       ucs4_result = g_utf8_to_ucs4_fast (utf8, -1, &items_written);
     116                 :         13 :       g_assert_nonnull (ucs4_result);
     117                 :            : 
     118                 :         13 :       g_assert_true (ucs4_equal (ucs4_result, ucs4));
     119                 :         13 :       g_assert_cmpint (items_written, ==, ucs4_len);
     120                 :            : 
     121                 :         13 :       utf8_result = g_ucs4_to_utf8 (ucs4_result, -1, &items_read, &items_written, &error);
     122                 :         13 :       g_assert_no_error (error);
     123                 :         13 :       g_assert_nonnull (utf8_result);
     124                 :            : 
     125                 :         13 :       g_assert_cmpstr ((char *) utf8_result, ==, (char *) utf8);
     126                 :         13 :       g_assert_cmpint (items_read, ==, ucs4_len);
     127                 :         13 :       g_assert_cmpint (items_written, ==, strlen (utf8));
     128                 :            : 
     129                 :         13 :       g_free (utf8_result);
     130                 :         13 :       g_free (ucs4_result);
     131                 :            :     }
     132                 :            : 
     133         [ +  + ]:         77 :   if (status == VALID)
     134                 :            :     {
     135                 :            :       gunichar2 *utf16_expected_tmp;
     136                 :            :       gunichar2 *utf16_expected;
     137                 :            :       gunichar2 *utf16_from_utf8;
     138                 :            :       gunichar2 *utf16_from_ucs4;
     139                 :            :       gunichar *ucs4_result;
     140                 :            :       gsize bytes_written;
     141                 :            :       gint n_chars;
     142                 :            :       gchar *utf8_result;
     143                 :            : 
     144                 :            : #if G_BYTE_ORDER == G_LITTLE_ENDIAN
     145                 :            : #define TARGET "UTF-16LE"
     146                 :            : #else
     147                 :            : #define TARGET "UTF-16"
     148                 :            : #endif
     149                 :            : 
     150                 :            :       utf16_expected_tmp =
     151                 :         13 :         (gunichar2 *) g_convert (utf8, -1, TARGET, "UTF-8", NULL, &bytes_written, NULL);
     152                 :         13 :       g_assert_nonnull (utf16_expected_tmp);
     153                 :            : 
     154                 :            :       /* zero-terminate and remove BOM */
     155                 :         13 :       n_chars = bytes_written / 2;
     156         [ -  + ]:         13 :       if (utf16_expected_tmp[0] == 0xfeff) /* BOM */
     157                 :            :         {
     158                 :          0 :           n_chars--;
     159                 :          0 :           utf16_expected = g_new (gunichar2, n_chars + 1);
     160                 :          0 :           memcpy (utf16_expected, utf16_expected_tmp + 1, sizeof(gunichar2) * n_chars);
     161                 :            :         }
     162                 :            :       else
     163                 :            :         {
     164                 :            :           /* We expect the result of the conversion
     165                 :            :              via iconv() to be native-endian. */
     166                 :         13 :           g_assert_false (utf16_expected_tmp[0] == 0xfffe);
     167                 :         13 :           utf16_expected = g_new (gunichar2, n_chars + 1);
     168                 :         13 :           memcpy (utf16_expected, utf16_expected_tmp, sizeof(gunichar2) * n_chars);
     169                 :            :         }
     170                 :            : 
     171                 :         13 :       utf16_expected[n_chars] = '\0';
     172                 :            : 
     173                 :            :       utf16_from_utf8 =
     174                 :         13 :         g_utf8_to_utf16 (utf8, -1, &items_read, &items_written, &error);
     175                 :         13 :       g_assert_no_error (error);
     176                 :         13 :       g_assert_nonnull (utf16_from_utf8);
     177                 :            : 
     178                 :         13 :       g_assert_cmpint (items_read, ==, (glong) strlen (utf8));
     179                 :         13 :       g_assert_cmpint (utf16_count (utf16_from_utf8), ==, items_written);
     180                 :            : 
     181                 :            :       utf16_from_ucs4 =
     182                 :         13 :         g_ucs4_to_utf16 (ucs4, -1, &items_read, &items_written, &error);
     183                 :         13 :       g_assert_no_error (error);
     184                 :         13 :       g_assert_nonnull (utf16_from_ucs4);
     185                 :            : 
     186                 :         13 :       g_assert_cmpint (items_read, ==, ucs4_len);
     187                 :         13 :       g_assert_cmpint (utf16_count (utf16_from_ucs4), ==, items_written);
     188                 :            : 
     189                 :         13 :       g_assert_true (utf16_equal (utf16_from_utf8, utf16_expected));
     190                 :         13 :       g_assert_true (utf16_equal (utf16_from_ucs4, utf16_expected));
     191                 :         13 :       g_assert_cmpstr ((char *) utf16_from_utf8, ==, (char *) utf16_expected);
     192                 :         13 :       g_assert_cmpstr ((char *) utf16_from_ucs4, ==, (char *) utf16_expected);
     193                 :            : 
     194                 :            :       utf8_result =
     195                 :         13 :         g_utf16_to_utf8 (utf16_from_utf8, -1, &items_read, &items_written, &error);
     196                 :         13 :       g_assert_no_error (error);
     197                 :         13 :       g_assert_nonnull (utf8_result);
     198                 :            : 
     199                 :         13 :       g_assert_cmpint (items_read, ==, utf16_count (utf16_from_utf8));
     200                 :         13 :       g_assert_cmpint (items_written, ==, (glong) strlen (utf8));
     201                 :            : 
     202                 :            :       ucs4_result =
     203                 :         13 :         g_utf16_to_ucs4 (utf16_from_ucs4, -1, &items_read, &items_written, &error);
     204                 :         13 :       g_assert_no_error (error);
     205                 :         13 :       g_assert_nonnull (ucs4_result);
     206                 :            : 
     207                 :         13 :       g_assert_cmpint (items_read, ==, utf16_count (utf16_from_utf8));
     208                 :         13 :       g_assert_cmpint (items_written, ==, ucs4_len);
     209                 :            : 
     210                 :         13 :       g_assert_cmpstr (utf8, ==, utf8_result);
     211                 :         13 :       g_assert_cmpstr ((char *) ucs4, ==, (char *) ucs4_result);
     212                 :            : 
     213                 :         13 :       g_free (utf16_expected_tmp);
     214                 :         13 :       g_free (utf16_expected);
     215                 :         13 :       g_free (utf16_from_utf8);
     216                 :         13 :       g_free (utf16_from_ucs4);
     217                 :         13 :       g_free (utf8_result);
     218                 :         13 :       g_free (ucs4_result);
     219                 :            :     }
     220                 :         77 : }
     221                 :            : 
     222                 :            : static void
     223                 :          1 : test_unicode_encoding (void)
     224                 :            : {
     225                 :            :   gchar *testfile;
     226                 :            :   gchar *contents;
     227                 :          1 :   GError *error = NULL;
     228                 :            :   gchar *p, *end;
     229                 :            :   char *tmp;
     230                 :          1 :   gint state = 0;
     231                 :          1 :   gint line = 1;
     232                 :          1 :   gint start_line = 0;   /* Quiet GCC */
     233                 :          1 :   gchar *utf8 = NULL;    /* Quiet GCC */
     234                 :            :   GArray *ucs4;
     235                 :          1 :   Status status = VALID; /* Quiet GCC */
     236                 :            : 
     237                 :          1 :   testfile = g_test_build_filename (G_TEST_DIST, "utf8.txt", NULL);
     238                 :            : 
     239                 :          1 :   g_file_get_contents (testfile, &contents, NULL, &error);
     240                 :          1 :   g_assert_no_error (error);
     241                 :            : 
     242                 :          1 :   ucs4 = g_array_new (TRUE, FALSE, sizeof(gunichar));
     243                 :            : 
     244                 :          1 :   p = contents;
     245                 :            : 
     246                 :            :   /* Loop over lines */
     247         [ +  + ]:        292 :   while (*p)
     248                 :            :     {
     249   [ +  -  -  +  :        291 :       while (*p && (*p == ' ' || *p == '\t'))
                   -  + ]
     250                 :          0 :         p++;
     251                 :            : 
     252                 :        291 :       end = p;
     253   [ +  -  +  -  :       3181 :       while (*end && (*end != '\r' && *end != '\n'))
                   +  + ]
     254                 :       2890 :         end++;
     255                 :            : 
     256   [ +  -  +  +  :        291 :       if (!*p || *p == '#' || *p == '\r' || *p == '\n')
             +  -  +  + ]
     257                 :        103 :         goto next_line;
     258                 :            : 
     259                 :        188 :       tmp = g_strstrip (g_strndup (p, end - p));
     260                 :            : 
     261   [ +  +  +  - ]:        188 :       switch (state)
     262                 :            :         {
     263                 :         77 :         case 0:
     264                 :            :           /* UTF-8 string */
     265                 :         77 :           start_line = line;
     266                 :         77 :           utf8 = tmp;
     267                 :         77 :           tmp = NULL;
     268                 :         77 :           break;
     269                 :            : 
     270                 :         77 :         case 1:
     271                 :            :           /* Status */
     272         [ +  + ]:         77 :           if (!strcmp (tmp, "VALID"))
     273                 :         13 :             status = VALID;
     274         [ +  + ]:         64 :           else if (!strcmp (tmp, "INCOMPLETE"))
     275                 :         10 :             status = INCOMPLETE;
     276         [ +  + ]:         54 :           else if (!strcmp (tmp, "NOTUNICODE"))
     277                 :         21 :             status = NOTUNICODE;
     278         [ +  + ]:         33 :           else if (!strcmp (tmp, "OVERLONG"))
     279                 :         15 :             status = OVERLONG;
     280         [ +  - ]:         18 :           else if (!strcmp (tmp, "MALFORMED"))
     281                 :         18 :             status = MALFORMED;
     282                 :            :           else
     283                 :            :             g_assert_not_reached ();
     284                 :            : 
     285   [ +  +  +  + ]:         77 :           if (status != VALID && status != NOTUNICODE)
     286                 :         43 :             state++;  /* No UCS-4 data */
     287                 :         77 :           break;
     288                 :            : 
     289                 :         34 :         case 2:
     290                 :            :           /* UCS-4 version */
     291                 :         34 :           p = strtok (tmp, " \t");
     292         [ +  + ]:         84 :           while (p)
     293                 :            :             {
     294                 :            :               gchar *endptr;
     295                 :         50 :               gunichar ch = strtoul (p, &endptr, 16);
     296                 :         50 :               g_assert_cmpint (*endptr, == ,'\0');
     297                 :            : 
     298                 :         50 :               g_array_append_val (ucs4, ch);
     299                 :            : 
     300                 :         50 :               p = strtok (NULL, " \t");
     301                 :            :             }
     302                 :         34 :           break;
     303                 :            :         }
     304                 :            : 
     305                 :        188 :       g_free (tmp);
     306                 :        188 :       state = (state + 1) % 3;
     307                 :            : 
     308         [ +  + ]:        188 :       if (state == 0)
     309                 :            :         {
     310                 :         77 :           process (start_line, utf8, status, (gunichar *)ucs4->data, ucs4->len);
     311                 :         77 :           g_array_set_size (ucs4, 0);
     312                 :         77 :           g_free (utf8);
     313                 :            :         }
     314                 :            : 
     315                 :        111 :     next_line:
     316                 :        291 :       p = end;
     317   [ +  -  -  + ]:        291 :       if (*p && *p == '\r')
     318                 :          0 :         p++;
     319   [ +  -  +  - ]:        291 :       if (*p && *p == '\n')
     320                 :        291 :         p++;
     321                 :        291 :       line++;
     322                 :            :     }
     323                 :            : 
     324                 :          1 :   g_free (testfile);
     325                 :          1 :   g_array_free (ucs4, TRUE);
     326                 :          1 :   g_free (contents);
     327                 :          1 : }
     328                 :            : 
     329                 :            : int
     330                 :          1 : main (int argc, char **argv)
     331                 :            : {
     332                 :          1 :   g_test_init (&argc, &argv, NULL);
     333                 :            : 
     334                 :          1 :   g_test_add_func ("/unicode/encoding", test_unicode_encoding);
     335                 :            : 
     336                 :          1 :   return g_test_run ();
     337                 :            : }

Generated by: LCOV version 1.14