Blame glib/tests/markup-subparser.c

Packit ae235b
/* 
Packit ae235b
 * Copyright © 2008 Ryan Lortie
Packit ae235b
 * 
Packit ae235b
 * This program is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 * 
Packit ae235b
 * See the included COPYING file for more information.
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include <string.h>
Packit ae235b
#include <stdio.h>
Packit ae235b
#include <glib.h>
Packit ae235b
Packit ae235b
/* keep track of GString instances to make sure nothing leaks */
Packit ae235b
static int strings_allocated;
Packit ae235b
Packit ae235b
/* === the GMarkupParser functions === */
Packit ae235b
static void
Packit ae235b
subparser_start_element (GMarkupParseContext  *context,
Packit ae235b
                         const gchar          *element_name,
Packit ae235b
                         const gchar         **attribute_names,
Packit ae235b
                         const gchar         **attribute_values,
Packit ae235b
                         gpointer              user_data,
Packit ae235b
                         GError              **error)
Packit ae235b
{
Packit ae235b
  g_string_append_printf (user_data, "{%s}", element_name);
Packit ae235b
Packit ae235b
  /* we don't like trouble... */
Packit ae235b
  if (strcmp (element_name, "trouble") == 0)
Packit ae235b
    g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
Packit ae235b
                 "we don't like trouble");
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
subparser_end_element (GMarkupParseContext  *context,
Packit ae235b
                       const gchar          *element_name,
Packit ae235b
                       gpointer              user_data,
Packit ae235b
                       GError              **error)
Packit ae235b
{
Packit ae235b
  g_string_append_printf (user_data, "{/%s}", element_name);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
subparser_error (GMarkupParseContext *context,
Packit ae235b
                 GError              *error,
Packit ae235b
                 gpointer             user_data)
Packit ae235b
{
Packit ae235b
  g_string_free (user_data, TRUE);
Packit ae235b
  strings_allocated--;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GMarkupParser subparser_parser =
Packit ae235b
{
Packit ae235b
  subparser_start_element,
Packit ae235b
  subparser_end_element,
Packit ae235b
  NULL,
Packit ae235b
  NULL,
Packit ae235b
  subparser_error
Packit ae235b
};
Packit ae235b
Packit ae235b
/* convenience functions for a parser that does not
Packit ae235b
 * replay the starting tag into the subparser...
Packit ae235b
 */
Packit ae235b
static void
Packit ae235b
subparser_start (GMarkupParseContext *ctx)
Packit ae235b
{
Packit ae235b
  gpointer user_data;
Packit ae235b
Packit ae235b
  user_data = g_string_new (NULL);
Packit ae235b
  strings_allocated++;
Packit ae235b
  g_markup_parse_context_push (ctx, &subparser_parser, user_data);
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
subparser_end (GMarkupParseContext  *ctx,
Packit ae235b
               GError              **error)
Packit ae235b
{
Packit ae235b
  GString *string;
Packit ae235b
  char *result;
Packit ae235b
Packit ae235b
  string = g_markup_parse_context_pop (ctx);
Packit ae235b
  result = string->str;
Packit ae235b
Packit ae235b
  g_string_free (string, FALSE);
Packit ae235b
  strings_allocated--;
Packit ae235b
Packit ae235b
  if (result == NULL || result[0] == '\0')
Packit ae235b
    {
Packit ae235b
      g_free (result);
Packit ae235b
      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
Packit ae235b
                   "got no data");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return result;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* convenience functions for a parser that -does-
Packit ae235b
 * replay the starting tag into the subparser...
Packit ae235b
 */
Packit ae235b
static gboolean
Packit ae235b
replay_parser_start (GMarkupParseContext  *ctx,
Packit ae235b
                     const char           *element_name,
Packit ae235b
                     const char          **attribute_names,
Packit ae235b
                     const char          **attribute_values,
Packit ae235b
                     GError              **error)
Packit ae235b
{
Packit ae235b
  GError *tmp_error = NULL;
Packit ae235b
  gpointer user_data;
Packit ae235b
Packit ae235b
  user_data = g_string_new (NULL);
Packit ae235b
  strings_allocated++;
Packit ae235b
Packit ae235b
  subparser_parser.start_element (ctx, element_name,
Packit ae235b
                                  attribute_names, attribute_values,
Packit ae235b
                                  user_data, &tmp_error);
Packit ae235b
Packit ae235b
  if (tmp_error)
Packit ae235b
    {
Packit ae235b
      g_propagate_error (error, tmp_error);
Packit ae235b
      g_string_free (user_data, TRUE);
Packit ae235b
      strings_allocated--;
Packit ae235b
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_markup_parse_context_push (ctx, &subparser_parser, user_data);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
replay_parser_end (GMarkupParseContext  *ctx,
Packit ae235b
                   GError              **error)
Packit ae235b
{
Packit ae235b
  GError *tmp_error = NULL;
Packit ae235b
  GString *string;
Packit ae235b
  char *result;
Packit ae235b
Packit ae235b
  string = g_markup_parse_context_pop (ctx);
Packit ae235b
Packit ae235b
  subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx),
Packit ae235b
                                string, &tmp_error);
Packit ae235b
Packit ae235b
  if (tmp_error)
Packit ae235b
    {
Packit ae235b
      g_propagate_error (error, tmp_error);
Packit ae235b
      g_string_free (string, TRUE);
Packit ae235b
      strings_allocated--;
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  result = string->str;
Packit ae235b
Packit ae235b
  g_string_free (string, FALSE);
Packit ae235b
  strings_allocated--;
Packit ae235b
Packit ae235b
  if (result == NULL || result[0] == '\0')
Packit ae235b
    {
Packit ae235b
      g_free (result);
Packit ae235b
      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
Packit ae235b
                   "got no data");
Packit ae235b
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return result;
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
/* === start interface between subparser and calling parser === */
Packit ae235b
static void      subparser_start      (GMarkupParseContext  *ctx);
Packit ae235b
static char     *subparser_end        (GMarkupParseContext  *ctx,
Packit ae235b
                                       GError              **error);
Packit ae235b
/* === end interface between subparser and calling parser === */
Packit ae235b
Packit ae235b
/* === start interface between replay parser and calling parser === */
Packit ae235b
static gboolean  replay_parser_start  (GMarkupParseContext  *ctx,
Packit ae235b
                                       const char           *element_name,
Packit ae235b
                                       const char          **attribute_names,
Packit ae235b
                                       const char          **attribute_values,
Packit ae235b
                                       GError              **error);
Packit ae235b
static char     *replay_parser_end    (GMarkupParseContext  *ctx,
Packit ae235b
                                       GError              **error);
Packit ae235b
/* === end interface between replay parser and calling parser === */
Packit ae235b
Packit ae235b
Packit ae235b
Packit ae235b
/* now comes our parser for the test.
Packit ae235b
 *
Packit ae235b
 * we recognise the tags <test> and <sub>.
Packit ae235b
 * <test> is ignored.
Packit ae235b
 * <sub> invokes the subparser (no replay).
Packit ae235b
 *
Packit ae235b
 * "unknown tags" are passed to the reply subparser
Packit ae235b
 * (so the unknown tag is fed to the subparser...)
Packit ae235b
 */
Packit ae235b
static void
Packit ae235b
start_element (GMarkupParseContext  *context,
Packit ae235b
               const gchar          *element_name,
Packit ae235b
               const gchar         **attribute_names,
Packit ae235b
               const gchar         **attribute_values,
Packit ae235b
               gpointer              user_data,
Packit ae235b
               GError              **error)
Packit ae235b
{
Packit ae235b
  g_string_append_printf (user_data, "<%s>", element_name);
Packit ae235b
Packit ae235b
  if (strcmp (element_name, "test") == 0)
Packit ae235b
    {
Packit ae235b
      /* do nothing */
Packit ae235b
    }
Packit ae235b
  else if (strcmp (element_name, "sub") == 0)
Packit ae235b
    {
Packit ae235b
      /* invoke subparser */
Packit ae235b
      subparser_start (context);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      /* unknown tag.  invoke replay subparser */
Packit ae235b
      if (!replay_parser_start (context, element_name,
Packit ae235b
                                attribute_names, attribute_values,
Packit ae235b
                                error))
Packit ae235b
        return;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
end_element (GMarkupParseContext  *context,
Packit ae235b
             const gchar          *element_name,
Packit ae235b
             gpointer              user_data,
Packit ae235b
             GError              **error)
Packit ae235b
{
Packit ae235b
  if (strcmp (element_name, "test") == 0)
Packit ae235b
    {
Packit ae235b
      /* do nothing */
Packit ae235b
    }
Packit ae235b
  else if (strcmp (element_name, "sub") == 0)
Packit ae235b
    {
Packit ae235b
      char *result;
Packit ae235b
Packit ae235b
      if ((result = subparser_end (context, error)) == NULL)
Packit ae235b
        return;
Packit ae235b
Packit ae235b
      g_string_append_printf (user_data, "<<%s>>", result);
Packit ae235b
      g_free (result);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      char *result;
Packit ae235b
Packit ae235b
      if ((result = replay_parser_end (context, error)) == NULL)
Packit ae235b
        return;
Packit ae235b
Packit ae235b
      g_string_append_printf (user_data, "[[%s]]", result);
Packit ae235b
      g_free (result);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_string_append_printf (user_data, "</%s>", element_name);
Packit ae235b
}
Packit ae235b
Packit ae235b
static GMarkupParser parser =
Packit ae235b
{
Packit ae235b
  start_element,
Packit ae235b
  end_element
Packit ae235b
};
Packit ae235b
Packit ae235b
typedef struct
Packit ae235b
{
Packit ae235b
  const char *markup;
Packit ae235b
  const char *result;
Packit ae235b
  const char *error_message;
Packit ae235b
} TestCase;
Packit ae235b
Packit ae235b
static void
Packit ae235b
test (gconstpointer user_data)
Packit ae235b
{
Packit ae235b
  const TestCase *tc = user_data;
Packit ae235b
  GMarkupParseContext *ctx;
Packit ae235b
  GString *string;
Packit ae235b
  gboolean result;
Packit ae235b
  GError *error;
Packit ae235b
Packit ae235b
  error = NULL;
Packit ae235b
  string = g_string_new (NULL);
Packit ae235b
  ctx = g_markup_parse_context_new (&parser, 0, string, NULL);
Packit ae235b
  result = g_markup_parse_context_parse (ctx, tc->markup,
Packit ae235b
                                         strlen (tc->markup), &error);
Packit ae235b
  if (result)
Packit ae235b
    result = g_markup_parse_context_end_parse (ctx, &error);
Packit ae235b
  g_markup_parse_context_free (ctx);
Packit ae235b
  g_assert (strings_allocated == 0);
Packit ae235b
Packit ae235b
  if (result)
Packit ae235b
    {
Packit ae235b
      if (tc->error_message)
Packit ae235b
        g_error ("expected failure (about '%s') passed!\n"
Packit ae235b
                 "  in: %s\n  out: %s",
Packit ae235b
                 tc->error_message, tc->markup, string->str);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      if (!tc->error_message)
Packit ae235b
        g_error ("unexpected failure: '%s'\n"
Packit ae235b
                 "  in: %s\n  out: %s",
Packit ae235b
                 error->message, tc->markup, string->str);
Packit ae235b
Packit ae235b
      if (!strstr (error->message, tc->error_message))
Packit ae235b
        g_error ("failed for the wrong reason.\n"
Packit ae235b
                 "  expecting message about '%s'\n"
Packit ae235b
                 "  got message '%s'\n"
Packit ae235b
                 "  in: %s\n  out: %s",
Packit ae235b
                 tc->error_message, error->message, tc->markup, string->str);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (strcmp (string->str, tc->result) != 0)
Packit ae235b
    g_error ("got the wrong result.\n"
Packit ae235b
             "  expected: '%s'\n"
Packit ae235b
             "  got: '%s'\n"
Packit ae235b
             "  input: %s",
Packit ae235b
             tc->result, string->str, tc->markup);
Packit ae235b
Packit ae235b
  if (error)
Packit ae235b
    g_error_free (error);
Packit ae235b
Packit ae235b
  g_string_free (string, TRUE);
Packit ae235b
}
Packit ae235b
Packit ae235b
TestCase test_cases[] = /* successful runs */
Packit ae235b
{
Packit ae235b
    /* in */                    /* out */
Packit ae235b
  { "<test/>",                  "<test></test>" },
Packit ae235b
  { "<sub><foo/></sub>",        "<sub><<{foo}{/foo}>></sub>" },
Packit ae235b
  { "<sub><foo/><bar/></sub>",  "<sub><<{foo}{/foo}{bar}{/bar}>></sub>" },
Packit ae235b
  { "<foo><bar/></foo>",        "<foo>[[{foo}{bar}{/bar}{/foo}]]</foo>" },
Packit ae235b
  { "<foo><x/><y/></foo>",      "<foo>[[{foo}{x}{/x}{y}{/y}{/foo}]]</foo>" },
Packit ae235b
  { "<foo/>",                   "<foo>[[{foo}{/foo}]]</foo>" },
Packit ae235b
  { "<sub><foo/></sub><bar/>",  "<sub><<{foo}{/foo}>></sub>"
Packit ae235b
                                "<bar>[[{bar}{/bar}]]</bar>" }
Packit ae235b
};
Packit ae235b
Packit ae235b
TestCase error_cases[] = /* error cases */
Packit ae235b
{
Packit ae235b
    /* in */                    /* out */                       /* error */
Packit ae235b
  { "<foo><>",                  "<foo>",                        ">"},
Packit ae235b
  { "",                         "",                             "empty" },
Packit ae235b
  { "<trouble/>",               "<trouble>",                    "trouble" },
Packit ae235b
  { "<sub><trouble>",           "<sub>",                        "trouble" },
Packit ae235b
  { "<foo><trouble>",           "<foo>",                        "trouble" },
Packit ae235b
  { "<sub></sub>",              "<sub>",                        "no data" },
Packit ae235b
  { "<sub/>",                   "<sub>",                        "no data" }
Packit ae235b
};
Packit ae235b
Packit ae235b
#define add_tests(func, basename, array) \
Packit ae235b
  G_STMT_START { \
Packit ae235b
    int __add_tests_i;                                                  \
Packit ae235b
                                                                        \
Packit ae235b
    for (__add_tests_i  = 0;                                            \
Packit ae235b
         __add_tests_i < G_N_ELEMENTS (array);                          \
Packit ae235b
         __add_tests_i++)                                               \
Packit ae235b
      {                                                                 \
Packit ae235b
        char *testname;                                                 \
Packit ae235b
                                                                        \
Packit ae235b
        testname = g_strdup_printf ("%s/%d", basename, __add_tests_i);  \
Packit ae235b
        g_test_add_data_func (testname, &array[__add_tests_i], func);   \
Packit ae235b
        g_free (testname);                                              \
Packit ae235b
      }                                                                 \
Packit ae235b
  } G_STMT_END
Packit ae235b
Packit ae235b
int
Packit ae235b
main (int argc, char **argv)
Packit ae235b
{
Packit ae235b
  g_setenv ("LC_ALL", "C", TRUE);
Packit ae235b
  g_test_init (&argc, &argv, NULL);
Packit ae235b
  add_tests (test, "/glib/markup/subparser/success", test_cases);
Packit ae235b
  add_tests (test, "/glib/markup/subparser/failure", error_cases);
Packit ae235b
  return g_test_run ();
Packit ae235b
}