diff --git a/gtk/tests/Makefile.am b/gtk/tests/Makefile.am
index f36d5e5..8d49e75 100644
--- a/gtk/tests/Makefile.am
+++ b/gtk/tests/Makefile.am
@@ -77,3 +77,7 @@ defaultvalue_LDADD 		 = $(progs_ldadd)
 TEST_PROGS			+= textbuffer
 textbuffer_SOURCES		 = textbuffer.c pixbuf-init.c
 textbuffer_LDADD		 = $(progs_ldadd)
+
+TEST_PROGS			+= is-c-identifier
+is_c_identifier_SOURCES		 = is-c-identifier.c
+is_c_identifier_LDADD		 = $(progs_ldadd)
diff --git a/gtk/tests/is-c-identifier.c b/gtk/tests/is-c-identifier.c
new file mode 100644
index 0000000..6cb403c
--- /dev/null
+++ b/gtk/tests/is-c-identifier.c
@@ -0,0 +1,202 @@
+/* is_c_identifier.c - test recognition of C identifiers
+ * Copyright (C) 2008 Christian Dywan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ */
+
+#include <string.h>
+#include <gtk/gtk.h>
+
+static gboolean
+is_c_identifier_old (const gchar *string)
+{
+  const gchar *p;
+  gboolean is_varname;
+
+  is_varname = strchr ("_" G_CSET_a_2_z G_CSET_A_2_Z, string[0]) != NULL;
+  for (p = string + 1; *p && is_varname; p++)
+    is_varname &= strchr (G_CSET_DIGITS "-_" G_CSET_a_2_z G_CSET_A_2_Z, *p) != NULL;
+
+  return is_varname;
+
+}
+
+static gboolean
+is_c_identifier_new (const gchar *string)
+{
+  if ((string[0] >= 'a' && string[0] <= 'z') ||
+      (string[0] >= 'A' && string[0] <= 'Z') ||
+       string[0] == '_')
+    {
+      const gchar *p;
+
+      for (p = string + 1; *p ; p++)
+        if (! ((*p >= 'a' && *p <= 'z') ||
+               (*p >= 'A' && *p <= 'Z') ||
+               (*p >= '0' && *p <= '9') ||
+                *p == '-' || *p == '_'))
+          return FALSE;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+is_c_identifier_likely (const gchar *string)
+{
+  if (G_LIKELY ((string[0] >= 'a' && string[0] <= 'z') ||
+      (string[0] >= 'A' && string[0] <= 'Z') ||
+       string[0] == '_'))
+    {
+      const gchar *p;
+
+      for (p = string + 1; *p ; p++)
+        if (G_UNLIKELY (! ((*p >= 'a' && *p <= 'z') ||
+               (*p >= 'A' && *p <= 'Z') ||
+               (*p >= '0' && *p <= '9') ||
+                *p == '-' || *p == '_')))
+          return FALSE;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+#define BEGIN \
+gint i; \
+g_test_timer_start (); \
+for (i = 0; i < 1000000; i++) { \
+
+#define END \
+} g_print ("\ttime: %f\t", g_test_timer_elapsed ());
+
+typedef gboolean (*is_c_identifier_func) (gchar const* identifier);
+
+static void
+all_true (is_c_identifier_func is_c_identifier)
+{
+  BEGIN
+
+  g_assert (is_c_identifier ("Gtk"));
+  g_assert (is_c_identifier ("GtkBin"));
+  g_assert (is_c_identifier ("GtkButton"));
+  g_assert (is_c_identifier ("GtkButtonBox"));
+  g_assert (is_c_identifier ("shadow"));
+  g_assert (is_c_identifier ("default-border"));
+  g_assert (is_c_identifier ("child-displacement-x"));
+  g_assert (is_c_identifier ("TRUE"));
+  g_assert (is_c_identifier ("colorize_scrollbar"));
+  g_assert (is_c_identifier ("reliefstyle"));
+  g_assert (is_c_identifier ("GUMMY"));
+
+  END
+}
+
+static void
+early_false (is_c_identifier_func is_c_identifier)
+{
+  BEGIN
+
+  g_assert (is_c_identifier ("Gtk"));
+  g_assert (is_c_identifier ("GtkBin"));
+  g_assert (is_c_identifier ("GtkButton"));
+  g_assert (!is_c_identifier ("4GtkButton"));
+
+  END
+}
+
+static void
+late_false (is_c_identifier_func is_c_identifier)
+{
+  BEGIN
+
+  g_assert (is_c_identifier ("Gtk"));
+  g_assert (is_c_identifier ("GtkBin"));
+  g_assert (is_c_identifier ("GtkButton"));
+  g_assert (is_c_identifier ("GtkButtonBox"));
+  g_assert (is_c_identifier ("shadow"));
+  g_assert (is_c_identifier ("default-border"));
+  g_assert (is_c_identifier ("child-displacement-x"));
+  g_assert (is_c_identifier ("TRUE"));
+  g_assert (is_c_identifier ("colorize_scrollbar"));
+  g_assert (is_c_identifier ("reliefstyle"));
+  g_assert (is_c_identifier ("GUMMY"));
+  g_assert (!is_c_identifier ("child-;displacement-x"));
+
+  END
+}
+
+static void
+all_false (is_c_identifier_func is_c_identifier)
+{
+  BEGIN
+
+  g_assert (!is_c_identifier ("1"));
+  g_assert (!is_c_identifier ("{ 0, 0, 0, 0 }"));
+  g_assert (!is_c_identifier ("::indicator-size"));
+  g_assert (!is_c_identifier ("fg[NORMAL]"));
+  g_assert (!is_c_identifier ("@fg_color"));
+  g_assert (!is_c_identifier ("shade (@bg_color)"));
+  g_assert (!is_c_identifier ("shade (1.02, @bg_color)"));
+  g_assert (!is_c_identifier ("\"use-hints\""));
+  g_assert (!is_c_identifier ("0.0"));
+  g_assert (!is_c_identifier ("*<GtkListItem>*"));
+
+  END
+}
+
+static void
+_test_add_data_func (const gchar          *path,
+                     is_c_identifier_func  func,
+                     gpointer              test_func)
+{
+    g_test_add_data_func (path, (gconstpointer)func, (gconstpointer)all_true);
+}
+
+static void
+add_test (const gchar          *base,
+          is_c_identifier_func  func)
+{
+  gchar* path;
+
+  path = g_strdup_printf ("%s/%s", base, "all_true ");
+  _test_add_data_func (path, func, all_true);
+  g_free (path);
+
+  path = g_strdup_printf ("%s/%s", base, "early_false");
+  _test_add_data_func (path, func, early_false);
+  g_free (path);
+
+  path = g_strdup_printf ("%s/%s", base, "late_false");
+  _test_add_data_func (path, func, late_false);
+  g_free (path);
+
+  path = g_strdup_printf ("%s/%s", base, "all_false");
+  _test_add_data_func (path, func, all_false);
+  g_free (path);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  gtk_test_init (&argc, &argv, NULL);
+
+  if (g_test_perf ())
+    {
+
+      add_test ("/is-c-identifier/old", is_c_identifier_old);
+
+      add_test ("/is-c-identifier/new", is_c_identifier_new);
+
+      add_test ("/is-c-identifier/likely", is_c_identifier_likely);
+    }
+
+  return g_test_run ();
+}
