Merge pull request #3 from dnarvaez/unit-tests2

Initial bits of unit tests
This commit is contained in:
dnarvaez 2013-04-09 05:10:28 -07:00
commit 7ac2cae7c6
42 changed files with 675 additions and 294 deletions

View File

@ -1,6 +1,9 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS_TMPDIR=$(abs_builddir)/tests-tmp
TESTS_PYTHONPATH=$(abs_srcdir)/src:$(PYTHONPATH)
DISTCLEANFILES = \ DISTCLEANFILES = \
intltool-extract \ intltool-extract \
intltool-merge \ intltool-merge \
@ -12,3 +15,12 @@ EXTRA_DIST = \
intltool-extract.in intltool-extract.in
SUBDIRS = bin src po SUBDIRS = bin src po
check: test
test:
cd $(top_srcdir)/tests && \
mkdir -p $(TESTS_TMPDIR) && \
TMPDIR=$(TESTS_TMPDIR) PYTHONPATH=$(TESTS_PYTHONPATH) \
python -m unittest discover && \
rm -rf $(TESTS_TMPDIR)

View File

@ -18,14 +18,9 @@ AC_PATH_PROG([GLIB_GENMARSHAL], [glib-genmarshal])
AM_PATH_PYTHON AM_PATH_PYTHON
AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
AC_PATH_PROG(PYGTK_CODEGEN, pygtk-codegen-2.0, no)
PKG_CHECK_MODULES(EXT, gtk+-3.0 gdk-3.0 gdk-pixbuf-2.0 sm ice alsa PKG_CHECK_MODULES(EXT, gtk+-3.0 gdk-3.0 gdk-pixbuf-2.0 sm ice alsa
librsvg-2.0 xfixes xi x11) librsvg-2.0 xfixes xi x11)
PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
AC_SUBST(PYGTK_DEFSDIR)
GLIB_MKENUMS=`$PKG_CONFIG glib-2.0 --variable=glib_mkenums` GLIB_MKENUMS=`$PKG_CONFIG glib-2.0 --variable=glib_mkenums`
AC_SUBST(GLIB_MKENUMS) AC_SUBST(GLIB_MKENUMS)
@ -53,5 +48,6 @@ src/sugar3/event-controller/Makefile
src/sugar3/presence/Makefile src/sugar3/presence/Makefile
src/sugar3/datastore/Makefile src/sugar3/datastore/Makefile
src/sugar3/dispatch/Makefile src/sugar3/dispatch/Makefile
src/sugar3/test/Makefile
po/Makefile.in po/Makefile.in
]) ])

View File

@ -4,3 +4,4 @@
src/sugar3/eggdesktopfile.c src/sugar3/eggdesktopfile.c
src/sugar3/eggsmclient.c src/sugar3/eggsmclient.c
src/sugar3/gsm-xsmp.c src/sugar3/gsm-xsmp.c
tests/data/sample.activity/activity.py

View File

@ -1,4 +1,11 @@
SUBDIRS = activity bundle event-controller graphics presence datastore dispatch SUBDIRS = activity \
bundle \
event-controller \
graphics \
presence \
datastore \
dispatch \
test
sugardir = $(pythondir)/sugar3 sugardir = $(pythondir)/sugar3
sugar_PYTHON = \ sugar_PYTHON = \
@ -11,11 +18,28 @@ sugar_PYTHON = \
session.py \ session.py \
util.py util.py
XDG_MIME_SOURCES = \
xdgmime.c \
xdgmime.h \
xdgmimealias.c \
xdgmimealias.h \
xdgmimecache.c \
xdgmimecache.h \
xdgmimeglob.c \
xdgmimeglob.h \
xdgmimeint.c \
xdgmimeint.h \
xdgmimemagic.c \
xdgmimemagic.h \
xdgmimeparent.c \
xdgmimeparent.h
lib_LTLIBRARIES = libsugarext.la lib_LTLIBRARIES = libsugarext.la
libsugarext_la_CFLAGS = \ libsugarext_la_CFLAGS = \
-DHAVE_ALSA \ -DHAVE_ALSA \
$(EXT_CFLAGS) \ -DXDG_PREFIX=sugar_mime \
$(EXT_CFLAGS) \
$(WARN_CFLAGS) $(WARN_CFLAGS)
libsugarext_la_LDFLAGS = $(LDADD) libsugarext_la_LDFLAGS = $(LDADD)
@ -55,51 +79,12 @@ libsugarext_la_SOURCES = \
sugar-key-grabber.c \ sugar-key-grabber.c \
sugar-key-grabber.h \ sugar-key-grabber.h \
sugar-wm.c \ sugar-wm.c \
sugar-wm.h $(XDG_MIME_SOURCES)
sugar_LTLIBRARIES = _sugarbaseext.la
_sugarbaseext_la_CFLAGS = \
-DXDG_PREFIX=sugar_mime \
$(WARN_CFLAGS) \
$(EXT_CFLAGS) \
$(PYTHON_INCLUDES)
BUILT_SOURCES = \ BUILT_SOURCES = \
sugar-marshal.c \ sugar-marshal.c \
sugar-marshal.h sugar-marshal.h
_sugarbaseext_la_LDFLAGS = -module -avoid-version
_sugarbaseext_la_LIBADD = $(EXT_LIBS)
_sugarbaseext_la_SOURCES = \
_sugarbaseextmodule.c \
xdgmime.c \
xdgmime.h \
xdgmimealias.c \
xdgmimealias.h \
xdgmimecache.c \
xdgmimecache.h \
xdgmimeglob.c \
xdgmimeglob.h \
xdgmimeint.c \
xdgmimeint.h \
xdgmimemagic.c \
xdgmimemagic.h \
xdgmimeparent.c \
xdgmimeparent.h
nodist__sugarbaseext_la_SOURCES = _sugarbaseext.c
_sugarbaseext.c: _sugarbaseext.defs _sugarbaseext.override
.defs.c:
(cd $(srcdir)\
&& $(PYGTK_CODEGEN) \
--override $*.override \
--prefix py$* $*.defs) > gen-$*.c \
&& cp gen-$*.c $*.c \
&& rm -f gen-$*.c
sugar-marshal.c: sugar-marshal.list sugar-marshal.c: sugar-marshal.list
$(GLIB_GENMARSHAL) --prefix=sugar_marshal \ $(GLIB_GENMARSHAL) --prefix=sugar_marshal \
$(srcdir)/sugar-marshal.list --header --body > sugar-marshal.c $(srcdir)/sugar-marshal.list --header --body > sugar-marshal.c
@ -108,12 +93,14 @@ sugar-marshal.h: sugar-marshal.list
$(GLIB_GENMARSHAL) --prefix=sugar_marshal \ $(GLIB_GENMARSHAL) --prefix=sugar_marshal \
$(srcdir)/sugar-marshal.list --header > sugar-marshal.h $(srcdir)/sugar-marshal.list --header > sugar-marshal.h
CLEANFILES = $(BUILT_SOURCES) _sugarbaseext.c CLEANFILES = $(BUILT_SOURCES)
EXTRA_DIST = sugar-marshal.list _sugarbaseext.override _sugarbaseext.defs EXTRA_DIST = sugar-marshal.list
-include $(INTROSPECTION_MAKEFILE) -include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS = SugarExt-1.0.gir INTROSPECTION_GIRS = SugarExt-1.0.gir
INTROSPECTION_SCANNER_ARGS = --identifier-prefix=Sugar --symbol-prefix=sugar \ INTROSPECTION_SCANNER_ARGS = \
-D XDG_PREFIX=sugar_mime \
--identifier-prefix=Sugar --symbol-prefix=sugar \
--identifier-prefix=EggSM --symbol-prefix=egg_sm \ --identifier-prefix=EggSM --symbol-prefix=egg_sm \
--identifier-prefix=Gsm --symbol-prefix=gsm \ --identifier-prefix=Gsm --symbol-prefix=gsm \
--identifier-prefix=Acme --symbol-prefix=acme \ --identifier-prefix=Acme --symbol-prefix=acme \
@ -142,7 +129,8 @@ SugarExt_1_0_gir_FILES = \
sugar-grid.c \ sugar-grid.c \
sugar-grid.h \ sugar-grid.h \
sugar-wm.c \ sugar-wm.c \
sugar-wm.h sugar-wm.h \
$(XDG_MIME_SOURCES)
SugarExt_1_0_gir_INCLUDES = Gtk-3.0 Gdk-3.0 SugarExt_1_0_gir_INCLUDES = Gtk-3.0 Gdk-3.0
SugarExt_1_0_gir_PACKAGES = gtk+-3.0 gdk-3.0 SugarExt_1_0_gir_PACKAGES = gtk+-3.0 gdk-3.0

View File

@ -1,33 +0,0 @@
; functions
(define-function get_mime_type_from_file_name
(c-name "sugar_mime_get_mime_type_from_file_name")
(return-type "const-char*")
(parameters
'("const-char*" "filename")
)
)
(define-function get_mime_type_for_file
(c-name "sugar_mime_get_mime_type_for_file")
(return-type "const-char*")
(parameters
'("const-char*" "filename")
)
)
(define-function list_mime_parents
(c-name "sugar_mime_list_mime_parents")
(return-type "char**")
(parameters
'("const-char*" "mime")
)
)
(define-function uri_list_extract_uris
(c-name "g_uri_list_extract_uris")
(return-type "gchar**")
(parameters
'("const-char*" "uri_list")
)
)

View File

@ -1,88 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4 -*- */
%%
headers
#include <Python.h>
#include <glib.h>
#include "xdgmime.h"
%%
modulename _sugarext
%%
ignore-glob
*_get_type
_*
%%
override sugar_mime_get_mime_type_for_file kwargs
static PyObject *
_wrap_sugar_mime_get_mime_type_for_file(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "filename", NULL };
char *filename;
const char *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:get_mime_type_for_file", kwlist, &filename))
return NULL;
ret = sugar_mime_get_mime_type_for_file(filename, NULL);
if (ret)
return PyString_FromString(ret);
Py_INCREF(Py_None);
return Py_None;
}
%%
override sugar_mime_list_mime_parents kwargs
static PyObject *
_wrap_sugar_mime_list_mime_parents(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "mime_type", NULL };
char *mime_type;
char **parents, **tmp;
int i = 0, j;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:list_mime_parents", kwlist, &mime_type))
return NULL;
parents = (char **)sugar_mime_list_mime_parents(mime_type);
if (!parents)
return PyTuple_New(0);
tmp = parents;
while (*tmp)
tmp++, i++;
ret = PyTuple_New(i);
for (j = 0; j < i; j++)
PyTuple_SetItem(ret, j, PyString_FromString(parents[j]));
return ret;
}
%%
override g_uri_list_extract_uris kwargs
static PyObject *
_wrap_g_uri_list_extract_uris(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "uri_list", NULL };
char *uri_list;
char **uris, **tmp;
int i = 0, j;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:uri_list_extract_uris", kwlist, &uri_list))
return NULL;
uris = (char **)g_uri_list_extract_uris(uri_list);
if (!uris)
return PyTuple_New(0);
tmp = uris;
while (*tmp)
tmp++, i++;
ret = PyTuple_New(i);
for (j = 0; j < i; j++)
PyTuple_SetItem(ret, j, PyString_FromString(uris[j]));
return ret;
}
%%

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2006-2007, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <Python.h>
extern PyMethodDef py_sugarbaseext_functions[];
DL_EXPORT(void)
init_sugarbaseext(void)
{
PyObject *m, *d;
m = Py_InitModule ("_sugarbaseext", py_sugarbaseext_functions);
d = PyModule_GetDict (m);
if (PyErr_Occurred ()) {
Py_FatalError ("can't initialise module _sugarext");
}
}

View File

@ -64,10 +64,10 @@ def list_files(base_dir, ignore_dirs=None, ignore_files=None):
class Config(object): class Config(object):
def __init__(self, source_dir=None, dist_dir=None, dist_name=None): def __init__(self, source_dir):
self.source_dir = source_dir or os.getcwd() self.source_dir = source_dir
self.dist_dir = dist_dir or os.path.join(self.source_dir, 'dist') self.build_dir = os.getcwd()
self.dist_name = dist_name self.dist_dir = os.path.join(self.build_dir, 'dist')
self.bundle = None self.bundle = None
self.version = None self.version = None
self.activity_name = None self.activity_name = None
@ -90,18 +90,15 @@ class Config(object):
self.bundle_name = reduce(operator.add, self.activity_name.split()) self.bundle_name = reduce(operator.add, self.activity_name.split())
self.bundle_root_dir = self.bundle_name + '.activity' self.bundle_root_dir = self.bundle_name + '.activity'
self.tar_root_dir = '%s-%s' % (self.bundle_name, self.version) self.tar_root_dir = '%s-%s' % (self.bundle_name, self.version)
self.xo_name = '%s-%s.xo' % (self.bundle_name, self.version)
if self.dist_name: self.tar_name = '%s-%s.tar.bz2' % (self.bundle_name, self.version)
self.xo_name = self.tar_name = self.dist_name
else:
self.xo_name = '%s-%s.xo' % (self.bundle_name, self.version)
self.tar_name = '%s-%s.tar.bz2' % (self.bundle_name, self.version)
class Builder(object): class Builder(object):
def __init__(self, config): def __init__(self, config):
self.config = config self.config = config
self.locale_dir = os.path.join(self.config.build_dir, 'locale')
def build(self): def build(self):
self.build_locale() self.build_locale()
@ -113,10 +110,8 @@ class Builder(object):
logging.warn('Missing po/ dir, cannot build_locale') logging.warn('Missing po/ dir, cannot build_locale')
return return
locale_dir = os.path.join(self.config.source_dir, 'locale') if os.path.exists(self.locale_dir):
shutil.rmtree(self.locale_dir)
if os.path.exists(locale_dir):
shutil.rmtree(locale_dir)
for f in os.listdir(po_dir): for f in os.listdir(po_dir):
if not f.endswith('.po') or f == 'pseudo.po': if not f.endswith('.po') or f == 'pseudo.po':
@ -125,7 +120,7 @@ class Builder(object):
file_name = os.path.join(po_dir, f) file_name = os.path.join(po_dir, f)
lang = f[:-3] lang = f[:-3]
localedir = os.path.join(self.config.source_dir, 'locale', lang) localedir = os.path.join(self.config.build_dir, 'locale', lang)
mo_path = os.path.join(localedir, 'LC_MESSAGES') mo_path = os.path.join(localedir, 'LC_MESSAGES')
if not os.path.isdir(mo_path): if not os.path.isdir(mo_path):
os.makedirs(mo_path) os.makedirs(mo_path)
@ -145,10 +140,8 @@ class Builder(object):
f.write('summary = %s\n' % translated_summary) f.write('summary = %s\n' % translated_summary)
f.close() f.close()
def get_files(self): def get_locale_files(self):
allfiles = list_files(self.config.source_dir, return list_files(self.locale_dir, IGNORE_DIRS, IGNORE_FILES)
IGNORE_DIRS, IGNORE_FILES)
return allfiles
class Packager(object): class Packager(object):
@ -200,10 +193,9 @@ class XOPackager(Packager):
for f in self.get_files_in_git(): for f in self.get_files_in_git():
bundle_zip.write(os.path.join(self.config.source_dir, f), bundle_zip.write(os.path.join(self.config.source_dir, f),
os.path.join(self.config.bundle_root_dir, f)) os.path.join(self.config.bundle_root_dir, f))
locale_dir = os.path.join(self.config.source_dir, 'locale')
locale_files = list_files(locale_dir, IGNORE_DIRS, IGNORE_FILES) for f in self.builder.get_locale_files():
for f in locale_files: bundle_zip.write(os.path.join(self.builder.locale_dir, f),
bundle_zip.write(os.path.join(locale_dir, f),
os.path.join(self.config.bundle_root_dir, os.path.join(self.config.bundle_root_dir,
'locale', f)) 'locale', f))
@ -225,19 +217,11 @@ class SourcePackager(Packager):
tar.close() tar.close()
class Installer(object): class Installer(Packager):
IGNORES = ['po/*', 'MANIFEST', 'AUTHORS']
def __init__(self, builder): def __init__(self, builder):
self.config = builder.config Packager.__init__(self, builder.config)
self.builder = builder self.builder = builder
def should_ignore(self, f):
for pattern in self.IGNORES:
if fnmatch(f, pattern):
return True
return False
def install(self, prefix): def install(self, prefix):
self.builder.build() self.builder.build()
@ -245,13 +229,21 @@ class Installer(object):
self.config.bundle_root_dir) self.config.bundle_root_dir)
source_to_dest = {} source_to_dest = {}
for f in self.builder.get_files():
if self.should_ignore(f): for f in self.get_files_in_git():
pass source_path = os.path.join(self.config.source_dir, f)
elif f.startswith('locale/') and f.endswith('.mo'): dest_path = os.path.join(activity_path, f)
source_to_dest[f] = os.path.join(prefix, 'share', f) source_to_dest[source_path] = dest_path
for f in self.builder.get_locale_files():
source_path = os.path.join(self.builder.locale_dir, f)
if source_path.endswith(".mo"):
dest_path = os.path.join(prefix, 'share', 'locale', f)
else: else:
source_to_dest[f] = os.path.join(activity_path, f) dest_path = os.path.join(activity_path, 'locale', f)
source_to_dest[source_path] = dest_path
for source, dest in source_to_dest.items(): for source, dest in source_to_dest.items():
print 'Install %s to %s.' % (source, dest) print 'Install %s to %s.' % (source, dest)
@ -337,6 +329,8 @@ def cmd_genpot(config, args):
print 'Usage: %prog genpot' print 'Usage: %prog genpot'
return return
os.chdir(config.source_dir)
po_path = os.path.join(config.source_dir, 'po') po_path = os.path.join(config.source_dir, 'po')
if not os.path.isdir(po_path): if not os.path.isdir(po_path):
os.mkdir(po_path) os.mkdir(po_path)
@ -403,7 +397,8 @@ def start():
parser.disable_interspersed_args() parser.disable_interspersed_args()
(options_, args) = parser.parse_args() (options_, args) = parser.parse_args()
config = Config() source_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
config = Config(source_dir)
try: try:
globals()['cmd_' + args[0]](config, args[1:]) globals()['cmd_' + args[0]](config, args[1:])

View File

@ -51,8 +51,8 @@ def get_logs_path(path=None):
def get_user_activities_path(): def get_user_activities_path():
return os.path.expanduser('~/Activities') return os.environ.get("SUGAR_ACTIVITIES_PATH",
os.path.expanduser('~/Activities'))
def get_user_library_path(): def get_user_library_path():
return os.path.expanduser('~/Library') return os.path.expanduser('~/Library')

View File

@ -25,10 +25,11 @@ import os
import logging import logging
import gettext import gettext
from gi.repository import GLib
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
from gi.repository import Gio from gi.repository import Gio
from sugar3 import _sugarbaseext from gi.repository import SugarExt
_ = lambda msg: gettext.dgettext('sugar-base', msg) _ = lambda msg: gettext.dgettext('sugar-base', msg)
@ -123,7 +124,7 @@ def get_for_file(file_name):
file_name = os.path.realpath(file_name) file_name = os.path.realpath(file_name)
mime_type = _sugarbaseext.get_mime_type_for_file(file_name) mime_type = SugarExt.mime_get_mime_type_for_file(file_name, None)
if mime_type == 'application/octet-stream': if mime_type == 'application/octet-stream':
if _file_looks_like_text(file_name): if _file_looks_like_text(file_name):
return 'text/plain' return 'text/plain'
@ -134,7 +135,7 @@ def get_for_file(file_name):
def get_from_file_name(file_name): def get_from_file_name(file_name):
return _sugarbaseext.get_mime_type_from_file_name(file_name) return SugarExt.mime_get_mime_type_from_file_name(file_name)
def get_mime_icon(mime_type): def get_mime_icon(mime_type):
@ -154,7 +155,7 @@ def get_mime_description(mime_type):
def get_mime_parents(mime_type): def get_mime_parents(mime_type):
return _sugarbaseext.list_mime_parents(mime_type) return SugarExt.mime_list_mime_parents(mime_type)
def get_primary_extension(mime_type): def get_primary_extension(mime_type):
@ -254,7 +255,7 @@ def choose_most_significant(mime_types):
def split_uri_list(uri_list): def split_uri_list(uri_list):
return _sugarbaseext.uri_list_extract_uris(uri_list) return GLib.uri_list_extract_uris(uri_list)
def _file_looks_like_text(file_name): def _file_looks_like_text(file_name):

View File

@ -0,0 +1,4 @@
sugardir = $(pythondir)/sugar3/test
sugar_PYTHON = \
__init__.py \
uitree.py

View File

153
src/sugar3/test/uitree.py Normal file
View File

@ -0,0 +1,153 @@
# Copyright (C) 2012, Daniel Narvaez
#
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
"""
UNSTABLE.
"""
import time
from gi.repository import Atspi
Atspi.set_timeout(-1, -1)
def get_root():
return Node(Atspi.get_desktop(0))
def _retry_find(func):
def wrapped(*args, **kwargs):
result = None
n_retries = 1
while n_retries <= 10:
print "Try %d, name=%s role_name=%s" % \
(n_retries,
kwargs.get("name", None),
kwargs.get("role_name", None))
result = func(*args, **kwargs)
expect_none = kwargs.get("expect_none", False)
if (not expect_none and result) or \
(expect_none and not result):
return result
time.sleep(5)
n_retries = n_retries + 1
get_root().dump()
return result
return wrapped
class Node:
def __init__(self, accessible):
self._accessible = accessible
def dump(self):
self._crawl_accessible(self, 0)
def do_action(self, name):
for i in range(self._accessible.get_n_actions()):
if Atspi.Action.get_name(self._accessible, i) == name:
self._accessible.do_action(i)
def click(self, button=1):
point = self._accessible.get_position(Atspi.CoordType.SCREEN)
Atspi.generate_mouse_event(point.x, point.y, "b%sc" % button)
@property
def name(self):
return self._accessible.get_name()
@property
def role_name(self):
return self._accessible.get_role_name()
@property
def text(self):
return Atspi.Text.get_text(self._accessible, 0, -1)
def get_children(self):
children = []
for i in range(self._accessible.get_child_count()):
child = self._accessible.get_child_at_index(i)
# We sometimes get none children from atspi
if child is not None:
children.append(Node(child))
return children
@_retry_find
def find_children(self, name=None, role_name=None):
def predicate(node):
return self._predicate(node, name, role_name)
descendants = []
self._find_all_descendants(self, predicate, descendants)
if not descendants:
return []
return descendants
@_retry_find
def find_child(self, name=None, role_name=None, expect_none=False):
def predicate(node):
return self._predicate(node, name, role_name)
node = self._find_descendant(self, predicate)
if node is None:
return None
return node
def __str__(self):
return "[%s | %s]" % (self.name, self.role_name)
def _predicate(self, node, name, role_name):
if name is not None and name != node.name:
return False
if role_name is not None and role_name != node.role_name:
return False
return True
def _find_descendant(self, node, predicate):
if predicate(node):
return node
for child in node.get_children():
descendant = self._find_descendant(child, predicate)
if descendant is not None:
return descendant
return None
def _find_all_descendants(self, node, predicate, matches):
if predicate(node):
matches.append(node)
for child in node.get_children():
self._find_all_descendants(child, predicate, matches)
def _crawl_accessible(self, node, depth):
print " " * depth + str(node)
for child in node.get_children():
self._crawl_accessible(child, depth + 1)

View File

@ -457,6 +457,13 @@ xdg_mime_get_mime_type_for_data (const void *data,
return XDG_MIME_TYPE_UNKNOWN; return XDG_MIME_TYPE_UNKNOWN;
} }
/**
* sugar_mime_get_mime_type_for_file:
* @file_name: the file path
* @statbuf: (allow-none)
*
* Returns: (transfer none): the mime type.
*/
const char * const char *
xdg_mime_get_mime_type_for_file (const char *file_name, xdg_mime_get_mime_type_for_file (const char *file_name,
struct stat *statbuf) struct stat *statbuf)
@ -752,6 +759,11 @@ xdg_mime_mime_type_subclass (const char *mime,
return _xdg_mime_mime_type_subclass (mime, base); return _xdg_mime_mime_type_subclass (mime, base);
} }
/**
* sugar_mime_list_mime_parents:
*
* Return value: (array zero-terminated=1) (transfer full):
**/
char ** char **
xdg_mime_list_mime_parents (const char *mime) xdg_mime_list_mime_parents (const char *mime)
{ {

3
tests/data/mime.svg Normal file
View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="2.0">
</svg>

After

Width:  |  Height:  |  Size: 117 B

View File

@ -0,0 +1,8 @@
from gettext import gettext as _
from sugar3.activity import activity
class SampleActivity(activity.Activity):
def __init__(self, handle):
activity.Activity.__init__(self, handle)
self._text = _("Text string")

View File

@ -0,0 +1,26 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
<!ENTITY stroke_color "#010101">
<!ENTITY fill_color "#FFFFFF">
]>
<svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px">
<g display="block" id="activity-helloworld">
<path d="M9.263,48.396c0.682,1.152,6.027,0.059,8.246-1.463 c2.102-1.432,3.207-2.596,4.336-2.596c1.133,0,12.54,0.92,20.935-5.715c7.225-5.707,9.773-13.788,4.52-21.437 c-5.252-7.644-13.832-9.08-20.878-8.56C16.806,9.342,4.224,16.91,4.677,28.313c0.264,6.711,3.357,9.143,4.922,10.703 c1.562,1.566,4.545,1.566,2.992,5.588C11.981,46.183,8.753,47.522,9.263,48.396z" display="inline" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/>
</g>
<circle cx="27.375" cy="27.5" r="19.903"
transform="matrix(0.6,0,0,0.6,10.95,11)"
id="circle4" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" display="inline" />
<g transform="matrix(0.6,0,0,0.6,10.95,11)" id="g6" style="display:inline">
<path d="m 27.376,7.598 c 0,0 -11.205,8.394 -11.205,19.976 0,11.583 11.205,19.829 11.205,19.829"
id="path8" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" />
<path d="m 27.376,7.598 c 0,0 11.066,9.141 11.066,19.976 0,10.839 -11.066,19.829 -11.066,19.829"
id="path10" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" />
<line x1="27.375999" x2="27.375999" y1="7.598" y2="47.402"
id="line12" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" />
<line x1="27.375999" x2="27.375999" y1="7.598" y2="47.402"
id="line14" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" />
<line x1="27.375999" x2="27.375999" y1="7.598" y2="47.402"
id="line16" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" />
<line x1="7.4720001" x2="47.278" y1="27.5" y2="27.5"
id="line18" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,7 @@
[Activity]
name = Sample
activity_version = 1
bundle_id = org.sugarlabs.Sample
exec = sugar-activity activity.SampleActivity
icon = activity-sample
license = GPLv2+

View File

@ -0,0 +1,26 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-12-06 20:10+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: activity/activity.info:2
msgid "Sample"
msgstr ""
#: activity.py:8
msgid "Text string"
msgstr ""

View File

@ -0,0 +1,26 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-12-06 20:10+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: activity/activity.info:2
msgid "Sample"
msgstr ""
#: activity.py:8
msgid "Text string"
msgstr ""

View File

@ -0,0 +1,5 @@
#!/usr/bin/env python
from sugar3.activity import bundlebuilder
bundlebuilder.start()

View File

@ -1,28 +0,0 @@
# Copyright (C) 2007, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
import unittest
import test_mime
runner = unittest.TextTestRunner()
loader = unittest.TestLoader()
suite = unittest.TestSuite()
suite.addTest(loader.loadTestsFromModule(test_mime))
runner.run(suite)

244
tests/test_bundlebuilder.py Normal file
View File

@ -0,0 +1,244 @@
# Copyright (C) 2012, Daniel Narvaez
#
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import unittest
import shutil
import subprocess
import tempfile
import tarfile
import zipfile
tests_dir = os.path.dirname(__file__)
data_dir = os.path.join(tests_dir, "data")
class TestGit(unittest.TestCase):
_source_files = ["activity.py",
"setup.py",
"po/Sample.pot",
"po/es.po",
"activity/activity.info",
"activity/activity-sample.svg"]
_activity_locale_files = ["locale/es/activity.linfo"]
_share_locale_files = ["locale/es/LC_MESSAGES/org.sugarlabs.Sample.mo"]
def _get_all_locale_files(self):
expected = self._share_locale_files[:]
expected.extend(self._activity_locale_files)
return expected
def _create_repo(self):
cwd = os.getcwd()
path = tempfile.mkdtemp()
os.chdir(path)
subprocess.check_call(["git", "init"])
subprocess.check_call(["git", "config", "user.name", "Test Test"])
subprocess.check_call(["git", "config", "user.email", "test@test.org"])
for source in self._source_files:
source_path = os.path.join(data_dir, "sample.activity", source)
dest_path = os.path.join(path, source)
try:
os.makedirs(os.path.dirname(dest_path))
except OSError:
pass
shutil.copyfile(source_path, dest_path)
shutil.copymode(source_path, dest_path)
subprocess.check_call(["git", "add", source])
subprocess.check_call(["git", "commit", "-m", "Initial commit", "-a"])
os.chdir(cwd)
return path
def _strip_root_dir(self, paths):
return [path[path.find("/") + 1:] for path in paths]
def _test_dist_xo(self, source_path, build_path):
cwd = os.getcwd()
os.chdir(build_path)
setup_path = os.path.join(source_path, "setup.py")
subprocess.call([setup_path, "dist_xo"])
xo_path = os.path.join(build_path, "dist", "Sample-1.xo")
filenames = zipfile.ZipFile(xo_path).namelist()
stripped_filenames = self._strip_root_dir(filenames)
expected = self._source_files[:]
expected.extend(self._get_all_locale_files())
self.assertItemsEqual(stripped_filenames, expected)
os.chdir(cwd)
def _test_dist_source(self, source_path, build_path):
cwd = os.getcwd()
os.chdir(build_path)
setup_path = os.path.join(source_path, "setup.py")
subprocess.call([setup_path, "dist_source"])
xo_path = os.path.join(build_path, "dist", "Sample-1.tar.bz2")
filenames = tarfile.open(name=xo_path, mode="r:bz2").getnames()
stripped_filenames = self._strip_root_dir(filenames)
self.assertItemsEqual(stripped_filenames, self._source_files)
os.chdir(cwd)
def _test_build(self, source_path, build_path):
cwd = os.getcwd()
os.chdir(build_path)
setup_path = os.path.join(source_path, "setup.py")
subprocess.call([setup_path, "build"])
locale_path = os.path.join(build_path, "locale")
filenames = []
for root, dirs, files in os.walk(locale_path):
rel_root = root[len(build_path) + 1:]
filenames.extend([os.path.join(rel_root, name) for name in files])
self.assertItemsEqual(filenames, self._get_all_locale_files())
os.chdir(cwd)
def _test_dev(self, source_path, build_path):
activities_path = tempfile.mkdtemp()
cwd = os.getcwd()
os.chdir(build_path)
os.environ["SUGAR_ACTIVITIES_PATH"] = activities_path
setup_path = os.path.join(source_path, "setup.py")
subprocess.call([setup_path, "dev"])
activity_py_path = os.path.join(activities_path, "Sample.activity",
"activity.py")
self.assertTrue(os.path.exists(activity_py_path))
os.chdir(cwd)
def _test_genpot(self, source_path, build_path):
cwd = os.getcwd()
os.chdir(build_path)
pot_path = os.path.join(source_path, "po", "Sample.pot")
os.unlink(pot_path)
setup_path = os.path.join(source_path, "setup.py")
subprocess.call([setup_path, "genpot"])
self.assertTrue(os.path.exists(pot_path))
os.chdir(cwd)
def _test_install(self, source_path, build_path):
install_path = tempfile.mkdtemp()
cwd = os.getcwd()
os.chdir(build_path)
setup_path = os.path.join(source_path, "setup.py")
subprocess.call([setup_path, "install", "--prefix", install_path])
filenames = []
activity_dir = os.path.join(install_path, "share",
"sugar", "activities", "Sample.activity")
for root, dirs, files in os.walk(activity_dir):
rel_root = root[len(activity_dir) + 1:]
filenames.extend([os.path.join(rel_root, name) for name in files])
expected = self._source_files[:]
expected.extend(self._activity_locale_files)
self.assertItemsEqual(filenames, expected)
filenames = []
share_dir = os.path.join(install_path, "share")
locale_dir = os.path.join(share_dir, "locale")
for root, dirs, files in os.walk(locale_dir):
rel_root = root[len(share_dir) + 1:]
for name in files:
if "org.sugarlabs.Sample" in name:
filenames.append(os.path.join(rel_root, name))
self.assertItemsEqual(filenames, self._share_locale_files)
os.chdir(cwd)
def test_dist_xo_in_source(self):
repo_path = self._create_repo()
self._test_dist_xo(repo_path, repo_path)
def test_dist_xo_out_of_source(self):
repo_path = self._create_repo()
build_path = tempfile.mkdtemp()
self._test_dist_xo(repo_path, build_path)
def test_dist_source_in_source(self):
repo_path = self._create_repo()
self._test_dist_source(repo_path, repo_path)
def test_dist_source_out_of_source(self):
repo_path = self._create_repo()
build_path = tempfile.mkdtemp()
self._test_dist_source(repo_path, build_path)
def test_install_in_source(self):
repo_path = self._create_repo()
self._test_install(repo_path, repo_path)
def test_install_out_of_source(self):
repo_path = self._create_repo()
build_path = tempfile.mkdtemp()
self._test_install(repo_path, build_path)
def test_build_in_source(self):
repo_path = self._create_repo()
self._test_build(repo_path, repo_path)
def test_build_out_of_source(self):
repo_path = self._create_repo()
build_path = tempfile.mkdtemp()
self._test_build(repo_path, build_path)
def test_dev_in_source(self):
repo_path = self._create_repo()
self._test_genpot(repo_path, repo_path)
def test_dev_out_of_source(self):
repo_path = self._create_repo()
build_path = tempfile.mkdtemp()
self._test_dev(repo_path, build_path)
def test_genpot_in_source(self):
repo_path = self._create_repo()
self._test_genpot(repo_path, repo_path)
def test_genpot_out_of_source(self):
repo_path = self._create_repo()
build_path = tempfile.mkdtemp()
self._test_genpot(repo_path, build_path)

View File

@ -17,12 +17,27 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import unittest import unittest
from sugar import mime from sugar3 import mime
tests_dir = os.path.dirname(__file__)
data_dir = os.path.join(tests_dir, "data")
class TestMime(unittest.TestCase): class TestMime(unittest.TestCase):
def test_split_uri_list(self):
self.assertSequenceEqual(mime.split_uri_list("http://one\nhttp://two"),
("http://one", "http://two"))
def test_get_mime_parents(self):
self.assertListEqual(mime.get_mime_parents("image/svg+xml"),
["application/xml"])
def test_get_for_file(self):
self.assertEqual(mime.get_for_file(os.path.join(data_dir, "mime.svg")),
'image/svg+xml')
def test_from_file_name(self): def test_from_file_name(self):
self.assertEqual(mime.get_from_file_name('test.pdf'), self.assertEqual(mime.get_from_file_name('test.pdf'),
'application/pdf') 'application/pdf')
@ -77,7 +92,3 @@ class TestMime(unittest.TestCase):
'text/plain;charset=utf-8', 'text/plain;charset=UTF-8', 'text/plain;charset=utf-8', 'text/plain;charset=UTF-8',
'text/plain']) 'text/plain'])
self.assertEqual(mime_type, 'text/plain') self.assertEqual(mime_type, 'text/plain')
if __name__ == '__main__':
unittest.main()

52
tests/test_uitree.py Normal file
View File

@ -0,0 +1,52 @@
# Copyright (C) 2012, Daniel Narvaez
#
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
import subprocess
import unittest
from sugar3.test import uitree
class TestUITree(unittest.TestCase):
def test_tree(self):
process = subprocess.Popen(["python", __file__, "show_window1"])
try:
root = uitree.get_root()
window = root.find_child(name="window1", role_name="frame")
button = window.find_child(name="button1", role_name="push button")
finally:
process.terminate()
self.assertIsNotNone(button)
def show_window1():
from gi.repository import Gtk
from gi.repository import GLib
window = Gtk.Window()
window.set_title("window1")
button = Gtk.Button(label="button1")
window.add(button)
button.show()
window.show()
Gtk.main()
if __name__ == '__main__':
globals()[sys.argv[1]]()