[gnome-code-assistance] Added start of basic tests



commit c253993b68d7840e54aef5ff787881f7cbc17c02
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Thu Nov 14 14:49:43 2013 +0100

    Added start of basic tests

 Makefile.am                |    2 +
 configure.ac               |    8 +-
 tests/Makefile.am          |    1 +
 tests/backends/c.json      |    5 +
 tests/backends/css.json    |    5 +
 tests/backends/go.json     |    5 +
 tests/backends/js.json     |    5 +
 tests/backends/python.json |    5 +
 tests/backends/ruby.json   |   27 +++++
 tests/backends/ruby.rb     |    5 +
 tests/backends/sh.json     |    5 +
 tests/backends/vala.json   |    5 +
 tests/backends/xml.json    |    5 +
 tests/config.py.in         |    1 +
 tests/dbus.conf.in         |   21 ++++
 tests/interfaces.json      |   21 ++++
 tests/service              |  255 ++++++++++++++++++++++++++++++++++++++++++++
 17 files changed, 379 insertions(+), 2 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 5da0e02..834cb6f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -29,9 +29,11 @@ GITIGNOREDEPS =
 BUILT_SOURCES =
 DISTCLEANFILES =
 gsettings_SCHEMAS =
+TESTS =
 
 include data/Makefile.am
 include backends/Makefile.am
+include tests/Makefile.am
 
 @GSETTINGS_RULES@
 
diff --git a/configure.ac b/configure.ac
index a27e197..4642503 100644
--- a/configure.ac
+++ b/configure.ac
@@ -467,8 +467,10 @@ backendexecdir_unex="$libexecdir/gnome-code-assistance"
 adl_RECURSIVE_EVAL("$backendexecdir_unex", [backendexecdir])
 AC_SUBST(backendexecdir)
 
-GCA_BACKENDS_EXEC_DIR="$libexecdir/gnome-code-assistance"
-AC_SUBST(GCA_BACKENDS_EXEC_DIR)
+adl_RECURSIVE_EVAL("$datadir", [datadirex])
+AC_SUBST(datadirex)
+
+GCA_BACKENDS_EXEC_DIR="$backendexecdir_unex"
 
 GCA_BACKENDS_DIR="$GCA_BACKENDS_EXEC_DIR/backends"
 AC_SUBST(GCA_BACKENDS_DIR)
@@ -546,6 +548,8 @@ backends/sh/sh
 backends/css/org.gnome.CodeAssist.v1.css.service
 backends/css/css
 data/org.gnome.codeassistance.gschema.xml
+tests/config.py
+tests/dbus.conf
 ])
 
 AC_OUTPUT
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..f51f67c
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1 @@
+TESTS += tests/service
diff --git a/tests/backends/c.json b/tests/backends/c.json
new file mode 100644
index 0000000..b36bc4d
--- /dev/null
+++ b/tests/backends/c.json
@@ -0,0 +1,5 @@
+{
+  "language": "python",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/css.json b/tests/backends/css.json
new file mode 100644
index 0000000..7325616
--- /dev/null
+++ b/tests/backends/css.json
@@ -0,0 +1,5 @@
+{
+  "language": "css",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/go.json b/tests/backends/go.json
new file mode 100644
index 0000000..50ddb83
--- /dev/null
+++ b/tests/backends/go.json
@@ -0,0 +1,5 @@
+{
+  "language": "go",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/js.json b/tests/backends/js.json
new file mode 100644
index 0000000..0103ab0
--- /dev/null
+++ b/tests/backends/js.json
@@ -0,0 +1,5 @@
+{
+  "language": "js",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/python.json b/tests/backends/python.json
new file mode 100644
index 0000000..b36bc4d
--- /dev/null
+++ b/tests/backends/python.json
@@ -0,0 +1,5 @@
+{
+  "language": "python",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/ruby.json b/tests/backends/ruby.json
new file mode 100644
index 0000000..c021d03
--- /dev/null
+++ b/tests/backends/ruby.json
@@ -0,0 +1,27 @@
+{
+  "language": "ruby",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"],
+  "diagnostics": [
+    {
+      "parse": {
+        "path": "ruby_fail.rb"
+      },
+      "diagnostics": [
+        {
+          "severity": 4,
+          "locations": [
+            {
+              "start": {
+                "line": 4,
+                "column": 8
+              }
+            }
+          ],
+          "fixits": [],
+          "message": "unexpected '<'"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/backends/ruby.rb b/tests/backends/ruby.rb
new file mode 100644
index 0000000..7f0121e
--- /dev/null
+++ b/tests/backends/ruby.rb
@@ -0,0 +1,5 @@
+def method
+end
+
+class < noname
+end
diff --git a/tests/backends/sh.json b/tests/backends/sh.json
new file mode 100644
index 0000000..20056de
--- /dev/null
+++ b/tests/backends/sh.json
@@ -0,0 +1,5 @@
+{
+  "language": "sh",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/vala.json b/tests/backends/vala.json
new file mode 100644
index 0000000..55ef263
--- /dev/null
+++ b/tests/backends/vala.json
@@ -0,0 +1,5 @@
+{
+  "language": "vala",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/backends/xml.json b/tests/backends/xml.json
new file mode 100644
index 0000000..cdae475
--- /dev/null
+++ b/tests/backends/xml.json
@@ -0,0 +1,5 @@
+{
+  "language": "xml",
+  "interfaces": [],
+  "document_interfaces": ["org.gnome.CodeAssist.v1.Diagnostics"]
+}
diff --git a/tests/config.py.in b/tests/config.py.in
new file mode 100644
index 0000000..c48f24b
--- /dev/null
+++ b/tests/config.py.in
@@ -0,0 +1 @@
+execdir = '@backendexecdir@'
diff --git a/tests/dbus.conf.in b/tests/dbus.conf.in
new file mode 100644
index 0000000..378cff8
--- /dev/null
+++ b/tests/dbus.conf.in
@@ -0,0 +1,21 @@
+<!-- This configuration file controls the per-user-login-session message bus.
+     Add a session-local.conf and edit that rather than changing this 
+     file directly. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd";>
+<busconfig>
+  <!-- Our well-known bus type, don't change this -->
+  <type>session</type>
+  <listen>unix:tmpdir=/tmp</listen>
+  <servicedir>@datadirex@/dbus-1/services</servicedir>
+
+  <policy context="default">
+    <!-- Allow everything to be sent -->
+    <allow send_destination="*" eavesdrop="true"/>
+    <!-- Allow everything to be received -->
+    <allow eavesdrop="true"/>
+    <!-- Allow anyone to own anything -->
+    <allow own="*"/>
+  </policy>
+</busconfig>
diff --git a/tests/interfaces.json b/tests/interfaces.json
new file mode 100644
index 0000000..5d5500a
--- /dev/null
+++ b/tests/interfaces.json
@@ -0,0 +1,21 @@
+{
+  "org.gnome.CodeAssist.v1.Service": {
+    "Parse": [
+      {"name": "path", "direction": "in", "type": "s"},
+      {"name": "data_path", "direction": "in", "type": "s"},
+      {"name": "cursor", "direction": "in", "type": "(xx)"},
+      {"name": "options", "direction": "in", "type": "a{sv}"},
+      {"name": "document", "direction": "out", "type": "o"}
+    ],
+    "Dispose": [
+      {"name": "path", "direction": "in", "type": "s"}
+    ]
+  },
+  "org.gnome.CodeAssist.v1.Document": {
+  },
+  "org.gnome.CodeAssist.v1.Diagnostics": {
+    "Diagnostics": [
+      {"name": "result", "direction": "out", "type": "a(ua((x(xx)(xx))s)a(x(xx)(xx))s)"}
+    ]
+  }
+}
diff --git a/tests/service b/tests/service
new file mode 100755
index 0000000..5dd0e96
--- /dev/null
+++ b/tests/service
@@ -0,0 +1,255 @@
+#!/usr/bin/python3
+
+import sys, dbus, json, subprocess, os, glob, traceback
+import lxml.objectify
+
+sys.path.insert(0, os.path.dirname(__file__))
+import config
+sys.path = sys.path[1:]
+
+class Interface:
+    class Arg:
+        def __init__(self):
+            self.name = ''
+            self.direction = 'in'
+            self.signature = ''
+
+        def assert_equal(self, other):
+            if self.direction != other.direction:
+                raise ValueError("Expected direction {0} for argument {1}, but got 
{2}".format(self.direction, self.name, other.direction))
+
+            if self.signature != other.signature:
+                raise ValueError("Expected signature {0} for argument {1}, but got 
{2}".format(self.signature, self.name, other.signature))
+
+    class Method:
+        def __init__(self):
+            self.name = ''
+            self.args = []
+
+        def assert_equal(self, other):
+            if self.name != other.name:
+                raise ValueError("Methods have different names, expected {0} but got {1}".format(self.name, 
other.name))
+
+            for i, a in enumerate(self.args):
+                if i >= len(other.args):
+                    raise ValueError("Missing expected argument {0}:{1} missing".format(a.name, a.signature))
+
+                a.assert_equal(other.args[i])
+
+            for a in other.args[len(self.args):]:
+                raise ValueError("Unexpected argument {0}:{1}".format(a.name, a.signature))
+
+    def __init__(self):
+        self.name = ''
+        self.methods = {}
+
+    def assert_equal(self, other):
+        if self.name != other.name:
+            raise ValueError("Interfaces have different names, expected {0} but got {1}".format(self.name, 
other.name))
+
+        otherm = {m: True for m in other.methods}
+
+        for m in self.methods:
+            m1 = self.methods[m]
+
+            if not m in otherm:
+                raise ValueError("Missing method {0}".format(m))
+
+            del otherm[m]
+            m1.assert_equal(other.methods[m])
+
+        for k in otherm:
+            raise ValueError("Unexpected method {0}".format(k))
+
+    @classmethod
+    def from_xml(cls, xml):
+        ret = {}
+        obj = lxml.objectify.fromstring(xml)
+
+        for i in obj.interface:
+            ii = cls()
+
+            ii.name = i.attrib['name']
+            ret[ii.name] = ii
+
+            if not hasattr(i, 'method'):
+                continue
+
+            for m in i.method:
+                meth = cls.Method()
+                meth.name = m.attrib['name']
+
+                ii.methods[meth.name] = meth
+
+                if not hasattr(m, 'arg'):
+                    continue
+
+                for a in m.arg:
+                    aa = cls.Arg()
+                    aa.direction = a.attrib['direction']
+                    aa.signature = a.attrib['type']
+
+                    if 'name' in a.attrib:
+                        aa.name = a.attrib['name']
+
+                    meth.args.append(aa)
+
+        return ret
+
+    @classmethod
+    def from_json(cls, js):
+        with open(js) as f:
+            contents = f.read()
+
+        js = json.loads(contents)
+        ret = {}
+
+        for k in js:
+            ii = cls()
+            ii.name = k
+
+            ret[k] = ii
+
+            methods = js[k]
+
+            for mname in methods:
+                meth = cls.Method()
+                meth.name = mname
+
+                m = methods[mname]
+
+                ii.methods[meth.name] = meth
+
+                for a in m:
+                    aa = cls.Arg()
+                    aa.direction = a['direction']
+                    aa.signature = a['type']
+
+                    if 'name' in a:
+                        aa.name = a['name']
+
+                    meth.args.append(aa)
+
+        return ret
+
+def test(name):
+    def decorator(f):
+        def dummy(*args, **kwargs):
+            class C:
+                def __init__(self, args, kwargs):
+                    self.args = args
+                    self.kwargs = kwargs
+
+                def __call__(self):
+                    f(*self.args, **self.kwargs)
+
+                def __enter__(self):
+                    txt = '  TEST {0} ({1}) ... '.format(name, ', '.join([str(x) for x in self.args[1:]]))
+                    sys.stdout.write(txt)
+                    return self
+
+                def __exit__(self, typ, value, tb):
+                    if not value is None:
+                        print('[FAIL]: {0}'.format(value))
+                        print('      {0}'.format(''.join(traceback.format_tb(tb)).replace("\n", '\n      ')))
+                    else:
+                        print('[OK]')
+
+                    return True
+
+            return C(args, kwargs)
+
+        return dummy
+
+    return decorator
+
+class ServiceTest:
+    interfaces = Interface.from_json(os.path.join(os.path.dirname(__file__), 'interfaces.json'))
+
+    def __init__(self, bus, test):
+        self.test = test
+        self.language = test['language']
+        self.name = 'org.gnome.CodeAssist.v1.' + self.language
+        self.path = '/org/gnome/CodeAssist/v1/' + self.language
+        self.bus = bus
+
+    def full_path(self, path):
+        if path != '/':
+            return self.path + path
+        else:
+            return self.path
+
+    @test('object')
+    def test_object(self, path):
+        self.bus.get_object(self.name, self.full_path(path))
+
+    @test('interface')
+    def test_interface(self, path, interface):
+        obj = self.bus.get_object(self.name, self.full_path(path))
+
+        intro = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
+        xml = intro.Introspect()
+        introf = Interface.from_xml(xml)
+
+        if not interface in introf:
+            raise ValueError("Missing interface {0}".format(interface))
+
+        if not interface in self.interfaces:
+            raise ValueError("Unknown interface {0}".format(interface))
+
+        introf[interface].assert_equal(self.interfaces[interface])
+
+    def run(self):
+        print('TESTING {0}'.format(self.name))
+
+        # Test for default interfaces and paths
+        with self.test_object('/') as t:
+            t()
+
+        with self.test_interface('/', 'org.gnome.CodeAssist.v1.Service') as t:
+            t()
+
+        if 'interfaces' in self.test:
+            for interface in self.test['interfaces']:
+                with self.test_interface('/', interface) as t:
+                    t()
+
+        with self.test_object('/document') as t:
+            t()
+
+        with self.test_interface('/document', 'org.gnome.CodeAssist.v1.Document') as t:
+            t()
+
+        if 'document_interfaces' in self.test:
+            for interface in self.test['document_interfaces']:
+                with self.test_interface('/document', interface) as t:
+                    t()
+
+def run_test(testfile):
+    with open(testfile, 'r') as j:
+        test = json.loads(j.read())
+
+    bus = dbus.SessionBus(private=True)
+    t = ServiceTest(bus, test)
+    t.run()
+
+dirname = os.path.dirname(__file__)
+
+testfiles = glob.glob(os.path.join(dirname, 'backends', '*.json'))
+
+dn = open(os.devnull, 'w')
+daemon = subprocess.Popen(['dbus-daemon', '--print-address', '--nofork', '--config-file', 
os.path.join(dirname, 'dbus.conf')], stdout=subprocess.PIPE, stderr=dn, close_fds=True)
+
+try:
+    address = daemon.stdout.readline().rstrip()
+
+    os.environ['DBUS_SESSION_BUS_ADDRESS'] = address.decode('utf-8')
+    os.environ['DBUS_SESSION_BUS_PID'] = str(daemon.pid)
+
+    for testfile in testfiles:
+        run_test(testfile)
+finally:
+    daemon.terminate()
+    daemon.wait()
+
+# vi:ts=4:et


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