Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  builder.c

  Sprache: C
 

/* buildertest.c
 * Copyright (C) 2006-2007 Async Open Source
 * Authors: Johan Dahlin
 *          Henrique Romano
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */


#include <string.h>
#include <libintl.h>
#include <locale.h>
#include <math.h>

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

G_GNUC_BEGIN_IGNORE_DEPRECATIONS

#ifdef G_OS_WIN32
define _BUILDER_TEST_EXPORT __declspec(dllexport)
#else
define _BUILDER_TEST_EXPORT __attribute__((visibility("default")))
#endif

/* exported for GtkBuilder */
_BUILDER_TEST_EXPORT void signal_normal (GtkWindow *window, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_after (GtkWindow *window, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_object (GtkButton *button, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_object_after (GtkButton *button, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_first (GtkButton *button, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_second (GtkButton *button, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_extra (GtkButton *button, GParamSpec *spec);
_BUILDER_TEST_EXPORT void signal_extra2 (GtkButton *button, GParamSpec *spec);


static GtkBuilder *
builder_new_from_string (const char *buffer,
                         gsize length,
                         const char *domain)
{
  GtkBuilder *builder;
  GError *error = NULL;

  builder = gtk_builder_new ();
  if (domain)
    gtk_builder_set_translation_domain (builder, domain);
  gtk_builder_add_from_string (builder, buffer, length, &error);
  if (error)
    {
      g_print ("ERROR: %s", error->message);
      g_error_free (error);
    }

  return builder;
}

static void
test_parser (void)
{
  GtkBuilder *builder;
  GError *error;

  builder = gtk_builder_new ();

  error = NULL;
  gtk_builder_add_from_string (builder, "<xxx/>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_UNHANDLED_TAG);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface invalid=\"X\"/>", -1, &error);
  g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><child/></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_TAG);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"GtkBox\" id=\"a\"><object class=\"GtkBox\" id=\"b\"/></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_TAG);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"Unknown\" id=\"a\"></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"GtkWidget\" id=\"a\" constructor=\"none\"></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"GtkButton\" id=\"a\"><child internal-child=\"foobar\"><object class=\"GtkButton\" id=\"int\"/></child></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"GtkButton\" id=\"a\"></object><object class=\"GtkButton\" id=\"a\"/></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_DUPLICATE_ID);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"GtkButton\" id=\"a\"><property name=\"deafbeef\"></property></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_PROPERTY);
  g_clear_error (&error);

  gtk_builder_add_from_string (builder, "<interface><object class=\"GtkButton\" id=\"a\"><signal name=\"deafbeef\" handler=\"gtk_true\"/></object></interface>", -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_SIGNAL);
  g_error_free (error);

  g_object_unref (builder);
}

static int normal = 0;
static int after = 0;
static int object = 0;
static int object_after = 0;

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_normal (GtkWindow *window, GParamSpec *spec)
{
  g_assert_true (GTK_IS_WINDOW (window));
  g_assert_true (normal == 0);
  g_assert_true (after == 0);

  normal++;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_after (GtkWindow *window, GParamSpec *spec)
{
  g_assert_true (GTK_IS_WINDOW (window));
  g_assert_true (normal == 1);
  g_assert_true (after == 0);

  after++;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_object (GtkButton *button, GParamSpec *spec)
{
  g_assert_true (GTK_IS_BUTTON (button));
  g_assert_true (object == 0);
  g_assert_true (object_after == 0);

  object++;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_object_after (GtkButton *button, GParamSpec *spec)
{
  g_assert_true (GTK_IS_BUTTON (button));
  g_assert_true (object == 1);
  g_assert_true (object_after == 0);

  object_after++;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_first (GtkButton *button, GParamSpec *spec)
{
  g_assert_true (normal == 0);
  normal = 10;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_second (GtkButton *button, GParamSpec *spec)
{
  g_assert_true (normal == 10);
  normal = 20;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_extra (GtkButton *button, GParamSpec *spec)
{
  g_assert_true (normal == 20);
  normal = 30;
}

_BUILDER_TEST_EXPORT
void /* exported for GtkBuilder */
signal_extra2 (GtkButton *button, GParamSpec *spec)
{
  g_assert_true (normal == 30);
  normal = 40;
}

static void
test_connect_signals (void)
{
  GtkBuilder *builder;
  GObject *window;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkButton\" id=\"button\"/>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <signal name=\"notify::title\" handler=\"signal_normal\"/>"
    "    <signal name=\"notify::title\" handler=\"signal_after\" after=\"yes\"/>"
    "    <signal name=\"notify::title\" handler=\"signal_object\""
    "            object=\"button\"/>"
    "    <signal name=\"notify::title\" handler=\"signal_object_after\""
    "            object=\"button\" after=\"yes\"/>"
    "  </object>"
    "</interface>";
  const char buffer_order[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <signal name=\"notify::title\" handler=\"signal_first\"/>"
    "    <signal name=\"notify::title\" handler=\"signal_second\"/>"
    "  </object>"
    "</interface>";
  const char buffer_extra[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window2\">"
    "    <signal name=\"notify::title\" handler=\"signal_extra\"/>"
    "  </object>"
    "</interface>";
  const char buffer_extra2[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window3\">"
    "    <signal name=\"notify::title\" handler=\"signal_extra2\"/>"
    "  </object>"
    "</interface>";
  const char buffer_after_child[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkButton\" id=\"button1\"/>"
    "    </child>"
    "    <signal name=\"notify::title\" handler=\"signal_normal\"/>"
    "  </object>"
    "</interface>";

  builder = builder_new_from_string (buffer, -1, NULL);

  window = gtk_builder_get_object (builder, "window1");
  gtk_window_set_title (GTK_WINDOW (window), "test");

  g_assert_cmpint (normal, ==, 1);
  g_assert_cmpint (after, ==, 1);
  g_assert_cmpint (object, ==, 1);
  g_assert_cmpint (object_after, ==, 1);

  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer_order, -1, NULL);
  window = gtk_builder_get_object (builder, "window1");
  normal = 0;
  gtk_window_set_title (GTK_WINDOW (window), "test");
  g_assert_true (normal == 20);

  gtk_window_destroy (GTK_WINDOW (window));

  gtk_builder_add_from_string (builder, buffer_extra,
          strlen (buffer_extra), NULL);
  gtk_builder_add_from_string (builder, buffer_extra2,
          strlen (buffer_extra2), NULL);
  window = gtk_builder_get_object (builder, "window2");
  gtk_window_set_title (GTK_WINDOW (window), "test");
  g_assert_true (normal == 30);

  gtk_window_destroy (GTK_WINDOW (window));
  window = gtk_builder_get_object (builder, "window3");
  gtk_window_set_title (GTK_WINDOW (window), "test");
  g_assert_true (normal == 40);
  gtk_window_destroy (GTK_WINDOW (window));

  g_object_unref (builder);

  /* new test, reset globals */
  after = 0;
  normal = 0;

  builder = builder_new_from_string (buffer_after_child, -1, NULL);
  window = gtk_builder_get_object (builder, "window1");
  gtk_window_set_title (GTK_WINDOW (window), "test");

  g_assert_true (normal == 1);
  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);
}

static void
test_domain (void)
{
  GtkBuilder *builder;
  const char buffer1[] = "<interface/>";
  const char buffer2[] = "<interface domain=\"domain\"/>";
  const char *domain;

  builder = builder_new_from_string (buffer1, -1, NULL);
  domain = gtk_builder_get_translation_domain (builder);
  g_assert_true (domain == NULL);
  g_object_unref (builder);

  builder = builder_new_from_string (buffer1, -1"domain-1");
  domain = gtk_builder_get_translation_domain (builder);
  g_assert_nonnull (domain);
  g_assert_true (strcmp (domain, "domain-1") == 0);
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  domain = gtk_builder_get_translation_domain (builder);
  g_assert_null (domain);
  g_object_unref (builder);
}

#if 0
static void
test_translation (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label\">"
    "        <property name=\"label\" translatable=\"yes\">File</property>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GtkLabel *window, *label;

  setlocale (LC_ALL, "sv_SE");
  textdomain ("builder");
  bindtextdomain ("builder""tests");

  builder = builder_new_from_string (buffer, -1, NULL);
  label = GTK_LABEL (gtk_builder_get_object (builder, "label"));
  g_assert_true (strcmp (gtk_label_get_text (label), "Arkiv") == 0);

  window = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);
}
#endif

static void
test_sizegroup (void)
{
  GtkBuilder * builder;
  const char buffer1[] =
    "<interface domain=\"test\">"
    "  <object class=\"GtkSizeGroup\" id=\"sizegroup1\">"
    "    <property name=\"mode\">horizontal</property>"
    "    <widgets>"
    "      <widget name=\"radio1\"/>"
    "      <widget name=\"radio2\"/>"
    "    </widgets>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"vbox1\">"
    "        <property name=\"orientation\">vertical</property>"
    "        <child>"
    "          <object class=\"GtkCheckButton\" id=\"radio1\"/>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkCheckButton\" id=\"radio2\"/>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface domain=\"test\">"
    "  <object class=\"GtkSizeGroup\" id=\"sizegroup1\">"
    "    <property name=\"mode\">horizontal</property>"
    "    <widgets>"
    "    </widgets>"
    "   </object>"
    "</interface>";
  const char buffer3[] =
    "<interface domain=\"test\">"
    "  <object class=\"GtkSizeGroup\" id=\"sizegroup1\">"
    "    <property name=\"mode\">horizontal</property>"
    "    <widgets>"
    "      <widget name=\"radio1\"/>"
    "      <widget name=\"radio2\"/>"
    "    </widgets>"
    "  </object>"
    "  <object class=\"GtkSizeGroup\" id=\"sizegroup2\">"
    "    <property name=\"mode\">horizontal</property>"
    "    <widgets>"
    "      <widget name=\"radio1\"/>"
    "      <widget name=\"radio2\"/>"
    "    </widgets>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"vbox1\">"
    "        <property name=\"orientation\">vertical</property>"
    "        <child>"
    "          <object class=\"GtkCheckButton\" id=\"radio1\"/>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkCheckButton\" id=\"radio2\"/>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *sizegroup;
  GSList *widgets;

  builder = builder_new_from_string (buffer1, -1, NULL);
  sizegroup = gtk_builder_get_object (builder, "sizegroup1");
  widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
  g_assert_cmpint (g_slist_length (widgets), ==, 2);
  g_slist_free (widgets);
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  sizegroup = gtk_builder_get_object (builder, "sizegroup1");
  widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
  g_assert_cmpint (g_slist_length (widgets), ==, 0);
  g_slist_free (widgets);
  g_object_unref (builder);

  builder = builder_new_from_string (buffer3, -1, NULL);
  sizegroup = gtk_builder_get_object (builder, "sizegroup1");
  widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
  g_assert_cmpint (g_slist_length (widgets), ==, 2);
  g_slist_free (widgets);
  sizegroup = gtk_builder_get_object (builder, "sizegroup2");
  widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (sizegroup));
  g_assert_cmpint (g_slist_length (widgets), ==, 2);
  g_slist_free (widgets);

#if 0
  {
    GObject *window;
    window = gtk_builder_get_object (builder, "window1");
    gtk_window_destroy (GTK_WINDOW (window));
  }
#endif
  g_object_unref (builder);
}

static void
test_list_store (void)
{
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"guint\"/>"
    "    </columns>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gint\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"0\" translatable=\"yes\">John</col>"
    "        <col id=\"1\" context=\"foo\">Doe</col>"
    "        <col id=\"2\" comments=\"foobar\">25</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"0\">Johan</col>"
    "        <col id=\"1\">Dole</col>"
    "        <col id=\"2\">50</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "</interface>";
  const char buffer3[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gint\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"1\" context=\"foo\">Doe</col>"
    "        <col id=\"0\" translatable=\"yes\">John</col>"
    "        <col id=\"2\" comments=\"foobar\">25</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"2\">50</col>"
    "        <col id=\"1\">Dole</col>"
    "        <col id=\"0\">Johan</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"2\">19</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "</interface>";
  GtkBuilder *builder;
  GObject *store;
  GtkTreeIter iter;
  char *surname, *lastname;
  int age;

  builder = builder_new_from_string (buffer1, -1, NULL);
  store = gtk_builder_get_object (builder, "liststore1");
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 2);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_UINT);
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  store = gtk_builder_get_object (builder, "liststore1");
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 3);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 2), ==, G_TYPE_INT);

  g_assert_cmpint (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter), ==, TRUE);
  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "John");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Doe");
  g_free (lastname);
  g_assert_cmpint (age, ==, 25);
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "Johan");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Dole");
  g_free (lastname);
  g_assert_cmpint (age, ==, 50);
  g_assert_false (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  g_object_unref (builder);

  builder = builder_new_from_string (buffer3, -1, NULL);
  store = gtk_builder_get_object (builder, "liststore1");
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 3);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 2), ==, G_TYPE_INT);

  g_assert_true (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter));
  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "John");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Doe");
  g_free (lastname);
  g_assert_cmpint (age, ==, 25);
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "Johan");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Dole");
  g_free (lastname);
  g_assert_cmpint (age, ==, 50);
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_null (surname);
  g_assert_null (lastname);
  g_assert_cmpint (age, ==, 19);
  g_assert_false (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  g_object_unref (builder);
}

static void
test_tree_store (void)
{
  const char buffer[] =
    "<interface domain=\"test\">"
    "  <object class=\"GtkTreeStore\" id=\"treestore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"guint\"/>"
    "    </columns>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkTreeStore\" id=\"treestore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gint\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"0\" translatable=\"yes\">John</col>"
    "        <col id=\"1\" context=\"foo\">Doe</col>"
    "        <col id=\"2\" comments=\"foobar\">25</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"0\">Johan</col>"
    "        <col id=\"1\">Dole</col>"
    "        <col id=\"2\">50</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "</interface>";
  const char buffer3[] =
    "<interface>"
    "  <object class=\"GtkTreeStore\" id=\"treestore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gint\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"1\" context=\"foo\">Doe</col>"
    "        <col id=\"0\" translatable=\"yes\">John</col>"
    "        <col id=\"2\" comments=\"foobar\">25</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"2\">50</col>"
    "        <col id=\"1\">Dole</col>"
    "        <col id=\"0\">Johan</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"2\">19</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "</interface>";
  const char buffer4[] =
    "<interface>"
    "  <object class=\"GtkTreeStore\" id=\"treestore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"gint\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"1\" context=\"foo\">Doe</col>"
    "        <col id=\"0\" translatable=\"yes\">John</col>"
    "        <col id=\"2\" comments=\"foobar\">25</col>"
    "        <row>"
    "          <col id=\"2\">50</col>"
    "          <col id=\"1\">Dole</col>"
    "          <col id=\"0\">Johan</col>"
    "        </row>"
    "      </row>"
    "      <row>"
    "        <col id=\"2\">19</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "</interface>";
  GtkBuilder *builder;
  GObject *store;
  GtkTreeIter iter, parent;
  char *surname, *lastname;
  int age;

  builder = builder_new_from_string (buffer, -1, NULL);
  store = gtk_builder_get_object (builder, "treestore1");
  g_assert_true (GTK_IS_TREE_STORE (store));
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 2);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_UINT);
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  store = gtk_builder_get_object (builder, "treestore1");
  g_assert_true (GTK_IS_TREE_STORE (store));
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 3);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 2), ==, G_TYPE_INT);

  g_assert_cmpint (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter), ==, TRUE);
  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "John");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Doe");
  g_free (lastname);
  g_assert_cmpint (age, ==, 25);
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "Johan");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Dole");
  g_free (lastname);
  g_assert_cmpint (age, ==, 50);
  g_assert_false (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  g_object_unref (builder);

  builder = builder_new_from_string (buffer3, -1, NULL);
  store = gtk_builder_get_object (builder, "treestore1");
  g_assert_true (GTK_IS_TREE_STORE (store));
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 3);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 2), ==, G_TYPE_INT);

  g_assert_true (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter));
  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "John");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Doe");
  g_free (lastname);
  g_assert_cmpint (age, ==, 25);
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "Johan");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Dole");
  g_free (lastname);
  g_assert_cmpint (age, ==, 50);
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_null (surname);
  g_assert_null (lastname);
  g_assert_cmpint (age, ==, 19);
  g_assert_false (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  g_object_unref (builder);

  builder = builder_new_from_string (buffer4, -1, NULL);
  store = gtk_builder_get_object (builder, "treestore1");
  g_assert_true (GTK_IS_TREE_STORE (store));
  g_assert_cmpint (gtk_tree_model_get_n_columns (GTK_TREE_MODEL (store)), ==, 3);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 0), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 1), ==, G_TYPE_STRING);
  g_assert_cmpint (gtk_tree_model_get_column_type (GTK_TREE_MODEL (store), 2), ==, G_TYPE_INT);

  g_assert_true (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter));
  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "John");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Doe");
  g_free (lastname);
  g_assert_cmpint (age, ==, 25);
  parent = iter;
  g_assert_true (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &iter, &parent));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_cmpstr (surname, ==, "Johan");
  g_free (surname);
  g_assert_cmpstr (lastname, ==, "Dole");
  g_free (lastname);
  g_assert_cmpint (age, ==, 50);
  g_assert_false (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
  iter = parent;
  g_assert_true (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
                      0, &surname,
                      1, &lastname,
                      2, &age,
                      -1);
  g_assert_null (surname);
  g_assert_null (lastname);
  g_assert_cmpint (age, ==, 19);
  g_assert_false (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

  g_object_unref (builder);
}

static void
test_types (void)
{
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkBox\" id=\"box\"/>"
    "  <object class=\"GtkButton\" id=\"button\"/>"
    "  <object class=\"GtkCheckButton\" id=\"checkbutton\"/>"
    "  <object class=\"GtkDialog\" id=\"dialog\"/>"
    "  <object class=\"GtkDrawingArea\" id=\"drawingarea\"/>"
    "  <object class=\"GtkEntry\" id=\"entry\"/>"
    "  <object class=\"GtkFontButton\" id=\"fontbutton\"/>"
    "  <object class=\"GtkImage\" id=\"image\"/>"
    "  <object class=\"GtkLabel\" id=\"label\"/>"
    "  <object class=\"GtkListStore\" id=\"liststore\"/>"
    "  <object class=\"GtkNotebook\" id=\"notebook\"/>"
    "  <object class=\"GtkProgressBar\" id=\"progressbar\"/>"
    "  <object class=\"GtkSizeGroup\" id=\"sizegroup\"/>"
    "  <object class=\"GtkScrolledWindow\" id=\"scrolledwindow\"/>"
    "  <object class=\"GtkSpinButton\" id=\"spinbutton\"/>"
    "  <object class=\"GtkStatusbar\" id=\"statusbar\"/>"
    "  <object class=\"GtkTextView\" id=\"textview\"/>"
    "  <object class=\"GtkToggleButton\" id=\"togglebutton\"/>"
    "  <object class=\"GtkTreeStore\" id=\"treestore\"/>"
    "  <object class=\"GtkTreeView\" id=\"treeview\"/>"
    "  <object class=\"GtkViewport\" id=\"viewport\"/>"
    "  <object class=\"GtkWindow\" id=\"window\"/>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkWindow\" type-func=\"gtk_window_get_type\" id=\"window\"/>"
    "</interface>";
  const char buffer3[] =
    "<interface>"
    "  <object class=\"XXXInvalidType\" type-func=\"gtk_window_get_type\" id=\"window\"/>"
    "</interface>";
  const char buffer4[] =
    "<interface>"
    "  <object class=\"GtkWindow\" type-func=\"xxx_invalid_get_type_function\" id=\"window\"/>"
    "</interface>";
  const char buffer5[] =
    "<interface>"
    "  <object type-func=\"gtk_window_get_type\" id=\"window\"/>"
    "</interface>";
  GtkBuilder *builder;
  GObject *window;
  GError *error;

  builder = builder_new_from_string (buffer, -1, NULL);
  gtk_window_destroy (GTK_WINDOW (gtk_builder_get_object (builder, "dialog")));
  gtk_window_destroy (GTK_WINDOW (gtk_builder_get_object (builder, "window")));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  window = gtk_builder_get_object (builder, "window");
  g_assert_true (GTK_IS_WINDOW (window));
  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer3, -1, NULL);
  window = gtk_builder_get_object (builder, "window");
  g_assert_true (GTK_IS_WINDOW (window));
  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);

  error = NULL;
  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer4, -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION);
  g_error_free (error);
  g_object_unref (builder);

  error = NULL;
  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer5, -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_MISSING_ATTRIBUTE);
  g_error_free (error);
  g_object_unref (builder);
}

static void
test_spin_button (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "<object class=\"GtkAdjustment\" id=\"adjustment1\">"
    "<property name=\"lower\">0</property>"
    "<property name=\"upper\">10</property>"
    "<property name=\"step-increment\">2</property>"
    "<property name=\"page-increment\">3</property>"
    "<property name=\"page-size\">0</property>"
    "<property name=\"value\">1</property>"
    "</object>"
    "<object class=\"GtkSpinButton\" id=\"spinbutton1\">"
    "<property name=\"visible\">True</property>"
    "<property name=\"adjustment\">adjustment1</property>"
    "</object>"
    "</interface>";
  GObject *obj;
  GtkAdjustment *adjustment;
  double value;

  builder = builder_new_from_string (buffer, -1, NULL);
  obj = gtk_builder_get_object (builder, "spinbutton1");
  g_assert_true (GTK_IS_SPIN_BUTTON (obj));
  adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (obj));
  g_assert_true (GTK_IS_ADJUSTMENT (adjustment));
  g_object_get (adjustment, "value", &value, NULL);
  g_assert_cmpint (value, ==, 1);
  g_object_get (adjustment, "lower", &value, NULL);
  g_assert_cmpint (value, ==, 0);
  g_object_get (adjustment, "upper", &value, NULL);
  g_assert_cmpint (value, ==, 10);
  g_object_get (adjustment, "step-increment", &value, NULL);
  g_assert_cmpint (value, ==, 2);
  g_object_get (adjustment, "page-increment", &value, NULL);
  g_assert_cmpint (value, ==, 3);
  g_object_get (adjustment, "page-size", &value, NULL);
  g_assert_cmpint (value, ==, 0);

  g_object_unref (builder);
}

static void
test_notebook (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkNotebook\" id=\"notebook1\">"
    "    <child>"
    "      <object class=\"GtkNotebookPage\">"
    "        <property name=\"child\">"
    "          <object class=\"GtkLabel\" id=\"label1\">"
    "            <property name=\"label\">label1</property>"
    "          </object>"
    "        </property>"
    "        <property name=\"tab\">"
    "          <object class=\"GtkLabel\" id=\"tablabel1\">"
    "           <property name=\"label\">tab_label1</property>"
    "          </object>"
    "        </property>"
    "      </object>"
    "    </child>"
    "    <child>"
    "      <object class=\"GtkNotebookPage\">"
    "        <property name=\"child\">"
    "          <object class=\"GtkLabel\" id=\"label2\">"
    "            <property name=\"label\">label2</property>"
    "          </object>"
    "        </property>"
    "        <property name=\"tab\">"
    "          <object class=\"GtkLabel\" id=\"tablabel2\">"
    "            <property name=\"label\">tab_label2</property>"
    "          </object>"
    "        </property>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *notebook;
  GtkWidget *label;

  builder = builder_new_from_string (buffer, -1, NULL);
  notebook = gtk_builder_get_object (builder, "notebook1");
  g_assert_nonnull (notebook);
  g_assert_cmpint (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)), ==, 2);

  label = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0);
  g_assert_true (GTK_IS_LABEL (label));
  g_assert_cmpstr (gtk_label_get_label (GTK_LABEL (label)), ==, "label1");
  label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), label);
  g_assert_true (GTK_IS_LABEL (label));
  g_assert_cmpstr (gtk_label_get_label (GTK_LABEL (label)), ==, "tab_label1");

  label = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1);
  g_assert_true (GTK_IS_LABEL (label));
  g_assert_cmpstr (gtk_label_get_label (GTK_LABEL (label)), ==, "label2");
  label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), label);
  g_assert_true (GTK_IS_LABEL (label));
  g_assert_cmpstr (gtk_label_get_label (GTK_LABEL (label)), ==, "tab_label2");

  g_object_unref (builder);
}

static void
test_construct_only_property (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <property name=\"css-name\">amazing</property>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkTextTagTable\" id=\"tagtable1\"/>"
    "  <object class=\"GtkTextBuffer\" id=\"textbuffer1\">"
    "    <property name=\"tag-table\">tagtable1</property>"
    "  </object>"
    "</interface>";
  GObject *widget, *tagtable, *textbuffer;

  builder = builder_new_from_string (buffer, -1, NULL);
  widget = gtk_builder_get_object (builder, "window1");
  g_assert_cmpstr (gtk_widget_get_css_name (GTK_WIDGET (widget)), ==, "amazing");

  gtk_window_destroy (GTK_WINDOW (widget));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  textbuffer = gtk_builder_get_object (builder, "textbuffer1");
  g_assert_nonnull (textbuffer);
  g_object_get (textbuffer, "tag-table", &tagtable, NULL);
  g_assert_true (tagtable == gtk_builder_get_object (builder, "tagtable1"));
  g_object_unref (tagtable);
  g_object_unref (builder);
}

static void
test_object_properties (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"vbox\">"
    "        <property name=\"orientation\">vertical</property>"
    "        <child>"
    "          <object class=\"GtkLabel\" id=\"label1\">"
    "            <property name=\"mnemonic-widget\">spinbutton1</property>"
    "          </object>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkSpinButton\" id=\"spinbutton1\"/>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window2\"/>"
    "</interface>";
  GObject *label, *spinbutton, *window;

  builder = builder_new_from_string (buffer, -1, NULL);
  label = gtk_builder_get_object (builder, "label1");
  g_assert_nonnull (label);
  spinbutton = gtk_builder_get_object (builder, "spinbutton1");
  g_assert_nonnull (spinbutton);
  g_assert_true (spinbutton == (GObject*)gtk_label_get_mnemonic_widget (GTK_LABEL (label)));

  gtk_builder_add_from_string (builder, buffer2, -1, NULL);
  window = gtk_builder_get_object (builder, "window2");
  g_assert_nonnull (window);
  gtk_window_destroy (GTK_WINDOW (window));

  g_object_unref (builder);
}

static void
test_children (void)
{
  GtkBuilder * builder;
  GtkWidget *content_area;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkButton\" id=\"button1\">"
    "        <property name=\"label\">Hello</property>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkDialog\" id=\"dialog1\">"
    "    <property name=\"use_header_bar\">1</property>"
    "    <child internal-child=\"content_area\">"
    "      <object class=\"GtkBox\" id=\"dialog1-vbox\">"
    "        <property name=\"orientation\">vertical</property>"
    "          <child internal-child=\"action_area\">"
    "            <object class=\"GtkBox\" id=\"dialog1-action_area\">"
    "              <property name=\"orientation\">horizontal</property>"
    "            </object>"
    "          </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  GObject *window, *button;
  GObject *dialog, *vbox, *action_area;
  GtkWidget *child;
  int count;

  builder = builder_new_from_string (buffer1, -1, NULL);
  window = gtk_builder_get_object (builder, "window1");
  g_assert_true (GTK_IS_WINDOW (window));

  button = gtk_builder_get_object (builder, "button1");
  g_assert_true (GTK_IS_BUTTON (button));
  g_assert_nonnull (gtk_widget_get_parent (GTK_WIDGET(button)));
  g_assert_cmpstr (gtk_buildable_get_buildable_id (GTK_BUILDABLE (gtk_widget_get_parent (GTK_WIDGET (button)))), ==, "window1");

  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  dialog = gtk_builder_get_object (builder, "dialog1");
  g_assert_true (GTK_IS_DIALOG (dialog));
  count = 0;
  for (child = gtk_widget_get_first_child (GTK_WIDGET (dialog));
       child != NULL;
       child = gtk_widget_get_next_sibling (child))
    count++;
  g_assert_cmpint (count, ==, 2);

  vbox = gtk_builder_get_object (builder, "dialog1-vbox");
  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  g_assert_true (GTK_IS_BOX (vbox));
  g_assert_cmpint (gtk_orientable_get_orientation (GTK_ORIENTABLE (vbox)), ==, GTK_ORIENTATION_VERTICAL);
  g_assert_cmpstr (gtk_buildable_get_buildable_id (GTK_BUILDABLE (content_area)), ==, "dialog1-vbox");

  action_area = gtk_builder_get_object (builder, "dialog1-action_area");
  g_assert_true (GTK_IS_BOX (action_area));
  g_assert_cmpint (gtk_orientable_get_orientation (GTK_ORIENTABLE (action_area)), ==, GTK_ORIENTATION_HORIZONTAL);
  g_assert_nonnull (gtk_widget_get_parent (GTK_WIDGET (action_area)));
  g_assert_nonnull (gtk_buildable_get_buildable_id (GTK_BUILDABLE (action_area)));
  gtk_window_destroy (GTK_WINDOW (dialog));
  g_object_unref (builder);
}

static void
test_layout_properties (void)
{
  GtkBuilder * builder;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkGrid\" id=\"grid1\">"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label1\">"
    "        <layout>"
    "          <property name=\"column\">1</property>"
    "        </layout>"
    "      </object>"
    "    </child>"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label2\">"
    "        <layout>"
    "          <property name=\"column\">0</property>"
    "        </layout>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  GObject *label, *vbox;

  builder = builder_new_from_string (buffer1, -1, NULL);
  vbox = gtk_builder_get_object (builder, "grid1");
  g_assert_true (GTK_IS_GRID (vbox));

  label = gtk_builder_get_object (builder, "label1");
  g_assert_true (GTK_IS_LABEL (label));

  label = gtk_builder_get_object (builder, "label2");
  g_assert_true (GTK_IS_LABEL (label));

  g_object_unref (builder);
}

static void
test_treeview_column (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "<object class=\"GtkListStore\" id=\"liststore1\">"
    "  <columns>"
    "    <column type=\"gchararray\"/>"
    "    <column type=\"guint\"/>"
    "  </columns>"
    "  <data>"
    "    <row>"
    "      <col id=\"0\">John</col>"
    "      <col id=\"1\">25</col>"
    "    </row>"
    "  </data>"
    "</object>"
    "<object class=\"GtkWindow\" id=\"window1\">"
    "  <child>"
    "    <object class=\"GtkTreeView\" id=\"treeview1\">"
    "      <property name=\"visible\">True</property>"
    "      <property name=\"model\">liststore1</property>"
    "      <child>"
    "        <object class=\"GtkTreeViewColumn\" id=\"column1\">"
    "          <property name=\"title\">Test</property>"
    "          <child>"
    "            <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
    "            <attributes>"
    "              <attribute name=\"text\">1</attribute>"
    "            </attributes>"
    "          </child>"
    "        </object>"
    "      </child>"
    "      <child>"
    "        <object class=\"GtkTreeViewColumn\" id=\"column2\">"
    "          <property name=\"title\">Number</property>"
    "          <child>"
    "            <object class=\"GtkCellRendererText\" id=\"renderer2\"/>"
    "            <attributes>"
    "              <attribute name=\"text\">0</attribute>"
    "            </attributes>"
    "          </child>"
    "        </object>"
    "      </child>"
    "    </object>"
    "  </child>"
    "</object>"
    "</interface>";
  GObject *window, *treeview;
  GtkTreeViewColumn *column;
  GList *renderers;
  GObject *renderer;

  builder = builder_new_from_string (buffer, -1, NULL);
  treeview = gtk_builder_get_object (builder, "treeview1");
  g_assert_true (GTK_IS_TREE_VIEW (treeview));
  column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0);
  g_assert_true (GTK_IS_TREE_VIEW_COLUMN (column));
  g_assert_cmpstr (gtk_tree_view_column_get_title (column), ==, "Test");

  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
  g_assert_cmpint (g_list_length (renderers), ==, 1);
  renderer = g_list_nth_data (renderers, 0);
  g_assert_true (GTK_IS_CELL_RENDERER_TEXT (renderer));
  g_list_free (renderers);

  window = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window));

  g_object_unref (builder);
}

static void
test_icon_view (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "      <column type=\"GdkPixbuf\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"0\">test</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkIconView\" id=\"iconview1\">"
    "        <property name=\"model\">liststore1</property>"
    "        <property name=\"text-column\">0</property>"
    "        <property name=\"pixbuf-column\">1</property>"
    "        <property name=\"visible\">True</property>"
    "        <child>"
    "          <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
    "          <attributes>"
    "            <attribute name=\"text\">0</attribute>"
    "          </attributes>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *window, *iconview;

  builder = builder_new_from_string (buffer, -1, NULL);
  iconview = gtk_builder_get_object (builder, "iconview1");
  g_assert_true (GTK_IS_ICON_VIEW (iconview));

  window = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);
}

static void
test_combo_box (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"guint\"/>"
    "      <column type=\"gchararray\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"0\">1</col>"
    "        <col id=\"1\">Foo</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"0\">2</col>"
    "        <col id=\"1\">Bar</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkComboBox\" id=\"combobox1\">"
    "        <property name=\"model\">liststore1</property>"
    "        <property name=\"visible\">True</property>"
    "        <child>"
    "          <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
    "          <attributes>"
    "            <attribute name=\"text\">0</attribute>"
    "          </attributes>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkCellRendererText\" id=\"renderer2\"/>"
    "          <attributes>"
    "            <attribute name=\"text\">1</attribute>"
    "          </attributes>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *window, *combobox;

  builder = builder_new_from_string (buffer, -1, NULL);
  combobox = gtk_builder_get_object (builder, "combobox1");
  g_assert_nonnull (combobox);

  window = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window));

  g_object_unref (builder);
}

#if 0
static void
test_combo_box_entry (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"guint\"/>"
    "      <column type=\"gchararray\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"0\">1</col>"
    "        <col id=\"1\">Foo</col>"
    "      </row>"
    "      <row>"
    "        <col id=\"0\">2</col>"
    "        <col id=\"1\">Bar</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkComboBox\" id=\"comboboxentry1\">"
    "        <property name=\"model\">liststore1</property>"
    "        <property name=\"has-entry\">True</property>"
    "        <property name=\"visible\">True</property>"
    "        <child>"
    "          <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
    "            <attributes>"
    "              <attribute name=\"text\">0</attribute>"
    "            </attributes>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkCellRendererText\" id=\"renderer2\"/>"
    "            <attributes>"
    "              <attribute name=\"text\">1</attribute>"
    "            </attributes>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *window, *combobox, *renderer;
  char *text;

  builder = builder_new_from_string (buffer, -1, NULL);
  combobox = gtk_builder_get_object (builder, "comboboxentry1");
  g_assert_nonnull (combobox);

  renderer = gtk_builder_get_object (builder, "renderer2");
  g_assert_nonnull (renderer);
  g_object_get (renderer, "text", &text, NULL);
  g_assert_cmpstr (text, ==, "Bar");
  g_free (text);

  renderer = gtk_builder_get_object (builder, "renderer1");
  g_assert_nonnull (renderer);
  g_object_get (renderer, "text", &text, NULL);
  g_assert_cmpstr (text, ==, "2");
  g_free (text);

  window = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window));

  g_object_unref (builder);
}
#endif

static void
test_cell_view (void)
{
  GtkBuilder *builder;
  const char *buffer =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\">"
    "    <columns>"
    "      <column type=\"gchararray\"/>"
    "    </columns>"
    "    <data>"
    "      <row>"
    "        <col id=\"0\">test</col>"
    "      </row>"
    "    </data>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkCellView\" id=\"cellview1\">"
    "        <property name=\"visible\">True</property>"
    "        <property name=\"model\">liststore1</property>"
    "        <child>"
    "          <object class=\"GtkCellRendererText\" id=\"renderer1\"/>"
    "          <attributes>"
    "            <attribute name=\"text\">0</attribute>"
    "          </attributes>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *cellview;
  GObject *model, *window;
  GtkTreePath *path;
  GList *renderers;

  builder = builder_new_from_string (buffer, -1, NULL);
  cellview = gtk_builder_get_object (builder, "cellview1");
  g_assert_nonnull (builder);
  g_assert_true (GTK_IS_CELL_VIEW (cellview));
  g_object_get (cellview, "model", &model, NULL);
  g_assert_true (GTK_IS_TREE_MODEL (model));
  g_object_unref (model);
  path = gtk_tree_path_new_first ();
  gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (cellview), path);
  gtk_tree_path_free (path);

  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (cellview));
  g_assert_cmpint (g_list_length (renderers), ==, 1);
  g_list_free (renderers);

  window = gtk_builder_get_object (builder, "window1");
  g_assert_nonnull (window);
  gtk_window_destroy (GTK_WINDOW (window));

  g_object_unref (builder);
}

static void
test_dialog (void)
{
  GtkBuilder * builder;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkDialog\" id=\"dialog1\">"
    "    <child internal-child=\"content_area\">"
    "      <object class=\"GtkBox\" id=\"dialog1-vbox\">"
    "        <property name=\"orientation\">vertical</property>"
    "          <child internal-child=\"action_area\">"
    "            <object class=\"GtkBox\" id=\"dialog1-action_area\">"
    "              <property name=\"orientation\">horizontal</property>"
    "              <child>"
    "                <object class=\"GtkButton\" id=\"button_cancel\"/>"
    "              </child>"
    "              <child>"
    "                <object class=\"GtkButton\" id=\"button_ok\"/>"
    "              </child>"
    "            </object>"
    "          </child>"
    "      </object>"
    "    </child>"
    "    <action-widgets>"
    "      <action-widget response=\"3\">button_ok</action-widget>"
    "      <action-widget response=\"-5\">button_cancel</action-widget>"
    "    </action-widgets>"
    "  </object>"
    "</interface>";

  GObject *dialog1;
  GObject *button_ok;
  GObject *button_cancel;

  builder = builder_new_from_string (buffer1, -1, NULL);
  dialog1 = gtk_builder_get_object (builder, "dialog1");
  button_ok = gtk_builder_get_object (builder, "button_ok");
  g_assert_cmpint (gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog1), GTK_WIDGET (button_ok)), ==, 3);
  button_cancel = gtk_builder_get_object (builder, "button_cancel");
  g_assert_cmpint (gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog1), GTK_WIDGET (button_cancel)), ==, -5);

  gtk_window_destroy (GTK_WINDOW (dialog1));
  g_object_unref (builder);
}

static void
test_message_dialog (void)
{
  GtkBuilder * builder;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkMessageDialog\" id=\"dialog1\">"
    "    <child internal-child=\"message_area\">"
    "      <object class=\"GtkBox\" id=\"dialog-message-area\">"
    "        <property name=\"orientation\">vertical</property>"
    "        <child>"
    "          <object class=\"GtkExpander\" id=\"expander\"/>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  GObject *dialog1;
  GObject *expander;

  builder = builder_new_from_string (buffer1, -1, NULL);
  dialog1 = gtk_builder_get_object (builder, "dialog1");
  expander = gtk_builder_get_object (builder, "expander");
  g_assert_true (GTK_IS_EXPANDER (expander));
  g_assert_true (gtk_widget_get_parent (GTK_WIDGET (expander)) == gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog1)));

  gtk_window_destroy (GTK_WINDOW (dialog1));
  g_object_unref (builder);
}

static void
test_widget (void)
{
  const char *buffer =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <property name=\"focus-widget\">button1</property>"
    "    <child>"
    "      <object class=\"GtkButton\" id=\"button1\">"
    "      </object>"
    "    </child>"
    "  </object>"
   "</interface>";
  const char *buffer2 =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkButton\" id=\"button1\">"
    "         <property name=\"receives-default\">True</property>"
    "      </object>"
    "    </child>"
    "  </object>"
   "</interface>";
  const char *buffer3 =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"vbox1\">"
    "        <property name=\"orientation\">vertical</property>"
    "        <child>"
    "          <object class=\"GtkLabel\" id=\"label1\">"
    "          </object>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkButton\" id=\"button1\">"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  const char *buffer4 =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label1\">"
    "         <property name=\"label\">Thelabel</property>"
    "      </object>"
    "    </child>"
    "  </object>"
   "</interface>";
  GtkBuilder *builder;
  GObject *window1, *button1, *label1;

  builder = builder_new_from_string (buffer, -1, NULL);
  button1 = gtk_builder_get_object (builder, "button1");

  g_assert_true (gtk_widget_is_focus (GTK_WIDGET (button1)));
  window1 = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window1));

  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  button1 = gtk_builder_get_object (builder, "button1");

  g_assert_true (gtk_widget_get_receives_default (GTK_WIDGET (button1)));

  g_object_unref (builder);

  builder = builder_new_from_string (buffer3, -1, NULL);

  window1 = gtk_builder_get_object (builder, "window1");
  label1 = gtk_builder_get_object (builder, "label1");
  g_assert_true (GTK_IS_LABEL (label1));

  gtk_window_destroy (GTK_WINDOW (window1));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer4, -1, NULL);
  label1 = gtk_builder_get_object (builder, "label1");
  g_assert_true (GTK_IS_LABEL (label1));

  g_object_unref (builder);
}

static void
test_window (void)
{
  const char *buffer1 =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "     <property name=\"title\"></property>"
    "  </object>"
   "</interface>";
  const char *buffer2 =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "  </object>"
   "</interface>";
  GtkBuilder *builder;
  GObject *window1;
  char *title;

  builder = builder_new_from_string (buffer1, -1, NULL);
  window1 = gtk_builder_get_object (builder, "window1");
  g_object_get (window1, "title", &title, NULL);
  g_assert_cmpstr (title, ==, "");
  g_free (title);
  gtk_window_destroy (GTK_WINDOW (window1));
  g_object_unref (builder);

  builder = builder_new_from_string (buffer2, -1, NULL);
  window1 = gtk_builder_get_object (builder, "window1");
  gtk_window_destroy (GTK_WINDOW (window1));
  g_object_unref (builder);
}

static void
test_value_from_string (void)
{
  GValue value = G_VALUE_INIT;
  GError *error = NULL;
  GtkBuilder *builder;

  builder = gtk_builder_new ();

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_STRING, "test", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_STRING (&value));
  g_assert_cmpstr (g_value_get_string (&value), ==, "test");
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "true", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_true (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "false", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_false (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "yes", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_true (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "no", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_false (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "0", &value, ;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_false (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "1", &value, ;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_true (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "tRuE", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_BOOLEAN (&value));
  g_assert_true (g_value_get_boolean (&value));
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "blaurgh", &value, &error) == FALSE);
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "yess", &value,&nbsp;&error) == FALSE);
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "trueee", &value, &error) == FALSE);
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_false (gtk_builder_value_from_string_type (builder, G_TYPE_BOOLEAN, "", &value, ;&error));
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_INT, "12345", &value, ;&error));
  g_assert_true (G_VALUE_HOLDS_INT (&value));
  g_assert_cmpint (g_value_get_int (&value), ==, 12345);
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_LONG, "9912345", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_LONG (&value));
  g_assert_cmpint (g_value_get_long (&value), ==, 9912345);
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_UINT, "2345", &value, ;&error));
  g_assert_true (G_VALUE_HOLDS_UINT (&value));
  g_assert_cmpint (g_value_get_uint (&value), ==, 2345);
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_INT64, "-2345", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_INT64 (&value));
  g_assert_cmpint (g_value_get_int64 (&value), ==, -2345);
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_UINT64, "2345", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_UINT64 (&value));
  g_assert_cmpint (g_value_get_uint64 (&value), ==, 2345);
  g_value_unset (&value);

  g_assert_true (gtk_builder_value_from_string_type (builder, G_TYPE_FLOAT, "1.454", &value,&nbsp;&error));
  g_assert_true (G_VALUE_HOLDS_FLOAT (&value));
  g_assert_cmpfloat (fabs (g_value_get_float (&value) - 1.454), <, 0.00001);
  g_value_unset (&value);

  g_assert_false (gtk_builder_value_from_string_type (builder, G_TYPE_FLOAT, "abc", &value,&nbsp;&error));
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_false (gtk_builder_value_from_string_type (builder, G_TYPE_INT, "/-+,abc", &value,&nbsp;&error));
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_true (gtk_builder_value_from_string_type (builder, GTK_TYPE_TEXT_DIRECTION"rtl", &value, &error));
  g_assert_true (G_VALUE_HOLDS_ENUM (&value));
  g_assert_cmpint (g_value_get_enum (&value), ==, GTK_TEXT_DIR_RTL);
  g_value_unset (&value);

  g_assert_false (gtk_builder_value_from_string_type (builder, GTK_TYPE_TEXT_DIRECTION, "sliff", &value, &error));
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_assert_false (gtk_builder_value_from_string_type (builder, GTK_TYPE_TEXT_DIRECTION, "foobar", &value, &error));
  g_value_unset (&value);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE);
  g_clear_error (&error);

  g_object_unref (builder);
}

static gboolean model_freed = FALSE;

static void
model_weakref (gpointer data,
               GObject *model)
{
  model_freed = TRUE;
}

static void
test_reference_counting (void)
{
  GtkBuilder *builder;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkListStore\" id=\"liststore1\"/>"
    "  <object class=\"GtkListStore\" id=\"liststore2\"/>"
    "  <object class=\"GtkWindow\" id=\"window1\">"
    "    <child>"
    "      <object class=\"GtkTreeView\" id=\"treeview1\">"
    "        <property name=\"model\">liststore1</property>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkBox\" id=\"vbox1\">"
    "        <property name=\"orientation\">vertical</property>"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label1\"/>"
    "    </child>"
    "  </object>"
    "</interface>";
  GObject *window, *treeview, *model;

  builder = builder_new_from_string (buffer1, -1, NULL);
  window = gtk_builder_get_object (builder, "window1");
  treeview = gtk_builder_get_object (builder, "treeview1");
  model = gtk_builder_get_object (builder, "liststore1");
  g_object_unref (builder);

  g_object_weak_ref (model, (GWeakNotify)model_weakref, NULL);

  g_assert_false (model_freed);
  gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), NULL);
  g_assert_true (model_freed);

  gtk_window_destroy (GTK_WINDOW (window));

  builder = builder_new_from_string (buffer2, -1, NULL);
  g_object_unref (builder);
}

G_GNUC_BEGIN_IGNORE_DEPRECATIONS

typedef struct {
  gboolean weight;
  gboolean foreground;
  gboolean underline;
  gboolean size;
  gboolean font_desc;
  gboolean language;
} FoundAttrs;

static gboolean
filter_pango_attrs (PangoAttribute *attr,
      gpointer        data)
{
  FoundAttrs *found = (FoundAttrs *)data;

  if (attr->klass->type == PANGO_ATTR_WEIGHT)
    found->weight = TRUE;
  else if (attr->klass->type == PANGO_ATTR_FOREGROUND)
    found->foreground = TRUE;
  else if (attr->klass->type == PANGO_ATTR_UNDERLINE)
    found->underline = TRUE;
  /* Make sure optional start/end properties are working */
  else if (attr->klass->type == PANGO_ATTR_SIZE &&
    attr->start_index == 5 &&
    attr->end_index   == 10)
    found->size = TRUE;
  else if (attr->klass->type == PANGO_ATTR_FONT_DESC)
    found->font_desc = TRUE;
  else if (attr->klass->type == PANGO_ATTR_LANGUAGE)
    found->language = TRUE;

  return TRUE;
}

static void
test_pango_attributes (void)
{
  GtkBuilder *builder;
  FoundAttrs found = { 0, };
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkLabel\" id=\"label1\">"
    "    <attributes>"
    "      <attribute name=\"weight\" value=\"PANGO_WEIGHT_BOLD\"/>"
    "      <attribute name=\"foreground\" value=\"DarkSlateGray\"/>"
    "      <attribute name=\"underline\" value=\"True\"/>"
    "      <attribute name=\"size\" value=\"4\" start=\"5\" end=\"10\"/>"
    "      <attribute name=\"font-desc\" value=\"Sans Italic 22\"/>"
    "      <attribute name=\"language\" value=\"pt_BR\"/>"
    "    </attributes>"
    "  </object>"
    "</interface>";
  const char err_buffer1[] =
    "<interface>"
    "  <object class=\"GtkLabel\" id=\"label1\">"
    "    <attributes>"
    "      <attribute name=\"weight\"/>"
    "    </attributes>"
    "  </object>"
    "</interface>";
  const char err_buffer2[] =
    "<interface>"
    "  <object class=\"GtkLabel\" id=\"label1\">"
    "    <attributes>"
    "      <attribute name=\"weight\" value=\"PANGO_WEIGHT_BOLD\" unrecognized=\"True\"/>"
    "    </attributes>"
    "  </object>"
    "</interface>";

  GObject *label;
  GError  *error = NULL;
  PangoAttrList *attrs, *filtered;

  /* Test attributes are set */
  builder = builder_new_from_string (buffer, -1, NULL);
  label = gtk_builder_get_object (builder, "label1");
  g_assert_nonnull (label);

  attrs = gtk_label_get_attributes (GTK_LABEL (label));
  g_assert_nonnull (attrs);

  filtered = pango_attr_list_filter (attrs, filter_pango_attrs, &found);
  g_assert_true (filtered);
  pango_attr_list_unref (filtered);

  g_assert_true (found.weight);
  g_assert_true (found.foreground);
  g_assert_true (found.underline);
  g_assert_true (found.size);
  g_assert_true (found.language);
  g_assert_true (found.font_desc);

  g_object_unref (builder);

  /* Test errors are set */
  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, err_buffer1, -1, &error);
  g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE);
  g_object_unref (builder);
  g_clear_error (&error);

  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, err_buffer2, -1, &error);
  g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE);
  g_object_unref (builder);
  g_error_free (error);
}

static void
test_requires (void)
{
  GtkBuilder *builder;
  GError     *error = NULL;
  char       *buffer;
  const char buffer_fmt[] =
    "<interface>"
    "  <requires lib=\"gtk\" version=\"%d.%d\"/>"
    "</interface>";

  buffer = g_strdup_printf (buffer_fmt, GTK_MAJOR_VERSION, GTK_MINOR_VERSION + 1);
  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer, -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_VERSION_MISMATCH);
  g_object_unref (builder);
  g_error_free (error);
  g_free (buffer);
}

static void
test_add_objects (void)
{
  GtkBuilder *builder;
  GError *error;
  int ret;
  GObject *obj;
  const char *objects[2] = {"mainbox", NULL};
  const char *objects2[3] = {"mainbox""window2", NULL};
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"mainbox\">"
    "        <property name=\"orientation\">vertical</property>"
    "        <property name=\"visible\">True</property>"
    "        <child>"
    "          <object class=\"GtkLabel\" id=\"label1\">"
    "            <property name=\"visible\">True</property>"
    "            <property name=\"label\" translatable=\"no\">first label</property>"
    "          </object>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkLabel\" id=\"label2\">"
    "            <property name=\"visible\">True</property>"
    "            <property name=\"label\" translatable=\"no\">second label</property>"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "  <object class=\"GtkWindow\" id=\"window2\">"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label3\">"
    "        <property name=\"label\" translatable=\"no\">second label</property>"
    "      </object>"
    "    </child>"
    "  </object>"
    "<interface/>";

  error = NULL;
  builder = gtk_builder_new ();
  ret = gtk_builder_add_objects_from_string (builder, buffer, -1, objects, &error);
  g_assert_no_error (error);
  obj = gtk_builder_get_object (builder, "window");
  g_assert_null (obj);
  obj = gtk_builder_get_object (builder, "window2");
  g_assert_null (obj);
  obj = gtk_builder_get_object (builder, "mainbox");
  g_assert_true (GTK_IS_WIDGET (obj));
  g_object_unref (builder);

  error = NULL;
  builder = gtk_builder_new ();
  ret = gtk_builder_add_objects_from_string (builder, buffer, -1, objects2, &error);
  g_assert_true (ret);
  g_assert_null (error);
  obj = gtk_builder_get_object (builder, "window");
  g_assert_null (obj);
  obj = gtk_builder_get_object (builder, "window2");
  g_assert_true (GTK_IS_WINDOW (obj));
  gtk_window_destroy (GTK_WINDOW (obj));
  obj = gtk_builder_get_object (builder, "mainbox");
  g_assert_true (GTK_IS_WIDGET (obj));
  g_object_unref (builder);
}

static void
test_message_area (void)
{
  GtkBuilder *builder;
  GObject *obj, *obj1;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkInfoBar\" id=\"infobar1\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"contentarea1\">"
    "        <property name=\"orientation\">horizontal</property>"
    "        <child>"
    "          <object class=\"GtkLabel\" id=\"content\">"
    "            <property name=\"label\" translatable=\"yes\">Message</property>"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "    <child type=\"action\">"
    "      <object class=\"GtkButton\" id=\"button_ok\">"
    "        <property name=\"label\">gtk-ok</property>"
    "      </object>"
    "    </child>"
    "    <action-widgets>"
    "      <action-widget response=\"1\">button_ok</action-widget>"
    "    </action-widgets>"
    "  </object>"
    "</interface>";

  builder = builder_new_from_string (buffer, -1, NULL);
  obj = gtk_builder_get_object (builder, "infobar1");
  g_assert_true (GTK_IS_INFO_BAR (obj));
  obj1 = gtk_builder_get_object (builder, "content");
  g_assert_true (GTK_IS_LABEL (obj1));

  obj1 = gtk_builder_get_object (builder, "button_ok");
  g_assert_true (GTK_IS_BUTTON (obj1));

  g_object_unref (builder);
}

static void
test_gmenu (void)
{
  GtkBuilder *builder;
  GObject *obj, *obj1;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window\">"
    "  </object>"
    "  <menu id='edit-menu'>"
    "    <section>"
    "      <item>"
    "        <attribute name='label'>Undo</attribute>"
    "        <attribute name='action'>undo</attribute>"
    "      </item>"
    "      <item>"
    "        <attribute name='label'>Redo</attribute>"
    "        <attribute name='action'>redo</attribute>"
    "      </item>"
    "    </section>"
    "    <section></section>"
    "    <section>"
    "      <attribute name='label'>Copy & Paste</attribute>"
    "      <item>"
    "        <attribute name='label'>Cut</attribute>"
    "        <attribute name='action'>cut</attribute>"
    "      </item>"
    "      <item>"
    "        <attribute name='label'>Copy</attribute>"
    "        <attribute name='action'>copy</attribute>"
    "      </item>"
    "      <item>"
    "        <attribute name='label'>Paste</attribute>"
    "        <attribute name='action'>paste</attribute>"
    "      </item>"
    "    </section>"
    "    <item><link name='section' id='blargh'>"
    "      <item>"
    "        <attribute name='label'>Bold</attribute>"
    "        <attribute name='action'>bold</attribute>"
    "      </item>"
    "      <submenu>"
    "        <attribute name='label'>Language</attribute>"
    "        <item>"
    "          <attribute name='label'>Latin</attribute>"
    "          <attribute name='action'>lang</attribute>"
    "          <attribute name='target'>'latin'</attribute>"
    "        </item>"
    "        <item>"
    "          <attribute name='label'>Greek</attribute>"
    "          <attribute name='action'>lang</attribute>"
    "          <attribute name='target'>'greek'</attribute>"
    "        </item>"
    "        <item>"
    "          <attribute name='label'>Urdu</attribute>"
    "          <attribute name='action'>lang</attribute>"
    "          <attribute name='target'>'urdu'</attribute>"
    "        </item>"
    "      </submenu>"
    "    </link></item>"
    "  </menu>"
    "</interface>";

  builder = builder_new_from_string (buffer, -1, NULL);
  obj = gtk_builder_get_object (builder, "window");
  g_assert_true (GTK_IS_WINDOW (obj));
  obj1 = gtk_builder_get_object (builder, "edit-menu");
  g_assert_true (G_IS_MENU_MODEL (obj1));
  obj1 = gtk_builder_get_object (builder, "blargh");
  g_assert_true (G_IS_MENU_MODEL (obj1));
  g_object_unref (builder);
}

static void
test_level_bar (void)
{
  GtkBuilder *builder;
  GError *error = NULL;
  GObject *obj, *obj1;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window\">"
    "    <child>"
    "      <object class=\"GtkLevelBar\" id=\"levelbar\">"
    "        <property name=\"value\">4.70</property>"
    "        <property name=\"min-value\">2</property>"
    "        <property name=\"max-value\">5</property>"
    "        <offsets>"
    "          <offset name=\"low\" value=\"2.25\"/>"
    "          <offset name=\"custom\" value=\"3\"/>"
    "          <offset name=\"high\" value=\"3\"/>"
    "        </offsets>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";
  const char buffer2[] =
    "<interface>"
    "  <object class=\"GtkLevelBar\" id=\"levelbar\">"
    "    <offsets>"
    "      <offset name=\"low\" bogus_attr=\"foo\"/>"
    "    </offsets>"
    "  </object>"
    "</interface>";
  const char buffer3[] =
    "<interface>"
    "  <object class=\"GtkLevelBar\" id=\"levelbar\">"
    "    <offsets>"
    "      <offset name=\"low\" value=\"1\"/>"
    "    </offsets>"
    "    <bogus_tag>"
    "    </bogus_tag>"
    "  </object>"
    "</interface>";

  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer1, -1, &error);
  g_assert_true (error == NULL);

  obj = gtk_builder_get_object (builder, "window");
  g_assert_true (GTK_IS_WINDOW (obj));
  obj1 = gtk_builder_get_object (builder, "levelbar");
  g_assert_true (GTK_IS_LEVEL_BAR (obj1));
  g_object_unref (builder);

  error = NULL;
  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer2, -1, &error);
  g_assert_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE);
  g_error_free (error);
  g_object_unref (builder);

  error = NULL;
  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer3, -1, &error);
  g_assert_error (error, GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_UNHANDLED_TAG);
  g_error_free (error);
  g_object_unref (builder);
}

static void
test_expose_object (void)
{
  GtkBuilder *builder;
  GError *error = NULL;
  GtkWidget *menu;
  GObject *obj;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkMenuButton\" id=\"button\">"
    "    <property name=\"popover\">external_menu</property>"
    "  </object>"
    "</interface>";

  menu = gtk_popover_new ();
  builder = gtk_builder_new ();
  gtk_builder_expose_object (builder, "external_menu", G_OBJECT (menu));
  gtk_builder_add_from_string (builder, buffer, -1, &error);
  g_assert_no_error (error);

  obj = gtk_builder_get_object (builder, "button");
  g_assert_true (GTK_IS_MENU_BUTTON (obj));

  g_assert_true (gtk_menu_button_get_popover (GTK_MENU_BUTTON (obj)) == GTK_POPOVER (menu));

  g_object_unref (builder);
}

static void
test_no_ids (void)
{
  GtkBuilder *builder;
  GError *error = NULL;
  GObject *obj;
  const char buffer[] =
    "<interface>"
    "  <object class=\"GtkInfoBar\">"
    "    <child>"
    "      <object class=\"GtkBox\">"
    "        <property name=\"orientation\">horizontal</property>"
    "        <child>"
    "          <object class=\"GtkLabel\">"
    "            <property name=\"label\" translatable=\"yes\">Message</property>"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "    <child type=\"action\">"
    "      <object class=\"GtkButton\" id=\"button_ok\">"
    "        <property name=\"label\">gtk-ok</property>"
    "      </object>"
    "    </child>"
    "    <action-widgets>"
    "      <action-widget response=\"1\">button_ok</action-widget>"
    "    </action-widgets>"
    "  </object>"
    "</interface>";

  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, buffer, -1, &error);
  g_assert_no_error (error);

  obj = gtk_builder_get_object (builder, "button_ok");
  g_assert_true (GTK_IS_BUTTON (obj));

  g_object_unref (builder);
}

static void
test_property_bindings (void)
{
  const char *buffer =
    "<interface>"
    "  <object class=\"GtkWindow\" id=\"window\">"
    "    <child>"
    "      <object class=\"GtkBox\" id=\"vbox\">"
    "        <property name=\"visible\">True</property>"
    "        <property name=\"orientation\">vertical</property>"
    "        <child>"
    "          <object class=\"GtkCheckButton\" id=\"checkbutton\">"
    "            <property name=\"active\">false</property>"
    "          </object>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkButton\" id=\"button\">"
    "            <property name=\"sensitive\" bind-source=\"checkbutton\" bind-property=\"active\" bind-flags=\"sync-create\">false</property>"
    "          </object>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkButton\" id=\"button2\">"
    "            <property name=\"sensitive\" bind-source=\"checkbutton\" bind-property=\"active\" />"
    "          </object>"
    "        </child>"
    "        <child>"
    "          <object class=\"GtkButton\" id=\"button3\">"
    "            <property name=\"sensitive\" bind-source=\"button\" bind-flags=\"sync-create\" />"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  GtkBuilder *builder;
  GObject *checkbutton, *button, *button2, *button3, *window;

  builder = builder_new_from_string (buffer, -1, NULL);

  checkbutton = gtk_builder_get_object (builder, "checkbutton");
  g_assert_true (GTK_IS_CHECK_BUTTON (checkbutton));
  g_assert_true (!gtk_check_button_get_active (GTK_CHECK_BUTTON (checkbutton)));

  button = gtk_builder_get_object (builder, "button");
  g_assert_true (GTK_IS_BUTTON (button));
  g_assert_false (gtk_widget_get_sensitive (GTK_WIDGET (button)));

  button2 = gtk_builder_get_object (builder, "button2");
  g_assert_true (GTK_IS_BUTTON (button2));
  g_assert_true (gtk_widget_get_sensitive (GTK_WIDGET (button2)));

  button3 = gtk_builder_get_object (builder, "button3");
  g_assert_true (GTK_IS_BUTTON (button3));
  g_assert_false (gtk_widget_get_sensitive (GTK_WIDGET (button3)));

  gtk_check_button_set_active (GTK_CHECK_BUTTON (checkbutton), TRUE);
  g_assert_true (gtk_widget_get_sensitive (GTK_WIDGET (button)));
  g_assert_true (gtk_widget_get_sensitive (GTK_WIDGET (button2)));
  g_assert_true (gtk_widget_get_sensitive (GTK_WIDGET (button3)));

  window = gtk_builder_get_object (builder, "window");
  gtk_window_destroy (GTK_WINDOW (window));
  g_object_unref (builder);
}

#define MY_GTK_GRID_TEMPLATE "\
<interface>\n\
 <template class=\"MyGtkGrid\" parent=\"GtkGrid\">\n\
   <property name=\"visible\">True</property>\n\
    <child>\n\
     <object class=\"GtkLabel\" id=\"label\">\n\
       <property name=\"visible\">True</property>\n\
     </object>\n\
  </child>\n\
 </template>\n\
</interface>\n"

#define MY_TYPE_GTK_GRID             (my_gtk_grid_get_type ())
#define MY_IS_GTK_GRID(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_GTK_GRID))

typedef struct
{
  GtkGridClass parent_class;
} MyGtkGridClass;

typedef struct
{
  GtkLabel *label;
} MyGtkGridPrivate;

typedef struct
{
  GtkGrid parent_instance;
  GtkLabel *label;
  MyGtkGridPrivate *priv;
} MyGtkGrid;

G_DEFINE_TYPE_WITH_PRIVATE (MyGtkGrid, my_gtk_grid, GTK_TYPE_GRID);

static void
my_gtk_grid_init (MyGtkGrid *grid)
{
  grid->priv = my_gtk_grid_get_instance_private (grid);
  gtk_widget_init_template (GTK_WIDGET (grid));
}

static void
my_gtk_grid_class_init (MyGtkGridClass *klass)
{
  GBytes *template = g_bytes_new_static (MY_GTK_GRID_TEMPLATE, strlen (MY_GTK_GRID_TEMPLATE));
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  gtk_widget_class_set_template (widget_class, template);
  gtk_widget_class_bind_template_child (widget_class, MyGtkGrid, label);
  gtk_widget_class_bind_template_child_private (widget_class, MyGtkGrid, label);

  g_bytes_unref (template);
}

static void
test_template (void)
{
  MyGtkGrid *my_gtk_grid;

  /* make sure the type we are trying to register does not exist */
  g_assert_false (g_type_from_name ("MyGtkGrid"));

  /* create the template object */
  my_gtk_grid = g_object_new (MY_TYPE_GTK_GRID, NULL);

  /* Check everything is fine */
  g_assert_true (g_type_from_name ("MyGtkGrid"));
  g_assert_true (MY_IS_GTK_GRID (my_gtk_grid));
  g_assert_true (my_gtk_grid->label == my_gtk_grid->priv->label);
  g_assert_true (GTK_IS_LABEL (my_gtk_grid->label));
  g_assert_true (GTK_IS_LABEL (my_gtk_grid->priv->label));

  g_object_ref_sink (my_gtk_grid);
  g_object_unref (my_gtk_grid);
}

_BUILDER_TEST_EXPORT void
on_cellrenderertoggle1_toggled (GtkCellRendererToggle *cell)
{
}

static void
test_anaconda_signal (void)
{
  GtkBuilder *builder;
  const char buffer[] =
    "<?xml version='1.0' encoding='UTF-8'?>"
    "<interface>"
    "  <requires lib='gtk' version='4.0'/>"
    "  <object class='GtkListStore' id='liststore1'>"
    "    <columns>"
    "      <!-- column-name use -->"
    "      <column type='gboolean'/>"
    "    </columns>"
    "  </object>"
    "  <object class='GtkWindow' id='window1'>"
    "    <child>"
    "      <object class='GtkTreeView' id='treeview1'>"
    "        <property name='visible'>True</property>"
    "        <property name='model'>liststore1</property>"
    "        <child internal-child='selection'>"
    "          <object class='GtkTreeSelection' id='treeview-selection1'/>"
    "        </child>"
    "        <child>"
    "          <object class='GtkTreeViewColumn' id='treeviewcolumn1'>"
    "            <property name='title' translatable='yes'>column</property>"
    "            <child>"
    "              <object class='GtkCellRendererToggle' id='cellrenderertoggle1'>"
    "                <signal name='toggled' handler='on_cellrenderertoggle1_toggled' swapped='no'/>"
    "              </object>"
    "              <attributes>"
    "                <attribute name='active'>0</attribute>"
    "              </attributes>"
    "            </child>"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  builder = builder_new_from_string (buffer, -1, NULL);

  g_object_unref (builder);
}

static void
test_file_filter (void)
{
  GtkBuilder *builder;
  GObject *obj;
  GtkFileFilter *filter;

  const char buffer[] =
    "<interface>"
    "  <object class='GtkFileFilter' id='filter1'>"
    "    <property name='name'>Text and Images</property>"
    "    <mime-types>"
    "      <mime-type>text/plain</mime-type>"
    "      <mime-type>image/*</mime-type>"
    "    </mime-types>"
    "    <patterns>"
    "      <pattern>*.txt</pattern>"
    "      <pattern>*.png</pattern>"
    "    </patterns>"
    "  </object>"
    "</interface>";

  builder = builder_new_from_string (buffer, -1, NULL);
  obj = gtk_builder_get_object (builder, "filter1");
  g_assert_true (GTK_IS_FILE_FILTER (obj));
  filter = GTK_FILE_FILTER (obj);
  g_assert_cmpstr (gtk_file_filter_get_name (filter), ==, "Text and Images");
  g_assert_true (g_strv_contains (gtk_file_filter_get_attributes (filter), G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE));
  g_assert_true (g_strv_contains (gtk_file_filter_get_attributes (filter), G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME));

  g_object_unref (builder);
}

static void
test_shortcuts (void)
{
  GtkBuilder *builder;
  GObject *obj;

  const char buffer[] =
    "<interface>"
    "  <object class='GtkBox' id='box'>"
    "    <child>"
    "      <object class='GtkShortcutController' id='controller'>"
    "        <property name='scope'>managed</property>"
    "        <child>"
    "          <object class='GtkShortcut'>"
    "            <property name='trigger'><Control>k</property>"
    "            <property name='action'>activate</property>"
    "          </object>"
    "        </child>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  builder = builder_new_from_string (buffer, -1, NULL);
  obj = gtk_builder_get_object (builder, "controller");
  g_assert_true (GTK_IS_SHORTCUT_CONTROLLER (obj));
  g_object_unref (builder);
}

static void
test_transforms (void)
{
  GtkBuilder * builder;
  const char buffer1[] =
    "<interface>"
    "  <object class=\"GtkFixed\" id=\"fixed1\">"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label1\">"
    "        <layout>"
    "          <property name=\"transform\">rotateX(45.0)</property>"
    "        </layout>"
    "      </object>"
    "    </child>"
    "    <child>"
    "      <object class=\"GtkLabel\" id=\"label2\">"
    "        <layout>"
    "          <property name=\"transform\">scale3d(1,2,3)translate3d(2,3,0)</property>"
    "        </layout>"
    "      </object>"
    "    </child>"
    "  </object>"
    "</interface>";

  GObject *label, *vbox;

  builder = builder_new_from_string (buffer1, -1, NULL);
  vbox = gtk_builder_get_object (builder, "fixed1");
  g_assert_true (GTK_IS_FIXED (vbox));

  label = gtk_builder_get_object (builder, "label1");
  g_assert_true (GTK_IS_LABEL (label));

  label = gtk_builder_get_object (builder, "label2");
  g_assert_true (GTK_IS_LABEL (label));

  g_object_unref (builder);
}

G_MODULE_EXPORT char *
builder_get_search (gpointer item)
{
  return g_strdup (gtk_string_filter_get_search (item));
}

G_MODULE_EXPORT char *
builder_copy_arg (gpointer item, const char *arg)
{
  return g_strdup (arg);
}

G_MODULE_EXPORT char *
builder_get_search_if_null (gpointer item, const char *arg)
{
  return (arg == NULL) ? g_strdup (gtk_string_filter_get_search (item)) : g_strdup (arg);
}

static void
test_expressions (void)
{
  const char *tests[] = {
    "<interface>"
    "  <object class='GtkStringFilter' id='filter'>"
    "    <property name='search'>Hello World</property>"
    "    <property name='expression'><constant type='gchararray'>Hello World</constant></property>"
    "  </object>"
    "</interface>",
    "<interface>"
    "  <object class='GtkStringFilter' id='filter'>"
    "    <property name='search'>Hello World</property>"
    "    <property name='expression'><closure type='gchararray' function='builder_get_search'></closure></property>"
    "  </object>"
    "</interface>",
    "<interface>"
    "  <object class='GtkStringFilter' id='filter'>"
    "    <property name='search'>Hello World</property>"
    "    <property name='expression'><lookup type='GtkStringFilter' name='search'></lookup></property>"
    "  </object>"
    "</interface>",
    "<interface>"
    "  <object class='GtkStringFilter' id='filter'>"
    "    <property name='search'>Hello World</property>"
    "    <property name='expression'><closure type='gchararray' function='builder_copy_arg'>"
    "      <constant type='gchararray'>Hello World</constant>"
    "    </closure></property>"
    "  </object>"
    "</interface>",
    "<interface>"
    "  <object class='GtkLabel' id='label'></object>"
    "  <object class='GtkStringFilter' id='filter'>"
    "    <property name='search'>Hello World</property>"
    "    <property name='expression'>"
    "      <try>"
    "        <lookup name='title' type='GtkWindow'>"
    "          <lookup name='root' type='GtkLabel'>label</lookup>"
    "        </lookup>"
    "        <constant type='gchararray'>Hello World</constant>"
    "      </try>"
    "    </property>"
    "  </object>"
    "</interface>",
    "<interface>"
    "  <object class='GtkStringFilter' id='filter'>"
    "    <property name='search'>Hello World</property>"
    "    <property name='expression'>"
    "      <closure type='gchararray' function='builder_get_search_if_null'>"
    "        <constant type='gchararray' initial='true' />"
    "      </closure>"
    "    </property>"
    "  </object>"
    "</interface>",
  };
  GtkBuilder *builder;
  GObject *obj;
  guint i;

  for (i = 0; i < G_N_ELEMENTS (tests); i++)
    {
      builder = builder_new_from_string (tests[i], -1, NULL);
      obj = gtk_builder_get_object (builder, "filter");
      g_assert_true (GTK_IS_FILTER (obj));
      g_assert_true (gtk_filter_match (GTK_FILTER (obj), obj));

      g_object_unref (builder);
    }
}

#define MY_GTK_BOX_TEMPLATE "\
<interface>\n\
 <template class=\"MyGtkBox\" parent=\"GtkWidget\">\n\
  <child>\n\
   <object class=\"GtkLabel\" id=\"label\">\n\
    <property name=\"label\">First</property>\n\
   </object>\n\
  </child>\n\
  <child>\n\
   <object class=\"GtkLabel\" id=\"label2\">\n\
    <property name=\"label\">Second</property>\n\
   </object>\n\
  </child>\n\
 </template>\n\
</interface>\n"

#define MY_TYPE_GTK_BOX (my_gtk_box_get_type ())
G_DECLARE_FINAL_TYPE    (MyGtkBox, my_gtk_box, MY, GTK_BOX, GtkWidget)

struct _MyGtkBox
{
  GtkWidget  parent_instance;
  GtkLabel  *label;
  GtkLabel  *label2;
};

G_DEFINE_TYPE (MyGtkBox, my_gtk_box, GTK_TYPE_WIDGET);

static void
my_gtk_box_init (MyGtkBox *grid)
{
  gtk_widget_init_template (GTK_WIDGET (grid));
}

static void
my_gtk_box_dispose (GObject *obj)
{
  MyGtkBox  *my_gtk_box = MY_GTK_BOX (obj);
  GtkWidget *child;

  while ((child = gtk_widget_get_first_child (GTK_WIDGET (my_gtk_box))))
    gtk_widget_unparent (child);

  G_OBJECT_CLASS (my_gtk_box_parent_class)->dispose (obj);
}

static void
my_gtk_box_class_init (MyGtkBoxClass *klass)
{
  GBytes *template = g_bytes_new_static (MY_GTK_BOX_TEMPLATE, strlen (MY_GTK_BOX_TEMPLATE));
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  gtk_widget_class_set_template (widget_class, template);
  gtk_widget_class_bind_template_child (widget_class, MyGtkBox, label);
  gtk_widget_class_bind_template_child (widget_class, MyGtkBox, label2);

  G_OBJECT_CLASS (klass)->dispose = my_gtk_box_dispose;

  g_bytes_unref (template);
}

typedef struct
{
  MyGtkBox *my_gtk_box;
  guint     destroy_count;
} BoxDestroyData;

static void
my_label_destroy (GtkLabel *label, BoxDestroyData *data)
{
  g_assert_true (MY_IS_GTK_BOX (data->my_gtk_box));
  /* Make sure the other label is null if it was disposed first */
  g_assert_true (!data->my_gtk_box->label2 || GTK_IS_LABEL (data->my_gtk_box->label2));
  data->destroy_count++;
}

static void
my_label2_destroy (GtkLabel *label2, BoxDestroyData *data)
{
  g_assert_true (MY_IS_GTK_BOX (data->my_gtk_box));
  /* Make sure the other label is null if it was disposed first */
  g_assert_true (!data->my_gtk_box->label || GTK_IS_LABEL (data->my_gtk_box->label));
  data->destroy_count++;
}

static void
test_child_dispose_order (void)
{
  BoxDestroyData data = { 0, };

  /* make sure the type we are trying to register does not exist */
  g_assert_false (g_type_from_name ("MyGtkBox"));

  /* create the template object */
  data.my_gtk_box = g_object_ref_sink (g_object_new (MY_TYPE_GTK_BOX, NULL));

  /* Check everything is fine */
  g_assert_true (g_type_from_name ("MyGtkBox"));
  g_assert_true (MY_IS_GTK_BOX (data.my_gtk_box));
  g_assert_true (GTK_IS_LABEL (data.my_gtk_box->label));
  g_assert_true (GTK_IS_LABEL (data.my_gtk_box->label2));

  /* Check if both labels are destroyed */
  g_signal_connect (data.my_gtk_box->label, "destroy", G_CALLBACK (my_label_destroy), &data);
  g_signal_connect (data.my_gtk_box->label2, "destroy", G_CALLBACK (my_label2_destroy), &data);
  g_object_unref (data.my_gtk_box);
  g_assert_cmpuint (data.destroy_count, ==, 2);
}

#define MY_GTK_BUILDABLE_TEMPLATE "\
<interface>\n\
 <template class=\"MyGtkBuildable\" parent=\"GtkWidget\">\n\
  <custom/>\n\
  <custom>\n\
    <custom/>\n\
  </custom>\n\
 </template>\n\
</interface>\n"

#define MY_TYPE_GTK_BUILDABLE (my_gtk_buildable_get_type ())
G_DECLARE_FINAL_TYPE          (MyGtkBuildable, my_gtk_buildable, MY, GTK_BUILDABLE, GtkWidget)

struct _MyGtkBuildable
{
  GtkWidget parent_instance;
};

static void my_gtk_buildable_buildable_init (GtkBuildableIface *iface);
static GtkBuildableIface *parent_buildable_iface;

G_DEFINE_TYPE_WITH_CODE (MyGtkBuildable, my_gtk_buildable, GTK_TYPE_WIDGET,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                my_gtk_buildable_buildable_init));

static void
my_gtk_buildable_init (MyGtkBuildable *buildable)
{
  gtk_widget_init_template (GTK_WIDGET (buildable));
}

static void
my_gtk_buildable_class_init (MyGtkBuildableClass *klass)
{
  GBytes *template = g_bytes_new_static (MY_GTK_BUILDABLE_TEMPLATE, strlen (MY_GTK_BUILDABLE_TEMPLATE));
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  gtk_widget_class_set_template (widget_class, template);

  g_bytes_unref (template);
}

static const GtkBuildableParser custom_parser = {
  NULL,
  NULL,
  NULL,
  NULL
};

static gboolean
my_gtk_buildable_custom_tag_start (GtkBuildable       *buildable,
                                   GtkBuilder         *builder,
                                   GObject            *child,
                                   const char         *tagname,
                                   GtkBuildableParser *parser,
                                   gpointer           *parser_data)
{
  if (strcmp (tagname, "custom") == 0) {
    *parser = custom_parser;
    *parser_data = NULL;

    return TRUE;
  }

  return FALSE;
}

static void
my_gtk_buildable_custom_finished (GtkBuildable *buildable,
                                  GtkBuilder   *builder,
                                  GObject      *child,
                                  const char   *tagname,
                                  gpointer      user_data)
{
  if (strcmp (tagname, "custom") == 0)
    return;

  parent_buildable_iface->custom_finished (buildable, builder, child,
                                           tagname, user_data);
}

static void
my_gtk_buildable_buildable_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);

  iface->custom_tag_start = my_gtk_buildable_custom_tag_start;
  iface->custom_finished = my_gtk_buildable_custom_finished;
}

static void
test_buildable (void)
{
  MyGtkBuildable *my_gtk_buildable;

  /* make sure the type we are trying to register does not exist */
  g_assert_false (g_type_from_name ("MyGtkBuildable"));

  /* create the template object */
  my_gtk_buildable = g_object_new (MY_TYPE_GTK_BUILDABLE, NULL);

  /* Check everything is fine */
  g_assert_true (g_type_from_name ("MyGtkBuildable"));
  g_assert_true (MY_IS_GTK_BUILDABLE (my_gtk_buildable));

  g_object_ref_sink (my_gtk_buildable);
  g_object_unref (my_gtk_buildable);
}


static GFile *
builder_object_get_file_property (GtkBuilder  *builder, const gchar *object_id)
{
  GObject *obj = gtk_builder_get_object (builder, object_id);
  GFile *value = NULL;

  g_assert_nonnull (obj);

  g_object_get (obj, "file", &value, NULL);
  g_assert_nonnull (value);

  g_assert_true (g_type_is_a (G_OBJECT_TYPE (value), G_TYPE_FILE));

  return value;
}

static void
test_picture (void)
{
  GtkBuilder *builder;
  GError *error = NULL;
  GFile *file_path, *file_uri;
  gchar *contents = NULL;
  gchar *path, *uri;

  /* Load from file so builder knows where to read the files from */
  path = g_test_build_filename (G_TEST_DIST, "ui""picture.ui", NULL);
  builder = gtk_builder_new ();
  gtk_builder_add_from_file (builder, path, &error);
  if (error)
    {
      g_print ("ERROR: %s", error->message);
      g_error_free (error);
    }
  g_assert_null (error);

  file_path = builder_object_get_file_property (builder, "relative_path");
  path = g_file_get_path (file_path);
  g_assert_nonnull (path);

  /* Check path is absolute */
  g_assert_true (g_path_is_absolute (path));

  /* Check contents can be loaded */
  g_assert_true (g_file_load_contents (file_path, NULL, &contents, NULL, NULL, NULL));
  g_free (contents);

  file_uri = builder_object_get_file_property (builder, "relative_uri");
  uri = g_file_get_uri (file_uri);
  g_assert_nonnull (uri);

  /* Check uri is absolute */
  g_assert_true (g_str_has_prefix (uri, "file://"));
  g_assert_true (g_path_is_absolute (uri + strlen("file://")));

  g_assert_true (g_file_load_contents (file_uri, NULL, &contents, NULL, NULL, NULL));
  g_free (contents);

  g_object_unref (builder);
  g_free (path);
  g_free (uri);
}

int
main (int argc, char **argv)
{
  /* initialize test program */
  gtk_test_init (&argc, &argv);

  g_test_add_func ("/Builder/Parser", test_parser);
  g_test_add_func ("/Builder/Types", test_types);
  g_test_add_func ("/Builder/Construct-Only Properties", test_construct_only_property);
  g_test_add_func ("/Builder/Children", test_children);
  g_test_add_func ("/Builder/Layout Properties", test_layout_properties);
  g_test_add_func ("/Builder/Object Properties", test_object_properties);
  g_test_add_func ("/Builder/Notebook", test_notebook);
  g_test_add_func ("/Builder/Domain", test_domain);
  g_test_add_func ("/Builder/Signal Autoconnect", test_connect_signals);
  g_test_add_func ("/Builder/Spin Button", test_spin_button);
  g_test_add_func ("/Builder/SizeGroup", test_sizegroup);
  g_test_add_func ("/Builder/ListStore", test_list_store);
  g_test_add_func ("/Builder/TreeStore", test_tree_store);
  g_test_add_func ("/Builder/TreeView Column", test_treeview_column);
  g_test_add_func ("/Builder/IconView", test_icon_view);
  g_test_add_func ("/Builder/ComboBox", test_combo_box);
#if 0
  g_test_add_func ("/Builder/ComboBox Entry", test_combo_box_entry);
#endif
  g_test_add_func ("/Builder/CellView", test_cell_view);
  g_test_add_func ("/Builder/Dialog", test_dialog);
  g_test_add_func ("/Builder/Widget", test_widget);
  g_test_add_func ("/Builder/Value From String", test_value_from_string);
  g_test_add_func ("/Builder/Reference Counting", test_reference_counting);
  g_test_add_func ("/Builder/Window", test_window);
  g_test_add_func ("/Builder/PangoAttributes", test_pango_attributes);
  g_test_add_func ("/Builder/Requires", test_requires);
  g_test_add_func ("/Builder/AddObjects", test_add_objects);
  g_test_add_func ("/Builder/MessageArea", test_message_area);
  g_test_add_func ("/Builder/MessageDialog", test_message_dialog);
  g_test_add_func ("/Builder/GMenu", test_gmenu);
  g_test_add_func ("/Builder/LevelBar", test_level_bar);
  g_test_add_func ("/Builder/Expose Object", test_expose_object);
  g_test_add_func ("/Builder/Template", test_template);
  g_test_add_func ("/Builder/No IDs", test_no_ids);
  g_test_add_func ("/Builder/Property Bindings", test_property_bindings);
  g_test_add_func ("/Builder/anaconda-signal", test_anaconda_signal);
  g_test_add_func ("/Builder/FileFilter", test_file_filter);
  g_test_add_func ("/Builder/Shortcuts", test_shortcuts);
  g_test_add_func ("/Builder/Transforms", test_transforms);
  g_test_add_func ("/Builder/Expressions", test_expressions);
  g_test_add_func ("/Builder/Child Dispose Order", test_child_dispose_order);
  g_test_add_func ("/Builder/Buildable", test_buildable);
  g_test_add_func ("/Builder/Picture", test_picture);

  return g_test_run();
}


Messung V0.5 in Prozent
C=99 H=90 G=94

¤ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik