(root)/
glib-2.79.0/
glib/
tests/
markup-subparser.c
       1  /* 
       2   * Copyright © 2008 Ryan Lortie
       3   * 
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This program is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   * 
      11   * See the included COPYING file for more information.
      12   */
      13  
      14  #include <string.h>
      15  #include <stdio.h>
      16  #include <glib.h>
      17  
      18  /* keep track of GString instances to make sure nothing leaks */
      19  static int strings_allocated;
      20  
      21  /* === the GMarkupParser functions === */
      22  static void
      23  subparser_start_element (GMarkupParseContext  *context,
      24                           const gchar          *element_name,
      25                           const gchar         **attribute_names,
      26                           const gchar         **attribute_values,
      27                           gpointer              user_data,
      28                           GError              **error)
      29  {
      30    g_string_append_printf (user_data, "{%s}", element_name);
      31  
      32    /* we don't like trouble... */
      33    if (strcmp (element_name, "trouble") == 0)
      34      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
      35                   "we don't like trouble");
      36  }
      37  
      38  static void
      39  subparser_end_element (GMarkupParseContext  *context,
      40                         const gchar          *element_name,
      41                         gpointer              user_data,
      42                         GError              **error)
      43  {
      44    g_string_append_printf (user_data, "{/%s}", element_name);
      45  }
      46  
      47  static void
      48  subparser_error (GMarkupParseContext *context,
      49                   GError              *error,
      50                   gpointer             user_data)
      51  {
      52    g_string_free (user_data, TRUE);
      53    strings_allocated--;
      54  }
      55  
      56  static GMarkupParser subparser_parser =
      57  {
      58    subparser_start_element,
      59    subparser_end_element,
      60    NULL,
      61    NULL,
      62    subparser_error
      63  };
      64  
      65  /* convenience functions for a parser that does not
      66   * replay the starting tag into the subparser...
      67   */
      68  static void
      69  subparser_start (GMarkupParseContext *ctx)
      70  {
      71    gpointer user_data;
      72  
      73    user_data = g_string_new (NULL);
      74    strings_allocated++;
      75    g_markup_parse_context_push (ctx, &subparser_parser, user_data);
      76  }
      77  
      78  static char *
      79  subparser_end (GMarkupParseContext  *ctx,
      80                 GError              **error)
      81  {
      82    GString *string;
      83    char *result;
      84  
      85    string = g_markup_parse_context_pop (ctx);
      86    result = g_string_free_and_steal (g_steal_pointer (&string));
      87    strings_allocated--;
      88  
      89    if (result == NULL || result[0] == '\0')
      90      {
      91        g_free (result);
      92        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
      93                     "got no data");
      94  
      95        return NULL;
      96      }
      97  
      98    return result;
      99  }
     100  
     101  /* convenience functions for a parser that -does-
     102   * replay the starting tag into the subparser...
     103   */
     104  static gboolean
     105  replay_parser_start (GMarkupParseContext  *ctx,
     106                       const char           *element_name,
     107                       const char          **attribute_names,
     108                       const char          **attribute_values,
     109                       GError              **error)
     110  {
     111    GError *tmp_error = NULL;
     112    gpointer user_data;
     113  
     114    user_data = g_string_new (NULL);
     115    strings_allocated++;
     116  
     117    subparser_parser.start_element (ctx, element_name,
     118                                    attribute_names, attribute_values,
     119                                    user_data, &tmp_error);
     120  
     121    if (tmp_error)
     122      {
     123        g_propagate_error (error, tmp_error);
     124        g_string_free (user_data, TRUE);
     125        strings_allocated--;
     126  
     127        return FALSE;
     128      }
     129  
     130    g_markup_parse_context_push (ctx, &subparser_parser, user_data);
     131  
     132    return TRUE;
     133  }
     134  
     135  static char *
     136  replay_parser_end (GMarkupParseContext  *ctx,
     137                     GError              **error)
     138  {
     139    GError *tmp_error = NULL;
     140    GString *string;
     141    char *result;
     142  
     143    string = g_markup_parse_context_pop (ctx);
     144  
     145    subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx),
     146                                  string, &tmp_error);
     147  
     148    if (tmp_error)
     149      {
     150        g_propagate_error (error, tmp_error);
     151        g_string_free (string, TRUE);
     152        strings_allocated--;
     153  
     154        return NULL;
     155      }
     156  
     157    result = g_string_free_and_steal (g_steal_pointer (&string));
     158    strings_allocated--;
     159  
     160    if (result == NULL || result[0] == '\0')
     161      {
     162        g_free (result);
     163        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     164                     "got no data");
     165  
     166        return NULL;
     167      }
     168  
     169    return result;
     170  }
     171  
     172  
     173  /* === start interface between subparser and calling parser === */
     174  static void      subparser_start      (GMarkupParseContext  *ctx);
     175  static char     *subparser_end        (GMarkupParseContext  *ctx,
     176                                         GError              **error);
     177  /* === end interface between subparser and calling parser === */
     178  
     179  /* === start interface between replay parser and calling parser === */
     180  static gboolean  replay_parser_start  (GMarkupParseContext  *ctx,
     181                                         const char           *element_name,
     182                                         const char          **attribute_names,
     183                                         const char          **attribute_values,
     184                                         GError              **error);
     185  static char     *replay_parser_end    (GMarkupParseContext  *ctx,
     186                                         GError              **error);
     187  /* === end interface between replay parser and calling parser === */
     188  
     189  
     190  
     191  /* now comes our parser for the test.
     192   *
     193   * we recognise the tags <test> and <sub>.
     194   * <test> is ignored.
     195   * <sub> invokes the subparser (no replay).
     196   *
     197   * "unknown tags" are passed to the reply subparser
     198   * (so the unknown tag is fed to the subparser...)
     199   */
     200  static void
     201  start_element (GMarkupParseContext  *context,
     202                 const gchar          *element_name,
     203                 const gchar         **attribute_names,
     204                 const gchar         **attribute_values,
     205                 gpointer              user_data,
     206                 GError              **error)
     207  {
     208    g_string_append_printf (user_data, "<%s>", element_name);
     209  
     210    if (strcmp (element_name, "test") == 0)
     211      {
     212        /* do nothing */
     213      }
     214    else if (strcmp (element_name, "sub") == 0)
     215      {
     216        /* invoke subparser */
     217        subparser_start (context);
     218      }
     219    else
     220      {
     221        /* unknown tag.  invoke replay subparser */
     222        if (!replay_parser_start (context, element_name,
     223                                  attribute_names, attribute_values,
     224                                  error))
     225          return;
     226      }
     227  }
     228  
     229  static void
     230  end_element (GMarkupParseContext  *context,
     231               const gchar          *element_name,
     232               gpointer              user_data,
     233               GError              **error)
     234  {
     235    if (strcmp (element_name, "test") == 0)
     236      {
     237        /* do nothing */
     238      }
     239    else if (strcmp (element_name, "sub") == 0)
     240      {
     241        char *result;
     242  
     243        if ((result = subparser_end (context, error)) == NULL)
     244          return;
     245  
     246        g_string_append_printf (user_data, "<<%s>>", result);
     247        g_free (result);
     248      }
     249    else
     250      {
     251        char *result;
     252  
     253        if ((result = replay_parser_end (context, error)) == NULL)
     254          return;
     255  
     256        g_string_append_printf (user_data, "[[%s]]", result);
     257        g_free (result);
     258      }
     259  
     260    g_string_append_printf (user_data, "</%s>", element_name);
     261  }
     262  
     263  static GMarkupParser parser =
     264  {
     265    start_element,
     266    end_element,
     267    NULL,
     268    NULL,
     269    NULL
     270  };
     271  
     272  typedef struct
     273  {
     274    const char *markup;
     275    const char *result;
     276    const char *error_message;
     277  } TestCase;
     278  
     279  static void
     280  test (gconstpointer user_data)
     281  {
     282    const TestCase *tc = user_data;
     283    GMarkupParseContext *ctx;
     284    GString *string;
     285    gboolean result;
     286    GError *error;
     287  
     288    error = NULL;
     289    string = g_string_new (NULL);
     290    ctx = g_markup_parse_context_new (&parser, G_MARKUP_DEFAULT_FLAGS, string, NULL);
     291    result = g_markup_parse_context_parse (ctx, tc->markup,
     292                                           strlen (tc->markup), &error);
     293    if (result)
     294      result = g_markup_parse_context_end_parse (ctx, &error);
     295    g_markup_parse_context_free (ctx);
     296    g_assert (strings_allocated == 0);
     297  
     298    if (result)
     299      {
     300        if (tc->error_message)
     301          g_error ("expected failure (about '%s') passed!\n"
     302                   "  in: %s\n  out: %s",
     303                   tc->error_message, tc->markup, string->str);
     304      }
     305    else
     306      {
     307        if (!tc->error_message)
     308          g_error ("unexpected failure: '%s'\n"
     309                   "  in: %s\n  out: %s",
     310                   error->message, tc->markup, string->str);
     311  
     312        if (!strstr (error->message, tc->error_message))
     313          g_error ("failed for the wrong reason.\n"
     314                   "  expecting message about '%s'\n"
     315                   "  got message '%s'\n"
     316                   "  in: %s\n  out: %s",
     317                   tc->error_message, error->message, tc->markup, string->str);
     318      }
     319  
     320    if (strcmp (string->str, tc->result) != 0)
     321      g_error ("got the wrong result.\n"
     322               "  expected: '%s'\n"
     323               "  got: '%s'\n"
     324               "  input: %s",
     325               tc->result, string->str, tc->markup);
     326  
     327    if (error)
     328      g_error_free (error);
     329  
     330    g_string_free (string, TRUE);
     331  }
     332  
     333  TestCase test_cases[] = /* successful runs */
     334  {
     335    /* in */                    /* out */                               /* error */
     336    { "<test/>",                  "<test></test>",                            NULL },
     337    { "<sub><foo/></sub>",        "<sub><<{foo}{/foo}>></sub>",               NULL },
     338    { "<sub><foo/><bar/></sub>",  "<sub><<{foo}{/foo}{bar}{/bar}>></sub>",    NULL },
     339    { "<foo><bar/></foo>",        "<foo>[[{foo}{bar}{/bar}{/foo}]]</foo>",    NULL },
     340    { "<foo><x/><y/></foo>",      "<foo>[[{foo}{x}{/x}{y}{/y}{/foo}]]</foo>", NULL },
     341    { "<foo/>",                   "<foo>[[{foo}{/foo}]]</foo>",               NULL },
     342    { "<sub><foo/></sub><bar/>",  "<sub><<{foo}{/foo}>></sub>"
     343                                  "<bar>[[{bar}{/bar}]]</bar>",               NULL }
     344  };
     345  
     346  TestCase error_cases[] = /* error cases */
     347  {
     348      /* in */                    /* out */                       /* error */
     349    { "<foo><>",                  "<foo>",                        ">"},
     350    { "",                         "",                             "empty" },
     351    { "<trouble/>",               "<trouble>",                    "trouble" },
     352    { "<sub><trouble>",           "<sub>",                        "trouble" },
     353    { "<foo><trouble>",           "<foo>",                        "trouble" },
     354    { "<sub></sub>",              "<sub>",                        "no data" },
     355    { "<sub/>",                   "<sub>",                        "no data" }
     356  };
     357  
     358  #define add_tests(func, basename, array) \
     359    G_STMT_START { \
     360      gsize __add_tests_i;                                                \
     361                                                                          \
     362      for (__add_tests_i  = 0;                                            \
     363           __add_tests_i < G_N_ELEMENTS (array);                          \
     364           __add_tests_i++)                                               \
     365        {                                                                 \
     366          char *testname;                                                 \
     367                                                                          \
     368          testname = g_strdup_printf ("%s/%" G_GSIZE_FORMAT,              \
     369                                      basename, __add_tests_i);           \
     370          g_test_add_data_func (testname, &array[__add_tests_i], func);   \
     371          g_free (testname);                                              \
     372        }                                                                 \
     373    } G_STMT_END
     374  
     375  int
     376  main (int argc, char **argv)
     377  {
     378    g_setenv ("LC_ALL", "C", TRUE);
     379    g_test_init (&argc, &argv, NULL);
     380    add_tests (test, "/glib/markup/subparser/success", test_cases);
     381    add_tests (test, "/glib/markup/subparser/failure", error_cases);
     382    return g_test_run ();
     383  }