From 284b0912af473912449a6db3592b396d4092ab27 Mon Sep 17 00:00:00 2001 From: Mark Doffman Date: Mon, 25 Aug 2008 11:25:25 +0100 Subject: [PATCH] 2008-08-25 Mark Doffman * pyatspi/relation.py Fix the generation of target objects. * pyatspi/accessible.py Fix demarshalling of relation objects. * pyatspi/base.py Add a string representation of the accessible class. * tests/pyatspi/realtiontest.py Add a relation unit test. * atk-adaptor/accessible.c Fix bug in marshalling relation object. --- atk-adaptor/accessible.c | 2 +- pyatspi/accessible.py | 2 +- pyatspi/base.py | 6 +++ pyatspi/relation.py | 9 ++--- tests/apps/Makefile.am | 8 +++- tests/apps/relation-app.c | 90 +++++++++++++++++++++++++++++++++++++++++++ tests/pyatspi/Makefile.am | 1 + tests/pyatspi/relationtest.py | 70 +++++++++++++++++++++++++++++++++ 8 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 tests/apps/relation-app.c create mode 100644 tests/pyatspi/relationtest.py diff --git a/atk-adaptor/accessible.c b/atk-adaptor/accessible.c index d7970fe..8154e4c 100644 --- a/atk-adaptor/accessible.c +++ b/atk-adaptor/accessible.c @@ -245,7 +245,7 @@ impl_getRelationSet (DBusConnection * bus, DBusMessage * message, char *path; if (!obj) continue; path = spi_dbus_get_path (obj); - dbus_message_iter_append (&iter_targets, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_append_basic (&iter_targets, DBUS_TYPE_OBJECT_PATH, &path); } dbus_message_iter_close_container (&iter_struct, &iter_targets); dbus_message_iter_close_container (&iter_array, &iter_struct); diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py index 093ac03..ea5e049 100644 --- a/pyatspi/accessible.py +++ b/pyatspi/accessible.py @@ -186,7 +186,7 @@ class Accessible(BaseProxy): """ func = self.get_dbus_method("getRelationSet") relation_set = func() - return _marshal_relation_set(self._cache, self._dbus_object, self._app_name, relation_set) + return _marshal_relation_set(self._cache, self._app_name, relation_set) def getRole(self): """ diff --git a/pyatspi/base.py b/pyatspi/base.py index e8ed466..4fabeec 100644 --- a/pyatspi/base.py +++ b/pyatspi/base.py @@ -109,6 +109,12 @@ class BaseProxy(Interface): def __getattr__(self, attr): raise AttributeError("\'%s\' has no attribute \'%s\'" % (self.__class__.__name__, attr)) + def __str__(self): + try: + return '[%s | %s]' % (self.getRoleName(), self.name) + except Exception: + return '[DEAD]' + def get_dbus_method(self, *args, **kwargs): method = Interface.get_dbus_method(self, *args, **kwargs) diff --git a/pyatspi/relation.py b/pyatspi/relation.py index 86e3a76..de91e25 100644 --- a/pyatspi/relation.py +++ b/pyatspi/relation.py @@ -99,7 +99,7 @@ RELATION_VALUE_TO_NAME = dict(((value, name[9:].lower().replace('_', ' ')) #------------------------------------------------------------------------------ -def _marshal_relation_set(cache, dbus_object, app_name, relation_set): +def _marshal_relation_set(cache, app_name, relation_set): """ The D-Bus protocol has a relation set passed as an array of relation types and object arrays. @@ -107,7 +107,7 @@ def _marshal_relation_set(cache, dbus_object, app_name, relation_set): This function marshals the D-Bus message into a list of relation objects. """ - return [Relation(cache, dbus_object, app_name, *relation) for relation in relation_set] + return [Relation(cache, app_name, *relation) for relation in relation_set] #------------------------------------------------------------------------------ @@ -118,11 +118,10 @@ class Relation(object): a "one-to-many" correspondance. """ - def __init__(self, cache, dbus_object, app_name, type, objects): + def __init__(self, cache, app_name, type, objects): self._type = type self._objects = objects - self._dbus_object = dbus_object self._cache = cache self._app_name = app_name @@ -154,6 +153,6 @@ class Relation(object): self._app_name, self._objects[index], interfaces.ATSPI_ACCESSIBLE, - dbus_object=self._dbus_object) + connection=self._cache._connection) #END---------------------------------------------------------------------------- diff --git a/tests/apps/Makefile.am b/tests/apps/Makefile.am index 7cd93d5..12a3257 100644 --- a/tests/apps/Makefile.am +++ b/tests/apps/Makefile.am @@ -2,7 +2,8 @@ check_PROGRAMS = test-application check_LTLIBRARIES = libnoopapp.la \ libaccessibleapp.la \ libcomponentapp.la \ - libactionapp.la + libactionapp.la \ + librelationapp.la test_application_CFLAGS = $(DBUS_GLIB_CFLAGS) \ $(ATK_CFLAGS) \ @@ -39,3 +40,8 @@ libactionapp_la_CFLAGS = $(TEST_APP_CFLAGS) libactionapp_la_LDFLAGS = $(TEST_APP_LDFLAGS) libactionapp_la_LIBADD = $(TEST_APP_LIBADD) libactionapp_la_SOURCES = action-app.c + +librelationapp_la_CFLAGS = $(TEST_APP_CFLAGS) +librelationapp_la_LDFLAGS = $(TEST_APP_LDFLAGS) +librelationapp_la_LIBADD = $(TEST_APP_LIBADD) +librelationapp_la_SOURCES = relation-app.c diff --git a/tests/apps/relation-app.c b/tests/apps/relation-app.c new file mode 100644 index 0000000..5734ffe --- /dev/null +++ b/tests/apps/relation-app.c @@ -0,0 +1,90 @@ +#include +#include +#include + +static AtkObject *root_accessible; + +G_MODULE_EXPORT void +test_init (gchar *path) +{ + AtkObject *r1, *r2, *r3; + AtkObject *m1, *m2, *m3; + AtkRelationSet *rset; + AtkRelation *rel; + AtkObject *rls[3]; + + root_accessible = g_object_new(MY_TYPE_ATK_OBJECT, NULL); + + r1 = ATK_OBJECT(g_object_new(MY_TYPE_ATK_OBJECT, + "accessible-name", "r1", + "accessible-description", "", + "accessible-role", ATK_ROLE_INVALID, + NULL)); + my_atk_object_add_child(MY_ATK_OBJECT(root_accessible), MY_ATK_OBJECT(r1)); + + r2 = ATK_OBJECT(g_object_new(MY_TYPE_ATK_OBJECT, + "accessible-name", "r2", + "accessible-description", "", + "accessible-role", ATK_ROLE_INVALID, + NULL)); + my_atk_object_add_child(MY_ATK_OBJECT(root_accessible), MY_ATK_OBJECT(r2)); + + r3 = ATK_OBJECT(g_object_new(MY_TYPE_ATK_OBJECT, + "accessible-name", "r3", + "accessible-description", "", + "accessible-role", ATK_ROLE_INVALID, + NULL)); + my_atk_object_add_child(MY_ATK_OBJECT(root_accessible), MY_ATK_OBJECT(r3)); + + m1 = ATK_OBJECT(g_object_new(MY_TYPE_ATK_OBJECT, + "accessible-name", "m1", + "accessible-description", "", + "accessible-role", ATK_ROLE_INVALID, + NULL)); + my_atk_object_add_child(MY_ATK_OBJECT(root_accessible), MY_ATK_OBJECT(m1)); + + m2 = ATK_OBJECT(g_object_new(MY_TYPE_ATK_OBJECT, + "accessible-name", "m2", + "accessible-description", "", + "accessible-role", ATK_ROLE_INVALID, + NULL)); + my_atk_object_add_child(MY_ATK_OBJECT(root_accessible), MY_ATK_OBJECT(m2)); + + m3 = ATK_OBJECT(g_object_new(MY_TYPE_ATK_OBJECT, + "accessible-name", "m3", + "accessible-description", "", + "accessible-role", ATK_ROLE_INVALID, + NULL)); + my_atk_object_add_child(MY_ATK_OBJECT(root_accessible), MY_ATK_OBJECT(m3)); + + atk_object_add_relationship(root_accessible, ATK_RELATION_EMBEDS, r1); + atk_object_add_relationship(root_accessible, ATK_RELATION_PARENT_WINDOW_OF, r2); + atk_object_add_relationship(root_accessible, ATK_RELATION_DESCRIBED_BY, r3); + + rls[0] = m1; + rls[1] = m2; + rls[2] = m3; + + rset = atk_object_ref_relation_set(root_accessible); + rel = atk_relation_new(rls, 3, ATK_RELATION_POPUP_FOR); + atk_relation_set_add(rset, rel); + g_object_unref(G_OBJECT(rset)); +} + +G_MODULE_EXPORT void +test_next (int argc, char *argv[]) +{ + g_print("Moving to next stage\n"); +} + +G_MODULE_EXPORT void +test_finished (int argc, char *argv[]) +{ + g_print("Test has completed\n"); +} + +G_MODULE_EXPORT AtkObject * +test_get_root (void) +{ + return root_accessible; +} diff --git a/tests/pyatspi/Makefile.am b/tests/pyatspi/Makefile.am index 8c22146..dbe32a8 100644 --- a/tests/pyatspi/Makefile.am +++ b/tests/pyatspi/Makefile.am @@ -8,6 +8,7 @@ EXTRA_DIST = \ Makefile.am\ Makefile.in\ setvars.sh\ + relationtest.py\ testrunner.py CLEANFILES = *.pyc diff --git a/tests/pyatspi/relationtest.py b/tests/pyatspi/relationtest.py new file mode 100644 index 0000000..6f93b14 --- /dev/null +++ b/tests/pyatspi/relationtest.py @@ -0,0 +1,70 @@ +import dbus +import gobject +import os.path + +from xml.dom import minidom +import os + +from pasytest import PasyTest as _PasyTest + +import pyatspi + +class RelationTest(_PasyTest): + + __tests__ = ["setup", + "teardown", + "test_getRelationType", + "test_getRelationTypeName", + "test_getNTargets", + "test_getTarget", + ] + + def __init__(self, bus, path): + _PasyTest.__init__(self, "Relation", False) + self._bus = bus + self._path = path + + def setup(self, test): + self._registry = pyatspi.registry.Registry(self._path) + self._desktop = self._registry.getDesktop(0) + self._root = self._desktop[0] + self._rset = self._root.getRelationSet() + test.assertEqual(len(self._rset), 4, "Num relations expected %d, recieved %d" % (6, len(self._rset))) + + def test_getRelationType(self, test): + expected = [pyatspi.RELATION_EMBEDS, + pyatspi.RELATION_PARENT_WINDOW_OF, + pyatspi.RELATION_DESCRIBED_BY, + pyatspi.RELATION_POPUP_FOR,] + rtypes = [rel.getRelationType() for rel in self._rset] + for exp, type in zip(expected, rtypes): + test.assertEqual(exp, type, "Relation type expected %s, recieved %s" % (exp, type)) + + def test_getRelationTypeName(self, test): + # FIXME This may not have been implemented in CORBA. + # Completely unused? + pass + + def test_getNTargets(self, test): + expected = [1, 1, 1, 3] + ntargs = [rel.getNTargets() for rel in self._rset] + for exp, ntarg in zip(expected, ntargs): + test.assertEqual(exp, ntarg, "Number of targets expected %s, recieved %s" % (exp, ntarg)) + + def test_getTarget(self, test): + rone = self._rset[0] + tone = rone.getTarget(0) + tonename = tone.name + test.assertEqual(tonename, "r1", "Target name expected %s, recieved %s" % ("r1", tonename)) + tonerole = tone.getRoleName() + test.assertEqual(tonerole, "invalid", "Target RoleName expected %s, recieved %s" % ("invalid", tonename)) + + rtwo = self._rset[3] + ttwo = rtwo.getTarget(2) + ttwoname = ttwo.name + test.assertEqual(ttwoname, "m3", "Target name expected %s, recieved %s" % ("m3", ttwoname)) + ttworole = ttwo.getRoleName() + test.assertEqual(ttworole, "invalid", "Target RoleName expected %s, recieved %s" % ("invalid", ttwoname)) + + def teardown(self, test): + pass -- 2.7.4