gobject-introspection r878 - in trunk: . tests tests/offsets



Author: otaylor
Date: Tue Nov 11 05:10:56 2008
New Revision: 878
URL: http://svn.gnome.org/viewvc/gobject-introspection?rev=878&view=rev

Log:
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.

Added:
   trunk/tests/offsets/
   trunk/tests/offsets/Makefile.am
   trunk/tests/offsets/gen-gitestoffsets   (contents, props changed)
   trunk/tests/offsets/offsets.c
   trunk/tests/offsets/offsets.h
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/tests/Makefile.am

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Tue Nov 11 05:10:56 2008
@@ -194,6 +194,7 @@
 tools/Makefile
 tests/Makefile
 tests/invoke/Makefile
+tests/offsets/Makefile
 tests/scanner/Makefile
 tests/repository/Makefile
 tests/everything/Makefile

Modified: trunk/tests/Makefile.am
==============================================================================
--- trunk/tests/Makefile.am	(original)
+++ trunk/tests/Makefile.am	Tue Nov 11 05:10:56 2008
@@ -1,4 +1,4 @@
-SUBDIRS = . scanner everything repository invoke
+SUBDIRS = . scanner everything repository invoke offsets
 
 EXTRA_DIST = \
 	array.gir	\

Added: trunk/tests/offsets/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/tests/offsets/Makefile.am	Tue Nov 11 05:10:56 2008
@@ -0,0 +1,62 @@
+BUILT_SOURCES =
+CLEANFILES =
+EXTRA_DIST =
+
+check_LTLIBRARIES =
+check_PROGRAMS =
+
+SCANNER = $(top_srcdir)/tools/g-ir-scanner
+SCANNER_PYTHONPATH = $(top_builddir):$(top_srcdir):$$PYTHONPATH
+SCANNER_LIBS = \
+	$(top_srcdir)/giscanner/*.py \
+	$(top_builddir)/giscanner/libgiscanner.la
+
+############################################################
+
+check_LTLIBRARIES += liboffsets.la
+
+liboffsets_la_SOURCES = \
+	offsets.h	\
+	offsets.c
+liboffsets_la_CPPFLAGS = $(GIREPO_CFLAGS)
+# dummy rpath to get built dynamically (huh?)
+liboffsets_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
+
+offsets-1.0.gir: liboffsets.la offsets.h $(SCANNER) $(SCANNER_LIBS) Makefile
+	PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \
+	--add-include-path=$(top_builddir)/gir --add-include-path=. \
+	--library=offsets \
+	--namespace=offsets \
+	--nsversion=1.0 \
+	--pkg gobject-2.0 \
+	$(srcdir)/offsets.h $(srcdir)/offsets.c \
+	 --output $@
+
+%.typelib: %.gir $(top_builddir)/tools/g-ir-compiler$(EXEEXT) Makefile
+	$(top_builddir)/tools/g-ir-compiler --includedir=. --includedir=$(top_builddir)/gir $< -o $@
+
+CLEANFILES += offsets-1.0.gir offsets-1.0.typelib
+
+############################################################
+
+check_PROGRAMS += gitestoffsets
+
+nodist_gitestoffsets_SOURCES = gitestoffsets.c
+gitestoffsets_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+gitestoffsets_LDADD = $(top_builddir)/girepository/libgirepository.la $(GIREPO_LIBS)
+
+gitestoffsets.c: gen-gitestoffsets offsets.h
+	$(PYTHON) $(srcdir)/gen-gitestoffsets offsets.h > $@ || ( rm -f $@ && false )
+
+EXTRA_DIST += gen-gitestoffsets
+BUILT_SOURCES += gitestoffsets.c
+CLEANFILES += gitestoffsets.c
+
+############################################################
+
+check-local: offsets-1.0.typelib
+	LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}$(builddir) GI_TYPELIB_PATH=$(builddir) \
+	  $(builddir)/gitestoffsets$(EXEEXT) offsets.compiled offsets.introspected
+	diff -u offsets.compiled offsets.introspected
+
+CLEANFILES += offsets.compiled offsets.introspected

Added: trunk/tests/offsets/gen-gitestoffsets
==============================================================================
--- (empty file)
+++ trunk/tests/offsets/gen-gitestoffsets	Tue Nov 11 05:10:56 2008
@@ -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;
+}
+''')

Added: trunk/tests/offsets/offsets.c
==============================================================================
--- (empty file)
+++ trunk/tests/offsets/offsets.c	Tue Nov 11 05:10:56 2008
@@ -0,0 +1,7 @@
+#include <offsets.h>
+
+void offsets_dummy(void);
+
+/* To avoid an empty compilation unit */
+void offsets_dummy(void) {
+}

Added: trunk/tests/offsets/offsets.h
==============================================================================
--- (empty file)
+++ trunk/tests/offsets/offsets.h	Tue Nov 11 05:10:56 2008
@@ -0,0 +1,107 @@
+#ifndef __OFFSETS_H__
+#define __OFFSETS_H__
+
+#include <glib.h>
+#include <time.h>
+
+/* Test we get the alignment right for various basic types; we put
+ * a char in front of of each field to make it more likely that we'll
+ * stress out the alignment code.
+ */
+typedef struct _OffsetsBasic OffsetsBasic;
+
+struct _OffsetsBasic {
+  char dummy1;
+  gint8 field_int8;
+  char dummy2;
+  gint16 field_int16;
+  char dummy3;
+  gint32 field_int32;
+  char dummy4;
+  gint64 field_int64;
+  char dummy5;
+  gchar *field_pointer;
+  char dummy6;
+  gfloat field_float;
+  char dummy7;
+  gdouble field_double;
+  char dummy8;
+  gsize field_size;
+  char dummy9;
+  time_t field_time;
+};
+
+typedef enum {
+  ENUM_1 = 1 /* compiler could use int8, uint8, int16, uint16, int32, uint32 */
+} Enum1;
+
+typedef enum {
+  ENUM_2 = 128 /* compiler could use uint8, int16, uint16, int32, uint32 */
+} Enum2;
+
+typedef enum {
+  ENUM_3 = 257 /* compiler could use int16, uint16, int32, uint32 */
+} Enum3;
+
+typedef enum {
+  ENUM_4 = G_MAXSHORT + 1 /* compiler could use uint16, int32, uint32 */
+} Enum4;
+
+typedef enum {
+  ENUM_5 = G_MAXUSHORT + 1 /* compiler could use int32, uint32 */
+} Enum5;
+
+typedef enum {
+  ENUM_6 = ((guint)G_MAXINT) + 1 /* compiler could use uint32 */
+} Enum6;
+
+/* Test that we get the width of enum fields right. The char after
+ * each field will have aligment 1 (almost certainly) so should
+ * be placed right the field.
+ */
+typedef struct _OffsetsEnum OffsetsEnum;
+
+struct _OffsetsEnum {
+  Enum1 enum1;
+  char dummy1;
+  Enum2 enum2;
+  char dummy2;
+  Enum3 enum3;
+  char dummy3;
+  Enum4 enum4;
+  char dummy4;
+  Enum5 enum5;
+  char dummy5;
+  Enum6 enum6;
+  char dummy6;
+};
+
+/* Test nested structures
+ */
+
+typedef struct _OffsetsNestee OffsetsNestee;
+
+struct _OffsetsNestee {
+  char field1;
+  double field2; /* alignment of structure is greater than its first element */
+  char field3; /* structure has tail padding */
+};
+
+typedef union _OffsetsNesteeUnion OffsetsNesteeUnion;
+
+union _OffsetsNesteeUnion {
+  char field1;
+  double field2;
+};
+
+typedef struct _OffsetsNested OffsetsNested;
+
+struct _OffsetsNested {
+  char dummy1;
+  OffsetsNestee nestee;
+  char dummy2;
+  OffsetsNesteeUnion nestee_union;
+  char dummy3;
+};
+
+#endif /* __OFFSETS_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]