Add --xpath-assertions option to g-ir-scanner
authorColin Walters <walters@src.gnome.org>
Fri, 12 Sep 2008 22:44:29 +0000 (22:44 +0000)
committerColin Walters <walters@src.gnome.org>
Fri, 12 Sep 2008 22:44:29 +0000 (22:44 +0000)
* giscanner/minixpath.py: Code to run an "XPath"
assertion against an XML tree, taken from
gir-repository/gir/tests.py.
* giscanner/Makefile.am: Ship it.
* tools/g-ir-scanner: Add --xpath-assertions option.
* gir/GLib-assertions.txt: Add a few assertions.
* gir/Makefile.am: Run them.

svn path=/trunk/; revision=592

gir/GLib-assertions.txt [new file with mode: 0644]
gir/Makefile.am
giscanner/Makefile.am
giscanner/minixpath.py [new file with mode: 0644]
tools/g-ir-scanner

diff --git a/gir/GLib-assertions.txt b/gir/GLib-assertions.txt
new file mode 100644 (file)
index 0000000..0d26271
--- /dev/null
@@ -0,0 +1,3 @@
+/namespace/alias[@name='Quark']
+/namespace/record[@name='PtrArray']
+/namespace/callback[@name='ThreadFunc']/return-value/type[@name='any']
index 52861f7..a31cdff 100644 (file)
@@ -28,6 +28,8 @@ GLib.gir: $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) Makefile
            -D__G_I18N_LIB_H__ \
            $(GLIB_LIBDIR)/glib-2.0/include/glibconfig.h \
            $(GLIB_INCLUDEDIR)/glib/*.h
+       PYTHONPATH=$(top_builddir):$$PYTHONPATH $(G_IR_SCANNER) \
+           --xpath-assertions=GLib-assertions.txt GLib.gir     
 BUILT_SOURCES += GLib.gir
 
 # gobject
index 5356c88..e824b34 100644 (file)
@@ -42,6 +42,7 @@ pkgpyexec_PYTHON =            \
        girwriter.py            \
        glibast.py              \
        glibtransformer.py      \
+       minixpath.py            \
        odict.py                \
        sourcescanner.py        \
        transformer.py          \
diff --git a/giscanner/minixpath.py b/giscanner/minixpath.py
new file mode 100644 (file)
index 0000000..a14afa9
--- /dev/null
@@ -0,0 +1,81 @@
+# -*- Mode: Python -*-
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2008 Colin Walters
+#
+# 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.
+#
+
+from .girparser import C_NS, GLIB_NS
+from .girparser import _corens
+
+_nsmap = {'c': C_NS,
+          'glib': GLIB_NS}
+
+
+def myxpath(node, expr):
+    """I Can't Believe It's Not XPath!"""
+    elts = expr.split('/')
+    curnode = node
+    for elt in elts:
+        if elt == '':
+            continue
+        try:
+            (elt, qual) = elt.split('[', 1)
+            qual = qual[1:-1]
+            pairs = [x.split('=', 1) for x in qual.split(',')]
+            exp_attrs = [(x[0], x[1][1:-1]) for x in pairs]
+        except ValueError, e:
+            (elt, exp_attrs) = (elt, [])
+        try:
+            (ns, elt) = elt.split(':', 1)
+            ns = _nsmap[ns]
+            elt = '{%s}%s' % (ns, elt)
+        except ValueError, e:
+            elt = _corens(elt)
+        curnodes = curnode.findall(elt)
+        if not curnodes:
+            return None
+        found = True
+        for node in curnodes:
+            passes = True
+            for (name, val) in exp_attrs:
+                a = node.attrib.get(name)
+                if not a or a != val:
+                    passes = False
+                    break
+            if passes:
+                found = True
+                #print 'ATTR PASS: %r' % (node, )
+                curnode = node
+                break
+            found = False
+        if not found:
+            return None
+    return curnode
+
+
+def xpath_assert(node, path, attribs=[]):
+    elt = myxpath(node, path)
+    if elt is None:
+        raise AssertionError("Failed to find %r" % (path, ))
+    for (name, expvalue) in attribs:
+        value = elt.attrib.get(name)
+        if not value:
+            raise AssertionError("Failed to find attibute %r" +
+                                 "in node %r" % (name, elt, ))
+        if value != expvalue:
+            raise AssertionError("Attibute %r in node %r has " +
+                                 "unexpected value %r" % (name, elt, expvalue))
index 3371b07..7d059fc 100755 (executable)
@@ -38,6 +38,7 @@ sys.path.insert(0, path)
 from giscanner.glibtransformer import GLibTransformer
 from giscanner.sourcescanner import SourceScanner
 from giscanner.transformer import Transformer
+from giscanner.minixpath import xpath_assert
 
 
 def _get_option_parser():
@@ -76,7 +77,9 @@ def _get_option_parser():
     parser.add_option("", "--typelib-xml",
                       action="store_true", dest="typelib_xml",
                       help="Just convert GIR to typelib XML")
-
+    parser.add_option("", "--xpath-assertions",
+                      action="store", dest="xpath_assertions",
+                      help="Use given file to create assertions on GIR content")
 
     group = optparse.OptionGroup(parser, "Preprocessor options")
     group.add_option("-I", help="Pre-processor include file",
@@ -110,6 +113,21 @@ def typelib_xml_strip(path):
     doc.write(sys.stdout)
     return 0
 
+def validate(assertions, path):
+    from xml.etree.cElementTree import parse
+    doc = parse(open(path))
+    root = doc.getroot()
+    f = open(assertions)
+    assertions_list = f.readlines()
+    print "=== CHECKING %s (%d assertions) ===" % (assertions, 
+                                                   len(assertions_list))
+    for assertion in assertions_list:
+        assertion = assertion.strip()
+        xpath_assert(root, assertion)
+    f.close()
+    print "=== PASSED %s ===" % (assertions, )
+    return 0
+
 def main(args):
     parser = _get_option_parser()
     (options, args) = parser.parse_args(args)
@@ -120,6 +138,9 @@ def main(args):
     if options.typelib_xml:
         return typelib_xml_strip(args[1])
 
+    if options.xpath_assertions:
+        return validate(options.xpath_assertions, args[1])
+
     if not options.namespace_name:
         _error('Namespace name missing')