summaryrefslogtreecommitdiff
path: root/tests/offsets/gen-gitestoffsets
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@src.gnome.org>2008-11-11 05:10:56 +0000
committerOwen Taylor <otaylor@src.gnome.org>2008-11-11 05:10:56 +0000
commit98d1d8b9e0fcbfe798eff20ccce44df5af18854b (patch)
treee37ff6f833b84357303599b2452de7bbf6bee000 /tests/offsets/gen-gitestoffsets
parent0dccc4596aad89333f7d23b2f95a19067df79724 (diff)
downloadgobject-introspection-98d1d8b9e0fcbfe798eff20ccce44df5af18854b.tar.gz
Add tests for field offset computations
tests/offsets/offsets.h: Header file with structure definitions to test tests/offsets/gen-gitestoffsets: Generate a C program that computes field offsets for the structures in offsets.h two ways: using the information from a generated typelib, and as computed by the compiler. We diff these two versions to test that everything is OK. svn path=/trunk/; revision=878
Diffstat (limited to 'tests/offsets/gen-gitestoffsets')
-rwxr-xr-xtests/offsets/gen-gitestoffsets242
1 files changed, 242 insertions, 0 deletions
diff --git a/tests/offsets/gen-gitestoffsets b/tests/offsets/gen-gitestoffsets
new file mode 100755
index 00000000..27fff23b
--- /dev/null
+++ b/tests/offsets/gen-gitestoffsets
@@ -0,0 +1,242 @@
+#!/bin/env python
+# -*- Mode: Python -*-
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2008 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+# The idea here is that we want to compare offset information two ways:
+#
+# 1) As generated by the compiler
+# 2) As found in the typelib
+#
+# So we find all the structures in the input file (offsets.h), parse out
+# fields within the structure and generate code that outputs the field
+# offsets using G_STRUCT_OFFSET() to one file and the field offsets using
+# the typelib to the another file. We can then diff the two files to see
+# if they are the same
+
+import re
+import sys
+
+if len(sys.argv) != 2:
+ print >>sys.stderr, "Usage: gen-gitestoffsets INPUT > OUTPUT"
+ sys.exit(1)
+
+# Helper function that we use to generate source. It does substitions
+# from a dictionary, removes white space at the ends and removes a
+# leading '|' from each line
+STRIP_AROUND_RE = re.compile("^[ \t]*\n?(.*?)[ \t]*$", re.DOTALL)
+STRIP_LEADER_RE = re.compile("^\|", re.MULTILINE)
+def output(args, format):
+ format = STRIP_AROUND_RE.sub(r"\1", format)
+ format = STRIP_LEADER_RE.sub(r"", format)
+ sys.stdout.write(format % args)
+
+#
+# Some regular expressions we use when parsing
+#
+TOKEN = "(?:[A-Za-z_][A-Za-z_0-9]+)"
+
+def compile_re(expr):
+ expr = expr.replace("TOKEN", TOKEN)
+ return re.compile(expr, re.VERBOSE)
+
+COMMENT_RE = compile_re("/\*([^*]+|\*[^/])*\*/")
+STRUCT_DEF_RE = compile_re("struct\s+_(TOKEN)\s*{([^}]*)}")
+
+# This certainly can't handle all type declarations, but it only
+# needs to handle the ones we use in the test cases
+FIELD_RE = compile_re("^(?:const\s+)?TOKEN(?:[\s*]+)(TOKEN)\s*;$");
+
+
+input_f = open(sys.argv[1])
+input = input_f.read()
+input_f.close()
+
+# Strip comments
+input = COMMENT_RE.sub("", input)
+
+symbols = []
+symbol_fields = {}
+
+for m in STRUCT_DEF_RE.finditer(input):
+ symbol = m.group(1)
+
+ fields = []
+
+ body = m.group(2)
+ for line in re.split("\n|\r\n", body):
+ line = line.strip()
+ if line == "":
+ continue
+ n = FIELD_RE.match(line)
+ if not n:
+ print sys.stderr, "Can't parse structure line '%s'" % line
+ sys.exit(1)
+ fields.append(n.group(1))
+
+ symbols.append(symbol)
+ symbol_fields[symbol] = fields
+
+# Sort for convenience
+symbols.sort()
+
+output({}, r'''
+| /* GENERATED FILE. DO NOT EDIT. See gen-gitestoffsets */
+|
+|#include <errno.h>
+|#include <stdio.h>
+|#include <string.h>
+|#include <glib.h>
+|#include <girepository.h>
+|#include "offsets.h"
+|
+|static GIRepository *repository;
+|static const char *namespace = "offsets";
+|static const char *version = "1.0";
+|
+|static void
+|print_field_offset(FILE *outfile,
+| GIStructInfo *struct_info,
+| const gchar *name)
+|{
+| gint i;
+| gint n_fields = g_struct_info_get_n_fields (struct_info);
+| for (i = 0; i < n_fields; i++)
+| {
+| GIFieldInfo *field_info = g_struct_info_get_field (struct_info, i);
+| const char *field_name = g_base_info_get_name ((GIBaseInfo *)field_info);
+| if (strcmp (field_name, name) == 0)
+| {
+| fprintf (outfile, "%%s %%d\n", name, g_field_info_get_offset (field_info));
+| g_base_info_unref ((GIBaseInfo *)field_info);
+| return;
+| }
+|
+| g_base_info_unref ((GIBaseInfo *)field_info);
+| }
+|
+| g_error("Can't find field '%%s.%%s' in introspection information",
+| g_base_info_get_name ((GIBaseInfo *)struct_info), name);
+|}
+|
+''')
+
+for symbol in symbols:
+ fields = symbol_fields[symbol]
+
+ output({'symbol' : symbol}, r'''
+|static void
+|compiled_%(symbol)s (FILE *outfile)
+|{
+| fprintf (outfile, "%(symbol)s:\n");
+|
+ ''')
+
+ for field in fields:
+ output({ 'field' : field, 'symbol' : symbol }, r'''
+| fprintf (outfile, "%%s %%ld\n", "%(field)s", G_STRUCT_OFFSET(%(symbol)s, %(field)s));
+ ''')
+
+ output({}, r'''
+|
+| fprintf (outfile, "\n");
+|}
+|
+ ''')
+
+ if not symbol.startswith("Offsets"):
+ print >> sys.stderr, "Symbol '%s' doesn't start with Offsets" % symbol
+ bare_symbol = symbol[len("Offsets"):]
+
+
+ output({'symbol' : symbol, 'bare_symbol' : bare_symbol}, r'''
+|static void
+|introspected_%(symbol)s (FILE *outfile)
+|{
+| GIStructInfo *struct_info = (GIStructInfo *)g_irepository_find_by_name(repository, namespace,
+| "%(bare_symbol)s");
+| if (!struct_info)
+| g_error ("Can't find GIStructInfo for '%(symbol)s'");
+|
+| fprintf (outfile, "%(symbol)s:\n");
+|
+ ''')
+ for field in fields:
+ output({'field' : field}, '''
+| print_field_offset(outfile, struct_info, "%(field)s");
+ ''')
+
+ output({}, r'''
+|
+| fprintf (outfile, "\n");
+|
+| g_base_info_unref ((GIBaseInfo *)struct_info);
+|}
+ ''')
+
+output({}, r'''
+|
+|int main(int argc, char **argv)
+|{
+| GError *error = NULL;
+| FILE *outfile;
+|
+| if (argc != 3)
+| g_error ("Usage: gitestoffsets COMPILED_OFFSETS_FILE INTROSPECTED_OFFSETS_FILE");
+|
+| g_type_init ();
+|
+| repository = g_irepository_get_default ();
+| if (!g_irepository_require (repository, namespace, version, 0, &error))
+| g_error ("Failed to load %%s-%%s.typelib: %%s", namespace, version, error->message);
+|
+| outfile = fopen (argv[1], "w");
+| if (!outfile)
+| g_error ("Cannot open '%%s': %%s'", argv[1], g_strerror(errno));
+|
+''')
+
+for symbol in symbols:
+ output({'symbol' : symbol}, '''
+| compiled_%(symbol)s (outfile);
+ ''')
+
+output({}, '''
+|
+| fclose (outfile);
+|
+| outfile = fopen (argv[2], "w");
+| if (!outfile)
+| g_error ("Cannot open '%%s': %%s'", argv[1], g_strerror(errno));
+|
+''')
+
+
+for symbol in symbols:
+ output({'symbol' : symbol}, '''
+| introspected_%(symbol)s (outfile);
+''')
+
+output({}, r'''
+|
+| fclose (outfile);
+|
+| return 0;
+}
+''')