dee-1.2.7+15.04.20150304/ 0000755 0000153 0000161 00000000000 12475676370 014626 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/build/ 0000755 0000153 0000161 00000000000 12475676370 015725 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/build/Makefile.am 0000644 0000153 0000161 00000000024 12475676210 017746 0 ustar pbuser pbgroup 0000000 0000000 SUBDIRS = autotools
dee-1.2.7+15.04.20150304/build/autotools/ 0000755 0000153 0000161 00000000000 12475676370 017756 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/build/autotools/gcov.m4 0000644 0000153 0000161 00000005014 12475676210 021147 0 ustar pbuser pbgroup 0000000 0000000 # Checks for existence of coverage tools:
# * gcov
# * lcov
# * genhtml
# * gcovr
#
# Sets ac_cv_check_gcov to yes if tooling is present
# and reports the executables to the variables LCOV, GCOVR and GENHTML.
AC_DEFUN([AC_TDD_GCOV],
[
AC_ARG_ENABLE(gcov,
AS_HELP_STRING([--enable-gcov],
[enable coverage testing with gcov]),
[use_gcov=$enableval], [use_gcov=no])
AM_CONDITIONAL(HAVE_GCOV, test "x$use_gcov" = "xyes")
if test "x$use_gcov" = "xyes"; then
# we need gcc:
if test "$GCC" != "yes"; then
AC_MSG_ERROR([GCC is required for --enable-gcov])
fi
# Check if ccache is being used
AC_CHECK_PROG(SHTOOL, shtool, shtool)
if test "$SHTOOL"; then
AS_CASE([`$SHTOOL path $CC`],
[*ccache*], [gcc_ccache=yes],
[gcc_ccache=no])
fi
if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then
AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.])
fi
lcov_version_list="1.6 1.7 1.8 1.9 1.10"
AC_CHECK_PROG(LCOV, lcov, lcov)
AC_CHECK_PROG(GENHTML, genhtml, genhtml)
if test "$LCOV"; then
AC_CACHE_CHECK([for lcov version], glib_cv_lcov_version, [
glib_cv_lcov_version=invalid
lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'`
for lcov_check_version in $lcov_version_list; do
if test "$lcov_version" = "$lcov_check_version"; then
glib_cv_lcov_version="$lcov_check_version (ok)"
fi
done
])
else
lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list"
AC_MSG_ERROR([$lcov_msg])
fi
case $glib_cv_lcov_version in
""|invalid[)]
lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)."
AC_MSG_ERROR([$lcov_msg])
LCOV="exit 0;"
;;
esac
if test -z "$GENHTML"; then
AC_MSG_ERROR([Could not find genhtml from the lcov package])
fi
ac_cv_check_gcov=yes
ac_cv_check_lcov=yes
# Remove all optimization flags from CFLAGS
changequote({,})
CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
changequote([,])
# Add the special gcc flags
COVERAGE_CFLAGS="-O0 --coverage"
COVERAGE_CXXFLAGS="-O0 --coverage"
COVERAGE_LDFLAGS="-lgcov"
# Check availability of gcovr
AC_CHECK_PROG(GCOVR, gcovr, gcovr)
if test -z "$GCOVR"; then
ac_cv_check_gcovr=no
else
ac_cv_check_gcovr=yes
fi
fi
]) # AC_TDD_GCOV
dee-1.2.7+15.04.20150304/build/autotools/Makefile.am 0000644 0000153 0000161 00000000036 12475676210 022002 0 ustar pbuser pbgroup 0000000 0000000 EXTRA_DIST = introspection.m4
dee-1.2.7+15.04.20150304/build/autotools/introspection.m4 0000644 0000153 0000161 00000006614 12475676210 023120 0 ustar pbuser pbgroup 0000000 0000000 dnl -*- mode: autoconf -*-
dnl Copyright 2009 Johan Dahlin
dnl
dnl This file is free software; the author(s) gives unlimited
dnl permission to copy and/or distribute it, with or without
dnl modifications, as long as this notice is preserved.
dnl
# serial 1
m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL],
[
AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
AC_BEFORE([LT_INIT],[$0])dnl setup libtool first
dnl enable/disable introspection
m4_if([$2], [require],
[dnl
enable_introspection=yes
],[dnl
AC_ARG_ENABLE(introspection,
AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]],
[Enable introspection for this build]),,
[enable_introspection=auto])
])dnl
AC_MSG_CHECKING([for gobject-introspection])
dnl presence/version checking
AS_CASE([$enable_introspection],
[no], [dnl
found_introspection="no (disabled, use --enable-introspection to enable)"
],dnl
[yes],[dnl
PKG_CHECK_EXISTS([gobject-introspection-1.0],,
AC_MSG_ERROR([gobject-introspection-1.0 is not installed]))
PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1],
found_introspection=yes,
AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME]))
],dnl
[auto],[dnl
PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no)
],dnl
[dnl
AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@])
])dnl
AC_MSG_RESULT([$found_introspection])
INTROSPECTION_SCANNER=
INTROSPECTION_COMPILER=
INTROSPECTION_GENERATE=
INTROSPECTION_GIRDIR=
INTROSPECTION_TYPELIBDIR=
if test "x$found_introspection" = "xyes"; then
INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0`
INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0`
INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0`
INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0`
INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0`
INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection
fi
AC_SUBST(INTROSPECTION_SCANNER)
AC_SUBST(INTROSPECTION_COMPILER)
AC_SUBST(INTROSPECTION_GENERATE)
AC_SUBST(INTROSPECTION_GIRDIR)
AC_SUBST(INTROSPECTION_TYPELIBDIR)
AC_SUBST(INTROSPECTION_CFLAGS)
AC_SUBST(INTROSPECTION_LIBS)
AC_SUBST(INTROSPECTION_MAKEFILE)
AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes")
])
dnl Usage:
dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version])
AC_DEFUN([GOBJECT_INTROSPECTION_CHECK],
[
_GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1])
])
dnl Usage:
dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version])
AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE],
[
_GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require])
])
dee-1.2.7+15.04.20150304/autogen.sh 0000755 0000153 0000161 00000000255 12475676210 016622 0 ustar pbuser pbgroup 0000000 0000000 #!/bin/sh
srcdir=`dirname $0`
PKG_NAME="dee"
which gnome-autogen.sh || {
echo "You need gnome-common from GNOME SVN"
exit 1
}
USE_GNOME2_MACROS=1 \
. gnome-autogen.sh
dee-1.2.7+15.04.20150304/bindings/ 0000755 0000153 0000161 00000000000 12475676370 016423 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/bindings/Makefile.am 0000644 0000153 0000161 00000000022 12475676210 020442 0 ustar pbuser pbgroup 0000000 0000000 SUBDIRS = python
dee-1.2.7+15.04.20150304/bindings/README 0000644 0000153 0000161 00000000642 12475676210 017276 0 ustar pbuser pbgroup 0000000 0000000 Currently none of these bindings are installed or even properly working.
Python
------
Currently not working because it's blocked on https://bugzilla.gnome.org/show_bug.cgi?id=638915 "Array of GVariants passed as NULL"
in pygobject.
If you want to play around copy the Dee.py file into the gi.overrides module,
fx. $prefix/lib/python2.7/site-packages/gi/overrides/ and you should be
able to run the Python samples.
dee-1.2.7+15.04.20150304/bindings/python/ 0000755 0000153 0000161 00000000000 12475676370 017744 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/bindings/python/Makefile.am 0000644 0000153 0000161 00000000147 12475676210 021773 0 ustar pbuser pbgroup 0000000 0000000 pygioverridesdir = $(PYGI_OVERRIDES_DIR)
pygioverrides_PYTHON = \
Dee.py
EXTRA_DIST = Dee.py
dee-1.2.7+15.04.20150304/bindings/python/Dee.py 0000644 0000153 0000161 00000015420 12475676210 021006 0 ustar pbuser pbgroup 0000000 0000000 from gi.overrides import override
from gi.importer import modules
Dee = modules['Dee']._introspection_module
from gi.repository import GLib
__all__ = []
class RowWrapper:
def __init__ (self, model, itr):
self.model = model
self.itr = itr
self.__initialized = True
def __getitem__ (self, column):
return self.model.get_value(self.itr, column)
def __setitem__ (self, column, val):
self.model.set_value (self.itr, column, val)
def __getattr__ (self, name):
col_index = self.model.get_column_index (name)
if col_index < 0:
raise AttributeError("object has no attribute '%s'" % name)
return self.model.get_value (self.itr, col_index)
def __setattr__ (self, name, value):
if not "_RowWrapper__initialized" in self.__dict__:
self.__dict__[name] = value
return
col_index = self.model.get_column_index (name)
if col_index < 0:
raise AttributeError("object has no attribute '%s'" % name)
self.model.set_value (self.itr, col_index, value)
def __iter__ (self):
for column in range(self.model.get_n_columns()):
yield self.model.get_value (self.itr, column)
def __len__ (self):
return self.model.get_n_columns()
def __str__ (self):
return "(%s)" % ", ".join(map(str,self))
def __eq__ (self, other):
if not isinstance (other, RowWrapper):
return False
if self.model != other.model:
return False
return self.itr == other.itr
class Model(Dee.Model):
def __init__(self):
Dee.Model.__init__(self)
def set_schema (self, *args):
self.set_schema_full (tuple(args))
def set_column_names (self, *args):
self.set_column_names_full (tuple(args))
def _build_row (self, args, kwargs):
schema = self.get_schema()
result = [None] * len(schema)
if len(args) > 0:
for i, arg in enumerate(args):
if isinstance(arg, GLib.Variant):
result[i] = arg
else:
result[i] = GLib.Variant(schema[i], arg)
# check
if result.count(None) > 0:
raise RuntimeError("Not all columns were set")
else:
names = self.get_column_names()
dicts = [None] * len(schema)
if len(names) == 0:
raise RuntimeError("Column names were not set")
for col_name, arg in kwargs.items():
if names.count(col_name) > 0:
col_index = names.index(col_name)
variant = arg if isinstance(arg, GLib.Variant) else GLib.Variant(schema[col_index], arg)
result[col_index] = variant
else:
col_schema, col_index = self.get_field_schema(col_name)
if col_schema:
variant = arg if isinstance(arg, GLib.Variant) else GLib.Variant(col_schema, arg)
colon_index = col_name.find("::")
field_name = col_name if colon_index < 0 else col_name[colon_index+2:]
if dicts[col_index] is None: dicts[col_index] = {}
dicts[col_index][field_name] = variant
else:
raise RuntimeError("Unknown column name: %s" % col_name)
# finish vardict creation
for index, d in enumerate(dicts):
if d: result[index] = GLib.Variant(schema[index], d)
# handle empty dicts (no "xrange" in python3)
for i in range(len(schema)):
if result[i] is None and schema[i] == "a{sv}":
result[i] = GLib.Variant(schema[i], {})
# checks
num_unset = result.count(None)
if num_unset > 0:
col_name = names[result.index(None)]
raise RuntimeError("Column '%s' was not set" % col_name)
return result
def prepend (self, *args, **kwargs):
return self.prepend_row (self._build_row(args, kwargs))
def append (self, *args, **kwargs):
return self.append_row (self._build_row(args, kwargs))
def insert (self, pos, *args, **kwargs):
return self.insert_row (pos, self._build_row(args, kwargs))
def insert_before (self, iter, *args, **kwargs):
return self.insert_row_before (iter, self._build_row(args, kwargs))
def insert_row_sorted (self, row_spec, sort_func, data):
return self.insert_row_sorted_with_sizes (row_spec, sort_func, data)
def insert_sorted (self, sort_func, *args, **kwargs):
return self.insert_row_sorted (self._build_row(args, kwargs), sort_func, None)
def find_row_sorted (self, row_spec, sort_func, data):
return self.find_row_sorted_with_sizes (row_spec, sort_func, data)
def find_sorted (self, sort_func, *args, **kwargs):
return self.find_row_sorted (self._build_row(args, kwargs), sort_func, None)
def get_schema (self):
return Dee.Model.get_schema(self)
def get_value (self, itr, column):
return Dee.Model.get_value (self, itr, column).unpack()
def set_value (self, itr, column, value):
var = GLib.Variant (self.get_column_schema(column), value)
if isinstance (itr, int):
itr = self.get_iter_at_row(itr)
Dee.Model.set_value (self, itr, column, var)
def __getitem__ (self, itr):
if isinstance (itr, int):
itr = self.get_iter_at_row(itr)
return RowWrapper(self, itr)
def __setitem__ (self, itr, row):
max_col = self.get_n_columns ()
for column, value in enumerate (row):
if column >= max_col:
raise IndexError("Too many columns in row assignment: %s" % column)
self.set_value (itr, column, value)
def get_row (self, itr):
return self[itr]
def __iter__ (self):
itr = self.get_first_iter ()
last = self.get_last_iter ()
while itr != last:
yield self.get_row(itr)
itr = self.next(itr)
raise StopIteration
def __len__ (self):
return self.get_n_rows()
class ModelIter(Dee.ModelIter):
def __init__(self):
Dee.ModelIter.__init__(self)
def __eq__ (self, other):
if not isinstance (other, ModelIter):
return False
return repr(self) == repr(other)
Model = override(Model)
__all__.append('Model')
ModelIter = override(ModelIter)
__all__.append('ModelIter')
dee-1.2.7+15.04.20150304/Makefile.am 0000644 0000153 0000161 00000001266 12475676210 016660 0 ustar pbuser pbgroup 0000000 0000000 ACLOCAL_AMFLAGS = -I build/autotools
include $(top_srcdir)/Makefile.am.coverage
SUBDIRS = build src doc examples tools vapi bindings
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = dee-1.0.pc
if HAVE_ICU
pkgconfig_DATA += dee-icu-1.0.pc
endif
if WANT_TESTS
SUBDIRS += tests
# Test framework
.PHONY: check-report full-report check-headless
check-report full-report check-headless:
$(MAKE) -C tests/ $(@)
endif
CLEANFILES = dee-1.0.pc
DISTCLEANFILES = dee-1.0.pc
EXTRA_DIST = \
autogen.sh \
dee-1.0.pc.in \
dee-icu-1.0.pc.in \
COPYING.GPL
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --with-pygi-overrides-dir='$$(pyexecdir)'/gi/overrides
benchmark:
cd tests && make benchmark
dee-1.2.7+15.04.20150304/tests/ 0000755 0000153 0000161 00000000000 12475676370 015770 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/tests/test-analyzer.c 0000644 0000153 0000161 00000010555 12475676210 020735 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
typedef struct
{
DeeAnalyzer *analyzer;
DeeTermList *terms;
} Fixture;
static void setup (Fixture *fix, gconstpointer data);
static void text_setup (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup (Fixture *fix, gconstpointer data)
{
fix->analyzer = dee_analyzer_new ();
fix->terms = g_object_new (DEE_TYPE_TERM_LIST, NULL);
}
static void
text_setup (Fixture *fix, gconstpointer data)
{
fix->analyzer = DEE_ANALYZER (dee_text_analyzer_new ());
fix->terms = g_object_new (DEE_TYPE_TERM_LIST, NULL);
}
static void
teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->analyzer);
g_object_unref (fix->terms);
fix->analyzer = NULL;
fix->terms = NULL;
}
static void
test_simple (Fixture *fix, gconstpointer data)
{
dee_analyzer_tokenize (fix->analyzer, "tok", fix->terms);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "tok");
dee_term_list_clear (fix->terms);
dee_analyzer_tokenize (fix->analyzer, "tok kot", fix->terms);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "tok kot");
dee_term_list_clear (fix->terms);
dee_analyzer_analyze (fix->analyzer, "foobar", fix->terms, NULL);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "foobar");
}
void
_casefold (DeeTermList *in, DeeTermList *out, gpointer data)
{
int i;
gchar *fold;
for (i = 0; i < dee_term_list_num_terms (in); i++)
{
fold = g_utf8_casefold (dee_term_list_get_term (in, i), -1);
dee_term_list_add_term (out, fold);
g_free (fold);
}
}
static void
test_term_filter1 (Fixture *fix, gconstpointer data)
{
dee_analyzer_analyze (fix->analyzer, "foobar", fix->terms, NULL);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "foobar");
dee_term_list_clear (fix->terms);
dee_analyzer_add_term_filter(fix->analyzer, _casefold, NULL, NULL);
dee_analyzer_analyze (fix->analyzer, "FooBar", fix->terms, NULL);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "foobar");
dee_term_list_clear (fix->terms);
}
void
test_text_analyzer_simple (Fixture *fix, gconstpointer data)
{
dee_analyzer_analyze (fix->analyzer, "foobar", fix->terms, NULL);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "foobar");
dee_term_list_clear (fix->terms);
dee_analyzer_analyze (fix->analyzer, "FooBar ", fix->terms, NULL);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "foobar");
dee_term_list_clear (fix->terms);
dee_analyzer_analyze (fix->analyzer, "foo baR", fix->terms, NULL);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 2);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "foo");
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 1), ==, "bar");
dee_term_list_clear (fix->terms);
}
void
test_analyzer_create_suite (void)
{
g_test_add ("/Index/Analyzer/Simple", Fixture, 0,
setup, test_simple, teardown);
g_test_add ("/Index/Analyzer/TermFilter1", Fixture, 0,
setup, test_term_filter1, teardown);
g_test_add ("/Index/TextAnalyzer/Simple", Fixture, 0,
text_setup, test_text_analyzer_simple, teardown);
}
dee-1.2.7+15.04.20150304/tests/test-python.py 0000644 0000153 0000161 00000001466 12475676210 020640 0 ustar pbuser pbgroup 0000000 0000000 import os, unittest
import gi, gi.overrides
gi.overrides.__path__ = os.environ["DEE_TEST_PYGOBJECT_OVERRIDEDIR"]
print "Running Python tests with overrides path '%s'" % gi.overrides.__path__
from gi.repository import Dee
class TreeIndexTest (unittest.TestCase):
model = None
analyzer = None
index = None
def testEmpty (self):
self.model = Dee.SequenceModel.new ()
self.model.set_schema ("i", "s")
self.analyzer = Dee.TextAnalyzer.new ()
def readString (model, iter, data):
return model[iter][1]
self.index = Dee.TreeIndex.new (self.model, self.analyzer, readString, None)
row = self.model.append (1, "one")
result = self.index.lookup_one ("one")
self.assertEquals (row, result)
self.assertEquals (self.model[row], self.model[result])
if __name__ == '__main__':
unittest.main()
dee-1.2.7+15.04.20150304/tests/server-helper-client.c 0000644 0000153 0000161 00000005407 12475676210 022172 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
#include
static void
on_peer_found (DeePeer *peer, gchar *name, gint *n_peers)
{
(*n_peers)++;
}
static void
on_peer_lost (DeePeer *peer, gchar *name, gint *n_peers)
{
(*n_peers)++;
}
static int
peer_function (gchar *argv[])
{
DeePeer *peer;
gint n_peers = 0;
peer = (DeePeer*) dee_client_new (argv[1]);
g_signal_connect (peer, "peer-found", G_CALLBACK (on_peer_found), &n_peers);
g_signal_connect (peer, "peer-lost", G_CALLBACK (on_peer_lost), &n_peers);
if (gtx_wait_for_signal (G_OBJECT (peer), 10000, "notify::swarm-leader", NULL))
g_error ("Peer helper timed out waiting for swarm leader");
/* The main process should be swarm leaders. Not us */
g_assert_cmpint (0, ==, dee_peer_is_swarm_leader (peer));
/* At this point we shouldn't have emitted 'peer-found' yet */
g_assert_cmpint (0, ==, n_peers);
if (gtx_wait_for_signal (G_OBJECT (peer), 10000, "peer-found", NULL))
g_error ("Peer helper timed out waiting for 'peer-found' signal");
g_assert_cmpint (1, ==, n_peers);
g_assert_cmpint (1, ==, g_strv_length (dee_peer_list_peers (peer)));
gtx_assert_last_unref (peer);
return 0;
}
static gint finished_children = 0;
static void
child_exited (GPid pid, gint status, gpointer user_data)
{
finished_children++;
}
gint
main (gint argc, gchar *argv[])
{
int num_clients, i;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc < 3) g_error ("Invalid invocation");
num_clients = i = atoi (argv[2]);
while (i-- > 0)
{
GPid pid = (GPid) fork ();
if (pid != 0) g_child_watch_add (pid, child_exited, NULL);
else
{
return peer_function (argv);
}
}
for (i = 0; i < 10; i++)
{
gtx_yield_main_loop (200);
if (finished_children == num_clients) break;
}
/* Give a window of opportunity for children to
* flush stdout/err before we exit */
gtx_yield_main_loop (200);
g_assert_cmpint (num_clients, ==, finished_children);
return 0;
}
dee-1.2.7+15.04.20150304/tests/Makefile.am 0000644 0000153 0000161 00000012127 12475676210 020020 0 ustar pbuser pbgroup 0000000 0000000 NULL =
noinst_PROGRAMS = \
test-dee \
test-benchmark \
$(NULL)
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_srcdir)/src \
-DTESTDIR=\""$(top_builddir)/tests"\" \
-DDEE_COMPILATION \
$(GCC_FLAGS) \
$(DEE_CFLAGS) \
$(MAINTAINER_CFLAGS)
test_benchmark_SOURCES = \
test-benchmark.c
test_benchmark_LDADD = $(top_builddir)/src/libdee-1.0.la $(DEE_LIBS) -lm
benchmark: test-benchmark
./test-benchmark
test_dee_SOURCES = \
test-analyzer.c \
test-dee.c \
test-filter-model.c \
test-glist-result-set.c \
test-index.c \
test-model-column.c \
test-model-complex-column.c \
test-model-readers.c \
test-model-rows.c \
test-model-signals.c \
test-model-seqnums.c \
test-model-tags.c \
test-resource-manager.c \
test-serializable.c \
test-transaction.c \
test-term-list.c \
$(top_srcdir)/src/dee-glist-result-set.h \
$(NULL)
test_dee_LDADD = $(top_builddir)/src/libdee-1.0.la $(DEE_LIBS)
if HAVE_ICU
test_dee_SOURCES += test-icu.c
endif
if HAVE_GTX
test_dee_SOURCES += test-model-interactions.c
test_dee_SOURCES += test-peer-interactions.c
test_dee_SOURCES += test-client-server.c
AM_CPPFLAGS += $(GTX_CFLAGS)
test_dee_LDADD += $(GTX_LIBS)
model_helpers = \
model-helper-add3rows.c \
model-helper-append1.c \
model-helper-change3rows.c \
model-helper-clear3rows.c \
model-helper-clear6rows.c \
model-helper-clone3rows.c \
model-helper-clone3rows-meta.c \
model-helper-clear3add5.c \
model-helper-insert1row.c \
model-helper-introspect.c \
model-helper-remove3rows.c \
model-helper-replace.c \
model-helper-resync3rows.c \
model-helper-schemaless.c \
$(NULL)
peer_helpers = \
peer-helper-1peer.c \
$(NULL)
server_helpers = \
server-helper-client.c
noinst_PROGRAMS += \
$(model_helpers:.c=) \
$(peer_helpers:.c=) \
$(server_helpers:.c=) \
$(NULL)
model_helper_clone3rows_SOURCES = model-helper-clone3rows.c
model_helper_clone3rows_LDADD = $(test_dee_LDADD)
model_helper_clone3rows_meta_SOURCES = model-helper-clone3rows-meta.c
model_helper_clone3rows_meta_LDADD = $(test_dee_LDADD)
model_helper_add3rows_SOURCES = model-helper-add3rows.c
model_helper_add3rows_LDADD = $(test_dee_LDADD)
model_helper_append1_SOURCES = model-helper-append1.c
model_helper_append1_LDADD = $(test_dee_LDADD)
model_helper_change3rows_SOURCES = model-helper-change3rows.c
model_helper_change3rows_LDADD = $(test_dee_LDADD)
model_helper_remove3rows_SOURCES = model-helper-remove3rows.c
model_helper_remove3rows_LDADD = $(test_dee_LDADD)
model_helper_clear3rows_SOURCES = model-helper-clear3rows.c
model_helper_clear3rows_LDADD = $(test_dee_LDADD)
model_helper_clear6rows_SOURCES = model-helper-clear6rows.c
model_helper_clear6rows_LDADD = $(test_dee_LDADD)
model_helper_clear3add5_SOURCES = model-helper-clear3add5.c
model_helper_clear3add5_LDADD = $(test_dee_LDADD)
model_helper_insert1row_SOURCES = model-helper-insert1row.c
model_helper_insert1row_LDADD = $(test_dee_LDADD)
model_helper_schemaless_SOURCES = model-helper-schemaless.c
model_helper_schemaless_LDADD = $(test_dee_LDADD)
model_helper_introspect_SOURCES = model-helper-introspect.c
model_helper_introspect_LDADD = $(test_dee_LDADD)
model_helper_replace_SOURCES = model-helper-replace.c
model_helper_replace_LDADD = $(test_dee_LDADD)
model_helper_resync3rows_SOURCES = model-helper-resync3rows.c
model_helper_resync3rows_LDADD = $(test_dee_LDADD)
peer_helper_1peer_SOURCES = peer-helper-1peer.c
peer_helper_1peer_LDADD = $(test_dee_LDADD)
server_helper_client_SOURCES = server-helper-client.c
server_helper_client_LDADD = $(test_dee_LDADD)
endif # HAVE_GTX
#
# Python tests disabled because of https://bugzilla.gnome.org/show_bug.cgi?id=660647
#
#PYTHON_TESTS_ENV_VARS= \
# PYTHONPATH=$(top_builddir)/tests:$${PYTHONPATH:+:$$PYTHONPATH} \
# GI_TYPELIB_PATH=$(top_builddir)/src:$$GI_TYPELIB_PATH \
# XDG_DATA_DIRS=$(top_builddir)/src:$XDG_DATA_DIRS:/usr/share \
# LD_LIBRARY_PATH=$(top_builddir)/src/.libs:$$LD_LIBRARY_PATH \
# DEE_TEST_PYGOBJECT_OVERRIDEDIR=$(top_srcdir)/bindings/python
#
#test-python:
# $(PYTHON_TESTS_ENV_VARS) python test-python.py
.PHONY: test
test:
@dbus-test-runner -m 60 --task gtester \
--parameter --verbose \
--parameter -o=test-dee-results.xml \
--parameter -k \
--parameter ./test-dee
.PHONY: check-report full-report
check-report:
@dbus-test-runner -m 60 --task gtester \
--parameter -o=test-dee-results.xml \
--parameter -k \
--parameter ./test-dee \
&& ( gtester-report test-dee-results.xml \
| sed 's/GTester Unit Test Report>GTester Unit Test Report (normal)' \
> test-dee-results.html ) \
&& gnome-open ./test-dee-results.html
full-report:
@dbus-test-runner -m 60 --task gtester \
--parameter -o=test-dee-results.xml \
--parameter -k \
--parameter -m=slow \
--parameter ./test-dee \
&& ( gtester-report test-dee-results.xml \
| sed 's/>GTester Unit Test Report>GTester Unit Test Report (normal)' \
> test-dee-results.html ) \
&& ( xdg-open test-dee-results.html )
#run make test as part of make check
#check-local: test test-python
check-local: test
clean-generic:
rm -rf test-dee-results.xml test-dee-results.html dee-test-resource-manager
dee-1.2.7+15.04.20150304/tests/model-helper-replace.c 0000644 0000153 0000161 00000003673 12475676210 022124 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
/* Joins an existing model, and then tries to define the column types,
* and add two rows with these types */
gint
main (gint argc, gchar *argv[])
{
DeePeer *peer;
DeeModel *model;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
{
peer = DEE_PEER (g_object_new (DEE_TYPE_PEER, "swarm-name", argv[1],
"swarm-owner", TRUE, NULL));
model = dee_shared_model_new_for_peer (peer);
dee_model_set_schema (model, "i", "s", NULL);
}
else
{
g_critical ("Missing swarm name! Use \"%s [swarm name]\"", argv[0]);
return 1;
}
if (gtx_wait_for_signal (G_OBJECT (model), 300, "notify::synchronized", NULL))
{
g_critical ("Model never synchronized");
return 1;
}
g_assert (dee_peer_is_swarm_leader (peer));
dee_model_append (model, 27, "skunkworks");
dee_model_append (model, 68, "wumbo");
dee_shared_model_flush_revision_queue_sync (DEE_SHARED_MODEL (model));
gtx_yield_main_loop (500);
/* And we're still the leader */
g_assert (dee_peer_is_swarm_leader (peer));
gtx_assert_last_unref (model);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-serializable.c 0000644 0000153 0000161 00000015456 12475676210 021563 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Neil Jagdish Patel
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
#include
typedef struct
{
DeeModel *orig;
DeeModel *copy;
} Fixture;
static void sequence_model_setup (Fixture *fix, gconstpointer data);
static void sequence_model_teardown (Fixture *fix, gconstpointer data);
static void shared_model_setup (Fixture *fix, gconstpointer data);
static void shared_model_teardown (Fixture *fix, gconstpointer data);
static void test_model_zero_rows (Fixture *fix, gconstpointer data);
static void test_model_one_rows (Fixture *fix, gconstpointer data);
static void test_model_two_rows (Fixture *fix, gconstpointer data);
static void test_model_non_zero_seqnum_offset (Fixture *fix, gconstpointer data);
void
test_serializable_create_suite (void)
{
#define SEQUENCE_MODEL_DOMAIN "/Serializable/SequenceModel"
#define SHARED_MODEL_DOMAIN "/Serializable/SharedModel"
g_test_add (SEQUENCE_MODEL_DOMAIN"/ZeroRows", Fixture, 0,
sequence_model_setup, test_model_zero_rows, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/ZeroRows", Fixture, 0,
shared_model_setup, test_model_zero_rows, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/OneRows", Fixture, 0,
sequence_model_setup, test_model_one_rows, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/OneRows", Fixture, 0,
sequence_model_setup, test_model_one_rows, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/TwoRows", Fixture, 0,
sequence_model_setup, test_model_two_rows, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/TwoRows", Fixture, 0,
shared_model_setup, test_model_two_rows, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/NonZeroSeqnumOffset", Fixture, 0,
sequence_model_setup, test_model_non_zero_seqnum_offset, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/NonZeroSeqnumOffset", Fixture, 0,
shared_model_setup, test_model_non_zero_seqnum_offset, shared_model_teardown);
}
static void
sequence_model_setup (Fixture *fix, gconstpointer data)
{
fix->orig = dee_sequence_model_new ();
dee_model_set_schema (fix->orig, "i", "s", NULL);
fix->copy = NULL;
g_assert (DEE_IS_SEQUENCE_MODEL (fix->orig));
}
static void
sequence_model_teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->orig);
fix->orig = NULL;
if (fix->copy)
g_object_unref (fix->copy);
fix->copy = NULL;
}
static void
shared_model_setup (Fixture *fix, gconstpointer data)
{
fix->orig = dee_shared_model_new ("org.example.ThisIsNotATest");
dee_model_set_schema (fix->orig, "i", "s", NULL);
fix->copy = NULL;
g_assert (DEE_IS_SHARED_MODEL (fix->orig));
}
static void
shared_model_teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->orig);
fix->orig = NULL;
if (fix->copy)
g_object_unref (fix->copy);
fix->copy = NULL;
}
static void
dee_assert_cmpmodel (DeeModel *m1, DeeModel *m2)
{
guint i, j, n_cols, n_rows;
DeeModelIter *row1, *row2;
GVariant *v1, *v2;
g_assert (m1 != NULL);
g_assert (m2 != NULL);
g_assert (DEE_IS_MODEL (m1));
g_assert (DEE_IS_MODEL (m2));
g_assert_cmpint (dee_model_get_n_columns (m1), ==, dee_model_get_n_columns (m2));
g_assert_cmpint (dee_model_get_n_rows (m1), ==, dee_model_get_n_rows (m2));
n_cols = dee_model_get_n_columns (m1);
for (i = 0; i < n_cols; i++)
{
g_assert_cmpstr (dee_model_get_column_schema (m1, i), ==, dee_model_get_column_schema (m1, i));
}
n_rows = dee_model_get_n_rows (m1);
for (i = 0; i < n_rows; i++)
{
row1 = dee_model_get_iter_at_row (m1, i);
row2 = dee_model_get_iter_at_row (m2, i);
for (j = 0; j < n_cols; j++)
{
v1 = dee_model_get_value (m1, row1, j);
v2 = dee_model_get_value (m2, row2, j);
g_assert (g_variant_equal (v1, v2));
g_variant_unref (v1);
g_variant_unref (v2);
}
}
if (DEE_IS_SERIALIZABLE_MODEL (m1) && DEE_IS_SERIALIZABLE_MODEL (m2))
{
g_assert_cmpuint(dee_serializable_model_get_seqnum (m1), ==, dee_serializable_model_get_seqnum (m2));
}
if (DEE_IS_SHARED_MODEL (m1) && DEE_IS_SHARED_MODEL (m2))
{
g_assert_cmpstr (dee_shared_model_get_swarm_name (DEE_SHARED_MODEL (m1)), ==, dee_shared_model_get_swarm_name (DEE_SHARED_MODEL (m2)));
}
}
static void
test_model_zero_rows (Fixture *fix, gconstpointer data)
{
GVariant *vdata;
vdata = dee_serializable_externalize (DEE_SERIALIZABLE (fix->orig));
g_assert (vdata != NULL);
fix->copy = DEE_MODEL (dee_serializable_parse_external (vdata));
dee_assert_cmpmodel (fix->orig, fix->copy);
}
static void
test_model_one_rows (Fixture *fix, gconstpointer data)
{
GVariant *vdata;
dee_model_append (fix->orig, 27, "Hello world");
vdata = dee_serializable_externalize (DEE_SERIALIZABLE (fix->orig));
g_assert (vdata != NULL);
fix->copy = DEE_MODEL (dee_serializable_parse_external (vdata));
dee_assert_cmpmodel (fix->orig, fix->copy);
}
static void
test_model_two_rows (Fixture *fix, gconstpointer data)
{
GVariant *vdata;
dee_model_append (fix->orig, 27, "Hello world");
dee_model_append (fix->orig, 68, "Hola Mars");
vdata = dee_serializable_externalize (DEE_SERIALIZABLE (fix->orig));
g_assert (vdata != NULL);
fix->copy = DEE_MODEL (dee_serializable_parse_external (vdata));
dee_assert_cmpmodel (fix->orig, fix->copy);
}
static void
test_model_non_zero_seqnum_offset (Fixture *fix, gconstpointer data)
{
GVariant *vdata;
DeeModelIter *first_row;
first_row = dee_model_append (fix->orig, 27, "Hello world");
dee_model_append (fix->orig, 68, "Hola Mars");
dee_model_remove (fix->orig, first_row);
vdata = dee_serializable_externalize (DEE_SERIALIZABLE (fix->orig));
g_assert (vdata != NULL);
fix->copy = DEE_MODEL (dee_serializable_parse_external (vdata));
g_assert_cmpuint (1, ==, dee_model_get_n_rows (fix->copy));
g_assert_cmpuint (3, ==, dee_serializable_model_get_seqnum (fix->copy));
dee_assert_cmpmodel (fix->orig, fix->copy);
}
dee-1.2.7+15.04.20150304/tests/model-helper-clear6rows.c 0000644 0000153 0000161 00000005630 12475676210 022573 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
guint64 before_begin_seqnum, before_end_seqnum,
after_begin_seqnum, after_end_seqnum;
static void
_begin_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
before_begin_seqnum = begin_seqnum;
before_end_seqnum = end_seqnum;
}
static void
_end_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
after_begin_seqnum = begin_seqnum;
after_end_seqnum = end_seqnum;
}
static void
_row_removed (DeeModel *model, DeeModelIter *iter, GSList **removed)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*removed = g_slist_append (*removed, iter);
}
/* Expects a clone with 3 rows in it, and a later transaction appending 3 more
* rows and a clear.
*/
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
GSList *removed;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
g_signal_connect (model, "begin-transaction", G_CALLBACK (_begin_txn), NULL);
g_signal_connect (model, "end-transaction", G_CALLBACK (_end_txn), NULL);
if (gtx_wait_for_signal (G_OBJECT (model), 100000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
/* Listen for removes */
removed = NULL;
g_signal_connect (model, "row-removed", G_CALLBACK (_row_removed), &removed);
/* Wait for some RowsChanged signals */
gtx_yield_main_loop (1000);
g_assert_cmpint (g_slist_length (removed), ==, 6);
g_assert_cmpint (dee_model_get_n_rows(model), ==, 0);
/* We expected 3 additions and a clear - ie. 3 additions and 6 removals */
g_assert_cmpint (12, ==, (guint) dee_serializable_model_get_seqnum (model));
g_assert (before_begin_seqnum == after_begin_seqnum);
g_assert (before_end_seqnum == after_end_seqnum);
g_assert_cmpint (3, ==, (guint) before_begin_seqnum);
g_assert_cmpint (12, ==, (guint) before_end_seqnum);
gtx_assert_last_unref (model);
g_slist_free (removed);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-model-seqnums.c 0000644 0000153 0000161 00000011227 12475676210 021676 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
* Neil Jagdish Patel
*
*/
#include
#include
#include
typedef struct
{
DeeModel *model;
} SeqnumFixture;
static void setup (SeqnumFixture *fix, gconstpointer data);
static void teardown (SeqnumFixture *fix, gconstpointer data);
static void proxy_setup (SeqnumFixture *fix, gconstpointer data);
static void proxy_teardown (SeqnumFixture *fix, gconstpointer data);
static void txn_setup (SeqnumFixture *fix, gconstpointer data);
static void txn_teardown (SeqnumFixture *fix, gconstpointer data);
static void test_getset_last (SeqnumFixture *fix, gconstpointer data);
static void test_auto_inc (SeqnumFixture *fix, gconstpointer data);
void
test_model_seqnums_create_suite (void)
{
#define SEQ_DOMAIN "/Model/Sequence/Seqnums"
#define PROXY_DOMAIN "/Model/Proxy/Seqnums"
#define TXN_DOMAIN "/Model/Transaction/Seqnums"
g_test_add (SEQ_DOMAIN"/GetSet", SeqnumFixture, 0,
setup, test_getset_last, teardown);
g_test_add (PROXY_DOMAIN"/GetSet", SeqnumFixture, 0,
proxy_setup, test_getset_last, proxy_teardown);
g_test_add (TXN_DOMAIN"/GetSet", SeqnumFixture, 0,
txn_setup, test_getset_last, txn_teardown);
g_test_add (SEQ_DOMAIN"/AutoInc", SeqnumFixture, 0,
setup, test_auto_inc, teardown);
g_test_add (PROXY_DOMAIN"/AutoInc", SeqnumFixture, 0,
proxy_setup, test_auto_inc, proxy_teardown);
g_test_add (TXN_DOMAIN"/AutoInc", SeqnumFixture, 0,
txn_setup, test_auto_inc, txn_teardown);
}
static void
setup (SeqnumFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "i", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
g_assert_cmpint (1, ==, dee_model_get_n_columns (fix->model));
g_assert_cmpstr ("i", ==, dee_model_get_column_schema (fix->model, 0));
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
}
static void
teardown (SeqnumFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
}
static void
proxy_setup (SeqnumFixture *fix, gconstpointer data)
{
setup (fix, data);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL,
"back-end", fix->model,
NULL);
g_assert (DEE_IS_PROXY_MODEL (fix->model));
}
static void
proxy_teardown (SeqnumFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_PROXY_MODEL (fix->model));
g_object_unref (fix->model);
}
static void
txn_setup (SeqnumFixture *fix, gconstpointer data)
{
DeeModel *dum;
setup (fix, data);
dum = fix->model;
fix->model = dee_transaction_new (dum);
g_object_unref (dum);
g_assert (DEE_IS_TRANSACTION (fix->model));
}
static void
txn_teardown (SeqnumFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_TRANSACTION (fix->model));
g_object_unref (fix->model);
}
static void
test_getset_last (SeqnumFixture *fix, gconstpointer data)
{
DeeModel *model = fix->model;
g_assert_cmpint (0, ==, dee_serializable_model_get_seqnum (model));
dee_serializable_model_set_seqnum (model, 68);
g_assert_cmpint (68, ==, dee_serializable_model_get_seqnum (model));
}
static void
test_auto_inc (SeqnumFixture *fix, gconstpointer data)
{
DeeModel *model = fix->model;
g_assert_cmpint (0, ==, dee_serializable_model_get_seqnum (model));
dee_model_append (fix->model, 9);
g_assert_cmpint (1, ==, dee_serializable_model_get_seqnum (model));
dee_model_set (fix->model, dee_model_get_first_iter (fix->model), 10);
g_assert_cmpint (2, ==, dee_serializable_model_get_seqnum (model));
dee_model_clear (fix->model);
g_assert_cmpint (3, ==, dee_serializable_model_get_seqnum (model));
dee_model_append (fix->model, 11);
dee_model_append (fix->model, 12);
dee_model_append (fix->model, 13);
g_assert_cmpint (6, ==, dee_serializable_model_get_seqnum (model));
dee_model_clear (fix->model);
g_assert_cmpint (9, ==, dee_serializable_model_get_seqnum (model));
}
dee-1.2.7+15.04.20150304/tests/model-helper-insert1row.c 0000644 0000153 0000161 00000004506 12475676210 022622 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
static void
_row_added (DeeModel *model, DeeModelIter *iter, GSList **rows_so_far)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*rows_so_far = g_slist_append (*rows_so_far, iter);
}
/* Expects and empty clone and three rows-added signals */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
GSList *rows_added;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
/* Wait until we find the leader */
if (gtx_wait_for_signal (G_OBJECT (model), 1000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
/* Listen for changes */
rows_added = NULL;
g_signal_connect (model, "row-added", G_CALLBACK (_row_added), &rows_added);
/* Wait for some RowsAdded signals */
gtx_yield_main_loop (1000);
/* Check that we got what we expected */
g_assert_cmpint (g_slist_length (rows_added), == , 1);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 4);
iter = (DeeModelIter*) g_slist_nth (rows_added, 0)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 27);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "twentyseven");
gtx_assert_last_unref (model);
g_slist_free (rows_added);
return 0;
}
dee-1.2.7+15.04.20150304/tests/model-helper-clear3add5.c 0000644 0000153 0000161 00000007636 12475676210 022423 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
guint64 before_begin_seqnum, before_end_seqnum,
after_begin_seqnum, after_end_seqnum;
static void
_begin_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
before_begin_seqnum = begin_seqnum;
before_end_seqnum = end_seqnum;
}
static void
_end_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
after_begin_seqnum = begin_seqnum;
after_end_seqnum = end_seqnum;
}
static void
_row_added (DeeModel *model, DeeModelIter *iter, GSList **added)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*added = g_slist_append (*added, iter);
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
GSList *added;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
g_signal_connect (model, "begin-transaction", G_CALLBACK (_begin_txn), NULL);
g_signal_connect (model, "end-transaction", G_CALLBACK (_end_txn), NULL);
if (gtx_wait_for_signal (G_OBJECT (model), 100000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
/* Listen for adds */
added = NULL;
g_signal_connect (model, "row-added", G_CALLBACK (_row_added), &added);
/* We expect the model to be cleared and 5 rows added */
gtx_yield_main_loop (1000);
/* The transaction could be optimized in the future and actually just add
* the two missing rows */
g_assert (g_slist_length (added) == 5 || g_slist_length (added) == 2);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 5);
/* Check ordering and contents */
iter = dee_model_get_first_iter (model);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), ==, 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), ==, "zero");
iter = dee_model_next (model, iter);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), ==, 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), ==, "one");
iter = dee_model_next (model, iter);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), ==, 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), ==, "two");
iter = dee_model_next (model, iter);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), ==, 3);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), ==, "three");
iter = dee_model_next (model, iter);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), ==, 4);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), ==, "four");
/* Disregarding the hypothetical optimization mentioned above we need the
* correct seqnum */
g_assert_cmpint (11, ==, (guint) dee_serializable_model_get_seqnum (model));
g_assert (before_begin_seqnum == after_begin_seqnum);
g_assert (before_end_seqnum == after_end_seqnum);
g_assert_cmpint (3, ==, (guint) before_begin_seqnum);
g_assert_cmpint (11, ==, (guint) before_end_seqnum);
gtx_assert_last_unref (model);
g_slist_free (added);
return 0;
}
dee-1.2.7+15.04.20150304/tests/model-helper-remove3rows.c 0000644 0000153 0000161 00000006570 12475676210 023003 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
static void
_row_removed (DeeModel *model, DeeModelIter *iter, GSList **changes_so_far)
{
guint pos;
pos = dee_model_get_position (model, iter);
/* Yes, I _know_ that append() is slow, but this is a test! */
*changes_so_far = g_slist_append (*changes_so_far, GUINT_TO_POINTER (pos));
}
/* Expects a clone with 5 rows in it. Rows 0, 4, and 2 will be removed remotely,
* in that order. Note that removed a row shifts the order of those below it,
* so we expect to see removals of rows 0, 3, and 1, when correcting for row
* shifts.
*
* This should leave the original rows 1 and 3, now in positions 0, and 1.
*/
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter, *orig_iter1, *orig_iter3;
GSList *changes;
guint pos;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
if (gtx_wait_for_signal (G_OBJECT (model), 1000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 5);
/* We should end up with the original rows 1 and 3, so
* save pointers to those rows */
orig_iter1 = dee_model_get_iter_at_row (model, 1);
orig_iter3 = dee_model_get_iter_at_row (model, 3);
/* Listen for changes */
changes = NULL;
g_signal_connect (model, "row-removed", G_CALLBACK (_row_removed), &changes);
/* Wait for some RowsRmoved signals */
gtx_yield_main_loop (1000);
/* Check that we got what we expected */
g_assert_cmpint (g_slist_length (changes), == , 3);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 2);
pos = GPOINTER_TO_UINT (g_slist_nth (changes, 0)->data);
g_assert_cmpint (pos, == , 0);
pos = GPOINTER_TO_UINT (g_slist_nth (changes, 1)->data);
g_assert_cmpint (pos, == , 3);
pos = GPOINTER_TO_UINT (g_slist_nth (changes, 2)->data);
g_assert_cmpint (pos, == , 1);
/* Now assert that the model contains the data from the original
* rows 1 and 3 */
iter = dee_model_get_iter_at_row (model, 0);
if (orig_iter1 != iter)
g_error ("Expected original row 1 on position 0. Found row with data '%s'",
dee_model_get_string (model, iter, 1));
iter = dee_model_get_iter_at_row (model, 1);
if (orig_iter3 != iter)
g_error ("Expected original row 3 on position 1. Found row with data '%s'",
dee_model_get_string (model, iter, 1));
gtx_assert_last_unref (model);
g_slist_free (changes);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-benchmark.c 0000644 0000153 0000161 00000042336 12475676210 021044 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
#include
typedef struct _Benchmark Benchmark;
typedef void (*BenchmarkFunc) (Benchmark *benchmark);
typedef void (*BenchmarkSetup) (Benchmark *benchmark);
typedef void (*BenchmarkTeardown) (Benchmark *benchmark);
typedef struct {
gdouble elapsed;
} RunData;
struct _Benchmark {
const gchar *name;
BenchmarkSetup benchmark_setup;
BenchmarkFunc benchmark_func;
BenchmarkTeardown benchmark_teardown;
guint n_runs;
RunData *runs;
gpointer state;
};
static GList *benchmarks = NULL;
static void
add_benchmark (Benchmark *benchmark)
{
benchmarks = g_list_append (benchmarks, benchmark);
}
static void
run_benchmark (Benchmark *bench)
{
GTimer *timer;
guint i;
gdouble total_runtime, avg_runtime, std_dev, coeff_of_var;
const gchar *coeff_of_var_msg;
bench->runs = g_new0 (RunData, bench->n_runs + 1);
timer = g_timer_new ();
total_runtime = 0;
bench->benchmark_setup (bench);
g_printf ("=== %s ===\n", bench->name);
for (i = 0; i < bench->n_runs; i++)
{
g_timer_start (timer);
bench->benchmark_func (bench);
bench->runs[i].elapsed = g_timer_elapsed (timer, NULL);
total_runtime += bench->runs[i].elapsed;
/* Some benchmarks will reset their own state */
if (bench->state == NULL)
bench->benchmark_setup (bench);
}
/* Compute average runtime */
avg_runtime = total_runtime / bench->n_runs;
/* Compute standard deviation */
std_dev = 0;
for (i = 0; i < bench->n_runs; i++)
{
gdouble delta = bench->runs[i].elapsed - avg_runtime;
std_dev += delta * delta;
}
std_dev = sqrt (std_dev / bench->n_runs);
coeff_of_var = (std_dev /avg_runtime) * 100;
/* This is not a very precise way of judging the quality,
* but better than rigorous hand waving */
if (coeff_of_var < 1.0)
coeff_of_var_msg = "super!";
else if (coeff_of_var < 5)
coeff_of_var_msg = "good";
else if (coeff_of_var < 10)
coeff_of_var_msg = "acceptable";
else
coeff_of_var_msg = "rejected!";
/* Print report */
g_printf ("Runs : %u\n", bench->n_runs);
g_printf ("Total runtime : %fs\n", total_runtime);
g_printf ("Avg. runtime : %fs\n", avg_runtime);
g_printf ("Std. deviation : %fs\n", std_dev);
g_printf ("Accuracy : %f%% [%s]\n", (100 - coeff_of_var), coeff_of_var_msg);
g_printf ("\n");
g_timer_destroy (timer);
bench->benchmark_teardown (bench);
// purposely leak bench->runs. Caller may want it
}
static void
run_benchmarks (gchar **prefixes)
{
GList *iter;
gchar **prefix;
for (iter = benchmarks; iter; iter = iter->next)
{
Benchmark *bench = (Benchmark*) iter->data;
if (prefixes == NULL)
run_benchmark (bench);
else
{
for (prefix = prefixes; *prefix; prefix++)
{
if (g_str_has_prefix (bench->name, *prefix))
{
run_benchmark (bench);
}
}
}
}
}
static void
bench_seqmodel_setup (Benchmark *bench)
{
DeeModel *model;
model = dee_sequence_model_new ();
dee_model_set_schema (model, "s", "s", "s", "u", "b", NULL);
bench->state = model;
}
static void
bench_seqmodel_named_setup (Benchmark *bench)
{
bench_seqmodel_setup (bench);
dee_model_set_column_names (bench->state,
"string1", "string2", "string3",
"count", "bool", NULL);
}
static void
bench_filter_model_collator_setup (Benchmark *bench)
{
DeeModel *fmodel, *base_model;
DeeFilter filter;
base_model = dee_sequence_model_new ();
dee_model_set_schema (base_model, "s", "s", "s", "u", "b", NULL);
dee_filter_new_collator (0, &filter);
fmodel = dee_filter_model_new (base_model, &filter);
g_object_unref (base_model);
bench->state = fmodel;
}
static void
bench_filter_model_collator_desc_setup (Benchmark *bench)
{
DeeModel *fmodel, *base_model;
DeeFilter filter;
base_model = dee_sequence_model_new ();
dee_model_set_schema (base_model, "s", "s", "s", "u", "b", NULL);
dee_filter_new_collator_desc (0, &filter);
fmodel = dee_filter_model_new (base_model, &filter);
g_object_unref (base_model);
bench->state = fmodel;
}
static gint
_cmp_uint (GVariant **row1, GVariant **row2, gpointer user_data)
{
return g_variant_get_uint32 (row1[3]) - g_variant_get_uint32 (row2[3]);
}
static void
bench_filter_model_sort_uint_setup (Benchmark *bench)
{
DeeModel *fmodel, *base_model;
DeeFilter filter;
base_model = dee_sequence_model_new ();
dee_model_set_schema (base_model, "s", "s", "s", "u", "b", NULL);
dee_filter_new_sort(_cmp_uint, NULL, NULL, &filter);
fmodel = dee_filter_model_new (base_model, &filter);
g_object_unref (base_model);
bench->state = fmodel;
}
static void
bench_seqmodel_read_string_setup (Benchmark *bench)
{
DeeModel *model;
guint limit = 25000, i;
model = dee_sequence_model_new ();
dee_model_set_schema (model, "s", "s", "s", "u", "b", NULL);
for (i = 0; i < limit; i++)
{
gchar *random_string = g_strdup_printf ("%"G_GINT32_FORMAT,
g_test_rand_int());
dee_model_prepend (model, random_string, "Hello world", "!", 42, TRUE);
g_free (random_string);
}
bench->state = model;
}
static void
bench_index_setup (Benchmark *bench)
{
DeeModel *model;
DeeIndex *index;
DeeModelReader reader;
guint limit = 25000, i;
model = dee_sequence_model_new ();
dee_model_reader_new_for_string_column (0, &reader);
dee_model_set_schema (model, "s", "s", "s", "u", "b", NULL);
index = DEE_INDEX (dee_tree_index_new (model, dee_analyzer_new (), &reader));
for (i = 0; i < limit; i++)
{
gchar *random_string = g_strdup_printf ("%"G_GINT32_FORMAT,
g_test_rand_int());
dee_model_prepend (model, random_string, "Hello world", "!", 42, TRUE);
g_free (random_string);
}
bench->state = index;
}
static void
bench_model_append_run (Benchmark *bench)
{
DeeModel *model;
guint limit = 2500, i;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
for (i = 0; i < limit; i++)
{
gchar *random_string = g_strdup_printf ("%"G_GINT32_FORMAT,
g_test_rand_int ());
dee_model_append (model, random_string, "Hello world", "!",
(guint32) g_test_rand_int (), TRUE);
g_free (random_string);
}
}
static void
bench_model_named_append_run (Benchmark *bench)
{
DeeModel *model;
GVariant **row_buf;
guint n_cols, i;
guint limit = 2500;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
n_cols = dee_model_get_n_columns (model);
row_buf = g_new0 (GVariant*, n_cols + 1);
for (i = 0; i < limit; i++)
{
gchar *random_string = g_strdup_printf ("%"G_GINT32_FORMAT,
g_test_rand_int ());
dee_model_build_named_row (model, row_buf,
"count", (guint32) g_test_rand_int (),
"string1", random_string,
"string2", "Hello world",
"string3", "!",
"bool", TRUE,
NULL);
dee_model_append_row (model, row_buf);
g_free (random_string);
}
}
static void
bench_model_prepend_run (Benchmark *bench)
{
DeeModel *model;
guint32 limit = 2500, i;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
for (i = 0; i < limit; i++)
{
gchar *random_string = g_strdup_printf ("%"G_GINT32_FORMAT,
g_test_rand_int ());
dee_model_prepend (model, random_string, "Hello world", "!",
(guint32)g_test_rand_int (), TRUE);
g_free (random_string);
}
}
static void
bench_model_sorted_run (Benchmark *bench)
{
DeeModel *model;
guint32 limit = 2500, i;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
for (i = 0; i < limit; i++)
{
gchar *random_string = g_strdup_printf ("%"G_GINT32_FORMAT,
g_test_rand_int ());
dee_model_insert_sorted (model, _cmp_uint, NULL, random_string,
"Hello world", "!", (guint32)g_test_rand_int (),
TRUE);
g_free (random_string);
}
}
static void
bench_model_read_string_run (Benchmark *bench)
{
DeeModel *model;
DeeModelIter *iter, *end;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
for (iter = dee_model_get_first_iter (model),
end = dee_model_get_last_iter (model);
iter != end; iter = dee_model_next (model, iter))
{
dee_model_get_string (model, iter, 0);
}
}
static void
bench_model_read_row_run (Benchmark *bench)
{
DeeModel *model;
DeeModelIter *iter, *end;
GVariant **row_buf;
guint n_cols, i;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
n_cols = dee_model_get_n_columns (model);
row_buf = g_new0 (GVariant*, n_cols + 1);
for (iter = dee_model_get_first_iter (model),
end = dee_model_get_last_iter (model);
iter != end; iter = dee_model_next (model, iter))
{
dee_model_get_row (model, iter, row_buf);
for (i = 0; i < n_cols; i++) g_variant_unref (row_buf[i]);
}
g_free (row_buf);
}
static void
bench_model_clear_run (Benchmark *bench)
{
DeeModel *model;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
dee_model_clear (model);
g_assert (dee_model_get_n_rows (model) == 0);
/* Force a re-run of the setup func */
bench->benchmark_teardown (bench);
}
static void
bench_model_walk_next_run (Benchmark *bench)
{
DeeModel *model;
DeeModelIter *iter, *end;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
for (iter = dee_model_get_first_iter (model),
end = dee_model_get_last_iter (model);
iter != end; iter = dee_model_next (model, iter))
{
}
}
static void
bench_model_walk_pos_run (Benchmark *bench)
{
DeeModel *model;
guint n_rows, i;
g_assert (DEE_IS_MODEL (bench->state));
model = DEE_MODEL (bench->state);
n_rows = dee_model_get_n_rows (model);
for (i = 0; i < n_rows; i++)
{
dee_model_get_iter_at_row (model, i);
}
}
static void
bench_index_prefix_search (Benchmark *bench)
{
DeeIndex *index;
guint i;
gchar *prefixes[] =
{
"-9", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
"1", "2", "3", "4", "5", "6", "7", "8", "9",
};
g_assert (DEE_IS_INDEX (bench->state));
index = DEE_INDEX (bench->state);
for (i = 0; i < G_N_ELEMENTS (prefixes); i++)
{
DeeResultSet *rs = dee_index_lookup (index, prefixes[i],
DEE_TERM_MATCH_PREFIX);
g_assert_cmpuint (dee_result_set_get_n_rows (rs), >, 0);
g_object_unref (G_OBJECT (rs));
}
}
static void
bench_gobject_teardown (Benchmark *bench)
{
GObject *obj;
if (bench->state)
{
obj = G_OBJECT (bench->state);
g_object_unref (obj);
bench->state = NULL;
}
}
Benchmark seqmodel_append = { "SequenceModel.append",
bench_seqmodel_setup,
bench_model_append_run,
bench_gobject_teardown,
100,
NULL };
Benchmark seqmodel_named_append = { "SequenceModel.append.named",
bench_seqmodel_named_setup,
bench_model_named_append_run,
bench_gobject_teardown,
100,
NULL };
Benchmark seqmodel_prepend = { "SequenceModel.prepend",
bench_seqmodel_setup,
bench_model_prepend_run,
bench_gobject_teardown,
100,
NULL };
Benchmark seqmodel_sorted = { "SequenceModel.sorted",
bench_seqmodel_setup,
bench_model_sorted_run,
bench_gobject_teardown,
100,
NULL };
Benchmark seqmodel_read_string = { "SequenceModel.read_string",
bench_seqmodel_read_string_setup,
bench_model_read_string_run,
bench_gobject_teardown,
100,
NULL };
Benchmark seqmodel_read_row = { "SequenceModel.read_row",
bench_seqmodel_read_string_setup,
bench_model_read_row_run,
bench_gobject_teardown,
100,
NULL };
Benchmark seqmodel_clear = { "SequenceModel.clear",
bench_seqmodel_read_string_setup,
bench_model_clear_run,
bench_gobject_teardown,
20,
NULL };
Benchmark seqmodel_walk_next = { "SequenceModel.walk_next",
bench_seqmodel_read_string_setup,
bench_model_walk_next_run,
bench_gobject_teardown,
1000,
NULL };
Benchmark seqmodel_walk_pos = { "SequenceModel.walk_pos",
bench_seqmodel_read_string_setup,
bench_model_walk_pos_run,
bench_gobject_teardown,
1000,
NULL };
Benchmark filtermodel_collate = { "FilterModel.collate",
bench_filter_model_collator_setup,
bench_model_prepend_run,
bench_gobject_teardown,
100,
NULL };
Benchmark filtermodel_collate_desc = { "FilterModel.collate_desc",
bench_filter_model_collator_desc_setup,
bench_model_prepend_run,
bench_gobject_teardown,
100,
NULL };
Benchmark filtermodel_sort_uint = { "FilterModel.sort_uint",
bench_filter_model_sort_uint_setup,
bench_model_prepend_run,
bench_gobject_teardown,
100,
NULL };
Benchmark tree_index_prefix_search = { "TreeIndex.prefix_search",
bench_index_setup,
bench_index_prefix_search,
bench_gobject_teardown,
25,
NULL };
/* Arguments are interpreted as prefixes that benchmark names must match
* in order to be run */
gint
main (gint argc, gchar *argv[])
{
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
g_test_init (&argc, &argv, NULL);
/* Extract NULL terminated array of prefixes from arguments */
int i;
gchar **prefixes = g_new0 (gchar*, argc);
for (i = 1; i < argc; i++)
{
prefixes[i-1] = argv[i];
}
add_benchmark (&seqmodel_append);
add_benchmark (&seqmodel_named_append);
add_benchmark (&seqmodel_prepend);
add_benchmark (&seqmodel_sorted);
add_benchmark (&seqmodel_read_string);
add_benchmark (&seqmodel_read_row);
add_benchmark (&seqmodel_clear);
add_benchmark (&seqmodel_walk_next);
add_benchmark (&seqmodel_walk_pos);
add_benchmark (&filtermodel_collate);
add_benchmark (&filtermodel_collate_desc);
add_benchmark (&filtermodel_sort_uint);
add_benchmark (&tree_index_prefix_search);
run_benchmarks (argc > 1 ? prefixes : NULL);
g_free (prefixes);
return 0;
}
dee-1.2.7+15.04.20150304/tests/model-helper-schemaless.c 0000644 0000153 0000161 00000003427 12475676210 022635 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
/* Joins an existing model, and then tries to define the column types,
* and add two rows with these types */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
/* Important: In this test it's the *slave* that sets the schema,
* the leader is schemaless at this point in time, and will
* pick up the schema from the initial transaction from the slave
*/
dee_model_set_schema (model, "i", "s", NULL);
if (gtx_wait_for_signal (G_OBJECT (model), 300, "notify::synchronized", NULL))
{
g_critical ("Model never synchronized");
return 1;
}
dee_model_append (model, 27, "skunkworks");
dee_model_append (model, 68, "wumbo");
gtx_yield_main_loop (500);
gtx_assert_last_unref (model);
return 0;
}
dee-1.2.7+15.04.20150304/tests/model-helper-clone3rows.c 0000644 0000153 0000161 00000004401 12475676210 022575 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
static void
row_added (DeeModel *model, DeeModelIter *iter, gpointer data)
{
gint *num_added = (gint*) data;
(*num_added)++;
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
gint num_added;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
g_set_prgname ("model-helper");
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
num_added = 0;
g_signal_connect (model, "row-added", G_CALLBACK (row_added), &num_added);
if (gtx_wait_for_signal (G_OBJECT (model), 100000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
iter = dee_model_get_iter_at_row (model, 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "zero");
iter = dee_model_get_iter_at_row (model, 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "one");
iter = dee_model_get_iter_at_row (model, 2);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "two");
gtx_assert_last_unref (model);
g_assert_cmpint (num_added, ==, 3);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-dee.c 0000644 0000153 0000161 00000005400 12475676210 017636 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by Neil Jagdish Patel
*
*/
#include "config.h"
#include
#include
#include
void test_model_column_create_suite (void);
void test_model_complex_column_create_suite (void);
void test_model_rows_create_suite (void);
void test_model_signals_create_suite (void);
void test_model_seqnums_create_suite (void);
void test_model_tags_create_suite (void);
void test_filter_model_create_suite (void);
void test_term_list_create_suite (void);
void test_hash_index_create_suite (void);
void test_analyzer_create_suite (void);
void test_model_readers_create_suite (void);
void test_glist_result_set_create_suite (void);
void test_serializable_create_suite (void);
void test_resource_manager_create_suite (void);
void test_transaction_create_suite (void);
#ifdef HAVE_GTX
void test_model_interactions_create_suite(void);
void test_peer_interactions_create_suite(void);
void test_client_server_interactions_create_suite(void);
#endif /* HAVE_GTX */
#ifdef HAVE_ICU
void test_icu_create_suite(void);
#endif /* HAVE_ICU */
gint
main (gint argc, gchar *argv[])
{
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
g_test_init (&argc, &argv, NULL);
setlocale (LC_ALL, "");
test_model_column_create_suite ();
test_model_complex_column_create_suite ();
test_model_rows_create_suite ();
test_model_signals_create_suite ();
test_model_seqnums_create_suite ();
test_model_tags_create_suite ();
test_filter_model_create_suite ();
test_term_list_create_suite ();
test_hash_index_create_suite ();
test_analyzer_create_suite ();
test_model_readers_create_suite ();
test_glist_result_set_create_suite ();
test_serializable_create_suite ();
test_resource_manager_create_suite ();
test_transaction_create_suite ();
#ifdef HAVE_GTX
test_model_interactions_create_suite();
test_peer_interactions_create_suite();
test_client_server_interactions_create_suite();
#else
g_message ("Interactions' test suite disabled. GTX not found. You can download GTX from https://launchpad.net/gtx");
#endif /* HAVE_GTX */
#ifdef HAVE_ICU
test_icu_create_suite ();
#endif
return g_test_run ();
}
dee-1.2.7+15.04.20150304/tests/test-peer-interactions.c 0000644 0000153 0000161 00000006461 12475676210 022544 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
#include
#define TIMEOUT 100
#define PEER_NAME "com.canonical.Dee.Peer.Tests.Interactions"
/* A command line that launches the appropriate peer-helper-* executable,
* giving $name as first argument */
#define PEER_HELPER(helper,name) \
(gchar *[]) { "./peer-helper-"#helper, name, NULL }
typedef struct
{
DeePeer *peer;
} Fixture;
static void peer_setup (Fixture *fix, gconstpointer data);
static void peer_teardown (Fixture *fix, gconstpointer data);
static void test_allocation (Fixture *fix, gconstpointer data);
static void test_become_leader (Fixture *fix, gconstpointer data);
static void test_1peer (Fixture *fix, gconstpointer data);
void
test_peer_interactions_create_suite (void)
{
#define DOMAIN "/Peer/Interactions"
g_test_add (DOMAIN"/Allocation", Fixture, 0,
peer_setup, test_allocation, peer_teardown);
g_test_add (DOMAIN"/BecomeLeader", Fixture, 0,
peer_setup, test_become_leader, peer_teardown);
g_test_add (DOMAIN"/OnePeer", Fixture, 0,
peer_setup, test_1peer, peer_teardown);
}
static void
peer_setup (Fixture *fix, gconstpointer data)
{
fix->peer = dee_peer_new (PEER_NAME);
g_assert_cmpint (0, ==, dee_peer_is_swarm_leader (fix->peer));
g_assert (DEE_IS_PEER (fix->peer));
}
static void
peer_teardown (Fixture *fix, gconstpointer data)
{
gtx_assert_last_unref (fix->peer);
/* Spin the mainloop a bit to check if we have any post-test
* async effect crashing us */
gtx_yield_main_loop (200);
}
static void
test_allocation (Fixture *fix, gconstpointer data)
{
/* Do nothing, this test basically just asserts that
* the fix->peer is cleaned up after immediate construction */
}
static void
test_become_leader (Fixture *fix, gconstpointer data)
{
gtx_wait_for_signal (G_OBJECT (fix->peer), TIMEOUT,
"notify::swarm-leader", NULL);
/* Assert that we have become swarm leaders.
* No other peers should be running */
g_assert_cmpint (0, !=, dee_peer_is_swarm_leader (fix->peer));
}
static void
test_1peer (Fixture *fix, gconstpointer data)
{
/* Wait for us to become swarm leaders */
gtx_wait_for_signal (G_OBJECT (fix->peer), TIMEOUT,
"notify::swarm-leader", NULL);
g_assert_cmpint (0, !=, dee_peer_is_swarm_leader (fix->peer));
/* We are now leaders - launch the helper */
if (gtx_wait_for_command (TESTDIR,
PEER_HELPER (1peer, PEER_NAME),
1000))
g_critical ("Peer helper timed out");
gtx_assert_last_command_status (0);
}
dee-1.2.7+15.04.20150304/tests/model-helper-introspect.c 0000644 0000153 0000161 00000006161 12475676210 022676 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
#include
static gchar*
build_model_path (const gchar *model_name)
{
gchar *dum = g_strdup (model_name);
gchar *path;
path = g_strconcat ("/com/canonical/dee/model/",
g_strdelimit (dum, ".", '/'),
NULL);
g_free (dum);
return path;
}
/* Does DBus introspection on a remote DeeModel */
gint
main (gint argc, gchar *argv[])
{
GDBusConnection *conn;
gchar *model_path;
gchar *introspection_data;
GError *error;
GVariant *introspection_value;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
error = NULL;
conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (error != NULL)
{
g_critical ("Unable to connect to session bus: %s", error->message);
g_error_free (error);
return 1;
}
model_path = build_model_path (argv[1]);
error = NULL;
introspection_value =
g_dbus_connection_call_sync (conn,
argv[1], /* name */
model_path, /* obj path */
"org.freedesktop.DBus.Introspectable",
"Introspect", /* member */
NULL, /* arguments */
G_VARIANT_TYPE ("(s)"), /* repl type*/
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */
NULL, /* cancel */
&error);
if (error != NULL)
{
g_critical ("Unable to get introspection data: %s", error->message);
g_error_free (error);
return 2;
}
if (introspection_value == NULL)
{
g_critical ("Introspection data was NULL");
return 3;
}
g_variant_get_child (introspection_value, 0, "s", &introspection_data);
if (strstr (introspection_data, "Clone") == NULL)
{
g_critical ("Introspection data does not declare Clone method:\n%s",
introspection_data);
return 4;
}
g_variant_unref (introspection_value);
g_free (introspection_data);
g_free (model_path);
g_object_unref (conn);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-transaction.c 0000644 0000153 0000161 00000120022 12475676210 021424 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
typedef struct
{
DeeModel *txn;
DeeModel *model;
} Fixture;
static void setup (Fixture *fix, gconstpointer data);
static void setup_proxy (Fixture *fix, gconstpointer data);
static void setup_shared (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup (Fixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", NULL);
/* The txn must be created during the tests because we need to verify how
* it works when constructed on top of various states of the fix->model */
}
static void
setup_basic_types (Fixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "b", "y", "i", "u", "x", "t", "d", "s", NULL);
/* The txn must be created during the tests because we need to verify how
* it works when constructed on top of various states of the fix->model */
}
static void
setup_proxy (Fixture *fix, gconstpointer data)
{
DeeModel *backend = dee_sequence_model_new ();
dee_model_set_schema (backend, "s", "i", NULL);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL, "back-end", backend, NULL);
/* The txn must be created during the tests because we need to verify how
* it works when constructed on top of various states of the fix->model */
g_object_unref (backend);
}
static void
setup_shared (Fixture *fix, gconstpointer data)
{
fix->model = dee_shared_model_new ("my.test.Model");
dee_model_set_schema (fix->model, "s", "i", NULL);
/* The txn must be created during the tests because we need to verify how
* it works when constructed on top of various states of the fix->model */
}
static void
teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
if (fix->txn)
g_object_unref (fix->txn);
}
static void
test_adopt_schema (Fixture *fix, gconstpointer data)
{
fix->txn = dee_transaction_new (fix->model);
g_assert_cmpint (dee_model_get_n_columns (fix->txn), == , 2);
g_assert_cmpstr (dee_model_get_column_schema (fix->txn, 0), ==, "s");
g_assert_cmpstr (dee_model_get_column_schema (fix->txn, 1), ==, "i");
g_assert (dee_transaction_get_target (DEE_TRANSACTION (fix->txn)) == fix->model);
}
static void
test_target_0_add_1 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *txn_iter;
gchar *s;
int i;
GError *error;
/**
* Target:
* Txn: I
*/
fix->txn = dee_transaction_new (fix->model);
/* Add one row to txn */
txn_iter = dee_model_append (fix->txn, "I", 1);
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->txn));
dee_model_get (fix->txn, txn_iter, &s, &i);
g_assert_cmpstr ("I", ==, s);
g_assert_cmpint (1, ==, i);
/* Commit and verify target */
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
iter = dee_model_get_first_iter (fix->model);
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("I", ==, s);
g_assert_cmpint (1, ==, i);
}
static void
test_target_1_add_1 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *txn_iter, *txn_end_iter;
gchar *s;
int i;
GError *error;
/**
* Target: A
* Txn: A, I
*/
/* The point of this test is that with 1 row in the target and 1 new row
* in the txn we can easily test out the behaviour when stepping back and
* forth over old and new rows in the txn */
iter = dee_model_append (fix->model, "TwentySeven", 27);
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
txn_iter = dee_model_get_first_iter (fix->txn);
g_assert (txn_iter == iter);
/* Append a row to txn and assert that txn and target are both as expected */
txn_iter = dee_model_append (fix->txn, "Append", 7);
g_assert (txn_iter != iter);
/* Orig row is unmodified */
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
/* New row is in txn */
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->txn));
g_assert (txn_iter == dee_model_next (fix->txn, iter));
g_assert (iter == dee_model_get_first_iter (fix->txn));
g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, txn_iter)));
dee_model_get (fix->txn, txn_iter, &s, &i);
g_assert_cmpstr ("Append", ==, s);
g_assert_cmpint (7, ==, i);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
/* New row not in target */
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
/* txn end iter is shared with target */
txn_end_iter = dee_model_get_last_iter (fix->txn);
g_assert (txn_end_iter == dee_model_get_last_iter (fix->model));
/* Check that we can step backwards */
g_assert (txn_iter == dee_model_prev (fix->txn, txn_end_iter));
g_assert (iter == dee_model_prev (fix->txn, txn_iter));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("Append", ==, s);
g_assert_cmpint (7, ==, i);
}
static void
test_target_1_change_1 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *txn_iter, *txn_end_iter;
gchar *s;
int i;
GError *error;
/*
* Target: A
* Txn: A'
*/
iter = dee_model_append (fix->model, "TwentySeven", 27);
/* Historically the pristine target seqmodel has had a bug here,
* make sure we don't loose sleep over it ;-) */
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (iter != dee_model_get_last_iter (fix->model));
g_assert (!dee_model_is_last (fix->model, iter));
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
txn_iter = dee_model_get_first_iter (fix->txn);
g_assert (txn_iter == iter);
/* Change the row in txn and assert that it looks right */
dee_model_set (fix->txn, iter, "TwentyOne", 21);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
g_assert (iter == dee_model_get_first_iter (fix->txn));
/* Change is not seen in target */
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
g_assert (iter == dee_model_get_first_iter (fix->model));
/* We can step to the end iter, and it is the same as that of the target */
txn_end_iter = dee_model_get_last_iter (fix->txn);
g_assert (dee_model_is_last (fix->txn, txn_end_iter));
g_assert (txn_end_iter == dee_model_next (fix->txn, iter));
g_assert (txn_end_iter == dee_model_get_last_iter (fix->model));
/* We can step back from the end iter to the changed row */
g_assert (iter == dee_model_prev (fix->txn, txn_end_iter));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
}
static void
test_target_2_add_3 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter0, *iter1, *txn_iter, *txn_middle, *end;
gchar *s;
int i;
GError *error;
/* Target: A, B
* Txn: I, A, II, B, III
* */
iter0 = dee_model_append (fix->model, "A", 0);
iter1 = dee_model_append (fix->model, "B", 1);
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
txn_iter = dee_model_get_first_iter (fix->txn);
g_assert (txn_iter == iter0);
dee_model_get (fix->txn, txn_iter, &s, &i);
g_assert_cmpstr ("A", ==, s);
g_assert_cmpint (0, ==, i);
txn_iter = dee_model_next (fix->txn, txn_iter);
g_assert (txn_iter == iter1);
dee_model_get (fix->txn, txn_iter, &s, &i);
g_assert_cmpstr ("B", ==, s);
g_assert_cmpint (1, ==, i);
/* Assert end iters are the same */
end = dee_model_get_last_iter (fix->txn);
g_assert (end == dee_model_get_last_iter (fix->model));
/* Prepend one row to txn and
* assert that txn and target are both as expected */
txn_iter = dee_model_prepend (fix->txn, "I", 11);
g_assert (txn_iter != iter0 && txn_iter != iter1 && txn_iter != end);
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->txn));
dee_model_get (fix->txn, txn_iter, &s, &i);
g_assert_cmpstr ("I", ==, s);
g_assert_cmpint (11, ==, i);
g_assert (iter0 == dee_model_next (fix->txn, txn_iter));
g_assert (iter1 == dee_model_next (fix->txn, iter0));
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
/* Append one row to txn */
txn_iter = dee_model_append (fix->txn, "III", 13);
g_assert (txn_iter != iter0 && txn_iter != iter1 && txn_iter != end);
g_assert_cmpint (4, ==, dee_model_get_n_rows (fix->txn));
dee_model_get (fix->txn, txn_iter, &s, &i);
g_assert_cmpstr ("III", ==, s);
g_assert_cmpint (13, ==, i);
g_assert (end == dee_model_next (fix->txn, txn_iter));
g_assert (txn_iter == dee_model_next (fix->txn, iter1));
g_assert (iter1 == dee_model_next (fix->txn, iter0));
g_assert (iter0 == dee_model_next (fix->txn, dee_model_get_first_iter (fix->txn)));
g_assert (txn_iter == dee_model_prev (fix->txn, end));
g_assert (iter1 == dee_model_prev (fix->txn, txn_iter));
g_assert (iter0 == dee_model_prev (fix->txn, iter1));
g_assert (dee_model_is_first (fix->txn, dee_model_prev (fix->txn, iter0)));
g_assert (dee_model_is_last (fix->txn, end));
/* Insert one row in the middle of txn */
txn_middle = dee_model_insert_before (fix->txn, iter1, "II", 12);
g_assert (txn_middle != iter0 && txn_middle != iter1 && txn_middle != end);
g_assert_cmpint (5, ==, dee_model_get_n_rows (fix->txn));
dee_model_get (fix->txn, txn_middle, &s, &i);
g_assert_cmpstr ("II", ==, s);
g_assert_cmpint (12, ==, i);
g_assert (iter0 == dee_model_prev (fix->txn, txn_middle));
g_assert (iter1 == dee_model_next (fix->txn, txn_middle));
g_assert (txn_middle == dee_model_prev (fix->txn, iter1));
g_assert (txn_middle == dee_model_next (fix->txn, iter0));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
g_assert_cmpint (5, ==, dee_model_get_n_rows (fix->model));
iter0 = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter0, &s, &i);
g_assert_cmpstr ("I", ==, s);
g_assert_cmpint (11, ==, i);
iter0 = dee_model_next (fix->model, iter0);
dee_model_get (fix->model, iter0, &s, &i);
g_assert_cmpstr ("A", ==, s);
g_assert_cmpint (0, ==, i);
iter0 = dee_model_next (fix->model, iter0);
dee_model_get (fix->model, iter0, &s, &i);
g_assert_cmpstr ("II", ==, s);
g_assert_cmpint (12, ==, i);
iter0 = dee_model_next (fix->model, iter0);
dee_model_get (fix->model, iter0, &s, &i);
g_assert_cmpstr ("B", ==, s);
g_assert_cmpint (1, ==, i);
iter0 = dee_model_next (fix->model, iter0);
dee_model_get (fix->model, iter0, &s, &i);
g_assert_cmpstr ("III", ==, s);
g_assert_cmpint (13, ==, i);
g_assert (end == dee_model_next (fix->model, iter0));
}
static void
test_target_2_clear (Fixture *fix, gconstpointer data)
{
GError *error;
/**
* Target: A B
* Txn: - -
*/
dee_model_append (fix->model, "TwentySeven", 27);
dee_model_append (fix->model, "TwentyEight", 28);
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
/* Clear txn */
dee_model_clear (fix->txn);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 0);
/* Target is unmodified */
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 2);
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
}
static void
test_target_1_clear_add_3 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter;
GError *error;
gchar *s;
gint32 i;
/**
* Target: A B
* Txn: - - I II III
*/
dee_model_append (fix->model, "TwentySeven", 27);
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
/* Clear txn */
dee_model_clear (fix->txn);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 0);
/* Target is unmodified */
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
/* Add rows to txn, funky order for fun */
dee_model_append (fix->txn, "II", 2);
dee_model_append (fix->txn, "III", 3);
dee_model_prepend (fix->txn, "I", 1);
/* Txn looks like we expect before commit */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 3);
iter = dee_model_get_first_iter (fix->txn);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("I", ==, s);
g_assert_cmpint (1, ==, i);
iter = dee_model_next (fix->txn, iter);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("II", ==, s);
g_assert_cmpint (2, ==, i);
iter = dee_model_next (fix->txn, iter);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("III", ==, s);
g_assert_cmpint (3, ==, i);
g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, iter)));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("I", ==, s);
g_assert_cmpint (1, ==, i);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("II", ==, s);
g_assert_cmpint (2, ==, i);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("III", ==, s);
g_assert_cmpint (3, ==, i);
g_assert (dee_model_is_last (fix->model, dee_model_next (fix->model, iter)));
}
static void
test_target_5_clear_append_2 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter;
GError *error;
gchar *s;
gint32 i;
/**
* Target: A B C D E
* Txn: - - - - - F G
*/
dee_model_append (fix->model, "A", (gint32) 'A');
dee_model_append (fix->model, "B", (gint32) 'B');
dee_model_append (fix->model, "C", (gint32) 'C');
dee_model_append (fix->model, "D", (gint32) 'D');
dee_model_append (fix->model, "E", (gint32) 'E');
fix->txn = dee_transaction_new (fix->model);
dee_model_clear (fix->txn);
dee_model_append (fix->txn, "F", (gint32) 'F');
dee_model_append (fix->txn, "G", (gint32) 'G');
/* Txn looks like we expect before commit */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
iter = dee_model_get_first_iter (fix->txn);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("F", ==, s);
g_assert_cmpint ((gint32) 'F', ==, i);
iter = dee_model_next (fix->txn, iter);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("G", ==, s);
g_assert_cmpint ((gint32) 'G', ==, i);
g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, iter)));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was set to: %s", error->message);
}
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("F", ==, s);
g_assert_cmpint ((gint32) 'F', ==, i);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("G", ==, s);
g_assert_cmpint ((gint32) 'G', ==, i);
g_assert (dee_model_is_last (fix->model, dee_model_next (fix->model, iter)));
}
static void
test_target_0_clear_append_2 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter;
GError *error;
gchar *s;
gint32 i;
/**
* Target:
* Txn: A B
*/
/* The trick to this is the clear() on an empty model.
* Or - hopefully that is not a trick... that is what we test ;-) */
fix->txn = dee_transaction_new (fix->model);
dee_model_clear (fix->txn);
dee_model_append (fix->txn, "A", (gint32) 'A');
dee_model_append (fix->txn, "B", (gint32) 'B');
/* Txn looks like we expect before commit */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
iter = dee_model_get_first_iter (fix->txn);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("A", ==, s);
g_assert_cmpint ((gint32) 'A', ==, i);
iter = dee_model_next (fix->txn, iter);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("B", ==, s);
g_assert_cmpint ((gint32) 'B', ==, i);
g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, iter)));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was set to: %s", error->message);
}
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("A", ==, s);
g_assert_cmpint ((gint32) 'A', ==, i);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("B", ==, s);
g_assert_cmpint ((gint32) 'B', ==, i);
g_assert (dee_model_is_last (fix->model, dee_model_next (fix->model, iter)));
}
static void
test_target_1_change_1_add_2 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *txn_iter;
gchar *s;
int i;
GError *error;
/*
* Target: - A -
* Txn: I A' II
*/
iter = dee_model_append (fix->model, "TwentySeven", 27);
g_assert (iter == dee_model_get_first_iter (fix->model));
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
txn_iter = dee_model_get_first_iter (fix->txn);
g_assert (txn_iter == iter);
/* Change the row in txn and assert that it looks right */
dee_model_set (fix->txn, iter, "TwentyOne", 21);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
g_assert (iter == dee_model_get_first_iter (fix->txn));
/* Change is not seen in target */
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
g_assert (iter == dee_model_get_first_iter (fix->model));
/* Add two more rows to txn */
dee_model_append (fix->txn, "ThirtyFour", 34);
dee_model_prepend (fix->txn, "Eleven", 11);
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), ==, 3);
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
dee_model_get (fix->model, dee_model_get_first_iter (fix->model), &s, &i);
g_assert_cmpstr ("Eleven", ==, s);
g_assert_cmpint (11, ==, i);
dee_model_get (fix->model, dee_model_get_iter_at_row (fix->model, 2), &s, &i);
g_assert_cmpstr ("ThirtyFour", ==, s);
g_assert_cmpint (34, ==, i);
}
static void
test_target_1_change_1_clear (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *txn_iter;
gchar *s;
int i;
GError *error;
/*
* Target: A
* Txn: -
*/
iter = dee_model_append (fix->model, "TwentySeven", 27);
g_assert (iter == dee_model_get_first_iter (fix->model));
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
txn_iter = dee_model_get_first_iter (fix->txn);
g_assert (txn_iter == iter);
/* Change the row in txn and assert that it looks right */
dee_model_set (fix->txn, iter, "TwentyOne", 21);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
g_assert (iter == dee_model_get_first_iter (fix->txn));
/* Change is not seen in target */
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
g_assert (iter == dee_model_get_first_iter (fix->model));
/* Clear the model */
dee_model_clear (fix->txn);
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), ==, 0);
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
}
static void
test_target_2_change_1_remove_1 (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *txn_iter;
gchar *s;
int i;
GError *error;
/*
* Target: A B
* Txn: - B'
*/
iter = dee_model_append (fix->model, "TwentySeven", 27);
dee_model_prepend (fix->model, "Nineteen", 19);
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
txn_iter = dee_model_get_iter_at_row (fix->txn, 1);
g_assert (txn_iter == iter);
/* Change the last row in txn and assert that it looks right */
dee_model_set (fix->txn, iter, "TwentyOne", 21);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
dee_model_get (fix->txn, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
g_assert (iter == dee_model_get_iter_at_row (fix->txn, 1));
/* Change is not seen in target */
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 2);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentySeven", ==, s);
g_assert_cmpint (27, ==, i);
g_assert (iter == dee_model_get_iter_at_row (fix->model, 1));
/* Remove the first row */
dee_model_remove (fix->txn, dee_model_get_first_iter (fix->txn));
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 2);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), ==, 1);
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr ("TwentyOne", ==, s);
g_assert_cmpint (21, ==, i);
}
static void
test_target_2_change_remove_append (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *iter_removed;
GError *error;
gchar *s;
gint32 i;
/**
* Target: A B
* Txn: A' - C
*/
dee_model_append (fix->model, "TwentySeven", 27);
dee_model_append (fix->model, "TwentyEight", 28);
fix->txn = dee_transaction_new (fix->model);
/* Assert that the unmodified txn is identical to the target */
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
/* Change the first row */
iter = dee_model_get_first_iter (fix->txn);
dee_model_set_value (fix->txn, iter, 0, g_variant_new_string ("***"));
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
g_assert (dee_model_is_first (fix->txn, iter));
/* Remove second row */
iter_removed = dee_model_next (fix->txn, iter);
dee_model_remove (fix->txn, iter_removed);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
g_assert (dee_model_is_first (fix->txn, iter));
/* Append a new row */
dee_model_append (fix->txn, "TehNew", 11);
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
g_assert (dee_model_is_first (fix->txn, iter));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was was to: %s", error->message);
}
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr (s, ==, "***");
g_assert_cmpint (i, ==, 27);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &s, &i);
g_assert_cmpstr (s, ==, "TehNew");
g_assert_cmpint (i, ==, 11);
}
static int txn_remaining_rows = 2;
void
txn_on_row_added (DeeModel *txn, DeeModelIter *iter)
{
if (txn_remaining_rows == 2)
{
g_assert_cmpstr (dee_model_get_string (txn, iter, 0), ==, "A");
g_assert_cmpint (dee_model_get_int32 (txn, iter, 1), ==, (gint32) 'A');
}
else if (txn_remaining_rows == 1)
{
g_assert_cmpstr (dee_model_get_string (txn, iter, 0), ==, "B");
g_assert_cmpint (dee_model_get_int32 (txn, iter, 1), ==, (gint32) 'B');
}
else
{
g_critical ("Unexpected row-added signal on txn with %i remaining rows",
txn_remaining_rows);
}
txn_remaining_rows--;
}
static int target_remaining_rows = 2;
void
target_on_row_added (DeeModel *target, DeeModelIter *iter)
{
if (target_remaining_rows == 2)
{
g_assert_cmpstr (dee_model_get_string (target, iter, 0), ==, "A");
g_assert_cmpint (dee_model_get_int32 (target, iter, 1), ==, (gint32) 'A');
}
else if (target_remaining_rows == 1)
{
g_assert_cmpstr (dee_model_get_string (target, iter, 0), ==, "B");
g_assert_cmpint (dee_model_get_int32 (target, iter, 1), ==, (gint32) 'B');
}
else
{
g_critical ("Unexpected row-added signal on target with %i remaining rows",
target_remaining_rows);
}
target_remaining_rows--;
}
static void
test_signal_order (Fixture *fix, gconstpointer data)
{
/* Reset global static state */
txn_remaining_rows = 2;
target_remaining_rows = 2;
GError *error;
/**
* Target:
* Txn: A B
*/
fix->txn = dee_transaction_new (fix->model);
g_assert_cmpint (txn_remaining_rows, ==, 2);
g_assert_cmpint (target_remaining_rows, ==, 2);
g_signal_connect (fix->model, "row-added",
G_CALLBACK (target_on_row_added), NULL);
g_signal_connect (fix->txn, "row-added",
G_CALLBACK (txn_on_row_added), NULL);
dee_model_append (fix->txn, "A", (gint32) 'A');
g_assert_cmpint (txn_remaining_rows, ==, 1);
g_assert_cmpint (target_remaining_rows, ==, 2);
dee_model_append (fix->txn, "B", (gint32) 'B');
g_assert_cmpint (txn_remaining_rows, ==, 0);
g_assert_cmpint (target_remaining_rows, ==, 2);
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit with: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was set to: %s", error->message);
}
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpint (txn_remaining_rows, ==, 0);
g_assert_cmpint (target_remaining_rows, ==, 0);
}
static void
test_concurrent_modification (Fixture *fix, gconstpointer data)
{
GError *error;
/**
* Target: - (add A while txn open)
* Txn: I
*/
fix->txn = dee_transaction_new (fix->model);
dee_model_append (fix->model, "TwentySeven", 27);
dee_model_clear (fix->txn);
/* COMMIT */
error = NULL;
if (dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction committed successfully. "
"Expected concurrent modification error.");
}
if (!error)
{
g_critical ("dee_transaction_commit() returned FALSE, "
"but error was not set.");
}
g_assert (g_error_matches (error,
DEE_TRANSACTION_ERROR,
DEE_TRANSACTION_ERROR_CONCURRENT_MODIFICATION));
g_assert (!dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
/* Target model should not have been cleared */
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
}
static void
test_double_commit (Fixture *fix, gconstpointer data)
{
GError *error;
/**
* Target: - (add A while txn open)
* Txn: I
*/
fix->txn = dee_transaction_new (fix->model);
dee_model_append (fix->txn, "TwentySeven", 27);
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit: %s", error->message);
g_error_free (error);
}
if (error)
{
g_critical ("dee_transaction_commit() returned TRUE, "
"but error was set.");
}
/* COMMIT.... AGAIN! */
error = NULL;
if (dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction committed successfully. "
"Expected because of double commit.");
}
if (!error)
{
g_critical ("dee_transaction_commit() returned FALSE, "
"but error was not set.");
}
g_assert (g_error_matches (error,
DEE_TRANSACTION_ERROR,
DEE_TRANSACTION_ERROR_COMMITTED));
/* Target model should be good with 1 row from the first commit */
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
}
static void
test_basic_types (Fixture *fix, gconstpointer data)
{
GError *error;
fix->txn = dee_transaction_new (fix->model);
dee_model_append (fix->txn, TRUE, 27, 28, 29,
G_GINT64_CONSTANT (30), G_GUINT64_CONSTANT (31),
32.0, "ThirtyThree");
DeeModelIter *iter = dee_model_get_first_iter (fix->txn);
g_assert (dee_model_get_bool (fix->txn, iter, 0) == TRUE);
g_assert (dee_model_get_uchar (fix->txn, iter, 1) == 27);
g_assert (dee_model_get_int32 (fix->txn, iter, 2) == 28);
g_assert (dee_model_get_uint32 (fix->txn, iter, 3) == 29);
g_assert (dee_model_get_int64 (fix->txn, iter, 4) == 30);
g_assert (dee_model_get_uint64 (fix->txn, iter, 5) == 31);
g_assert (ABS (dee_model_get_double (fix->txn, iter, 6) - 32.0) <= 0.001);
g_assert_cmpstr ("ThirtyThree", ==, dee_model_get_string (fix->txn, iter, 7));
g_assert_cmpstr ("s", ==, g_variant_get_type_string (dee_model_get_value (fix->txn, iter, 7)));
/* COMMIT */
error = NULL;
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
{
g_critical ("Transaction failed to commit: %s", error->message);
g_error_free (error);
}
if (error)
{
g_assert_not_reached ();
}
}
// FIXME tags
void
test_transaction_create_suite (void)
{
#define DOMAIN "/Model/Transaction"
#define PROXY_DOMAIN "/Model/Transaction/Proxy"
#define SHARED_DOMAIN "/Model/Transaction/Shared"
g_test_add (DOMAIN"/AdoptSchema", Fixture, 0,
setup, test_adopt_schema, teardown);
g_test_add (PROXY_DOMAIN"/AdoptSchema", Fixture, 0,
setup_proxy, test_adopt_schema, teardown);
g_test_add (DOMAIN"/Target0Add1", Fixture, 0,
setup, test_target_0_add_1, teardown);
g_test_add (PROXY_DOMAIN"/Target0Add1", Fixture, 0,
setup_proxy, test_target_0_add_1, teardown);
g_test_add (DOMAIN"/Target1Add1", Fixture, 0,
setup, test_target_1_add_1, teardown);
g_test_add (PROXY_DOMAIN"/Target1Add1", Fixture, 0,
setup_proxy, test_target_1_add_1, teardown);
g_test_add (DOMAIN"/Target1Change1", Fixture, 0,
setup, test_target_1_change_1, teardown);
g_test_add (PROXY_DOMAIN"/Target1Change1", Fixture, 0,
setup_proxy, test_target_1_change_1, teardown);
g_test_add (DOMAIN"/Target2Add3", Fixture, 0,
setup, test_target_2_add_3, teardown);
g_test_add (PROXY_DOMAIN"/Target2Add3", Fixture, 0,
setup_proxy, test_target_2_add_3, teardown);
g_test_add (DOMAIN"/Target2Clear", Fixture, 0,
setup, test_target_2_clear, teardown);
g_test_add (PROXY_DOMAIN"/Target2Clear", Fixture, 0,
setup_proxy, test_target_2_clear, teardown);
g_test_add (DOMAIN"/Target1ClearAdd3", Fixture, 0,
setup, test_target_1_clear_add_3, teardown);
g_test_add (PROXY_DOMAIN"/Target1ClearAdd3", Fixture, 0,
setup_proxy, test_target_1_clear_add_3, teardown);
g_test_add (DOMAIN"/Target5ClearAppend2", Fixture, 0,
setup, test_target_5_clear_append_2, teardown);
g_test_add (PROXY_DOMAIN"/Target5ClearAppend2", Fixture, 0,
setup_proxy, test_target_5_clear_append_2, teardown);
g_test_add (SHARED_DOMAIN"/Target5ClearAppend2", Fixture, 0,
setup_shared, test_target_5_clear_append_2, teardown);
g_test_add (DOMAIN"/Target0ClearAppend2", Fixture, 0,
setup, test_target_0_clear_append_2, teardown);
g_test_add (PROXY_DOMAIN"/Target0ClearAppend2", Fixture, 0,
setup_proxy, test_target_0_clear_append_2, teardown);
g_test_add (SHARED_DOMAIN"/Target0ClearAppend2", Fixture, 0,
setup_shared, test_target_0_clear_append_2, teardown);
g_test_add (DOMAIN"/Target1Change1Add2", Fixture, 0,
setup, test_target_1_change_1_add_2, teardown);
g_test_add (PROXY_DOMAIN"/Target1Change1Add2", Fixture, 0,
setup_proxy, test_target_1_change_1_add_2, teardown);
g_test_add (SHARED_DOMAIN"/Target1Change1Add2", Fixture, 0,
setup_shared, test_target_1_change_1_add_2, teardown);
g_test_add (DOMAIN"/Target1Change1Clear", Fixture, 0,
setup, test_target_1_change_1_clear, teardown);
g_test_add (PROXY_DOMAIN"/Target1Change1Clear", Fixture, 0,
setup_proxy, test_target_1_change_1_clear, teardown);
g_test_add (SHARED_DOMAIN"/Target1Change1Clear", Fixture, 0,
setup_shared, test_target_1_change_1_clear, teardown);
g_test_add (DOMAIN"/Target2Change1Remove1", Fixture, 0,
setup, test_target_2_change_1_remove_1, teardown);
g_test_add (PROXY_DOMAIN"/Target2Change1Remove1", Fixture, 0,
setup_proxy, test_target_2_change_1_remove_1, teardown);
g_test_add (DOMAIN"/Target2ChangeRemoveAppend", Fixture, 0,
setup, test_target_2_change_remove_append, teardown);
g_test_add (PROXY_DOMAIN"/Target2ChangeRemoveAppend", Fixture, 0,
setup_proxy, test_target_2_change_remove_append, teardown);
g_test_add (DOMAIN"/SignalOrder", Fixture, 0,
setup, test_signal_order, teardown);
g_test_add (PROXY_DOMAIN"/SignalOrder", Fixture, 0,
setup_proxy, test_signal_order, teardown);
g_test_add (SHARED_DOMAIN"/SignalOrder", Fixture, 0,
setup_shared, test_signal_order, teardown);
g_test_add (DOMAIN"/ConcurrentModification", Fixture, 0,
setup, test_concurrent_modification, teardown);
g_test_add (PROXY_DOMAIN"/ConcurrentModification", Fixture, 0,
setup_proxy, test_concurrent_modification, teardown);
g_test_add (DOMAIN"/DoubleCommit", Fixture, 0,
setup, test_double_commit, teardown);
g_test_add (PROXY_DOMAIN"/DoubleCommit", Fixture, 0,
setup_proxy, test_double_commit, teardown);
g_test_add (DOMAIN"/BasicTypes", Fixture, 0,
setup_basic_types, test_basic_types, teardown);
}
dee-1.2.7+15.04.20150304/tests/test-filter-model.c 0000644 0000153 0000161 00000066334 12475676210 021501 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
typedef struct
{
DeeModel *model;
} FilterFixture;
typedef struct
{
gint first;
gint second;
} TwoIntsTuple;
static void setup (FilterFixture *fix, gconstpointer data);
static void setup_empty (FilterFixture *fix, gconstpointer data);
static void teardown (FilterFixture *fix, gconstpointer data);
static void test_empty_orig (FilterFixture *fix,
gconstpointer data);
static void test_append_all (FilterFixture *fix,
gconstpointer data);
static void test_discard_all (FilterFixture *fix,
gconstpointer data);
static void test_discard_all_append_notify (FilterFixture *fix,
gconstpointer data);
static void test_change_backend (FilterFixture *fix,
gconstpointer data);
static void test_collator_asc (FilterFixture *fix,
gconstpointer data);
static void test_collator_desc (FilterFixture *fix,
gconstpointer data);
static void test_key (FilterFixture *fix,
gconstpointer data);
static void test_any (FilterFixture *fix,
gconstpointer data);
static void test_regex (FilterFixture *fix,
gconstpointer data);
static void test_changesets (FilterFixture *fix,
gconstpointer data);
void
test_filter_model_create_suite (void)
{
#define DOMAIN "/Model/Filter"
g_test_add (DOMAIN"/EmptyOrig", FilterFixture, 0,
setup, test_empty_orig, teardown);
g_test_add (DOMAIN"/AppendAll", FilterFixture, 0,
setup, test_append_all, teardown);
g_test_add (DOMAIN"/DiscardAll", FilterFixture, 0,
setup, test_discard_all, teardown);
g_test_add (DOMAIN"/DiscardAllAppendNotify", FilterFixture, 0,
setup, test_discard_all_append_notify, teardown);
g_test_add (DOMAIN"/ChangeBackend", FilterFixture, 0,
setup, test_change_backend, teardown);
g_test_add (DOMAIN"/CollatorAscending", FilterFixture, 0,
setup, test_collator_asc, teardown);
g_test_add (DOMAIN"/CollatorDescending", FilterFixture, 0,
setup, test_collator_desc, teardown);
g_test_add (DOMAIN"/Key", FilterFixture, 0,
setup, test_key, teardown);
g_test_add (DOMAIN"/Any", FilterFixture, 0,
setup, test_any, teardown);
g_test_add (DOMAIN"/Regex", FilterFixture, 0,
setup, test_regex, teardown);
g_test_add (DOMAIN"/Changesets", FilterFixture, 0,
setup_empty, test_changesets, teardown);
}
static void
setup_empty (FilterFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "i", "s", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
}
static void
add_3rows(DeeModel *model)
{
dee_model_append (model, 0, "Zero");
dee_model_append (model, 1, "One");
dee_model_append (model, 2, "Two");
}
static void
setup (FilterFixture *fix, gconstpointer data)
{
setup_empty (fix, data);
add_3rows (fix->model);
}
static void
teardown (FilterFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
fix->model = NULL;
}
static void
discard_all_model_map (DeeModel *orig_model,
DeeFilterModel *mapped_model,
gpointer user_data)
{
/* Don't do anything! */
}
static void
append_all_model_map (DeeModel *orig_model,
DeeFilterModel *mapped_model,
gpointer user_data)
{
DeeModelIter *iter;
iter = dee_model_get_first_iter (orig_model);
while (!dee_model_is_last (orig_model, iter))
{
dee_filter_model_append_iter (mapped_model, iter);
iter = dee_model_next (orig_model, iter);
}
}
static gboolean
discard_all_model_notify (DeeModel *orig_model,
DeeModelIter *orig_iter,
DeeFilterModel *mapped_model,
gpointer user_data)
{
/* Do nothing */
return FALSE;
}
static gboolean
append_all_model_notify (DeeModel *orig_model,
DeeModelIter *orig_iter,
DeeFilterModel *mapped_model,
gpointer user_data)
{
/* Always say "Thank you, I am delighted",
* and append the new row to @mapped_model */
dee_filter_model_append_iter (mapped_model, orig_iter);
return TRUE;
}
static void
signal_counter (DeeModel *model, DeeModelIter *iter, guint *count)
{
*count = *count + 1;
}
/* Test behaviouor when orig_model is empty */
static void
test_empty_orig (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new (append_all_model_map,
append_all_model_notify,
fix,
NULL,
&filter);
dee_model_clear (fix->model);
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
DeeModel *m = dee_filter_model_new (fix->model, &filter);
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
DeeModelIter *iter = dee_model_get_first_iter (m);
g_assert (dee_model_is_first (m, iter));
g_assert (dee_model_is_last (m, iter));
g_assert_cmpuint (0, ==, dee_serializable_model_get_seqnum (m));
}
/* A filter model that is a complete copy of the orig */
static void
test_append_all (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new (append_all_model_map,
append_all_model_notify,
fix,
NULL,
&filter);
DeeModel *m = dee_filter_model_new (fix->model, &filter);
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
DeeModelIter *iter = dee_model_get_first_iter (m);
g_assert (dee_model_is_first (m, iter));
g_assert (!dee_model_is_last (m, iter));
g_assert_cmpint (0, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, iter, 1));
iter = dee_model_next (m, iter);
g_assert (!dee_model_is_first (m, iter));
g_assert (!dee_model_is_last (m, iter));
g_assert_cmpint (1, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("One", ==, dee_model_get_string (m, iter, 1));
g_assert (dee_model_get_first_iter (m) == dee_model_prev (m, iter));
iter = dee_model_next (m, iter);
g_assert (!dee_model_is_first (m, iter));
g_assert (!dee_model_is_last (m, iter));
g_assert_cmpint (2, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("Two", ==, dee_model_get_string (m, iter, 1));
g_assert (iter == dee_model_prev (m, dee_model_get_last_iter (m)));
iter = dee_model_next (m, iter);
g_assert (!dee_model_is_first (m, iter));
g_assert (dee_model_is_last (m, iter));
g_assert (dee_model_is_last (m, iter));
g_assert_cmpuint (dee_serializable_model_get_seqnum (fix->model), ==,
dee_serializable_model_get_seqnum (m));
}
/* Test a filter that blocks everything */
static void
test_discard_all (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new (discard_all_model_map,
discard_all_model_notify,
fix,
NULL,
&filter);
DeeModel *m = dee_filter_model_new (fix->model, &filter);
/* Check expected sizes */
g_return_if_fail (DEE_IS_FILTER_MODEL (m));
g_assert_cmpint (0, ==, dee_model_get_n_rows (m));
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
/* Check that the begin iter is indeed also the end iter */
DeeModelIter *iter = dee_model_get_first_iter (m);
g_assert (dee_model_is_first (m, iter));
g_assert (dee_model_is_last (m, iter));
/* Check that seqnum is still zero */
g_assert_cmpuint (0, ==, dee_serializable_model_get_seqnum (m));
guint filter_add_count = 0;
guint orig_add_count = 0;
g_signal_connect (m, "row-added", G_CALLBACK (signal_counter), &filter_add_count);
g_signal_connect (fix->model, "row-added", G_CALLBACK (signal_counter), &orig_add_count);
dee_model_append (fix->model, 3, "Three");
dee_model_append (fix->model, 4, "Four");
/* Updates to the orig model should be ignored by this filter */
g_assert_cmpint (0, ==, filter_add_count);
g_assert_cmpint (2, ==, orig_add_count);
g_assert_cmpint (0, ==, dee_model_get_n_rows (m));
g_assert_cmpint (5, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpuint (0, ==, dee_serializable_model_get_seqnum (m));
/* Now add stuff to the filtered model directly. This should work,
* and should be written through to the orig model as well */
dee_model_append (m, 27, "TwentySeven");
g_assert_cmpint (1, ==, filter_add_count);
g_assert_cmpint (3, ==, orig_add_count);
g_assert_cmpint (1, ==, dee_model_get_n_rows (m));
g_assert_cmpint (6, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpuint (1, ==, dee_serializable_model_get_seqnum (m));
/* The first (and only) row of 'm' should be at offset 5 in fix->model */
iter = dee_model_get_first_iter (m);
g_assert (iter == dee_model_get_iter_at_row (fix->model, 5));
g_assert_cmpint (27, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpint (27, ==, dee_model_get_int32 (fix->model, iter, 0));
g_assert_cmpstr ("TwentySeven", ==, dee_model_get_string (m, iter, 1));
g_assert_cmpstr ("TwentySeven", ==, dee_model_get_string (fix->model, iter, 1));
/* And append two more rows to the filtered model, to ensure the order */
dee_model_prepend (m, -1, "MinusOne");
dee_model_append (m, 39, "ThirtyNine");
g_assert_cmpint (3, ==, filter_add_count);
g_assert_cmpint (5, ==, orig_add_count);
g_assert_cmpint (3, ==, dee_model_get_n_rows (m));
g_assert_cmpint (8, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpuint (3, ==, dee_serializable_model_get_seqnum (m));
iter = dee_model_prev (m, dee_model_get_last_iter (m));
g_assert_cmpint (39, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("ThirtyNine", ==, dee_model_get_string (m, iter, 1));
iter = dee_model_prev (m, iter);
g_assert_cmpint (27, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("TwentySeven", ==, dee_model_get_string (m, iter, 1));
iter = dee_model_prev (m, iter);
g_assert_cmpint (-1, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("MinusOne", ==, dee_model_get_string (m, iter, 1));
iter = dee_model_prev (fix->model, dee_model_get_last_iter (fix->model));
g_assert_cmpint (39, ==, dee_model_get_int32 (fix->model, iter, 0));
g_assert_cmpstr ("ThirtyNine", ==, dee_model_get_string (fix->model, iter, 1));
g_object_unref (m);
}
/* Test a filter that blocks everything */
static void
test_discard_all_append_notify (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new (discard_all_model_map,
append_all_model_notify,
fix,
NULL,
&filter);
DeeModel *m = dee_filter_model_new (fix->model, &filter);
/* Nothing was added to the filter model, seqnum should be zero */
g_assert_cmpuint (0, ==, dee_serializable_model_get_seqnum (m));
guint filter_add_count = 0;
guint orig_add_count = 0;
g_signal_connect (m, "row-added", G_CALLBACK (signal_counter), &filter_add_count);
g_signal_connect (fix->model, "row-added", G_CALLBACK (signal_counter), &orig_add_count);
dee_model_append (fix->model, 3, "Three");
dee_model_append (fix->model, 4, "Four");
/* Updates to the orig model should be detected by this filter */
g_assert_cmpint (2, ==, filter_add_count);
g_assert_cmpint (2, ==, orig_add_count);
g_assert_cmpint (2, ==, dee_model_get_n_rows (m));
g_assert_cmpint (5, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpuint (2, ==, dee_serializable_model_get_seqnum (m));
/* The first row of 'm' should be at offset 3 in fix->model */
DeeModelIter *iter = dee_model_get_first_iter (m);
g_assert (iter == dee_model_get_iter_at_row (fix->model, 3));
g_assert_cmpint (3, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpint (3, ==, dee_model_get_int32 (fix->model, iter, 0));
g_assert_cmpstr ("Three", ==, dee_model_get_string (m, iter, 1));
g_assert_cmpstr ("Three", ==, dee_model_get_string (fix->model, iter, 1));
/* The second row of 'm' should be at offset 4 in fix->model */
iter = dee_model_next (m, iter);
g_assert (iter == dee_model_get_iter_at_row (fix->model, 4));
g_assert_cmpint (4, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpint (4, ==, dee_model_get_int32 (fix->model, iter, 0));
g_assert_cmpstr ("Four", ==, dee_model_get_string (m, iter, 1));
g_assert_cmpstr ("Four", ==, dee_model_get_string (fix->model, iter, 1));
/* Assert that the next iter in 'm is the end iter */
iter = dee_model_next (m, iter);
g_assert (dee_model_is_last (m, iter));
g_object_unref (m);
}
static void
test_change_backend (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new (append_all_model_map,
append_all_model_notify,
fix,
NULL,
&filter);
DeeModel *m = dee_filter_model_new (fix->model, &filter);
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
DeeModelIter *iter = dee_model_get_first_iter (m);
g_assert (dee_model_is_first (m, iter));
g_assert (!dee_model_is_last (m, iter));
g_assert_cmpint (0, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, iter, 1));
g_assert_cmpuint (0, ==, dee_model_get_position (m, iter));
iter = dee_model_get_first_iter (fix->model);
dee_model_remove (fix->model, iter);
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpint (2, ==, dee_model_get_n_rows (m));
iter = dee_model_get_first_iter (fix->model);
dee_model_remove (fix->model, iter);
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpint (1, ==, dee_model_get_n_rows (m));
iter = dee_model_get_first_iter (m);
g_assert (dee_model_is_first (m, iter));
g_assert (!dee_model_is_last (m, iter));
g_assert_cmpint (2, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("Two", ==, dee_model_get_string (m, iter, 1));
iter = dee_model_get_first_iter (fix->model);
dee_model_set (fix->model, iter, -1, "Minus one");
iter = dee_model_get_first_iter (m);
g_assert (dee_model_is_first (m, iter));
g_assert (!dee_model_is_last (m, iter));
g_assert_cmpint (-1, ==, dee_model_get_int32 (m, iter, 0));
g_assert_cmpstr ("Minus one", ==, dee_model_get_string (m, iter, 1));
g_assert_cmpuint (0, ==, dee_model_get_position (m, iter));
/* and finally remove the last row via the filter model */
dee_model_remove (m, iter);
g_assert_cmpint (0, ==, dee_model_get_n_rows (m));
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
}
/* Test dee_filter_new_collator() ascending */
static void
test_collator_asc (FilterFixture *fix, gconstpointer data)
{
DeeModelIter *r0, *r1, *r2, *r3, *r4, *r5;
DeeFilter collator;
DeeModel *m;
dee_filter_new_collator (1, &collator);
m = dee_filter_model_new (fix->model, &collator);
/* Test alphabetic sorting after initial construction */
r0 = dee_model_get_iter_at_row (m, 0);
r1 = dee_model_get_iter_at_row (m, 1);
r2 = dee_model_get_iter_at_row (m, 2);
g_assert_cmpstr ("One", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpstr ("Two", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r2, 1));
/* Test alphabetic sorting after updates */
dee_model_append (fix->model, 3, "Three");
dee_model_append (fix->model, 4, "Four");
r0 = dee_model_get_iter_at_row (m, 0);
r1 = dee_model_get_iter_at_row (m, 1);
r2 = dee_model_get_iter_at_row (m, 2);
r3 = dee_model_get_iter_at_row (m, 3);
r4 = dee_model_get_iter_at_row (m, 4);
g_assert_cmpstr ("Four", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpstr ("One", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpstr ("Three", ==, dee_model_get_string (m, r2, 1));
g_assert_cmpstr ("Two", ==, dee_model_get_string (m, r3, 1));
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r4, 1));
/* Appending to the end of the sorted model is a special case in the code,
* so double check on that... */
dee_model_append (fix->model, 5, "Zzzz");
r0 = dee_model_get_iter_at_row (m, 0);
r5 = dee_model_get_iter_at_row (m, 5);
g_assert_cmpstr ("Four", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpstr ("Zzzz", ==, dee_model_get_string (m, r5, 1));
g_object_unref (m);
}
/* Test dee_filter_new_collator_desc() descending*/
static void
test_collator_desc (FilterFixture *fix, gconstpointer data)
{
DeeModelIter *r0, *r1, *r2, *r3, *r4, *r5;
DeeFilter collator;
DeeModel *m;
dee_filter_new_collator_desc (1, &collator);
m = dee_filter_model_new (fix->model, &collator);
/* Test alphabetic sorting after initial construction */
r0 = dee_model_get_iter_at_row (m, 0);
r1 = dee_model_get_iter_at_row (m, 1);
r2 = dee_model_get_iter_at_row (m, 2);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpstr ("Two", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpstr ("One", ==, dee_model_get_string (m, r2, 1));
/* Test alphabetic sorting after updates */
dee_model_append (fix->model, 3, "Three");
dee_model_append (fix->model, 4, "Four");
r0 = dee_model_get_iter_at_row (m, 0);
r1 = dee_model_get_iter_at_row (m, 1);
r2 = dee_model_get_iter_at_row (m, 2);
r3 = dee_model_get_iter_at_row (m, 3);
r4 = dee_model_get_iter_at_row (m, 4);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpstr ("Two", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpstr ("Three", ==, dee_model_get_string (m, r2, 1));
g_assert_cmpstr ("One", ==, dee_model_get_string (m, r3, 1));
g_assert_cmpstr ("Four", ==, dee_model_get_string (m, r4, 1));
/* Appending to the end of the sorted model is a special case in the code,
* so double check on that... */
dee_model_append (fix->model, 5, "Zzzz");
r0 = dee_model_get_iter_at_row (m, 0);
r5 = dee_model_get_iter_at_row (m, 5);
g_assert_cmpstr ("Four", ==, dee_model_get_string (m, r5, 1));
g_assert_cmpstr ("Zzzz", ==, dee_model_get_string (m, r0, 1));
g_object_unref (m);
}
static void
_test_orig_ordering (FilterFixture *fix,
DeeFilter *filter)
{
DeeModelIter *r0, *r1, *r2, *r3, *r4;//, *r5;
DeeModel *m = dee_filter_model_new (fix->model, filter);
/* Assert that the initial filtering is good:
* { [ 0, "Zero" ] } { [ 0, "Zero" ],
* [ 1, "One" ],
* [ 2, "Two" ]}
* */
g_assert_cmpint (1, ==, dee_model_get_n_rows (m));
r0 = dee_model_get_first_iter (m);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpint (0, ==, dee_model_get_int32 (m, r0, 0));
g_assert (dee_model_next (m, r0) == dee_model_get_last_iter (m));
/* Assert that we can append rows:
* { [ 0, "Zero" ], { [ 0, "Zero" ],
* [ 12, "Zero" ], [ 1, "One" ],
* [ 13, "Zero" ] } [ 2, "Two" ],
* [ 1, "One" ],
* [ 12, "Zero" ],
* [ 13, "Zero" ] }
* */
dee_model_append (fix->model, 11, "One"); // Discard
dee_model_append (fix->model, 12, "Zero"); // Include
dee_model_append (fix->model, 13, "Zero"); // Include
g_assert_cmpint (3, ==, dee_model_get_n_rows (m));
r0 = dee_model_get_iter_at_row (m, 0);
r1 = dee_model_get_iter_at_row (m, 1);
r2 = dee_model_get_iter_at_row (m, 2);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpint (0, ==, dee_model_get_int32 (m, r0, 0));
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpint (12, ==, dee_model_get_int32 (m, r1, 0));
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r2, 1));
g_assert_cmpint (13, ==, dee_model_get_int32 (m, r2, 0));
/* Assert sorting is correct for prepends:
* { [ -1, "Zero" ], { [ -1, "Zero" ],
* [ 0, "Zero" ], [ 0, "Zero" ],
* [ 12, "Zero" ], [ 1, "One" ],
* [ 13, "Zero" ] } [ 2, "Two" ],
* [ 1, "One" ],
* [ 12, "Zero" ],
* [ 13, "Zero" ] }
* */
dee_model_prepend (fix->model, -1, "Zero");
g_assert_cmpint (4, ==, dee_model_get_n_rows (m));
r0 = dee_model_get_first_iter (m);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r0, 1));
g_assert_cmpint (-1, ==, dee_model_get_int32 (m, r0, 0));
/* Assert sorting is correct for inserts before a row that is already
* in the filtered model:
* { [ -1, "Zero" ], { [ -1, "Zero" ],
* [ -2, "Zero" ], [ -2, "Zero" ],
* [ 0, "Zero" ], [ 0, "Zero" ],
* [ 12, "Zero" ], [ 1, "One" ],
* [ 13, "Zero" ] } [ 2, "Two" ],
* [ 1, "One" ],
* [ 12, "Zero" ],
* [ 13, "Zero" ] }
* */
r1 = dee_model_get_iter_at_row (m, 1); // The (0, "Zero") row
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpint (0, ==, dee_model_get_int32 (m, r1, 0));
dee_model_insert_before (fix->model, r1, -2, "Zero");
r1 = dee_model_get_iter_at_row (m, 1);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r1, 1));
g_assert_cmpint (-2, ==, dee_model_get_int32 (m, r1, 0));
/* Assert sorting is correct for inserts before a row that is *not* included
* in the filtered model:
* { [ -1, "Zero" ], { [ -1, "Zero" ],
* [ -2, "Zero" ], [ -2, "Zero" ],
* [ 0, "Zero" ], [ 0, "Zero" ],
* [ -3, "Zero" ], [ 1, "One" ],
* [ 12, "Zero" ], [ -3, "Zero" ]
* [ 2, "Two" ],
* [ 13, "Zero" ] } [ 1, "One" ],
* [ 12, "Zero" ],
* [ 13, "Zero" ] }
* */
r4 = dee_model_get_iter_at_row (fix->model, 4);
g_assert_cmpstr ("Two", ==, dee_model_get_string (fix->model, r4, 1));
g_assert (!dee_filter_model_contains (DEE_FILTER_MODEL (m), r4));
dee_model_insert_before (fix->model, r4, -3, "Zero");
r3 = dee_model_get_iter_at_row (m, 3);
g_assert_cmpstr ("Zero", ==, dee_model_get_string (m, r3, 1));
g_assert_cmpint (-3, ==, dee_model_get_int32 (m, r3, 0));
g_object_unref (m);
}
/* Test dee_filter_new_for_key_column() */
static void
test_key (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new_for_key_column (1, "Zero", &filter);
_test_orig_ordering (fix, &filter);
}
/* Test dee_filter_new_for_any_column() */
static void
test_any (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
dee_filter_new_for_any_column (1, g_variant_new_string ("Zero"), &filter);
_test_orig_ordering (fix, &filter);
}
/* Test dee_filter_new_regex() */
static void
test_regex (FilterFixture *fix, gconstpointer data)
{
DeeFilter filter;
GRegex *regex;
regex = g_regex_new (".ero", 0, 0, NULL);
dee_filter_new_regex (1, regex, &filter);
_test_orig_ordering (fix, &filter);
g_regex_unref (regex);
}
static void
increment_first (TwoIntsTuple *tuple)
{
tuple->first++;
// first always has to be incremented before second
g_assert (tuple->first > tuple->second);
}
static void
increment_second (TwoIntsTuple *tuple)
{
tuple->second++;
// second needs to be incremented after first
g_assert (tuple->second == tuple->first);
}
static void
test_changesets (FilterFixture *fix, gconstpointer data)
{
GRegex *regex;
DeeFilter filter;
DeeModel *filter_m1;
DeeModel *filter_m2;
DeeModel *filter_m3;
regex = g_regex_new ("^..[eo]", 0, 0, NULL);
dee_filter_new_regex (1, regex, &filter);
filter_m1 = dee_filter_model_new (fix->model, &filter);
g_regex_unref (regex);
regex = g_regex_new ("^Z", 0, 0, NULL);
dee_filter_new_regex (1, regex, &filter);
filter_m2 = dee_filter_model_new (fix->model, &filter);
g_regex_unref (regex);
regex = g_regex_new ("^X", 0, 0, NULL);
dee_filter_new_regex (1, regex, &filter);
filter_m3 = dee_filter_model_new (fix->model, &filter);
g_regex_unref (regex);
g_assert_cmpuint (0, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m1));
g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m2));
g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m3));
TwoIntsTuple tuple_m0 = { 0, 0 };
TwoIntsTuple tuple_m1 = { 0, 0 };
TwoIntsTuple tuple_m2 = { 0, 0 };
TwoIntsTuple tuple_m3 = { 0, 0 };
g_signal_connect_swapped (fix->model, "changeset-started",
G_CALLBACK (increment_first), &tuple_m0);
g_signal_connect_swapped (fix->model, "changeset-finished",
G_CALLBACK (increment_second), &tuple_m0);
g_signal_connect_swapped (filter_m1, "changeset-started",
G_CALLBACK (increment_first), &tuple_m1);
g_signal_connect_swapped (filter_m1, "changeset-finished",
G_CALLBACK (increment_second), &tuple_m1);
g_signal_connect_swapped (filter_m2, "changeset-started",
G_CALLBACK (increment_first), &tuple_m2);
g_signal_connect_swapped (filter_m2, "changeset-finished",
G_CALLBACK (increment_second), &tuple_m2);
g_signal_connect_swapped (filter_m3, "changeset-started",
G_CALLBACK (increment_first), &tuple_m3);
g_signal_connect_swapped (filter_m3, "changeset-finished",
G_CALLBACK (increment_second), &tuple_m3);
dee_model_begin_changeset (fix->model);
add_3rows (fix->model);
dee_model_end_changeset (fix->model);
g_assert_cmpuint (3, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpuint (2, ==, dee_model_get_n_rows (filter_m1));
g_assert_cmpuint (1, ==, dee_model_get_n_rows (filter_m2));
g_assert_cmpuint (0, ==, dee_model_get_n_rows (filter_m3));
g_assert_cmpint (tuple_m0.first, ==, 1);
g_assert_cmpint (tuple_m0.second, ==, 1);
g_assert_cmpint (tuple_m1.first, ==, 1);
g_assert_cmpint (tuple_m1.second, ==, 1);
g_assert_cmpint (tuple_m2.first, ==, 1);
g_assert_cmpint (tuple_m2.second, ==, 1);
g_assert_cmpint (tuple_m3.first, ==, 1);
g_assert_cmpint (tuple_m3.second, ==, 1);
}
dee-1.2.7+15.04.20150304/tests/test-model-rows.c 0000644 0000153 0000161 00000117703 12475676210 021203 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Neil Jagdish Patel
* Mikkel Kamstrup Erlandsen
* Michal Hruby
*
*/
#include
#include
#include
#include
typedef struct
{
DeeModel *model;
} RowsFixture;
static void seq_rows_setup (RowsFixture *fix, gconstpointer data);
static void seq_rows_teardown (RowsFixture *fix, gconstpointer data);
static void proxy_rows_setup (RowsFixture *fix, gconstpointer data);
static void proxy_rows_teardown (RowsFixture *fix, gconstpointer data);
static void txn_rows_setup (RowsFixture *fix, gconstpointer data);
static void txn_rows_teardown (RowsFixture *fix, gconstpointer data);
static void seq_rows_asv_setup (RowsFixture *fix, gconstpointer data);
static void proxy_rows_asv_setup (RowsFixture *fix, gconstpointer data);
static void txn_rows_asv_setup (RowsFixture *fix, gconstpointer data);
static void test_rows_allocation (RowsFixture *fix, gconstpointer data);
static void test_rows_clear (RowsFixture *fix, gconstpointer data);
static void test_insert_at_pos (RowsFixture *fix, gconstpointer data);
static void test_insert_at_iter (RowsFixture *fix, gconstpointer data);
static void test_prepend (RowsFixture *fix, gconstpointer data);
static void test_append (RowsFixture *fix, gconstpointer data);
static void test_get_value (RowsFixture *fix, gconstpointer data);
static void test_no_transfer (RowsFixture *fix, gconstpointer data);
static void test_iter_backwards (RowsFixture *fix, gconstpointer data);
static void test_illegal_access (RowsFixture *fix, gconstpointer data);
static void test_sorted (RowsFixture *fix, gconstpointer data);
static void test_sort_stable (RowsFixture *fix, gconstpointer data);
static void test_sorted_with_sizes (RowsFixture *fix, gconstpointer data);
static void test_named_cols_append (RowsFixture *fix, gconstpointer data);
static void test_named_cols_fields (RowsFixture *fix, gconstpointer data);
static void test_named_cols_duplicated_fields (RowsFixture *fix, gconstpointer data);
static void test_named_cols_error (RowsFixture *fix, gconstpointer data);
static void test_model_iter_copy (RowsFixture *fix, gconstpointer data);
static void test_model_iter_free (RowsFixture *fix, gconstpointer data);
void
test_model_rows_create_suite (void)
{
#define ITER_DOMAIN "/ModelIter/Boxing"
#define SEQ_DOMAIN "/Model/Sequence/Rows"
#define PROXY_DOMAIN "/Model/Proxy/Rows"
#define TXN_DOMAIN "/Model/Transaction/Rows"
g_test_add (ITER_DOMAIN"/Copy", RowsFixture, 0,
seq_rows_setup, test_model_iter_copy, seq_rows_teardown);
g_test_add (ITER_DOMAIN"/Free", RowsFixture, 0,
seq_rows_setup, test_model_iter_free, seq_rows_teardown);
g_test_add (SEQ_DOMAIN"/Allocation", RowsFixture, 0,
seq_rows_setup, test_rows_allocation, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/Allocation", RowsFixture, 0,
proxy_rows_setup, test_rows_allocation, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/Allocation", RowsFixture, 0,
txn_rows_setup, test_rows_allocation, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/Clear", RowsFixture, 0,
seq_rows_setup, test_rows_clear, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/Clear", RowsFixture, 0,
proxy_rows_setup, test_rows_clear, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/Clear", RowsFixture, 0,
txn_rows_setup, test_rows_clear, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/InsertAtPos", RowsFixture, 0,
seq_rows_setup, test_insert_at_pos, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/InsertAtPos", RowsFixture, 0,
proxy_rows_setup, test_insert_at_pos, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/InsertAtPos", RowsFixture, 0,
txn_rows_setup, test_insert_at_pos, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/InsertAtIter", RowsFixture, 0,
seq_rows_setup, test_insert_at_iter, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/InsertAtIter", RowsFixture, 0,
proxy_rows_setup, test_insert_at_iter, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/InsertAtIter", RowsFixture, 0,
txn_rows_setup, test_insert_at_iter, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/Prepend", RowsFixture, 0,
seq_rows_setup, test_prepend, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/Prepend", RowsFixture, 0,
proxy_rows_setup, test_prepend, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/Prepend", RowsFixture, 0,
txn_rows_setup, test_prepend, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/Append", RowsFixture, 0,
seq_rows_setup, test_append, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/Append", RowsFixture, 0,
proxy_rows_setup, test_append, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/Append", RowsFixture, 0,
txn_rows_setup, test_append, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/GetValue", RowsFixture, 0,
seq_rows_setup, test_get_value, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/GetValue", RowsFixture, 0,
proxy_rows_setup, test_get_value, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/GetValue", RowsFixture, 0,
txn_rows_setup, test_get_value, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/NoTransfer", RowsFixture, 0,
seq_rows_setup, test_no_transfer, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/NoTransfer", RowsFixture, 0,
proxy_rows_setup, test_no_transfer, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/NoTransfer", RowsFixture, 0,
txn_rows_setup, test_no_transfer, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/IterBackwards", RowsFixture, 0,
seq_rows_setup, test_iter_backwards, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/IterBackwards", RowsFixture, 0,
proxy_rows_setup, test_iter_backwards, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/IterBackwards", RowsFixture, 0,
txn_rows_setup, test_iter_backwards, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/IllegalAccess", RowsFixture, 0,
seq_rows_setup, test_illegal_access, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/IllegalAccess", RowsFixture, 0,
proxy_rows_setup, test_illegal_access, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/IllegalAccess", RowsFixture, 0,
txn_rows_setup, test_illegal_access, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/Sorted", RowsFixture, 0,
seq_rows_setup, test_sorted, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/Sorted", RowsFixture, 0,
proxy_rows_setup, test_sorted, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/Sorted", RowsFixture, 0,
txn_rows_setup, test_sorted, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/Sorted/WithSizes", RowsFixture, 0,
seq_rows_setup, test_sorted_with_sizes, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/Sorted/WithSizes", RowsFixture, 0,
proxy_rows_setup, test_sorted_with_sizes, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/Sorted/WithSizes", RowsFixture, 0,
txn_rows_setup, test_sorted_with_sizes, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/StableSorted", RowsFixture, 0,
seq_rows_setup, test_sort_stable, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/StableSorted", RowsFixture, 0,
proxy_rows_setup, test_sort_stable, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/StableSorted", RowsFixture, 0,
txn_rows_setup, test_sort_stable, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/NamedColumns/Append", RowsFixture, 0,
seq_rows_setup, test_named_cols_append, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/NamedColumns/Append", RowsFixture, 0,
proxy_rows_setup, test_named_cols_append, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/NamedColumns/Append", RowsFixture, 0,
txn_rows_setup, test_named_cols_append, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/NamedColumns/Fields", RowsFixture, 0,
seq_rows_asv_setup, test_named_cols_fields, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/NamedColumns/Fields", RowsFixture, 0,
proxy_rows_asv_setup, test_named_cols_fields, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/NamedColumns/Fields", RowsFixture, 0,
txn_rows_asv_setup, test_named_cols_fields, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/NamedColumns/DuplicatedFields", RowsFixture, 0,
seq_rows_asv_setup, test_named_cols_duplicated_fields, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/NamedColumns/DuplicatedFields", RowsFixture, 0,
proxy_rows_asv_setup, test_named_cols_duplicated_fields, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/NamedColumns/DuplicatedFields", RowsFixture, 0,
txn_rows_asv_setup, test_named_cols_duplicated_fields, txn_rows_teardown);
g_test_add (SEQ_DOMAIN"/NamedColumns/Invalid", RowsFixture, 0,
seq_rows_setup, test_named_cols_error, seq_rows_teardown);
g_test_add (PROXY_DOMAIN"/NamedColumns/Invalid", RowsFixture, 0,
proxy_rows_setup, test_named_cols_error, proxy_rows_teardown);
g_test_add (TXN_DOMAIN"/NamedColumns/Invalid", RowsFixture, 0,
txn_rows_setup, test_named_cols_error, txn_rows_teardown);
}
/* setup & teardown functions */
static void
seq_rows_setup (RowsFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "i", "s", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
}
static void
seq_rows_teardown (RowsFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
fix->model = NULL;
}
static void
proxy_rows_setup (RowsFixture *fix, gconstpointer data)
{
seq_rows_setup (fix, data);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL,
"back-end", fix->model,
NULL);
g_assert (DEE_IS_PROXY_MODEL (fix->model));
}
static void
proxy_rows_teardown (RowsFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
fix->model = NULL;
}
static void
txn_rows_setup (RowsFixture *fix, gconstpointer data)
{
seq_rows_setup (fix, data);
fix->model = dee_transaction_new (fix->model);
g_assert (DEE_IS_TRANSACTION (fix->model));
}
static void
txn_rows_teardown (RowsFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
fix->model = NULL;
}
static void
seq_rows_asv_setup (RowsFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "i", "s", "a{sv}", "a{sv}", NULL);
dee_model_set_column_names (fix->model, "count", "name",
"hints", "hints2", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
}
static void
proxy_rows_asv_setup (RowsFixture *fix, gconstpointer data)
{
seq_rows_asv_setup (fix, data);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL,
"back-end", fix->model,
NULL);
g_assert (DEE_IS_PROXY_MODEL (fix->model));
}
static void
txn_rows_asv_setup (RowsFixture *fix, gconstpointer data)
{
seq_rows_asv_setup (fix, data);
fix->model = dee_transaction_new (fix->model);
g_assert (DEE_IS_TRANSACTION (fix->model));
}
/* test cases */
static void test_model_iter_copy (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter, *copied;
iter = dee_model_append (fix->model, 10, "Rooney");
copied = g_boxed_copy (DEE_TYPE_MODEL_ITER, iter);
g_assert (iter == copied);
}
static void test_model_iter_free (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
iter = dee_model_append (fix->model, 10, "Rooney");
g_boxed_free (DEE_TYPE_MODEL_ITER, iter);
/* And since it's supposed to be a no-op we can do this */
for (i = 0; i < 100; i++)
g_boxed_free (DEE_TYPE_MODEL_ITER, iter);
/* Didn't crash? Good! */
}
static void
test_rows_allocation (RowsFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_MODEL (fix->model));
}
static gint n_clear_sigs = 0;
static void
on_clear_row_removed (DeeModel *model, DeeModelIter *iter)
{
n_clear_sigs++;
}
static void
test_rows_clear (RowsFixture *fix, gconstpointer data)
{
gint i;
for (i = 0; i < 1000; i++)
{
dee_model_append (fix->model, 10, "Rooney");
}
g_assert_cmpint (1000, ==, dee_model_get_n_rows (fix->model));
g_signal_connect (fix->model, "row-removed",
G_CALLBACK (on_clear_row_removed), NULL);
n_clear_sigs = 0;
dee_model_clear (fix->model);
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
g_assert_cmpint (1000, ==, n_clear_sigs);
}
static void
test_insert_at_pos (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
dee_model_append (fix->model, 10, "Rooney");
dee_model_append (fix->model, 10, "Rooney");
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
dee_model_insert (fix->model, 1, 27, "Not Rooney");
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
g_assert (dee_model_is_first (fix->model, iter));
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Rooney");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (27, ==, i);
g_assert_cmpstr (str, ==, "Not Rooney");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Rooney");
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static void
test_insert_at_iter (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
dee_model_append (fix->model, 10, "Rooney");
dee_model_append (fix->model, 10, "Rooney");
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
iter = dee_model_next (fix->model, iter);
dee_model_insert_before (fix->model, iter, 27, "Not Rooney");
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Rooney");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (27, ==, i);
g_assert_cmpstr (str, ==, "Not Rooney");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Rooney");
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static void
test_prepend (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
dee_model_prepend (fix->model, 11, "Mid");
dee_model_append (fix->model, 12, "Last");
dee_model_prepend (fix->model, 10, "First");
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "First");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (11, ==, i);
g_assert_cmpstr (str, ==, "Mid");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (12, ==, i);
g_assert_cmpstr (str, ==, "Last");
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static void
test_append (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
dee_model_append (fix->model, 11, "First");
dee_model_append (fix->model, 12, "Mid");
dee_model_append (fix->model, 10, "Last");
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (11, ==, i);
g_assert_cmpstr (str, ==, "First");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (12, ==, i);
g_assert_cmpstr (str, ==, "Mid");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Last");
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static void
test_get_value (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
GVariant *variant;
dee_model_set_column_names (fix->model, "count", "name", NULL);
dee_model_append (fix->model, 11, "First");
dee_model_append (fix->model, 12, "Mid");
dee_model_append (fix->model, 10, "Last");
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
variant = dee_model_get_value (fix->model, iter, 0);
g_assert_cmpint (g_variant_get_int32 (variant), ==, 11);
g_variant_unref (variant);
iter = dee_model_next (fix->model, iter);
variant = dee_model_get_value (fix->model, iter, 1);
g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "Mid");
g_variant_unref (variant);
iter = dee_model_next (fix->model, iter);
variant = dee_model_get_value_by_name (fix->model, iter, "count");
g_assert_cmpint (g_variant_get_int32 (variant), ==, 10);
g_variant_unref (variant);
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static void
test_iter_backwards (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
dee_model_append (fix->model, 11, "First");
dee_model_append (fix->model, 12, "Mid");
dee_model_append (fix->model, 10, "Last");
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_last_iter (fix->model);
g_assert (dee_model_is_last (fix->model, iter));
iter = dee_model_prev (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Last");
iter = dee_model_prev (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (12, ==, i);
g_assert_cmpstr (str, ==, "Mid");
iter = dee_model_prev (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (11, ==, i);
g_assert_cmpstr (str, ==, "First");
g_assert (dee_model_is_first (fix->model, iter));
}
/* Make sure the the memory allocated for strings is not reffed inside
* the model. Also checks that strings are returned as const pointers */
static void
test_no_transfer (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gchar *orig, *str1, *str2;
orig = g_strdup ("test");
dee_model_append (fix->model, 1, orig);
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
/* This should work, of course */
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, NULL, &str1);
g_assert_cmpstr (str1, ==, "test");
/* Assert that we get a const pointer to the string back.
* Strings should behave like that */
dee_model_get (fix->model, iter, NULL, &str2);
g_assert (str1 == str2);
/* Modify orig in place and assert it doesn't affect the model */
orig[0] = 'P';
dee_model_get (fix->model, iter, NULL, &str1, -1);
g_assert_cmpstr (str1, ==, "test");
/* Now free orig and make sure we can still read from the model */
g_free (orig);
dee_model_get (fix->model, iter, NULL, &str1, -1);
g_assert_cmpstr (str1, ==, "test");
}
/* Try to get and set values from a removed row */
static void
test_illegal_access (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
dee_model_append (fix->model, 1, "Hello");
iter = dee_model_append (fix->model, 1, "Mary");
dee_model_append (fix->model, 1, "Lou");
dee_model_remove (fix->model, iter);
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "Mary");
exit (0); /* successful test run */
}
g_test_trap_assert_failed ();
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
dee_model_set (fix->model, iter, 27, "Marie");
exit (0); /* successful test run */
}
g_test_trap_assert_failed ();
}
static gint
cmp_constant (GVariant **row1, GVariant **row2, gpointer user_data)
{
g_assert_cmpstr (user_data, ==, "test-user-data");
return 0;
}
static gint
cmp_col_0 (GVariant **row1, GVariant **row2, gpointer user_data)
{
g_assert_cmpstr (user_data, ==, "test-user-data");
//g_debug ("CMP %i %i", g_variant_get_int32 (row1[0]), g_variant_get_int32 (row2[0]));
return g_variant_get_int32 (row2[0]) - g_variant_get_int32 (row1[0]);
}
static void
test_sorted (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *hter, *iter, *jter, *kter;
gboolean was_found;
/* FINAL MODEL: [(28,s), (27,s), (26,s), (25,s)]
* ~= [hter, iter, jter, kter] */
/* Test find() with an empty model. With NULL was_found arg */
iter = dee_model_find_sorted (fix->model, cmp_col_0, "test-user-data", NULL,
0, "");
g_assert (iter == dee_model_get_last_iter (fix->model));
/* Test find() with an empty model. With non-NULL was_found arg */
was_found = TRUE;
iter = dee_model_find_sorted (fix->model, cmp_col_0, "test-user-data", &was_found,
0, "");
g_assert (!was_found);
g_assert (iter == dee_model_get_last_iter (fix->model));
/* Insert the first row */
iter = dee_model_insert_sorted (fix->model, cmp_col_0, "test-user-data",
27, "Sorta sorted");
g_assert (iter != dee_model_get_last_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
/* Test append */
kter = dee_model_insert_sorted (fix->model, cmp_col_0, "test-user-data",
25, "Sorta sorted");
g_assert (kter != dee_model_get_last_iter (fix->model));
g_assert (kter != dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (kter != iter);
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
g_assert (kter == dee_model_next (fix->model, iter));
/* Test insert in between rows */
jter = dee_model_insert_sorted (fix->model, cmp_col_0, "test-user-data",
26, "Sorta sorted");
g_assert (jter != dee_model_get_last_iter (fix->model));
g_assert (jter != dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (jter != iter);
g_assert (jter != kter);
g_assert (jter == dee_model_next (fix->model, iter));
g_assert (kter == dee_model_next (fix->model, jter));
g_assert (dee_model_get_last_iter (fix->model) == dee_model_next (fix->model, kter));
/* Test prepend */
hter = dee_model_insert_sorted (fix->model, cmp_col_0, "test-user-data",
28, "Sorta sorted");
g_assert (hter == dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_next (fix->model, hter));
g_assert_cmpint (4, ==, dee_model_get_n_rows (fix->model));
/* Test find() again now that we have data in the model */
DeeModelIter *result;
result = dee_model_find_sorted (fix->model, cmp_col_0, "test-user-data", NULL,
24, "");
g_assert (result == dee_model_get_last_iter (fix->model));
result = dee_model_find_sorted (fix->model, cmp_col_0, "test-user-data", NULL,
28, "");
g_assert (result == hter);
/* Test find(). With non-NULL was_found arg */
was_found = TRUE;
result = dee_model_find_sorted (fix->model, cmp_col_0, "test-user-data", &was_found,
24, "");
g_assert (result == dee_model_get_last_iter (fix->model));
result = dee_model_find_sorted (fix->model, cmp_col_0, "test-user-data", &was_found,
28, "");
g_assert (was_found);
g_assert (result == hter);
}
static void
test_sort_stable (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *hter, *iter, *jter, *kter;
/* FINAL MODEL: [(25,s), (26,s), (27,s), (28,s)]
* ~= [hter, iter, jter, kter] */
/* Insert the first row */
iter = dee_model_insert_sorted (fix->model, cmp_constant, "test-user-data",
25, "Stable");
g_assert (iter != dee_model_get_last_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
/* Second row */
kter = dee_model_insert_sorted (fix->model, cmp_constant, "test-user-data",
26, "Stable");
g_assert (kter != dee_model_get_last_iter (fix->model));
g_assert (kter != dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (kter != iter);
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
g_assert (kter == dee_model_next (fix->model, iter));
/* Third row */
jter = dee_model_insert_sorted (fix->model, cmp_constant, "test-user-data",
27, "Stable");
g_assert (jter != dee_model_get_last_iter (fix->model));
g_assert (jter != dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (jter != iter);
g_assert (jter != kter);
g_assert (jter == dee_model_next (fix->model, kter));
g_assert (dee_model_get_last_iter (fix->model) == dee_model_next (fix->model, jter));
/* Fourth row */
hter = dee_model_insert_sorted (fix->model, cmp_constant, "test-user-data",
28, "Stable");
g_assert (hter == dee_model_next (fix->model, jter));
g_assert_cmpint (4, ==, dee_model_get_n_rows (fix->model));
}
static gint
sized_cmp_col_0 (GVariant **row1, guint row1_length,
GVariant **row2, guint row2_length, gpointer user_data)
{
g_assert_cmpstr (user_data, ==, "test-user-data");
g_assert_cmpuint (row1_length, ==, 2);
g_assert_cmpuint (row2_length, ==, 2);
g_assert_cmpuint (row1_length, ==, row2_length);
return g_variant_get_int32 (row2[0]) - g_variant_get_int32 (row1[0]);
}
static void
test_sorted_with_sizes (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *hter, *iter, *jter, *kter;
gboolean was_found;
GVariant *row_spec[2];
/* FINAL MODEL: [(28,s), (27,s), (26,s), (25,s)]
* ~= [hter, iter, jter, kter] */
row_spec[0] = g_variant_new_int32 (0);
row_spec[1] = g_variant_new_string ("");
/* Test find() with an empty model. With NULL was_found arg */
iter = dee_model_find_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data",
NULL);
g_assert (iter == dee_model_get_last_iter (fix->model));
/* Test find() with an empty model. With non-NULL was_found arg */
was_found = TRUE;
iter = dee_model_find_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data",
&was_found);
g_assert (!was_found);
g_assert (iter == dee_model_get_last_iter (fix->model));
/* Insert the first row */
row_spec[0] = g_variant_new_int32 (27);
row_spec[1] = g_variant_new_string ("Sorta sorted");
iter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data");
g_assert (iter != dee_model_get_last_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
/* Test append */
row_spec[0] = g_variant_new_int32 (25);
row_spec[1] = g_variant_new_string ("Sorta sorted");
kter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data");
g_assert (kter != dee_model_get_last_iter (fix->model));
g_assert (kter != dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (kter != iter);
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
g_assert (kter == dee_model_next (fix->model, iter));
/* Test insert in between rows */
row_spec[0] = g_variant_new_int32 (26);
row_spec[1] = g_variant_new_string ("Sorta sorted");
jter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data");
g_assert (jter != dee_model_get_last_iter (fix->model));
g_assert (jter != dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_get_first_iter (fix->model));
g_assert (jter != iter);
g_assert (jter != kter);
g_assert (jter == dee_model_next (fix->model, iter));
g_assert (kter == dee_model_next (fix->model, jter));
g_assert (dee_model_get_last_iter (fix->model) == dee_model_next (fix->model, kter));
/* Test prepend */
row_spec[0] = g_variant_new_int32 (28);
row_spec[1] = g_variant_new_string ("Sorta sorted");
hter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data");
g_assert (hter == dee_model_get_first_iter (fix->model));
g_assert (iter == dee_model_next (fix->model, hter));
g_assert_cmpint (4, ==, dee_model_get_n_rows (fix->model));
/* Test find() again now that we have data in the model */
DeeModelIter *result;
row_spec[0] = g_variant_new_int32 (24);
row_spec[1] = g_variant_new_string ("");
result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data", NULL);
g_assert (result == dee_model_get_last_iter (fix->model));
row_spec[0] = g_variant_new_int32 (28);
row_spec[1] = g_variant_new_string ("");
result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data", NULL);
g_assert (result == hter);
/* Test find(). With non-NULL was_found arg */
was_found = FALSE;
row_spec[0] = g_variant_new_int32 (24);
row_spec[1] = g_variant_new_string ("");
result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data", &was_found);
g_assert (result == dee_model_get_last_iter (fix->model));
row_spec[0] = g_variant_new_int32 (28);
row_spec[1] = g_variant_new_string ("");
result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec,
sized_cmp_col_0,
"test-user-data", &was_found);
g_assert (was_found);
g_assert (result == hter);
}
static void
test_named_cols_append (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
GVariant *row_members[2];
dee_model_set_column_names (fix->model, "count", "name", NULL);
dee_model_build_named_row (fix->model, row_members,
"count", 11, "name", "First", NULL);
dee_model_append_row (fix->model, row_members);
dee_model_build_named_row (fix->model, row_members,
"name", "Mid", "count", 12, NULL);
dee_model_append_row (fix->model, row_members);
dee_model_build_named_row (fix->model, row_members,
"count", 10, "name", "Last", NULL);
dee_model_append_row (fix->model, row_members);
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (11, ==, i);
g_assert_cmpstr (str, ==, "First");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (12, ==, i);
g_assert_cmpstr (str, ==, "Mid");
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Last");
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static void
test_named_cols_fields (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
gchar *str;
GVariant *row_members[4];
GVariant *dict, *dummy;
GHashTable *fields_schemas;
fields_schemas = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (fields_schemas, "object-path", "o");
g_hash_table_insert (fields_schemas, "id", "i");
dee_model_register_vardict_schema (fix->model, 2, fields_schemas);
g_hash_table_unref (fields_schemas);
dee_model_build_named_row (fix->model, row_members,
"count", 11, "name", "First", NULL);
dee_model_append_row (fix->model, row_members);
dee_model_build_named_row (fix->model, row_members,
"name", "Mid", "count", 12,
"object-path", "/org/example",
"hints::id", 8123, NULL);
dee_model_append_row (fix->model, row_members);
dee_model_build_named_row (fix->model, row_members,
"count", 10, "name", "Last", "id", 90, NULL);
dee_model_append_row (fix->model, row_members);
/* Commence checks */
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &i, &str, &dict, &dummy);
g_assert_cmpint (11, ==, i);
g_assert_cmpstr (str, ==, "First");
g_assert_cmpuint (0, ==, g_variant_n_children (dict));
g_assert (dee_model_get_value_by_name (fix->model, iter, "object-path") == NULL);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str, &dict, &dummy);
g_assert_cmpint (12, ==, i);
g_assert_cmpstr (str, ==, "Mid");
g_assert_cmpuint (2, ==, g_variant_n_children (dict));
g_assert_cmpstr ("/org/example", ==, g_variant_get_string (g_variant_lookup_value (dict, "object-path", G_VARIANT_TYPE_OBJECT_PATH), NULL));
g_assert_cmpint (8123, ==, g_variant_get_int32 (dee_model_get_value_by_name (fix->model, iter, "id")));
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str, &dict, &dummy);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Last");
g_assert_cmpuint (1, ==, g_variant_n_children (dict));
g_assert_cmpint (90, ==, g_variant_get_int32 (dee_model_get_value_by_name (fix->model, iter, "id")));
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
}
static gboolean
expected_error_handler (const gchar *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data)
{
return FALSE;
}
static void
ignore_error_handler (const gchar *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data)
{
}
static void
test_named_cols_duplicated_fields (RowsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
guint handler_id;
gchar *str;
GVariant *row_members[4];
GVariant *dict1, *dict2;
GHashTable *fields_schemas;
g_test_log_set_fatal_handler (expected_error_handler, NULL);
handler_id = g_log_set_handler ("dee", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL,
ignore_error_handler, NULL);
fields_schemas = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (fields_schemas, "id", "i");
dee_model_register_vardict_schema (fix->model, 2, fields_schemas);
g_hash_table_insert (fields_schemas, "id", "s");
g_hash_table_insert (fields_schemas, "extra-id", "i");
dee_model_register_vardict_schema (fix->model, 3, fields_schemas);
g_hash_table_unref (fields_schemas);
dee_model_build_named_row (fix->model, row_members,
"count", 11, "name", "First", NULL);
dee_model_append_row (fix->model, row_members);
dee_model_build_named_row (fix->model, row_members,
"name", "Mid", "count", 12,
"hints::id", 8123,
"hints2::id", "8123", NULL);
dee_model_append_row (fix->model, row_members);
dee_model_build_named_row (fix->model, row_members,
"count", 10, "name", "Last",
"hints2::id", "foo", NULL);
dee_model_append_row (fix->model, row_members);
/* Commence checks */
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
iter = dee_model_get_first_iter (fix->model);
dee_model_get (fix->model, iter, &i, &str, &dict1, &dict2);
g_assert_cmpint (11, ==, i);
g_assert_cmpstr (str, ==, "First");
g_assert_cmpuint (0, ==, g_variant_n_children (dict1));
g_assert_cmpuint (0, ==, g_variant_n_children (dict2));
g_assert (dee_model_get_value_by_name (fix->model, iter, "hints::id") == NULL);
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str, &dict1, &dict2);
g_assert_cmpint (12, ==, i);
g_assert_cmpstr (str, ==, "Mid");
g_assert_cmpuint (1, ==, g_variant_n_children (dict1));
g_assert_cmpuint (1, ==, g_variant_n_children (dict2));
g_assert_cmpint (8123, ==, g_variant_get_int32 (dee_model_get_value_by_name (fix->model, iter, "hints::id")));
g_assert_cmpstr ("8123", ==, g_variant_get_string (dee_model_get_value_by_name (fix->model, iter, "hints2::id"), NULL));
iter = dee_model_next (fix->model, iter);
dee_model_get (fix->model, iter, &i, &str, &dict1, &dict2);
g_assert_cmpint (10, ==, i);
g_assert_cmpstr (str, ==, "Last");
g_assert_cmpuint (0, ==, g_variant_n_children (dict1));
g_assert_cmpuint (1, ==, g_variant_n_children (dict2));
g_assert_cmpstr ("foo", ==, g_variant_get_string (dee_model_get_value_by_name (fix->model, iter, "hints2::id"), NULL));
iter = dee_model_next (fix->model, iter);
g_assert (dee_model_is_last (fix->model, iter));
g_log_remove_handler ("dee", handler_id);
}
static void
test_named_cols_error (RowsFixture *fix, gconstpointer data)
{
GVariant *row_members[2];
GVariant **result;
guint handler_id;
dee_model_set_column_names (fix->model, "count", "name", NULL);
g_test_log_set_fatal_handler (expected_error_handler, NULL);
handler_id = g_log_set_handler ("dee", G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL,
ignore_error_handler, NULL);
/* Only first col set */
result = dee_model_build_named_row (fix->model, row_members,
"name", "First", NULL);
g_assert (result == NULL);
/* Only second col set */
result = dee_model_build_named_row (fix->model, row_members,
"count", 12, NULL);
g_assert (result == NULL);
/* Unregistered cols set */
result = dee_model_build_named_row (fix->model, row_members,
"nm", "Foo", "cnt", 12, NULL);
g_assert (result == NULL);
g_log_remove_handler ("dee", handler_id);
}
dee-1.2.7+15.04.20150304/tests/test-model-tags.c 0000644 0000153 0000161 00000026710 12475676210 021144 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Neil Jagdish Patel
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
#include
#include
typedef struct
{
DeeModel *m;
} Fixture;
static void sequence_model_setup (Fixture *fix, gconstpointer data);
static void sequence_model_teardown (Fixture *fix, gconstpointer data);
static void shared_model_setup (Fixture *fix, gconstpointer data);
static void shared_model_teardown (Fixture *fix, gconstpointer data);
static void test_no_tags (Fixture *fix, gconstpointer data);
static void test_one_tag (Fixture *fix, gconstpointer data);
static void test_two_tags (Fixture *fix, gconstpointer data);
static void test_late_tag (Fixture *fix, gconstpointer data);
static void test_destroy_tag (Fixture *fix, gconstpointer data);
static void test_tag_access_in_row_removed_handler (Fixture *fix, gconstpointer data);
void
test_model_tags_create_suite (void)
{
#define SEQUENCE_MODEL_DOMAIN "/ModelTags/SequenceModel"
#define SHARED_MODEL_DOMAIN "/ModelTags/SharedModel"
g_test_add (SEQUENCE_MODEL_DOMAIN"/NoTags", Fixture, 0,
sequence_model_setup, test_no_tags, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/NoTags", Fixture, 0,
shared_model_setup, test_no_tags, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/OneTag", Fixture, 0,
sequence_model_setup, test_one_tag, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/OneTag", Fixture, 0,
shared_model_setup, test_one_tag, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/TwoTags", Fixture, 0,
sequence_model_setup, test_two_tags, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/TwoTags", Fixture, 0,
shared_model_setup, test_two_tags, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/LateTag", Fixture, 0,
sequence_model_setup, test_late_tag, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/LateTag", Fixture, 0,
shared_model_setup, test_late_tag, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/DestroyFunc", Fixture, 0,
sequence_model_setup, test_destroy_tag, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/DestroyFunc", Fixture, 0,
shared_model_setup, test_destroy_tag, shared_model_teardown);
g_test_add (SEQUENCE_MODEL_DOMAIN"/TagAccessInRowRemovedHandler", Fixture, 0,
sequence_model_setup, test_tag_access_in_row_removed_handler, sequence_model_teardown);
g_test_add (SHARED_MODEL_DOMAIN"/TagAccessInRowRemovedHandler", Fixture, 0,
shared_model_setup, test_tag_access_in_row_removed_handler, shared_model_teardown);
}
static void
sequence_model_setup (Fixture *fix, gconstpointer data)
{
fix->m = dee_sequence_model_new ();
dee_model_set_schema (fix->m, "i", "s", NULL);
}
static void
sequence_model_teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->m);
fix->m = NULL;
}
static void
shared_model_setup (Fixture *fix, gconstpointer data)
{
fix->m = dee_shared_model_new ("org.example.ThisIsNotATest");
dee_model_set_schema (fix->m, "i", "s", NULL);
}
static void
shared_model_teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->m);
fix->m = NULL;
}
static void
test_no_tags (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gpointer tag;
iter = dee_model_append (fix->m, 27, "Hello");
/* Check that getting an undefined tag fails gracefully */
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
tag = NULL;
tag = dee_model_get_tag (fix->m, iter, GUINT_TO_POINTER (123));
g_assert (tag == NULL);
exit (0); /* successful test run */
}
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*Unable to look up tag. No tags registered on DeeSequenceModel*");
/* Ditto for setting undefined tags */
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
dee_model_set_tag (fix->m, iter, GUINT_TO_POINTER (123), GUINT_TO_POINTER (321));
exit (0); /* successful test run */
}
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*Unable to look up tag. No tags registered on DeeSequenceModel*");
}
static void
test_one_tag (Fixture *fix, gconstpointer data)
{
DeeModelTag *tag;
DeeModelIter *iter1, *iter2;
tag = dee_model_register_tag (fix->m, NULL);
iter1 = dee_model_append (fix->m, 27, "Hello");
iter2 = dee_model_append (fix->m, 68, "world");
/* Set+Get */
dee_model_set_tag (fix->m, iter1, tag, "tag1");
dee_model_set_tag (fix->m, iter2, tag, "tag2");
g_assert_cmpstr ("tag1", ==, dee_model_get_tag (fix->m, iter1, tag));
g_assert_cmpstr ("tag2", ==, dee_model_get_tag (fix->m, iter2, tag));
/* Clear a tag */
dee_model_clear_tag (fix->m, iter1, tag);
g_assert (dee_model_get_tag (fix->m, iter1, tag) == NULL);
g_assert_cmpstr ("tag2", ==, dee_model_get_tag (fix->m, iter2, tag));
/* Override exiting */
dee_model_set_tag (fix->m, iter2, tag, "tag3");
g_assert (dee_model_get_tag (fix->m, iter1, tag) == NULL);
g_assert_cmpstr ("tag3", ==, dee_model_get_tag (fix->m, iter2, tag));
/* Check that getting an undefined tag fails gracefully */
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
tag = NULL;
tag = dee_model_get_tag (fix->m, iter1, GUINT_TO_POINTER (123));
g_assert (tag == NULL);
exit (0); /* successful test run */
}
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*Unable to find tag 123*");
/* Ditto for setting undefined tags */
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
dee_model_set_tag (fix->m, iter1, GUINT_TO_POINTER (123), GUINT_TO_POINTER (321));
exit (0); /* successful test run */
}
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*Unable to find tag 123*");
}
static void
test_two_tags (Fixture *fix, gconstpointer data)
{
DeeModelTag *tag1, *tag2;
DeeModelIter *iter1, *iter2;
tag1 = dee_model_register_tag (fix->m, NULL);
tag2 = dee_model_register_tag (fix->m, (GDestroyNotify) g_free);
iter1 = dee_model_append (fix->m, 27, "Hello");
iter2 = dee_model_append (fix->m, 68, "world");
dee_model_set_tag (fix->m, iter1, tag1, "tag1-value1");
dee_model_set_tag (fix->m, iter2, tag1, "tag1-value2");
dee_model_set_tag (fix->m, iter1, tag2, g_strdup ("tag2-value1"));
dee_model_set_tag (fix->m, iter2, tag2, g_strdup ("tag2-value2"));
g_assert_cmpstr ("tag1-value1", ==, dee_model_get_tag (fix->m, iter1, tag1));
g_assert_cmpstr ("tag1-value2", ==, dee_model_get_tag (fix->m, iter2, tag1));
g_assert_cmpstr ("tag2-value1", ==, dee_model_get_tag (fix->m, iter1, tag2));
g_assert_cmpstr ("tag2-value2", ==, dee_model_get_tag (fix->m, iter2, tag2));
/* Clear one tag. The rest should be unchanged */
dee_model_clear_tag (fix->m, iter1, tag1);
g_assert (dee_model_get_tag (fix->m, iter1, tag1) == NULL);
g_assert_cmpstr ("tag1-value2", ==, dee_model_get_tag (fix->m, iter2, tag1));
g_assert_cmpstr ("tag2-value1", ==, dee_model_get_tag (fix->m, iter1, tag2));
g_assert_cmpstr ("tag2-value2", ==, dee_model_get_tag (fix->m, iter2, tag2));
}
static void
test_late_tag (Fixture *fix, gconstpointer data)
{
/* The point here is to try and register a tag *after* we begun populating
* the model */
DeeModelTag *tag1, *tag2;
DeeModelIter *iter1, *iter2;
tag1 = dee_model_register_tag (fix->m, NULL);
iter1 = dee_model_append (fix->m, 27, "Hello");
iter2 = dee_model_append (fix->m, 68, "world");
/* Start working randomly with the model */
dee_model_set_tag (fix->m, iter1, tag1, "tag1-value1");
g_assert_cmpstr ("tag1-value1", ==, dee_model_get_tag (fix->m, iter1, tag1));
g_assert (dee_model_get_tag (fix->m, iter2, tag1) == NULL);
/* With some rows and tags in the model, now register another tag.
* Assert that all rows have this tag in unset state */
tag2 = dee_model_register_tag (fix->m, (GDestroyNotify) g_free);
g_assert (dee_model_get_tag (fix->m, iter1, tag2) == NULL);
g_assert (dee_model_get_tag (fix->m, iter2, tag2) == NULL);
/* Set the new tag and verify the complete state */
dee_model_set_tag (fix->m, iter1, tag2, g_strdup ("tag2-value1"));
dee_model_set_tag (fix->m, iter2, tag2, g_strdup ("tag2-value2"));
g_assert_cmpstr ("tag1-value1", ==, dee_model_get_tag (fix->m, iter1, tag1));
g_assert (dee_model_get_tag (fix->m, iter2, tag1) == NULL);
g_assert_cmpstr ("tag2-value1", ==, dee_model_get_tag (fix->m, iter1, tag2));
g_assert_cmpstr ("tag2-value2", ==, dee_model_get_tag (fix->m, iter2, tag2));
}
static void
destroy_tag (gpointer tag_value)
{
/* A GDestroyNotify that twiddles with a string */
((gchar *) tag_value)[0] = '*';
}
static void
test_destroy_tag (Fixture *fix, gconstpointer data)
{
/* Assert that the destroy function is indeed called */
gchar *tag_value = g_strdup ("#");
DeeModelTag *tag;
DeeModelIter *iter1;
tag = dee_model_register_tag (fix->m, destroy_tag);
iter1 = dee_model_append (fix->m, 27, "Hello");
/* Set+Get */
dee_model_set_tag (fix->m, iter1, tag, tag_value);
g_assert_cmpstr ("#", ==, dee_model_get_tag (fix->m, iter1, tag));
/* Assert destroy func triggered. Changing "#" to "*" */
dee_model_clear_tag (fix->m, iter1, tag);
g_assert (dee_model_get_tag (fix->m, iter1, tag) == NULL);
g_assert_cmpstr ("*", ==, tag_value);
/* Change the annotation back to "#" and make sure that destroy is also
* called when we remove the row */
tag_value[0] = '#';
dee_model_set_tag (fix->m, iter1, tag, tag_value);
g_assert_cmpstr ("#", ==, dee_model_get_tag (fix->m, iter1, tag));
dee_model_remove (fix->m, iter1);
g_assert_cmpstr ("*", ==, tag_value);
g_free (tag_value);
}
static int row_removed_handler_called = 0;
static void
row_removed_handler (DeeModel *model, DeeModelIter *iter, DeeModelTag *tag)
{
/* Assert that we can read the tag before it's freed. We use a dummy
* free that sets the tag to "*" to detect this */
g_assert_cmpstr (dee_model_get_tag (model, iter, tag), ==, "#");
row_removed_handler_called = 1;
}
static void
test_tag_access_in_row_removed_handler (Fixture *fix, gconstpointer data)
{
/* Check that we can access a tag in the row-removed handler,
* before the tag is destroyed */
gchar *tag_value = g_strdup ("#");
DeeModelTag *tag;
DeeModelIter *iter1;
tag = dee_model_register_tag (fix->m, destroy_tag);
iter1 = dee_model_append (fix->m, 27, "Hello");
dee_model_set_tag (fix->m, iter1, tag, tag_value);
g_signal_connect (fix->m, "row-removed",
G_CALLBACK (row_removed_handler), tag);
dee_model_clear (fix->m);
g_assert_cmpint (row_removed_handler_called, ==, 1);
g_assert_cmpstr ("*", ==, tag_value);
g_free (tag_value);
}
dee-1.2.7+15.04.20150304/tests/model-helper-add3rows.c 0000644 0000153 0000161 00000007166 12475676210 022240 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
guint64 before_begin_seqnum, before_end_seqnum,
after_begin_seqnum, after_end_seqnum;
static void
_begin_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
before_begin_seqnum = begin_seqnum;
before_end_seqnum = end_seqnum;
}
static void
_end_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
after_begin_seqnum = begin_seqnum;
after_end_seqnum = end_seqnum;
}
static void
_row_added (DeeModel *model, DeeModelIter *iter, GSList **rows_so_far)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*rows_so_far = g_slist_append (*rows_so_far, iter);
}
/* Expects and empty clone and three rows-added signals */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
GSList *rows_added;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
g_signal_connect (model, "begin-transaction", G_CALLBACK (_begin_txn), NULL);
g_signal_connect (model, "end-transaction", G_CALLBACK (_end_txn), NULL);
/* Wait until we find the leader */
if (gtx_wait_for_signal (G_OBJECT (model), 1000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for model to synchronize");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 0);
/* Listen for changes */
rows_added = NULL;
g_signal_connect (model, "row-added", G_CALLBACK (_row_added), &rows_added);
/* Wait for some RowsAdded signals */
gtx_yield_main_loop (1000);
/* Check that we got what we expected */
g_assert_cmpint (g_slist_length (rows_added), == , 3);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
iter = (DeeModelIter*) g_slist_nth (rows_added, 0)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "zero");
iter = (DeeModelIter*) g_slist_nth (rows_added, 1)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "one");
iter = (DeeModelIter*) g_slist_nth (rows_added, 2)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 2);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "two");
gtx_assert_last_unref (model);
g_slist_free (rows_added);
g_assert (before_begin_seqnum == after_begin_seqnum);
g_assert (before_end_seqnum == after_end_seqnum);
g_assert_cmpint (0, ==, (guint) before_begin_seqnum);
g_assert_cmpint (3, ==, (guint) before_end_seqnum);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-resource-manager.c 0000644 0000153 0000161 00000014516 12475676210 022350 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Neil Jagdish Patel
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
#include
typedef struct
{
DeeModel *orig;
DeeModel *copy;
DeeResourceManager *rm;
} Fixture;
static void sequence_model_setup (Fixture *fix, gconstpointer data);
static void sequence_model_teardown (Fixture *fix, gconstpointer data);
static void shared_model_setup (Fixture *fix, gconstpointer data);
static void shared_model_teardown (Fixture *fix, gconstpointer data);
static void test_model_persistence (Fixture *fix, gconstpointer data);
static void test_resource_manager_default (Fixture *fix, gconstpointer data);
void
test_resource_manager_create_suite (void)
{
#define DOMAIN "/ResourceManager"
g_test_add (DOMAIN"/Default", Fixture, 0,
NULL, test_resource_manager_default, NULL);
g_test_add (DOMAIN"/SequenceModel", Fixture, 0,
sequence_model_setup, test_model_persistence, sequence_model_teardown);
g_test_add (DOMAIN"/SharedModel", Fixture, 0,
shared_model_setup, test_model_persistence, shared_model_teardown);
}
static void
sequence_model_setup (Fixture *fix, gconstpointer data)
{
fix->orig = dee_sequence_model_new ();
dee_model_set_schema (fix->orig, "i", "s", NULL);
fix->copy = NULL;
fix->rm = dee_file_resource_manager_new ("dee-test-resource-manager/nested/resources");
g_assert (DEE_IS_SEQUENCE_MODEL (fix->orig));
}
static void
sequence_model_teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->orig);
fix->orig = NULL;
if (fix->copy)
g_object_unref (fix->copy);
fix->copy = NULL;
g_object_unref (fix->rm);
fix->rm = NULL;
}
static void
shared_model_setup (Fixture *fix, gconstpointer data)
{
fix->orig = dee_shared_model_new ("org.example.ThisIsNotATest");
dee_model_set_schema (fix->orig, "i", "s", NULL);
fix->copy = NULL;
fix->rm = dee_file_resource_manager_new ("dee-test-resource-manager/nested/resources");
g_assert (DEE_IS_SHARED_MODEL (fix->orig));
}
static void
shared_model_teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->orig);
fix->orig = NULL;
if (fix->copy)
g_object_unref (fix->copy);
fix->copy = NULL;
g_object_unref (fix->rm);
fix->rm = NULL;
}
static void
dee_assert_cmpmodel (DeeModel *m1, DeeModel *m2)
{
guint i, j, n_cols, n_rows;
DeeModelIter *row1, *row2;
GVariant *v1, *v2;
g_assert (m1 != NULL);
g_assert (m2 != NULL);
g_assert (DEE_IS_MODEL (m1));
g_assert (DEE_IS_MODEL (m2));
g_assert_cmpint (dee_model_get_n_columns (m1), ==, dee_model_get_n_columns (m2));
g_assert_cmpint (dee_model_get_n_rows (m1), ==, dee_model_get_n_rows (m2));
n_cols = dee_model_get_n_columns (m1);
for (i = 0; i < n_cols; i++)
{
g_assert_cmpstr (dee_model_get_column_schema (m1, i), ==, dee_model_get_column_schema (m1, i));
}
n_rows = dee_model_get_n_rows (m1);
for (i = 0; i < n_rows; i++)
{
row1 = dee_model_get_iter_at_row (m1, i);
row2 = dee_model_get_iter_at_row (m2, i);
for (j = 0; j < n_cols; j++)
{
v1 = dee_model_get_value (m1, row1, j);
v2 = dee_model_get_value (m2, row2, j);
g_assert (g_variant_equal (v1, v2));
g_variant_unref (v1);
g_variant_unref (v2);
}
}
if (DEE_IS_SERIALIZABLE_MODEL (m1) && DEE_IS_SERIALIZABLE_MODEL (m2))
{
g_assert_cmpuint(dee_serializable_model_get_seqnum (m1), ==, dee_serializable_model_get_seqnum (m2));
}
if (DEE_IS_SHARED_MODEL (m1) && DEE_IS_SHARED_MODEL (m2))
{
g_assert_cmpstr (dee_shared_model_get_swarm_name (DEE_SHARED_MODEL (m1)), ==, dee_shared_model_get_swarm_name (DEE_SHARED_MODEL (m2)));
}
}
static void
test_model_persistence (Fixture *fix, gconstpointer data)
{
GError *error = NULL;
const gchar *resource_name = "com.canonical.Dee.TestResource";
dee_model_append (fix->orig, 27, "Hello world");
dee_model_append (fix->orig, 68, "Hola Mars");
dee_resource_manager_store (fix->rm,
DEE_SERIALIZABLE (fix->orig),
resource_name,
&error);
if (error)
{
g_critical ("Failed to write serializable model to resource %s: %s 111111 %s %i",
resource_name, error->message, g_quark_to_string(error->domain), error->code);
g_error_free (error);
return;
}
fix->copy = DEE_MODEL (dee_resource_manager_load(fix->rm,
resource_name,
&error));
if (error)
{
g_critical ("Failed to read serializable model from resource %s: %s",
resource_name, error->message);
g_error_free (error);
return;
}
if (fix->copy == NULL)
{
g_critical ("No parser registered for serialized model");
}
dee_assert_cmpmodel (fix->orig, fix->copy);
}
static void
test_resource_manager_default (Fixture *fix, gconstpointer data)
{
DeeResourceManager *manager;
GError *error;
GObject *result;
gchar *primary_path;
error = NULL;
manager = dee_resource_manager_get_default ();
g_object_get (manager, "primary-path", &primary_path, NULL);
g_assert (g_str_has_suffix (primary_path, "resources"));
g_free (primary_path);
result = dee_resource_manager_load (manager,
"com.this.hopefully.doesnt.exist.com",
&error);
g_assert (result == NULL);
/* loading non-existing resource just returns NULL, doesn't throw error */
g_assert_no_error (error);
}
dee-1.2.7+15.04.20150304/tests/test-icu.c 0000644 0000153 0000161 00000006730 12475676210 017670 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#include
#include
typedef struct
{
DeeICUTermFilter *filter;
} Fixture;
static void setup (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup (Fixture *fix, gconstpointer data)
{
fix->filter = NULL;
}
static void
teardown (Fixture *fix, gconstpointer data)
{
if (fix->filter)
dee_icu_term_filter_destroy (fix->filter);
}
static void
test_ascii_folder (Fixture *fix, gconstpointer data)
{
gchar *result;
fix->filter = dee_icu_term_filter_new_ascii_folder();
result = dee_icu_term_filter_apply (fix->filter, "Hello world");
g_assert_cmpstr (result, ==, "Hello world");
g_free (result);
result = dee_icu_term_filter_apply (fix->filter, "øöô");
g_assert_cmpstr (result, ==, "ooo");
g_free (result);
result = dee_icu_term_filter_apply (fix->filter, "Θεοδωράτου, Ελένη");
g_assert_cmpstr (result, ==, "Theodoratou, Elene");
g_free (result);
result = dee_icu_term_filter_apply (fix->filter, "Догилева, Татьяна");
g_assert_cmpstr (result, ==, "Dogileva, Tatʹana");
g_free (result);
result = dee_icu_term_filter_apply (fix->filter, "김, 국삼");
g_assert_cmpstr (result, ==, "gim, gugsam");
g_free (result);
result = dee_icu_term_filter_apply (fix->filter, "たけだ, まさゆき");
g_assert_cmpstr (result, ==, "takeda, masayuki");
g_free (result);
/* One last time to honor the French ;-) */
result = dee_icu_term_filter_apply (fix->filter, "Est-ce que tes enfants sont de bons élèves? Ça va pour eux?");
g_assert_cmpstr (result, ==, "Est-ce que tes enfants sont de bons eleves? Ca va pour eux?");
g_free (result);
}
static void
test_bad_id (Fixture *fix, gconstpointer data)
{
GError *error = NULL;
fix->filter = dee_icu_term_filter_new ("*-sad ???", NULL, &error);
g_assert (fix->filter == NULL);
g_assert (error != NULL);
g_assert_cmpint (error->domain, ==, DEE_ICU_ERROR);
g_assert_cmpint (error->code, ==, DEE_ICU_ERROR_BAD_ID);
g_error_free (error);
}
static void
test_bad_rule (Fixture *fix, gconstpointer data)
{
GError *error = NULL;
fix->filter = dee_icu_term_filter_new (NULL, "*-sad ???", &error);
g_assert (fix->filter == NULL);
g_assert (error != NULL);
g_assert_cmpint (error->domain, ==, DEE_ICU_ERROR);
g_assert_cmpint (error->code, ==, DEE_ICU_ERROR_BAD_RULE);
g_error_free (error);
}
void
test_icu_create_suite (void)
{
#define DOMAIN "/ICU/TermFilter"
g_test_add (DOMAIN"/Default/AsciiFolder", Fixture, 0,
setup, test_ascii_folder, teardown);
g_test_add (DOMAIN"/Default/BadId", Fixture, 0,
setup, test_bad_id, teardown);
g_test_add (DOMAIN"/Default/BadRule", Fixture, 0,
setup, test_bad_rule, teardown);
}
dee-1.2.7+15.04.20150304/tests/test-glist-result-set.c 0000644 0000153 0000161 00000007705 12475676210 022342 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
DeeResultSet* dee_glist_result_set_new (GList *rows,
DeeModel *model,
GObject *row_owner);
typedef struct
{
DeeResultSet *results;
DeeModel *model;
GList *list;
} Fixture;
static void setup (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter;
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", NULL);
fix->list = NULL;
iter = dee_model_append (fix->model, "Hello world", 27);
fix->list = g_list_append (fix->list, iter);
iter = dee_model_append (fix->model, "how are you", 28);
fix->list = g_list_append (fix->list, iter);
iter = dee_model_append (fix->model, "today", 28);
fix->list = g_list_append (fix->list, iter);
fix->results = dee_glist_result_set_new (fix->list, fix->model, NULL);
}
static void
teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->results);
g_object_unref (fix->model);
g_list_free (fix->list);
fix->results = NULL;
fix->model = NULL;
fix->list = NULL;
}
static void
test_three (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter;
g_assert (DEE_IS_RESULT_SET (fix->results));
g_assert_cmpint (dee_result_set_get_n_rows (fix->results), ==, 3);
g_assert_cmpint (dee_result_set_tell(fix->results), ==, 0);
g_assert (dee_result_set_has_next (fix->results));
iter = dee_result_set_next (fix->results);
g_assert (iter != NULL);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 0), ==, "Hello world");
g_assert_cmpint (dee_result_set_get_n_rows (fix->results), ==, 3);
g_assert_cmpint (dee_result_set_tell(fix->results), ==, 1);
g_assert (dee_result_set_has_next (fix->results));
iter = dee_result_set_next (fix->results);
g_assert (iter != NULL);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 0), ==, "how are you");
g_assert_cmpint (dee_result_set_get_n_rows (fix->results), ==, 3);
g_assert_cmpint (dee_result_set_tell(fix->results), ==, 2);
g_assert (dee_result_set_has_next (fix->results));
iter = dee_result_set_next (fix->results);
g_assert (iter != NULL);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 0), ==, "today");
g_assert_cmpint (dee_result_set_get_n_rows (fix->results), ==, 3);
g_assert_cmpint (dee_result_set_tell(fix->results), ==, 3);
g_assert (!dee_result_set_has_next (fix->results));
g_assert (dee_result_set_get_model (fix->results) == fix->model);
}
static void
test_empty (Fixture *fix, gconstpointer data)
{
DeeResultSet *results;
results = dee_glist_result_set_new (NULL, fix->model, NULL);
g_assert (DEE_IS_RESULT_SET (results));
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 0);
g_assert_cmpint (dee_result_set_tell(results), ==, 0);
g_assert (!dee_result_set_has_next (results));
g_object_unref (results);
}
void
test_glist_result_set_create_suite (void)
{
#define DOMAIN "/Index/ResultSet/GList"
g_test_add (DOMAIN"/Test3", Fixture, 0,
setup, test_three, teardown);
g_test_add (DOMAIN"/Test0", Fixture, 0,
setup, test_empty, teardown);
}
dee-1.2.7+15.04.20150304/tests/model-helper-resync3rows.c 0000644 0000153 0000161 00000007410 12475676210 023003 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by:
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
static void
row_added (DeeModel *model, DeeModelIter *iter, gpointer data)
{
gint *num_added = (gint*) data;
(*num_added)++;
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
gint num_added;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
g_set_prgname ("model-helper");
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
num_added = 0;
g_signal_connect (model, "row-added", G_CALLBACK (row_added), &num_added);
if (gtx_wait_for_signal (G_OBJECT (model), 10000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
iter = dee_model_get_iter_at_row (model, 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "zero");
iter = dee_model_get_iter_at_row (model, 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "one");
iter = dee_model_get_iter_at_row (model, 2);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "two");
/* The swarm leader goes away and later reappears,
* swarm-leader prop should toggle */
if (gtx_wait_for_signal (G_OBJECT (dee_shared_model_get_peer (DEE_SHARED_MODEL (model))), 10000, "notify::swarm-leader", NULL))
g_error ("Helper model timed out waiting for 'swarm-leader' notification");
if (!dee_shared_model_is_leader (DEE_SHARED_MODEL (model)))
g_error ("Helper didn't become leader");
if (gtx_wait_for_signal (G_OBJECT (dee_shared_model_get_peer (DEE_SHARED_MODEL (model))), 10000, "notify::swarm-leader", NULL))
g_error ("Helper model timed out waiting for second 'swarm-leader' notification");
if (dee_shared_model_is_leader (DEE_SHARED_MODEL (model)))
g_error ("Helper didn't loose swarm leadership");
/* And let's wait for synchronization again */
if (gtx_wait_for_signal (G_OBJECT (model), 10000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
iter = dee_model_get_iter_at_row (model, 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "zero");
iter = dee_model_get_iter_at_row (model, 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "one");
iter = dee_model_get_iter_at_row (model, 2);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "two");
gtx_assert_last_unref (model);
g_assert_cmpint (num_added, >, 3);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-model-interactions.c 0000644 0000153 0000161 00000072546 12475676210 022720 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
#include
#define TIMEOUT 500
#define MODEL_NAME "com.canonical.DeeModel.Tests.Interactions"
/* A command line that launches the appropriaye model-helper-* executable,
* giving $name as first argument */
#define MODEL_HELPER(helper,name) \
(gchar *[]) { "./model-helper-"#helper, name, NULL }
typedef struct
{
DeeModel *model;
} Fixture;
static void model_setup (Fixture *fix, gconstpointer data);
static void model_teardown (Fixture *fix, gconstpointer data);
static void model_setup_null (Fixture *fix, gconstpointer data);
static void model_teardown_null (Fixture *fix, gconstpointer data);
static void model_setup_with_meta (Fixture *fix, gconstpointer data);
static void test_ready (Fixture *fix, gconstpointer data);
static void test_clone (Fixture *fix, gconstpointer data);
static void test_clone_meta (Fixture *fix, gconstpointer data);
static void test_row_added (Fixture *fix, gconstpointer data);
static void test_row_changed (Fixture *fix, gconstpointer data);
static void test_row_removed (Fixture *fix, gconstpointer data);
static void test_model_clear (Fixture *fix, gconstpointer data);
static void test_clear_add (Fixture *fix, gconstpointer data);
static void test_clear_add_txn (Fixture *fix, gconstpointer data);
static void test_clear_then_add (Fixture *fix, gconstpointer data);
static void test_add_clear (Fixture *fix, gconstpointer data);
static void test_row_inserted (Fixture *fix, gconstpointer data);
static void test_schemaless_leader (Fixture *fix, gconstpointer data);
static void test_introspect (Fixture *fix, gconstpointer data);
static void test_ownership_stealing (Fixture *fix, gconstpointer data);
static void test_remote_append (Fixture *fix, gconstpointer data);
static void test_disabled_writes (Fixture *fix, gconstpointer data);
static void test_commit_before_clone (Fixture *fix, gconstpointer data);
static void test_force_resync (Fixture *fix, gconstpointer data);
static void test_manual_flush (Fixture *fix, gconstpointer data);
void
test_model_interactions_create_suite (void)
{
#define DOMAIN "/Model/Interactions"
g_test_add (DOMAIN"/Ready", Fixture, 0,
model_setup, test_ready, model_teardown);
g_test_add (DOMAIN"/Clone", Fixture, 0,
model_setup, test_clone, model_teardown);
g_test_add (DOMAIN"/Clone/WithMeta", Fixture, 0,
model_setup_with_meta, test_clone_meta, model_teardown);
g_test_add (DOMAIN"/RowAdded", Fixture, 0,
model_setup, test_row_added, model_teardown);
g_test_add (DOMAIN"/RowChanged", Fixture, 0,
model_setup, test_row_changed, model_teardown);
g_test_add (DOMAIN"/RowRemoved", Fixture, 0,
model_setup, test_row_removed, model_teardown);
g_test_add (DOMAIN"/Clear", Fixture, 0,
model_setup, test_model_clear, model_teardown);
g_test_add (DOMAIN"/ClearAndAdd", Fixture, 0,
model_setup, test_clear_add, model_teardown);
g_test_add (DOMAIN"/TxnClearAndAdd", Fixture, 0,
model_setup, test_clear_add_txn, model_teardown);
g_test_add (DOMAIN"/ClearThenAdd", Fixture, 0,
model_setup, test_clear_then_add, model_teardown);
g_test_add (DOMAIN"/AddAndClear", Fixture, 0,
model_setup, test_add_clear, model_teardown);
g_test_add (DOMAIN"/RowInserted", Fixture, 0,
model_setup, test_row_inserted, model_teardown);
g_test_add (DOMAIN"/SchemalessLeader", Fixture, 0,
model_setup_null, test_schemaless_leader, model_teardown_null);
g_test_add (DOMAIN"/Introspect", Fixture, 0,
model_setup, test_introspect, model_teardown);
g_test_add (DOMAIN"/OwnershipStealing", Fixture, 0,
model_setup, test_ownership_stealing, model_teardown);
g_test_add (DOMAIN"/RemoteAppend", Fixture, 0,
model_setup, test_remote_append, model_teardown);
g_test_add (DOMAIN"/DisabledWrites", Fixture, 0,
model_setup_null, test_disabled_writes, model_teardown_null);
g_test_add (DOMAIN"/CommitBeforeClone", Fixture, 0,
model_setup, test_commit_before_clone, model_teardown);
g_test_add (DOMAIN"/ForceResync", Fixture, 0,
model_setup, test_force_resync, model_teardown);
g_test_add (DOMAIN"/ManualFlush", Fixture, 0,
model_setup, test_manual_flush, model_teardown);
}
static void
model_setup (Fixture *fix, gconstpointer data)
{
fix->model = dee_shared_model_new (MODEL_NAME);
dee_model_set_schema (fix->model, "i", "s", NULL);
g_assert (DEE_IS_MODEL (fix->model));
}
static void
model_teardown (Fixture *fix, gconstpointer data)
{
gtx_assert_last_unref (fix->model);
}
static void
model_setup_null (Fixture *fix, gconstpointer data)
{
fix->model = NULL;
}
static void
model_teardown_null (Fixture *fix, gconstpointer data)
{
g_assert (fix->model == NULL);
}
static void
model_setup_with_meta (Fixture *fix, gconstpointer data)
{
GHashTable *vardict_schema;
fix->model = dee_shared_model_new (MODEL_NAME);
dee_model_set_schema (fix->model, "i", "s", "a{sv}", "a{sv}", NULL);
dee_model_set_column_names (fix->model, "count", "title", "hints", "extra-hints", NULL);
vardict_schema = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (vardict_schema, "uri", "s");
dee_model_register_vardict_schema (fix->model, 2, vardict_schema);
g_assert (DEE_IS_MODEL (fix->model));
g_hash_table_unref (vardict_schema);
}
static void
test_ready (Fixture *fix, gconstpointer data)
{
GParamSpec *pspec;
gboolean synchronized;
/* Test the GObject property reports FALSE */
g_object_get (fix->model, "synchronized", &synchronized, NULL);
g_assert_cmpint (0, == , synchronized);
/* Check that convenience getter now reports FALSE */
g_assert_cmpint (0, ==, dee_shared_model_is_synchronized (DEE_SHARED_MODEL (fix->model)));
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", &pspec))
g_critical ("Model never synchronized");
else
g_param_spec_unref (pspec);
/* Test the GObject property reports TRUE */
g_object_get (fix->model, "synchronized", &synchronized, NULL);
g_assert_cmpint (0, != , synchronized);
/* Check that convenience getter now reports TRUE */
g_assert_cmpint (0, !=, dee_shared_model_is_synchronized (DEE_SHARED_MODEL (fix->model)));
if (!gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
{
g_critical ("Model changed synchronization state twice");
g_param_spec_unref (pspec);
}
}
static gboolean
_add3rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_append (model, 0, "zero");
dee_model_append (model, 1, "one");
dee_model_append (model, 2, "two");
return FALSE;
}
static gboolean
_add5rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_append (model, 0, "zero");
dee_model_append (model, 1, "one");
dee_model_append (model, 2, "two");
dee_model_append (model, 3, "three");
dee_model_append (model, 4, "four");
return FALSE;
}
static gboolean
_change3rows (DeeModel *model)
{
DeeModelIter *iter;
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
iter = dee_model_get_iter_at_row (model, 0);
dee_model_set_value (model, iter, 1, g_variant_new_string ("changed_zero"));
iter = dee_model_get_iter_at_row (model, 1);
dee_model_set_value (model, iter, 1, g_variant_new_string ("changed_one"));
iter = dee_model_get_iter_at_row (model, 2);
dee_model_set_value (model, iter, 1, g_variant_new_string ("changed_two"));
return FALSE;
}
/* Assumes a model with 5 rows. Removes rows 0, 4, and 2
* in that order. Accounting for rows shifts this becomes
* 0, 3, and 1. Leaving the original rows 1 and 3 now in
* positions 0 and 1 */
static gboolean
_remove3rows (DeeModel *model)
{
DeeModelIter *iter0, *iter4, *iter2;
DeeModelIter *orig_iter1, *orig_iter3;
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
g_return_val_if_fail (dee_model_get_n_rows (model) == 5, FALSE);
iter0 = dee_model_get_iter_at_row (model, 0);
iter4 = dee_model_get_iter_at_row (model, 4);
iter2 = dee_model_get_iter_at_row (model, 2);
orig_iter1 = dee_model_get_iter_at_row (model, 1);
orig_iter3 = dee_model_get_iter_at_row (model, 3);
dee_model_remove (model, iter0);
dee_model_remove (model, iter4);
dee_model_remove (model, iter2);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 2);
g_assert (dee_model_get_iter_at_row (model, 0) == orig_iter1);
g_assert (dee_model_get_iter_at_row (model, 1) == orig_iter3);
return FALSE;
}
static gboolean
_insert1row (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_insert (model, 1, 27, "twentyseven");
return FALSE;
}
static gboolean
_clear_model (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_clear (model);
return FALSE;
}
static gboolean
_add_and_clear6rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
_add3rows (model);
_clear_model (model);
return FALSE;
}
static gboolean
_clear_and_add5rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
_clear_model (model);
_add5rows (model);
return FALSE;
}
static gboolean
_txn_clear_and_add5rows (DeeModel *model)
{
DeeTransaction *txn;
GError *error;
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
txn = DEE_TRANSACTION (dee_transaction_new (model));
_clear_model (DEE_MODEL (txn));
_add5rows (DEE_MODEL (txn));
error = NULL;
dee_transaction_commit (txn, &error);
if (error)
{
g_critical ("Failed to commit clear-add5 transaction: %s", error->message);
}
g_object_unref (txn);
return FALSE;
}
static void
test_clone (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never synchronized");
_add3rows (fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clone3rows, MODEL_NAME),
1000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
/* We test that we can do this two times */
/*if (gtx_wait_for_command (TESTDIR, MODEL_HELPER (3rows, MODEL_NAME), 1000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);*/
}
static void
test_clone_meta (Fixture *fix, gconstpointer data)
{
GVariant *row_buf[3];
DeeModel *model;
model = fix->model;
if (gtx_wait_for_signal (G_OBJECT (model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never synchronized");
dee_model_append_row (model,
dee_model_build_named_row (model, row_buf,
"count", 0, "title", "zero", NULL));
dee_model_append_row (model,
dee_model_build_named_row (model, row_buf,
"count", 1, "title", "one", NULL));
dee_model_append_row (model,
dee_model_build_named_row (model, row_buf,
"count", 2, "title", "two", NULL));
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clone3rows-meta, MODEL_NAME),
1000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_added (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_changed (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
g_timeout_add (500, (GSourceFunc)_change3rows, fix->model);
//const gchar *cmd[] = {"dbus-monitor", NULL};
//const gchar *cmd[] = {"sleep", "1",NULL};
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (change3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_removed (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add5rows (fix->model);
g_timeout_add (500, (GSourceFunc)_remove3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (remove3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_model_clear (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
g_timeout_add (500, (GSourceFunc)_clear_model, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_clear_add (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
g_timeout_add (500, (GSourceFunc)_clear_and_add5rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3add5, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_clear_add_txn (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
g_timeout_add (500, (GSourceFunc)_txn_clear_and_add5rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3add5, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
/* Test that the local model looks as expected */
DeeModelIter *iter = dee_model_get_first_iter (fix->model);
g_assert_cmpint (dee_model_get_int32 (fix->model, iter, 0), ==, 0);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "zero");
iter = dee_model_next (fix->model, iter);
g_assert_cmpint (dee_model_get_int32 (fix->model, iter, 0), ==, 1);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "one");
iter = dee_model_next (fix->model, iter);
g_assert_cmpint (dee_model_get_int32 (fix->model, iter, 0), ==, 2);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "two");
iter = dee_model_next (fix->model, iter);
g_assert_cmpint (dee_model_get_int32 (fix->model, iter, 0), ==, 3);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "three");
iter = dee_model_next (fix->model, iter);
g_assert_cmpint (dee_model_get_int32 (fix->model, iter, 0), ==, 4);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "four");
gtx_assert_last_command_status (0);
}
static void
test_clear_then_add (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_clear_model (fix->model);
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
g_timeout_add (500, (GSourceFunc)_clear_model, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_add_clear (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
g_timeout_add (500, (GSourceFunc)_add_and_clear6rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear6rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_inserted (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
g_timeout_add (500, (GSourceFunc)_insert1row, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (insert1row, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
_ready (DeeModel *model, GParamSpec *pspec, GSList **rows_so_far)
{
/* We must not have any rows when 'ready' is emitted */
g_assert (*rows_so_far == NULL);
}
static void
_collect_row (DeeModel *model, DeeModelIter *iter, GSList **rows_so_far)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*rows_so_far = g_slist_append (*rows_so_far, iter);
}
/* This case must run without a Fixture */
static void
test_schemaless_leader (Fixture *fix, gconstpointer data)
{
DeeModel *model;
DeeModelIter *iter;
GSList *rows_added;
g_assert (fix->model == NULL);
/* Set up a clean model *without* a schema. We will pick up the schema
* with the first transaction from the slave. Or at least, that's what we
* want to assert ;-) */
model = dee_shared_model_new (MODEL_NAME);
// no set_schema() on purpose!
/* Listen for changes */
rows_added = NULL;
g_signal_connect (model, "row-added", G_CALLBACK (_collect_row), &rows_added);
g_signal_connect (model, "notify::synchronized", G_CALLBACK (_ready), &rows_added);
/* Remote process defines column types and adds two rows */
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (schemaless, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
/* Check that we got the right schema from the peer */
g_assert_cmpint (dee_model_get_n_columns (model), ==, 2);
g_assert_cmpstr (dee_model_get_column_schema (model, 0), ==, "i");
g_assert_cmpstr (dee_model_get_column_schema (model, 1), ==, "s");
/* Check that we got what we expected */
g_assert_cmpint (g_slist_length (rows_added), == , 2);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 2);
g_assert_cmpint (dee_model_get_n_columns (model), ==, 2);
iter = (DeeModelIter*) g_slist_nth (rows_added, 0)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 27);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "skunkworks");
iter = (DeeModelIter*) g_slist_nth (rows_added, 1)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 68);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "wumbo");
gtx_assert_last_unref (model);
g_slist_free (rows_added);
}
static void
test_introspect (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (introspect, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
stealing_notify (GObject *object, GParamSpec *pspec, Fixture *fix)
{
g_assert (DEE_IS_PEER (object));
if (!dee_peer_is_swarm_leader (DEE_PEER (object)))
{
g_object_set_data (G_OBJECT (fix->model), "stealing-success",
GINT_TO_POINTER (1));
}
}
static void
test_ownership_stealing (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
/* We should be leader before starting the helper process */
g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
/* But loose it later on */
g_signal_connect (dee_shared_model_get_peer (DEE_SHARED_MODEL (fix->model)),
"notify::swarm-leader", G_CALLBACK (stealing_notify), fix);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (replace, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
gtx_flush_sources (FALSE);
g_assert (g_object_get_data (G_OBJECT (fix->model), "stealing-success"));
g_assert_cmpuint (dee_model_get_n_rows (fix->model), >, 0);
}
static void
changeset_signal (DeeModel *model, gboolean *value)
{
*value = TRUE;
}
static void
test_remote_append (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
/* We should be leader before starting the helper process */
g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 0);
gboolean got_changeset_start = FALSE;
gboolean got_changeset_finish = FALSE;
g_signal_connect (fix->model, "changeset-started",
G_CALLBACK (changeset_signal), &got_changeset_start);
g_signal_connect (fix->model, "changeset-finished",
G_CALLBACK (changeset_signal), &got_changeset_finish);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (append1, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
/* There should be a new row in the model */
g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 1);
g_assert (got_changeset_start);
g_assert (got_changeset_finish);
}
static void
test_disabled_writes (Fixture *fix, gconstpointer data)
{
DeePeer *peer;
DeeModelIter *iter;
peer = dee_peer_new (MODEL_NAME);
fix->model = DEE_MODEL (
g_object_new (DEE_TYPE_SHARED_MODEL,
"peer", peer,
"back-end", dee_sequence_model_new (),
"access-mode", DEE_SHARED_MODEL_ACCESS_MODE_LEADER_WRITABLE,
NULL));
dee_model_set_schema (fix->model, "i", "s", NULL);
g_object_unref (G_OBJECT (peer));
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
/* We should be leader before starting the helper process */
g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
dee_model_prepend (fix->model, 81, "eightyone");
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (append1, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
/* The peer tried to append a row, but we should have ignored that */
g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 1);
iter = dee_model_get_first_iter (fix->model);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "eightyone");
gtx_assert_last_unref (fix->model);
fix->model = NULL;
}
static gboolean
quit_loop (GMainLoop *ml)
{
g_main_loop_quit (ml);
return FALSE;
}
static void
child_quit (GPid pid, gint status, gpointer user_data)
{
GMainLoop *ml;
gpointer *data;
data = user_data;
ml = (GMainLoop*) data[0];
data[1] = GINT_TO_POINTER (status);
g_main_loop_quit (ml);
}
static void
test_commit_before_clone (Fixture *fix, gconstpointer data)
{
GPid pid;
GMainLoop *ml;
gpointer *wait_data;
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
/* need special handling of synchronization - commit must be emmitted after
* the client is up (and possibly waiting for clone) */
g_spawn_async (TESTDIR,
MODEL_HELPER (clone3rows, MODEL_NAME),
NULL,
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
NULL,
NULL,
&pid,
NULL);
ml = g_main_loop_new (NULL, FALSE);
wait_data = g_new0 (gpointer, 2);
wait_data[0] = ml;
wait_data[1] = GINT_TO_POINTER (837);
g_child_watch_add (pid, child_quit, wait_data);
/* wait for the helper process to start up, then flush the commits */
g_usleep (500000);
/* don't wait indefinitely for the child */
g_timeout_add (5000, (GSourceFunc) quit_loop, ml);
g_main_loop_run (ml);
if (GPOINTER_TO_INT (wait_data[1]) == 837)
{
g_critical ("Model helper timed out");
}
else if (GPOINTER_TO_INT (wait_data[1]) != 0)
{
g_critical ("Model helper returned error");
}
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 3);
}
static void
test_force_resync (Fixture *fix, gconstpointer data)
{
GPid pid;
GMainLoop *ml;
gpointer *wait_data;
DeePeer *leader_peer;
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
/* need special handling of synchronization */
g_spawn_async (TESTDIR,
MODEL_HELPER (resync3rows, MODEL_NAME),
NULL,
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
NULL,
NULL,
&pid,
NULL);
ml = g_main_loop_new (NULL, FALSE);
wait_data = g_new0 (gpointer, 2);
wait_data[0] = ml;
wait_data[1] = GINT_TO_POINTER (837);
g_child_watch_add (pid, child_quit, wait_data);
/* We don't really have a better way atm. Peer discovery doesn't work
* with latest changes done to DBus (no watching of method calls from other
* processes) */
gtx_yield_main_loop (500); /* 500ms yield */
/* Peer should be synced now, let's throw away our model */
gtx_assert_last_unref (fix->model);
gtx_yield_main_loop (50); /* 50ms yield */
/* And re-own it */
leader_peer = DEE_PEER (g_object_new (DEE_TYPE_PEER,
"swarm-name", MODEL_NAME,
"swarm-owner", TRUE, NULL));
fix->model = dee_shared_model_new_for_peer (leader_peer);
dee_model_set_schema (fix->model, "i", "s", NULL);
g_assert (DEE_IS_MODEL (fix->model));
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
/* don't wait indefinitely for the child */
g_timeout_add (5000, (GSourceFunc) quit_loop, ml);
g_main_loop_run (ml);
if (GPOINTER_TO_INT (wait_data[1]) == 837)
{
g_critical ("Model helper timed out");
}
else if (GPOINTER_TO_INT (wait_data[1]) != 0)
{
g_critical ("Model helper returned error");
}
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 3);
}
static void
test_manual_flush (Fixture *fix, gconstpointer data)
{
DeeSharedModel *sm;
sm = DEE_SHARED_MODEL (fix->model);
dee_shared_model_set_flush_mode (sm, DEE_SHARED_MODEL_FLUSH_MODE_MANUAL);
_add5rows (fix->model);
/* A timeout would normally cause the model to flush, but with manual
* flushing it shouldn't */
gtx_yield_main_loop (50); /* 50ms yield */
g_assert_cmpuint (dee_shared_model_flush_revision_queue_sync (sm), >, 0);
}
dee-1.2.7+15.04.20150304/tests/test-model-complex-column.c 0000644 0000153 0000161 00000011023 12475676210 023137 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
* Neil Jagdish Patel
*
*/
#include
#include
#include
typedef struct
{
DeeModel *model;
} ColumnFixture;
static void column_setup (ColumnFixture *fix, gconstpointer data);
static void column_teardown (ColumnFixture *fix, gconstpointer data);
static void proxy_column_setup (ColumnFixture *fix, gconstpointer data);
static void proxy_column_teardown (ColumnFixture *fix, gconstpointer data);
static void test_column_allocation (ColumnFixture *fix, gconstpointer data);
static void test_set_get (ColumnFixture *fix, gconstpointer data);
void
test_model_complex_column_create_suite (void)
{
#define SEQ_DOMAIN "/Model/Sequence/ComplexColumn"
#define PROXY_DOMAIN "/Model/Proxy/ComplexColumn"
g_test_add (SEQ_DOMAIN"/Allocation", ColumnFixture, 0,
column_setup, test_column_allocation, column_teardown);
g_test_add (PROXY_DOMAIN"/Allocation", ColumnFixture, 0,
proxy_column_setup, test_column_allocation, proxy_column_teardown);
g_test_add (SEQ_DOMAIN"/SetGet", ColumnFixture, 0,
column_setup, test_set_get, column_teardown);
g_test_add (PROXY_DOMAIN"/SetGet", ColumnFixture, 0,
proxy_column_setup, test_set_get, proxy_column_teardown);
}
static void
column_setup (ColumnFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "as", "(ii)", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
g_assert_cmpint (2, ==, dee_model_get_n_columns (fix->model));
g_assert_cmpstr ("as", ==, dee_model_get_column_schema (fix->model, 0));
g_assert_cmpstr ("(ii)", ==, dee_model_get_column_schema(fix->model, 1));
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
}
static void
column_teardown (ColumnFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
}
static void
proxy_column_setup (ColumnFixture *fix, gconstpointer data)
{
column_setup (fix, data);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL,
"back-end", fix->model,
NULL);
g_assert (DEE_IS_PROXY_MODEL (fix->model));
}
static void
proxy_column_teardown (ColumnFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_PROXY_MODEL (fix->model));
g_object_unref (fix->model);
}
static void
test_column_allocation (ColumnFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_MODEL (fix->model));
}
static void
test_set_get (ColumnFixture *fix, gconstpointer data)
{
DeeModel *model = fix->model;
DeeModelIter *iter;
GVariantBuilder as;
GVariant *value, *tmp, *col1, *col2;
gint32 i1, i2;
g_variant_builder_init (&as, G_VARIANT_TYPE ("as"));
g_variant_builder_add (&as, "s", "Hello");
g_variant_builder_add (&as, "s", "World");
dee_model_append (fix->model,
g_variant_builder_end (&as),
g_variant_new ("(ii)", 27, 68));
g_assert (dee_model_get_n_rows (model) == 1);
iter = dee_model_get_first_iter (model);
dee_model_get (model, iter, &col1, &col2);
value = dee_model_get_value (model, iter, 0);
g_assert (value == col1);
g_assert_cmpstr ("as", ==, g_variant_get_type_string (value));
g_assert_cmpint (2, ==, g_variant_n_children(value));
tmp = g_variant_get_child_value (value, 0);
g_assert_cmpstr ("Hello", ==, g_variant_get_string (tmp, NULL));
g_variant_unref (tmp);
tmp = g_variant_get_child_value (value, 1);
g_assert_cmpstr ("World", ==, g_variant_get_string (tmp, NULL));
g_variant_unref (tmp);
g_variant_unref (value);
value = dee_model_get_value (model, iter, 1);
g_assert (value == col2);
g_variant_get (value, "(ii)", &i1, &i2);
g_assert_cmpint (27, ==, i1);
g_assert_cmpint (68, ==, i2);
g_variant_unref (value);
g_variant_unref (col1);
g_variant_unref (col2);
}
dee-1.2.7+15.04.20150304/tests/test-index.c 0000644 0000153 0000161 00000053121 12475676210 020213 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010-2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
#include
typedef struct
{
DeeModel *model;
DeeIndex *index;
} Fixture;
static void setup_hash (Fixture *fix, gconstpointer data);
static void setup_tree (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup_hash (Fixture *fix, gconstpointer data)
{
DeeAnalyzer *analyzer = dee_analyzer_new ();
DeeModelReader reader;
dee_model_reader_new_for_string_column (0, &reader);
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", NULL);
fix->index = DEE_INDEX (dee_hash_index_new(fix->model, analyzer, &reader));
g_object_unref (analyzer);
}
static void
setup_text_hash (Fixture *fix, gconstpointer data)
{
DeeAnalyzer *analyzer = DEE_ANALYZER (dee_text_analyzer_new ());
DeeModelReader reader;
dee_model_reader_new_for_string_column (0, &reader);
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", NULL);
fix->index = DEE_INDEX (dee_hash_index_new(fix->model, analyzer, &reader));
g_object_unref (analyzer);
}
static void
setup_tree (Fixture *fix, gconstpointer data)
{
DeeAnalyzer *analyzer = dee_analyzer_new ();
DeeModelReader reader;
dee_model_reader_new_for_string_column (0, &reader);
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", NULL);
fix->index = DEE_INDEX (dee_tree_index_new(fix->model, analyzer, &reader));
g_object_unref (analyzer);
}
static void
setup_text_tree (Fixture *fix, gconstpointer data)
{
DeeAnalyzer *analyzer = DEE_ANALYZER (dee_text_analyzer_new ());
DeeModelReader reader;
dee_model_reader_new_for_string_column (0, &reader);
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", NULL);
fix->index = DEE_INDEX (dee_tree_index_new(fix->model, analyzer, &reader));
g_object_unref (analyzer);
}
static void
teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->index);
g_object_unref (fix->model);
fix->index = NULL;
fix->model = NULL;
}
static void
test_empty (Fixture *fix, gconstpointer data)
{
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
g_assert (NULL == dee_index_lookup_one (fix->index, "foobar"));
}
static void
test_one (Fixture *fix, gconstpointer data)
{
DeeModelIter *orig_iter, *iter;
DeeResultSet *results;
orig_iter = dee_model_append (fix->model, "Hello world", 27);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 1);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 1);
results = dee_index_lookup (fix->index, "Hello", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 0);
g_object_unref (results);
results = dee_index_lookup (fix->index, "Hello world", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
iter = dee_result_set_next (results);
g_assert (iter == orig_iter);
g_assert (NULL == dee_index_lookup_one (fix->index, "foobar"));
g_assert (orig_iter == dee_index_lookup_one (fix->index, "Hello world"));
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
g_object_unref (results);
}
static void
test_two (Fixture *fix, gconstpointer data)
{
DeeModelIter *orig_iter, *iter;
DeeResultSet *results;
orig_iter = dee_model_append (fix->model, "Hello world", 27);
dee_model_append (fix->model, "Dee world", 68);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 2);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Dee world"), ==, 1);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 2);
results = dee_index_lookup (fix->index, "Hello world", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows(results), ==, 1);
iter = dee_result_set_next (results);
g_assert (iter == orig_iter);
g_object_unref (results);
results = dee_index_lookup (fix->index, "Dee world", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows(results), ==, 1);
g_object_unref (results);
g_assert (NULL == dee_index_lookup_one (fix->index, "foobar"));
g_assert (NULL == dee_index_lookup_one (fix->index, "Hello"));
g_assert (NULL == dee_index_lookup_one (fix->index, "Dee"));
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Dee world"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
}
/* Test that we can create an index on a model that already has some rows in it */
static void
test_index_on_existing_rows (Fixture *fix, gconstpointer data)
{
DeeAnalyzer *analyzer;
DeeModelReader reader;
DeeIndex *extra_idx;
DeeResultSet *results;
dee_model_append (fix->model, "Hello world", 27);
dee_model_append (fix->model, "Hello Dee", 68);
analyzer = DEE_ANALYZER (dee_text_analyzer_new ());
dee_model_reader_new_for_string_column (0, &reader);
/* Test DeeHashIndex */
extra_idx = DEE_INDEX (dee_hash_index_new(fix->model, analyzer, &reader));
results = dee_index_lookup (extra_idx, "hello", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows(results), ==, 2);
g_object_unref (results);
g_object_unref (extra_idx);
/* Test DeeTreeIndex */
extra_idx = DEE_INDEX (dee_tree_index_new(fix->model, analyzer, &reader));
results = dee_index_lookup (extra_idx, "hello", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows(results), ==, 2);
g_object_unref (results);
g_object_unref (extra_idx);
g_object_unref (analyzer);
}
static void
test_change (Fixture *fix, gconstpointer data)
{
DeeModelIter *orig_iter, *iter;
DeeResultSet *results;
dee_model_append (fix->model, "Hello world", 27);
dee_model_append (fix->model, "Hello world", 27);
dee_model_append (fix->model, "Hello world", 27);
orig_iter = dee_model_append (fix->model, "xyz", 27);
dee_model_append (fix->model, "Hello world", 27);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 5);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 4);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 1);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 2);
results = dee_index_lookup (fix->index, "xyz", DEE_TERM_MATCH_EXACT);
g_assert_cmpint (dee_result_set_get_n_rows(results), ==, 1);
iter = dee_result_set_next(results);
g_assert (iter == orig_iter);
/* Change the model and assert that the changes propagate to the index */
dee_model_set (fix->model, orig_iter, "Hello Yoda", 27);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 5);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 4);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello Yoda"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 2);
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello world"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "Hello Yoda"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
g_object_unref (results);
}
static void
test_text (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter1, *iter2;
/* 1 row, 2 terms */
iter1 = dee_model_append (fix->model, "Hello world", 27);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "hello"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "world"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 2);
g_assert (dee_index_lookup_one (fix->index, "hello") == iter1);
g_assert (dee_index_lookup_one (fix->index, "world") == iter1);
/* Verify that model.clear() works */
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "hello"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "world"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
g_assert (dee_index_lookup_one (fix->index, "hello") == NULL);
g_assert (dee_index_lookup_one (fix->index, "world") == NULL);
/* 2 rows, 3 terms */
iter1 = dee_model_append (fix->model, "Hello world", 27);
iter2 = dee_model_append (fix->model, "Hello... dee?", 68);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 2);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "hello"), ==, 2);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "world"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "dee"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 3);
g_assert (dee_index_lookup_one (fix->index, "world") == iter1);
g_assert (dee_index_lookup_one (fix->index, "dee") == iter2);
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
/* lookup_one() should warn on more than 1 result */
g_message("This should not print!!! %p",
dee_index_lookup_one (fix->index, "hello"));
exit (0);
}
g_test_trap_assert_failed();
/* Verify that model.clear() works with 2 rows and 3 terms */
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "hello"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "world"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "xyz"), ==, 0);
g_assert_cmpint (dee_index_get_n_terms(fix->index), ==, 0);
g_assert (dee_index_lookup_one (fix->index, "hello") == NULL);
g_assert (dee_index_lookup_one (fix->index, "world") == NULL);
}
static void
test_text_with_dupe_terms_per_row (Fixture *fix, gconstpointer data)
{
dee_model_append (fix->model, "Hello hello there!", 27);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "hello"), ==, 1);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "there"), ==, 1);
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "hello"), ==, 0);
g_assert_cmpint (dee_index_get_n_rows_for_term(fix->index, "there"), ==, 0);
}
static void
test_prefix_1_row (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *result_iter;
DeeResultSet *results;
g_assert (dee_index_get_supported_term_match_flags (fix->index) &
DEE_TERM_MATCH_PREFIX);
iter = dee_model_append (fix->model, "Hello world", 27);
results = dee_index_lookup (fix->index, "hello", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
result_iter = dee_result_set_next (results);
g_assert (iter == result_iter);
g_object_unref (results);
results = dee_index_lookup (fix->index, "hel", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
result_iter = dee_result_set_next (results);
g_assert (iter == result_iter);
g_object_unref (results);
results = dee_index_lookup (fix->index, "h", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
result_iter = dee_result_set_next (results);
g_assert (iter == result_iter);
g_object_unref (results);
results = dee_index_lookup (fix->index, "hellop", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 0);
g_object_unref (results);
}
static void
test_prefix_1_row_multiterm (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *result_iter;
DeeResultSet *results;
g_assert (dee_index_get_supported_term_match_flags (fix->index) &
DEE_TERM_MATCH_PREFIX);
iter = dee_model_append (fix->model, "To test this tremendous trouble", 27);
results = dee_index_lookup (fix->index, "to", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
result_iter = dee_result_set_next (results);
g_assert (iter == result_iter);
g_object_unref (results);
results = dee_index_lookup (fix->index, "t", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
result_iter = dee_result_set_next (results);
g_assert (iter == result_iter);
g_object_unref (results);
}
static void
test_prefix_2_rows (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *i0, *i1;
DeeResultSet *results;
g_assert (dee_index_get_supported_term_match_flags (fix->index) &
DEE_TERM_MATCH_PREFIX);
i0 = dee_model_append (fix->model, "Caravan scrap yard", 0);
i1 = dee_model_append (fix->model, "Scraper foo", 1);
/* NOTE: We can NOT infer anything about the ordering of the matching
* iters inside a single term */
results = dee_index_lookup (fix->index, "scrap", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 2);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
g_object_unref (results);
results = dee_index_lookup (fix->index, "scra", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 2);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
g_object_unref (results);
results = dee_index_lookup (fix->index, "scraper", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 1);
iter = dee_result_set_next (results);
g_assert (iter == i1);
g_object_unref (results);
results = dee_index_lookup (fix->index, "scraperer", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 0);
g_object_unref (results);
}
static void
test_prefix_3_rows (Fixture *fix, gconstpointer data)
{
DeeModelIter *iter, *i0, *i1;
DeeResultSet *results;
g_assert (dee_index_get_supported_term_match_flags (fix->index) &
DEE_TERM_MATCH_PREFIX);
i0 = dee_model_append (fix->model, "Hello world", 0);
i1 = dee_model_append (fix->model, "Hello dee", 1);
dee_model_append (fix->model, "Whopping heroes", 2);
/* NOTE: We can NOT infer anything about the ordering of the matching
* iters inside a single term */
results = dee_index_lookup (fix->index, "hello", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 2);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
g_object_unref (results);
results = dee_index_lookup (fix->index, "hel", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 2);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
iter = dee_result_set_next (results);
g_assert (iter == i0 || iter == i1);
g_object_unref (results);
results = dee_index_lookup (fix->index, "h", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 3);
g_object_unref (results);
/* NOTE: We CAN infer the ordering below because the test model is crafted
* so that we have 2 hits each from distinct terms */
results = dee_index_lookup (fix->index, "w", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 2);
iter = dee_result_set_next (results);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 0), ==, "Whopping heroes");
iter = dee_result_set_next (results);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 0), ==, "Hello world");
g_object_unref (results);
results = dee_index_lookup (fix->index, "hellop", DEE_TERM_MATCH_PREFIX);
g_assert_cmpint (dee_result_set_get_n_rows (results), ==, 0);
g_object_unref (results);
}
static void
test_prefix_4_rows_and_clear (Fixture *fix, gconstpointer data)
{
DeeModelIter *i0;
DeeResultSet *rs;
dee_model_append (fix->model, "file:///local_uri", 44);
dee_model_append (fix->model, "http://foo.com", 23);
dee_model_append (fix->model, "ftp://bar.org", 11);
i0 = dee_model_append (fix->model, "file:///home/username/file@home", 07);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 4);
rs = dee_index_lookup (fix->index, "user", DEE_TERM_MATCH_PREFIX);
g_assert (i0 == dee_result_set_next (rs));
g_assert (!dee_result_set_has_next (rs));
g_object_unref (rs);
dee_model_clear (fix->model);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
}
static void
test_prefix_search_empty (Fixture *fix, gconstpointer data)
{
DeeResultSet *rs;
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 0);
rs = dee_index_lookup (fix->index, "a", DEE_TERM_MATCH_PREFIX);
g_assert_cmpuint (0, ==, dee_result_set_get_n_rows (rs));
g_object_unref (rs);
}
static void
test_prefix_search_near_beginning (Fixture *fix, gconstpointer data)
{
DeeResultSet *rs;
dee_model_append (fix->model, "vl", 44);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 1);
rs = dee_index_lookup (fix->index, "a", DEE_TERM_MATCH_PREFIX);
g_assert_cmpuint (0, ==, dee_result_set_get_n_rows (rs));
g_object_unref (rs);
}
static void
test_prefix_search_near_end (Fixture *fix, gconstpointer data)
{
DeeResultSet *rs;
dee_model_append (fix->model, "a", 44);
g_assert_cmpint (dee_index_get_n_rows (fix->index), ==, 1);
rs = dee_index_lookup (fix->index, "vl", DEE_TERM_MATCH_PREFIX);
g_assert_cmpuint (0, ==, dee_result_set_get_n_rows (rs));
g_object_unref (rs);
}
void
test_hash_index_create_suite (void)
{
g_test_add ("/Index/Hash/Empty", Fixture, 0,
setup_hash, test_empty, teardown);
g_test_add ("/Index/Tree/Empty", Fixture, 0,
setup_tree, test_empty, teardown);
g_test_add ("/Index/Hash/One", Fixture, 0,
setup_hash, test_one, teardown);
g_test_add ("/Index/Tree/One", Fixture, 0,
setup_tree, test_one, teardown);
g_test_add ("/Index/Hash/Two", Fixture, 0,
setup_hash, test_two, teardown);
g_test_add ("/Index/Tree/Two", Fixture, 0,
setup_tree, test_two, teardown);
g_test_add ("/Index/WithExistingRows", Fixture, 0,
setup_tree, test_index_on_existing_rows, teardown);
g_test_add ("/Index/Hash/Change", Fixture, 0,
setup_hash, test_change, teardown);
g_test_add ("/Index/Tree/Change", Fixture, 0,
setup_tree, test_change, teardown);
g_test_add ("/Index/Hash/Text", Fixture, 0,
setup_text_hash, test_text, teardown);
g_test_add ("/Index/Tree/Text", Fixture, 0,
setup_text_tree, test_text, teardown);
g_test_add ("/Index/Hash/TextWithDupeTermsPerRow", Fixture, 0,
setup_text_hash, test_text_with_dupe_terms_per_row, teardown);
g_test_add ("/Index/Tree/TextWithDupeTermsPerRow", Fixture, 0,
setup_text_tree, test_text_with_dupe_terms_per_row, teardown);
g_test_add ("/Index/Tree/Prefix1Row", Fixture, 0,
setup_text_tree, test_prefix_1_row, teardown);
g_test_add ("/Index/Tree/Prefix1RowMultiterm", Fixture, 0,
setup_text_tree, test_prefix_1_row_multiterm, teardown);
g_test_add ("/Index/Tree/Prefix2Rows", Fixture, 0,
setup_text_tree, test_prefix_2_rows, teardown);
g_test_add ("/Index/Tree/Prefix3Rows", Fixture, 0,
setup_text_tree, test_prefix_3_rows, teardown);
g_test_add ("/Index/Tree/Prefix4RowsAndClear", Fixture, 0,
setup_text_tree, test_prefix_4_rows_and_clear, teardown);
g_test_add ("/Index/Tree/PrefixSearchEmpty", Fixture, 0,
setup_text_tree, test_prefix_search_empty, teardown);
g_test_add ("/Index/Tree/PrefixSearchNearBeginning", Fixture, 0,
setup_text_tree, test_prefix_search_near_beginning, teardown);
g_test_add ("/Index/Tree/PrefixSearchNearEnd", Fixture, 0,
setup_text_tree, test_prefix_search_near_end, teardown);
}
dee-1.2.7+15.04.20150304/tests/test-model-readers.c 0000644 0000153 0000161 00000006303 12475676210 021627 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
typedef struct
{
DeeModel *model;
} Fixture;
static void setup (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup (Fixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "s", "i", "s", "u", NULL);
dee_model_append (fix->model,
"Hello world",
27,
"Three Danish characters... æøå?",
68);
}
static void
teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
fix->model = NULL;
}
static void
test_string0 (Fixture *fix, gconstpointer data)
{
DeeModelReader reader;
gchar *val;
dee_model_reader_new_for_string_column (0, &reader);
val = dee_model_reader_read (&reader, fix->model,
dee_model_get_first_iter (fix->model));
g_assert_cmpstr ("Hello world", ==, val);
g_free (val);
}
static void
test_string2 (Fixture *fix, gconstpointer data)
{
DeeModelReader reader;
gchar *val;
dee_model_reader_new_for_string_column (2, &reader);
val = dee_model_reader_read (&reader, fix->model,
dee_model_get_first_iter (fix->model));
g_assert_cmpstr ("Three Danish characters... æøå?", ==, val);
g_free (val);
}
static void
test_int (Fixture *fix, gconstpointer data)
{
DeeModelReader reader;
gchar *val;
dee_model_reader_new_for_int32_column (1, &reader);
val = dee_model_reader_read (&reader, fix->model,
dee_model_get_first_iter (fix->model));
g_assert_cmpstr ("27", ==, val);
g_free (val);
}
static void
test_uint (Fixture *fix, gconstpointer data)
{
DeeModelReader reader;
gchar *val;
dee_model_reader_new_for_uint32_column (3, &reader);
val = dee_model_reader_read (&reader, fix->model,
dee_model_get_first_iter (fix->model));
g_assert_cmpstr ("68", ==, val);
g_free (val);
}
void
test_model_readers_create_suite (void)
{
#define DOMAIN "/Index/ModelReaders"
g_test_add (DOMAIN"/String0", Fixture, 0,
setup, test_string0, teardown);
g_test_add (DOMAIN"/String2", Fixture, 0,
setup, test_string2, teardown);
g_test_add (DOMAIN"/Int", Fixture, 0,
setup, test_int, teardown);
g_test_add (DOMAIN"/UInt", Fixture, 0,
setup, test_uint, teardown);
}
dee-1.2.7+15.04.20150304/tests/model-helper-clear3rows.c 0000644 0000153 0000161 00000005433 12475676210 022571 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
guint64 before_begin_seqnum, before_end_seqnum,
after_begin_seqnum, after_end_seqnum;
static void
_begin_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
before_begin_seqnum = begin_seqnum;
before_end_seqnum = end_seqnum;
}
static void
_end_txn (DeeSharedModel *model, guint64 begin_seqnum, guint64 end_seqnum)
{
after_begin_seqnum = begin_seqnum;
after_end_seqnum = end_seqnum;
}
static void
_row_removed (DeeModel *model, DeeModelIter *iter, GSList **removed)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*removed = g_slist_append (*removed, iter);
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
GSList *removed;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
g_signal_connect (model, "begin-transaction", G_CALLBACK (_begin_txn), NULL);
g_signal_connect (model, "end-transaction", G_CALLBACK (_end_txn), NULL);
if (gtx_wait_for_signal (G_OBJECT (model), 100000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
/* Listen for removes */
removed = NULL;
g_signal_connect (model, "row-removed", G_CALLBACK (_row_removed), &removed);
/* Wait for some RowsChanged signals */
gtx_yield_main_loop (1000);
g_assert_cmpint (g_slist_length (removed), ==, 3);
g_assert_cmpint (dee_model_get_n_rows(model), ==, 0);
g_assert_cmpint (6, ==, (guint) dee_serializable_model_get_seqnum (model));
g_assert (before_begin_seqnum == after_begin_seqnum);
g_assert (before_end_seqnum == after_end_seqnum);
g_assert_cmpint (3, ==, (guint) before_begin_seqnum);
g_assert_cmpint (6, ==, (guint) before_end_seqnum);
gtx_assert_last_unref (model);
g_slist_free (removed);
return 0;
}
dee-1.2.7+15.04.20150304/tests/model-helper-change3rows.c 0000644 0000153 0000161 00000005452 12475676210 022731 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
static void
_row_changed (DeeModel *model, DeeModelIter *iter, GSList **changes_so_far)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*changes_so_far = g_slist_append (*changes_so_far, iter);
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
GSList *changes;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
if (gtx_wait_for_signal (G_OBJECT (model), 1000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
/* Listen for changes */
changes = NULL;
g_signal_connect (model, "row-changed", G_CALLBACK (_row_changed), &changes);
/* Wait for some RowsChanged signals */
gtx_yield_main_loop (1000);
/* Check that we got what we expected */
g_assert_cmpint (g_slist_length (changes), == , 3);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
iter = (DeeModelIter*) g_slist_nth (changes, 0)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "changed_zero");
iter = (DeeModelIter*) g_slist_nth (changes, 1)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "changed_one");
iter = (DeeModelIter*) g_slist_nth (changes, 2)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 2);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "changed_two");
gtx_assert_last_unref (model);
g_slist_free (changes);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-client-server.c 0000644 0000153 0000161 00000072467 12475676210 021704 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by Michal Hruby
*
*/
#include
#include
#include
#include
#define TIMEOUT 100
#define PEER_NAME "com.canonical.Dee.Peer.Tests.Interactions"
#define MODEL_NAME "com.canonical.Dee.Peer.Tests.Interactions"
/* A command line that launches the appropriate *-helper-* executable,
* giving $name as first argument */
#define SERVER_HELPER(helper,name,count) \
(gchar *[]) { "./server-helper-"#helper, name, #count, NULL }
#define MODEL_HELPER(helper,name) \
(gchar *[]) { "./model-helper-"#helper, name, "DeeClient", NULL }
typedef struct
{
DeeServer *server;
} ServerFixture;
typedef struct
{
DeeModel *model;
} Fixture;
static void server_setup (ServerFixture *fix, gconstpointer data);
static void server_teardown (ServerFixture *fix, gconstpointer data);
static void model_setup (Fixture *fix, gconstpointer data);
static void model_teardown (Fixture *fix, gconstpointer data);
static void model_setup_null (Fixture *fix, gconstpointer data);
static void model_teardown_null (Fixture *fix, gconstpointer data);
static void test_allocation (ServerFixture *fix, gconstpointer data);
static void test_become_leader (ServerFixture *fix, gconstpointer data);
static void test_valid_client_address (ServerFixture *fix, gconstpointer data);
static void test_one_client (ServerFixture *fix, gconstpointer data);
static void test_multiple_clients (ServerFixture *fix, gconstpointer data);
static void test_shared_server (ServerFixture *fix, gconstpointer data);
static void test_ready (Fixture *fix, gconstpointer data);
static void test_clone (Fixture *fix, gconstpointer data);
static void test_row_added (Fixture *fix, gconstpointer data);
static void test_row_changed (Fixture *fix, gconstpointer data);
static void test_row_removed (Fixture *fix, gconstpointer data);
static void test_model_clear (Fixture *fix, gconstpointer data);
static void test_clear_add (Fixture *fix, gconstpointer data);
static void test_clear_then_add (Fixture *fix, gconstpointer data);
static void test_row_inserted (Fixture *fix, gconstpointer data);
static void test_schemaless_leader (Fixture *fix, gconstpointer data);
static void test_client_commit (Fixture *fix, gconstpointer data);
static void test_multiple_models (Fixture *fix, gconstpointer data);
static void test_multiple_models2 (Fixture *fix, gconstpointer data);
static void test_remote_append (Fixture *fix, gconstpointer data);
static void test_disabled_writes (Fixture *fix, gconstpointer data);
void
test_client_server_interactions_create_suite (void)
{
#define DOMAIN "/ClientServer/Interactions"
g_test_add (DOMAIN"/Allocation", ServerFixture, 0,
server_setup, test_allocation, server_teardown);
g_test_add (DOMAIN"/BecomeLeader", ServerFixture, 0,
server_setup, test_become_leader, server_teardown);
g_test_add (DOMAIN"/ValidClientAddress", ServerFixture, 0,
server_setup, test_valid_client_address, server_teardown);
g_test_add (DOMAIN"/OneClient", ServerFixture, 0,
server_setup, test_one_client, server_teardown);
g_test_add (DOMAIN"/MultipleClients", ServerFixture, 0,
server_setup, test_multiple_clients, server_teardown);
g_test_add (DOMAIN"/SharedServer", ServerFixture, 0,
server_setup, test_shared_server, server_teardown);
#undef DOMAIN
#define DOMAIN "/ClientServer/Model/Interactions"
g_test_add (DOMAIN"/Ready", Fixture, 0,
model_setup, test_ready, model_teardown);
g_test_add (DOMAIN"/Clone", Fixture, 0,
model_setup, test_clone, model_teardown);
g_test_add (DOMAIN"/RowAdded", Fixture, 0,
model_setup, test_row_added, model_teardown);
g_test_add (DOMAIN"/RowChanged", Fixture, 0,
model_setup, test_row_changed, model_teardown);
g_test_add (DOMAIN"/RowRemoved", Fixture, 0,
model_setup, test_row_removed, model_teardown);
g_test_add (DOMAIN"/Clear", Fixture, 0,
model_setup, test_model_clear, model_teardown);
g_test_add (DOMAIN"/ClearAndAdd", Fixture, 0,
model_setup, test_clear_add, model_teardown);
g_test_add (DOMAIN"/ClearThenAdd", Fixture, 0,
model_setup, test_clear_then_add, model_teardown);
g_test_add (DOMAIN"/RowInserted", Fixture, 0,
model_setup, test_row_inserted, model_teardown);
g_test_add (DOMAIN"/SchemalessLeader", Fixture, 0,
model_setup_null, test_schemaless_leader, model_teardown_null);
g_test_add (DOMAIN"/ClientCommit", Fixture, 0,
model_setup, test_client_commit, model_teardown);
g_test_add (DOMAIN"/MultipleModels", Fixture, 0,
model_setup_null, test_multiple_models, model_teardown_null);
g_test_add (DOMAIN"/MultipleModels2", Fixture, 0,
model_setup_null, test_multiple_models2, model_teardown_null);
g_test_add (DOMAIN"/RemoteAppend", Fixture, 0,
model_setup, test_remote_append, model_teardown);
g_test_add (DOMAIN"/DisabledWrites", Fixture, 0,
model_setup_null, test_disabled_writes, model_teardown_null);
}
static void
server_setup (ServerFixture *fix, gconstpointer data)
{
fix->server = dee_server_new (PEER_NAME);
g_assert_cmpint (0, ==, dee_peer_is_swarm_leader (DEE_PEER (fix->server)));
g_assert (DEE_IS_SERVER (fix->server));
}
static void
server_teardown (ServerFixture *fix, gconstpointer data)
{
gtx_assert_last_unref (fix->server);
/* Spin the mainloop a bit to check if we have any post-test
* async effect crashing us */
gtx_yield_main_loop (200);
}
static void
model_setup (Fixture *fix, gconstpointer data)
{
DeeServer *server = dee_server_new (MODEL_NAME);
fix->model = (DeeModel*) dee_shared_model_new_for_peer (DEE_PEER (server));
dee_model_set_schema (fix->model, "i", "s", NULL);
g_assert (DEE_IS_MODEL (fix->model));
}
static void
model_teardown (Fixture *fix, gconstpointer data)
{
gtx_assert_last_unref (fix->model);
/* Spin the mainloop so the socket service gets into usable state again */
gtx_yield_main_loop (200);
}
static void
model_setup_null (Fixture *fix, gconstpointer data)
{
}
static void
model_teardown_null (Fixture *fix, gconstpointer data)
{
}
/******************** The actual test cases ********************/
static void
test_allocation (ServerFixture *fix, gconstpointer data)
{
/* Do nothing, this test basically just asserts that
* the fix->server is cleaned up after immediate construction */
}
static void
test_become_leader (ServerFixture *fix, gconstpointer data)
{
gtx_wait_for_signal (G_OBJECT (fix->server), TIMEOUT,
"notify::swarm-leader", NULL);
/* Assert that we have become swarm leaders.
* No other peers should be running */
g_assert_cmpint (0, !=, dee_peer_is_swarm_leader (DEE_PEER (fix->server)));
}
static void
test_valid_client_address (ServerFixture *fix, gconstpointer data)
{
gtx_wait_for_signal (G_OBJECT (fix->server), TIMEOUT,
"notify::swarm-leader", NULL);
g_assert (dee_server_get_client_address (fix->server) != NULL);
}
static void
on_connection_acquired (DeeServer *server, GDBusConnection *connection,
GSList **list)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*list = g_slist_append (*list, connection);
}
static void
test_one_client (ServerFixture *fix, gconstpointer data)
{
GSList *list = NULL;
g_signal_connect (fix->server, "connection-acquired",
G_CALLBACK (on_connection_acquired), &list);
gtx_wait_for_signal (G_OBJECT (fix->server), TIMEOUT,
"notify::swarm-leader", NULL);
/* We are leaders - launch the helper */
if (gtx_wait_for_command (TESTDIR,
SERVER_HELPER (client, PEER_NAME, 1),
2000))
g_critical ("Peer helper timed out");
gtx_assert_last_command_status (0);
g_assert_cmpuint (g_slist_length (list), ==, 1);
g_slist_free (list);
}
static void
test_multiple_clients (ServerFixture *fix, gconstpointer data)
{
GSList *list = NULL;
g_signal_connect (fix->server, "connection-acquired",
G_CALLBACK (on_connection_acquired), &list);
gtx_wait_for_signal (G_OBJECT (fix->server), TIMEOUT,
"notify::swarm-leader", NULL);
/* We are leaders - launch the helper */
if (gtx_wait_for_command (TESTDIR,
SERVER_HELPER (client, PEER_NAME, 4),
4000))
g_critical ("Peer helper timed out");
gtx_assert_last_command_status (0);
g_assert_cmpuint (g_slist_length (list), ==, 4);
g_slist_free (list);
}
static void
test_shared_server (ServerFixture *fix, gconstpointer data)
{
DeeServer *another_server;
gtx_wait_for_signal (G_OBJECT (fix->server), TIMEOUT,
"notify::swarm-leader", NULL);
/* Make sure we're able to use the same bus_address on multiple servers */
another_server = dee_server_new_for_address (
PEER_NAME ".T1", dee_server_get_client_address (fix->server));
gtx_wait_for_signal (G_OBJECT (another_server), TIMEOUT,
"notify::swarm-leader", NULL);
g_assert_cmpstr (dee_peer_get_swarm_leader (DEE_PEER (fix->server)), ==,
dee_peer_get_swarm_leader (DEE_PEER (another_server)));
g_assert_cmpstr (dee_server_get_client_address (fix->server), ==,
dee_server_get_client_address (another_server));
g_object_unref (another_server);
}
static void
test_ready (Fixture *fix, gconstpointer data)
{
GParamSpec *pspec;
gboolean synchronized;
/* Test the GObject property reports FALSE */
g_object_get (fix->model, "synchronized", &synchronized, NULL);
g_assert_cmpint (0, == , synchronized);
/* Check that convenience getter now reports FALSE */
g_assert_cmpint (0, ==, dee_shared_model_is_synchronized (DEE_SHARED_MODEL (fix->model)));
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", &pspec))
g_critical ("Model never synchronized");
else
g_param_spec_unref (pspec);
/* Test the GObject property reports TRUE */
g_object_get (fix->model, "synchronized", &synchronized, NULL);
g_assert_cmpint (0, != , synchronized);
/* Check that convenience getter now reports TRUE */
g_assert_cmpint (0, !=, dee_shared_model_is_synchronized (DEE_SHARED_MODEL (fix->model)));
if (!gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", &pspec))
{
g_critical ("Model changed synchronization state twice");
g_param_spec_unref (pspec);
}
}
static gboolean
_add3rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_append (model, 0, "zero");
dee_model_append (model, 1, "one");
dee_model_append (model, 2, "two");
return FALSE;
}
static gboolean
_add5rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_append (model, 0, "zero");
dee_model_append (model, 1, "one");
dee_model_append (model, 2, "two");
dee_model_append (model, 3, "three");
dee_model_append (model, 4, "four");
return FALSE;
}
static gboolean
_change3rows (DeeModel *model)
{
DeeModelIter *iter;
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
iter = dee_model_get_iter_at_row (model, 0);
dee_model_set_value (model, iter, 1, g_variant_new_string ("changed_zero"));
iter = dee_model_get_iter_at_row (model, 1);
dee_model_set_value (model, iter, 1, g_variant_new_string ("changed_one"));
iter = dee_model_get_iter_at_row (model, 2);
dee_model_set_value (model, iter, 1, g_variant_new_string ("changed_two"));
return FALSE;
}
/* Assumes a model with 5 rows. Removes rows 0, 4, and 2
* in that order. Accounting for rows shifts this becomes
* 0, 3, and 1. Leaving the original rows 1 and 3 now in
* positions 0 and 1 */
static gboolean
_remove3rows (DeeModel *model)
{
DeeModelIter *iter0, *iter4, *iter2;
DeeModelIter *orig_iter1, *orig_iter3;
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
g_return_val_if_fail (dee_model_get_n_rows (model) == 5, FALSE);
iter0 = dee_model_get_iter_at_row (model, 0);
iter4 = dee_model_get_iter_at_row (model, 4);
iter2 = dee_model_get_iter_at_row (model, 2);
orig_iter1 = dee_model_get_iter_at_row (model, 1);
orig_iter3 = dee_model_get_iter_at_row (model, 3);
dee_model_remove (model, iter0);
dee_model_remove (model, iter4);
dee_model_remove (model, iter2);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 2);
g_assert (dee_model_get_iter_at_row (model, 0) == orig_iter1);
g_assert (dee_model_get_iter_at_row (model, 1) == orig_iter3);
return FALSE;
}
static gboolean
_insert1row (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_insert (model, 1, 27, "twentyseven");
return FALSE;
}
static gboolean
_clear_model (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
dee_model_clear (model);
return FALSE;
}
static gboolean
_clear_and_add5rows (DeeModel *model)
{
g_return_val_if_fail (DEE_IS_MODEL (model), FALSE);
_clear_model (model);
_add5rows (model);
return FALSE;
}
static void
test_clone (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never synchronized");
_add3rows (fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clone3rows, MODEL_NAME),
1000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
/* We test that we can do this two times */
/*if (gtx_wait_for_command (TESTDIR, MODEL_HELPER (3rows, MODEL_NAME), 1000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);*/
}
static void
test_row_added (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_changed (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
g_timeout_add (500, (GSourceFunc)_change3rows, fix->model);
//const gchar *cmd[] = {"dbus-monitor", NULL};
//const gchar *cmd[] = {"sleep", "1",NULL};
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (change3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_removed (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add5rows (fix->model);
g_timeout_add (500, (GSourceFunc)_remove3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (remove3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_model_clear (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
g_timeout_add (500, (GSourceFunc)_clear_model, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_clear_add (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
g_timeout_add (500, (GSourceFunc)_clear_and_add5rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3add5, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_clear_then_add (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_clear_model (fix->model);
g_timeout_add (500, (GSourceFunc)_add3rows, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (add3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
g_timeout_add (500, (GSourceFunc)_clear_model, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (clear3rows, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
test_row_inserted (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
_add3rows (fix->model);
g_timeout_add (500, (GSourceFunc)_insert1row, fix->model);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (insert1row, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
}
static void
_ready (DeeModel *model, GParamSpec *pspec, GSList **rows_so_far)
{
/* We must not have any rows when 'ready' is emitted */
g_assert (*rows_so_far == NULL);
}
static void
_collect_row (DeeModel *model, DeeModelIter *iter, GSList **rows_so_far)
{
/* Yes, I _know_ that append() is slow, but this is a test! */
*rows_so_far = g_slist_append (*rows_so_far, iter);
}
/* This case must run without a Fixture */
static void
test_schemaless_leader (Fixture *fix, gconstpointer data)
{
DeeModel *model;
DeeModelIter *iter;
GSList *rows_added;
g_assert (fix->model == NULL);
/* Set up a clean model *without* a schema. We will pick up the schema
* with the first transaction from the slave. Or at least, that's what we
* want to assert ;-) */
model = dee_shared_model_new_for_peer (DEE_PEER (dee_server_new (MODEL_NAME)));
// no set_schema() on purpose!
/* Listen for changes */
rows_added = NULL;
g_signal_connect (model, "row-added", G_CALLBACK (_collect_row), &rows_added);
g_signal_connect (model, "notify::synchronized", G_CALLBACK (_ready), &rows_added);
/* Remote process defines column types and adds two rows */
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (schemaless, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
/* Check that we got the right schema from the peer */
g_assert_cmpint (dee_model_get_n_columns (model), ==, 2);
g_assert_cmpstr (dee_model_get_column_schema (model, 0), ==, "i");
g_assert_cmpstr (dee_model_get_column_schema (model, 1), ==, "s");
/* Check that we got what we expected */
g_assert_cmpint (g_slist_length (rows_added), == , 2);
g_assert_cmpint (dee_model_get_n_rows (model), ==, 2);
g_assert_cmpint (dee_model_get_n_columns (model), ==, 2);
iter = (DeeModelIter*) g_slist_nth (rows_added, 0)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 27);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "skunkworks");
iter = (DeeModelIter*) g_slist_nth (rows_added, 1)->data;
g_assert_cmpint (dee_model_get_position (model, iter), == , 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 68);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "wumbo");
gtx_assert_last_unref (model);
g_slist_free (rows_added);
/* Spin the mainloop so the socket service gets into usable state again */
gtx_yield_main_loop (200);
}
static void
test_client_commit (Fixture *fix, gconstpointer data)
{
gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT,
"notify::synchronized", NULL);
DeeModel *client_model1 = dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new (MODEL_NAME)));
DeeModel *client_model2 = dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new (MODEL_NAME)));
gtx_wait_for_signal (G_OBJECT (client_model1), TIMEOUT,
"notify::synchronized", NULL);
g_assert (dee_shared_model_is_synchronized (DEE_SHARED_MODEL (client_model1)));
if (!dee_shared_model_is_synchronized (DEE_SHARED_MODEL (client_model2)))
{
gtx_wait_for_signal (G_OBJECT (client_model2), TIMEOUT,
"notify::synchronized", NULL);
}
dee_model_append (client_model1, 38, "client_change");
gtx_yield_main_loop (500);
g_assert_cmpuint (dee_model_get_n_rows (fix->model), >, 0);
g_assert_cmpuint (dee_model_get_n_rows (client_model1), >, 0);
g_assert_cmpuint (dee_model_get_n_rows (client_model2), >, 0);
g_object_unref (client_model1);
g_object_unref (client_model2);
}
static void
test_multiple_models (Fixture *fix, gconstpointer data)
{
gchar *address = dee_server_bus_address_for_name (PEER_NAME, TRUE);
DeeModel *model1 = dee_shared_model_new_for_peer (
DEE_PEER (dee_server_new_for_address (PEER_NAME ".T1", address))
);
DeeModel *model2 = dee_shared_model_new_for_peer (
DEE_PEER (dee_server_new_for_address (PEER_NAME ".T2", address))
);
dee_model_set_schema (model1, "i", "s", NULL);
dee_model_set_schema (model2, "i", "s", NULL);
gtx_wait_for_signal (G_OBJECT (model1), TIMEOUT,
"notify::synchronized", NULL);
if (!dee_shared_model_is_synchronized (DEE_SHARED_MODEL (model2)))
{
gtx_wait_for_signal (G_OBJECT (model2), TIMEOUT,
"notify::synchronized", NULL);
}
g_assert (dee_shared_model_is_synchronized (DEE_SHARED_MODEL (model1)) &&
dee_shared_model_is_synchronized (DEE_SHARED_MODEL (model2)));
DeeModel *client_model1 = dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new_for_address (PEER_NAME ".T1", address)));
DeeModel *client_model2 = dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new_for_address (PEER_NAME ".T2", address)));
_add5rows (model1);
_add3rows (model2);
gtx_wait_for_signal (G_OBJECT (client_model1), TIMEOUT,
"notify::synchronized", NULL);
g_assert_cmpuint (dee_model_get_n_rows (client_model1), ==, 5);
g_assert_cmpuint (dee_model_get_n_rows (model1), ==, 5);
if (!dee_shared_model_is_synchronized (DEE_SHARED_MODEL (client_model2)))
{
gtx_wait_for_signal (G_OBJECT (client_model2), TIMEOUT,
"notify::synchronized", NULL);
}
g_assert_cmpuint (dee_model_get_n_rows (client_model2), ==, 3);
g_assert_cmpuint (dee_model_get_n_rows (model2), ==, 3);
/* Make sure the first model still has 5 rows */
g_assert_cmpuint (dee_model_get_n_rows (client_model1), ==, 5);
g_assert_cmpuint (dee_model_get_n_rows (model1), ==, 5);
g_object_unref (client_model1);
g_object_unref (client_model2);
g_object_unref (model1);
g_object_unref (model2);
g_free (address);
/* Spin the mainloop so the socket service gets into usable state again */
gtx_yield_main_loop (200);
}
static void
test_multiple_models2 (Fixture *fix, gconstpointer data)
{
gchar *address = dee_server_bus_address_for_name (PEER_NAME, TRUE);
DeeModel *model1 = dee_shared_model_new_for_peer (
DEE_PEER (dee_server_new_for_address (PEER_NAME ".T1", address))
);
DeeModel *model2 = dee_shared_model_new_for_peer (
DEE_PEER (dee_server_new_for_address (PEER_NAME ".T2", address))
);
dee_model_set_schema (model1, "i", "s", NULL);
dee_model_set_schema (model2, "i", "s", NULL);
gtx_wait_for_signal (G_OBJECT (model1), TIMEOUT,
"notify::synchronized", NULL);
if (!dee_shared_model_is_synchronized (DEE_SHARED_MODEL (model2)))
{
gtx_wait_for_signal (G_OBJECT (model2), TIMEOUT,
"notify::synchronized", NULL);
}
g_assert (dee_shared_model_is_synchronized (DEE_SHARED_MODEL (model1)) &&
dee_shared_model_is_synchronized (DEE_SHARED_MODEL (model2)));
DeeModel *client_model1 = dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new_for_address (PEER_NAME ".T1", address)));
DeeModel *client_model2 = dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new_for_address (PEER_NAME ".T2", address)));
_add5rows (model1);
_add3rows (model2);
gtx_wait_for_signal (G_OBJECT (client_model1), TIMEOUT,
"notify::synchronized", NULL);
g_assert_cmpuint (dee_model_get_n_rows (client_model1), ==, 5);
g_assert_cmpuint (dee_model_get_n_rows (model1), ==, 5);
if (!dee_shared_model_is_synchronized (DEE_SHARED_MODEL (client_model2)))
{
gtx_wait_for_signal (G_OBJECT (client_model2), TIMEOUT,
"notify::synchronized", NULL);
}
g_assert_cmpuint (dee_model_get_n_rows (client_model2), ==, 3);
g_assert_cmpuint (dee_model_get_n_rows (model2), ==, 3);
/* Make sure the first model still has 5 rows */
g_assert_cmpuint (dee_model_get_n_rows (client_model1), ==, 5);
g_assert_cmpuint (dee_model_get_n_rows (model1), ==, 5);
/* get rid of the first client and server */
g_object_unref (client_model1);
g_object_unref (model1);
/* and make sure the second ones still work fine */
dee_model_clear (model2);
gtx_yield_main_loop (500); /* sync */
g_assert_cmpuint (dee_model_get_n_rows (client_model2), ==, 0);
g_assert_cmpuint (dee_model_get_n_rows (model2), ==, 0);
g_object_unref (client_model2);
g_object_unref (model2);
g_free (address);
/* Spin the mainloop so the socket service gets into usable state again */
gtx_yield_main_loop (200);
}
static void
changeset_signal (DeeModel *model, gboolean *value)
{
*value = TRUE;
}
static void
test_remote_append (Fixture *fix, gconstpointer data)
{
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
/* We should be leader before starting the helper process */
g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 0);
gboolean got_changeset_start = FALSE;
gboolean got_changeset_finish = FALSE;
g_signal_connect (fix->model, "changeset-started",
G_CALLBACK (changeset_signal), &got_changeset_start);
g_signal_connect (fix->model, "changeset-finished",
G_CALLBACK (changeset_signal), &got_changeset_finish);
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (append1, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
/* There should be a new row in the model */
g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 1);
g_assert (got_changeset_start);
g_assert (got_changeset_finish);
}
static void
test_disabled_writes (Fixture *fix, gconstpointer data)
{
DeePeer *peer;
DeeModelIter *iter;
peer = DEE_PEER (dee_server_new (MODEL_NAME));
fix->model = DEE_MODEL (g_object_new (DEE_TYPE_SHARED_MODEL,
"peer", peer,
"back-end", dee_sequence_model_new (),
"access-mode", DEE_SHARED_MODEL_ACCESS_MODE_LEADER_WRITABLE, NULL));
dee_model_set_schema (fix->model, "i", "s", NULL);
g_object_unref (G_OBJECT (peer));
if (gtx_wait_for_signal (G_OBJECT (fix->model), TIMEOUT, "notify::synchronized", NULL))
g_critical ("Model never emitted 'ready' signal");
/* We should be leader before starting the helper process */
g_assert (dee_shared_model_is_leader (DEE_SHARED_MODEL (fix->model)));
dee_model_prepend (fix->model, 81, "eightyone");
if (gtx_wait_for_command (TESTDIR,
MODEL_HELPER (append1, MODEL_NAME),
2000))
g_critical ("Model helper timed out");
gtx_assert_last_command_status (0);
/* The peer tried to append a row, but we should have ignored that */
g_assert_cmpuint (dee_model_get_n_rows (fix->model), ==, 1);
iter = dee_model_get_first_iter (fix->model);
g_assert_cmpstr (dee_model_get_string (fix->model, iter, 1), ==, "eightyone");
}
dee-1.2.7+15.04.20150304/tests/model-helper-clone3rows-meta.c 0000644 0000153 0000161 00000006137 12475676210 023531 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
static void
row_added (DeeModel *model, DeeModelIter *iter, gpointer data)
{
gint *num_added = (gint*) data;
(*num_added)++;
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
DeeModelIter *iter;
const gchar **column_names;
GVariant *column_namesv;
GHashTable *vardict_schema;
gint num_added;
guint column;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
g_set_prgname ("model-helper");
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
num_added = 0;
g_signal_connect (model, "row-added", G_CALLBACK (row_added), &num_added);
if (gtx_wait_for_signal (G_OBJECT (model), 100000, "notify::synchronized", NULL))
g_error ("Helper model timed out waiting for 'ready' signal");
g_assert_cmpint (dee_model_get_n_rows (model), ==, 3);
iter = dee_model_get_iter_at_row (model, 0);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 0);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "zero");
iter = dee_model_get_iter_at_row (model, 1);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 1);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "one");
iter = dee_model_get_iter_at_row (model, 2);
g_assert_cmpint (dee_model_get_int32 (model, iter, 0), == , 2);
g_assert_cmpstr (dee_model_get_string (model, iter, 1), == , "two");
column_names = dee_model_get_column_names (model, NULL);
g_assert (column_names != NULL);
column_namesv = g_variant_new_strv (column_names, -1);
g_assert_cmpstr (g_variant_print (column_namesv, FALSE), ==,
"['count', 'title', 'hints', 'extra-hints']");
g_assert_cmpstr (dee_model_get_field_schema (model, "uri", &column), ==, "s");
g_assert_cmpuint (column, ==, 2);
vardict_schema = dee_model_get_vardict_schema (model, 2);
g_assert_cmpuint (g_hash_table_size (vardict_schema), >, 0);
g_hash_table_unref (vardict_schema);
vardict_schema = dee_model_get_vardict_schema (model, 3);
g_assert (vardict_schema == NULL || g_hash_table_size (vardict_schema) == 0);
if (vardict_schema) g_hash_table_unref (vardict_schema);
gtx_assert_last_unref (model);
g_assert_cmpint (num_added, ==, 3);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-term-list.c 0000644 0000153 0000161 00000011467 12475676210 021033 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
typedef struct
{
DeeTermList *terms;
} Fixture;
static void setup (Fixture *fix, gconstpointer data);
static void teardown (Fixture *fix, gconstpointer data);
static void
setup (Fixture *fix, gconstpointer data)
{
fix->terms = g_object_new (DEE_TYPE_TERM_LIST, NULL);
g_assert (DEE_IS_TERM_LIST (fix->terms));
}
static void
teardown (Fixture *fix, gconstpointer data)
{
g_object_unref (fix->terms);
fix->terms = NULL;
}
static void
test_empty (Fixture *fix, gconstpointer data)
{
g_assert (DEE_IS_TERM_LIST (fix->terms));
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 0);
dee_term_list_clear (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 0);
}
static void
test_one (Fixture *fix, gconstpointer data)
{
dee_term_list_add_term (fix->terms, "one");
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "one");
dee_term_list_clear (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 0);
}
static void
test_two (Fixture *fix, gconstpointer data)
{
dee_term_list_add_term (fix->terms, "one");
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "one");
dee_term_list_add_term (fix->terms, "two");
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 2);
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 0), ==, "one");
g_assert_cmpstr (dee_term_list_get_term (fix->terms, 1), ==, "two");
dee_term_list_clear (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 0);
}
static void
test_clone (Fixture *fix, gconstpointer data)
{
DeeTermList *clone;
/* Cloning an empty list should work */
clone = dee_term_list_clone (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (clone), ==, 0);
g_object_unref (clone);
/* Clone with 1 item */
dee_term_list_add_term (fix->terms, "one");
clone = dee_term_list_clone (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (clone), ==, 1);
g_assert_cmpstr (dee_term_list_get_term(clone, 0), ==, "one");
/* Terms from cloned lists should compare by pointers directly */
g_assert (dee_term_list_get_term (fix->terms, 0) ==
dee_term_list_get_term (clone, 0));
/* Clearing clone should not affect original */
dee_term_list_clear (clone);
g_assert_cmpint (dee_term_list_num_terms (clone), ==, 0);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 1);
g_object_unref (clone);
/* Clone with 3 items */
dee_term_list_add_term (fix->terms, "two");
dee_term_list_add_term (fix->terms, "three");
clone = dee_term_list_clone (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (clone), ==, 3);
g_assert_cmpstr (dee_term_list_get_term(clone, 0), ==, "one");
g_assert_cmpstr (dee_term_list_get_term(clone, 1), ==, "two");
g_assert_cmpstr (dee_term_list_get_term(clone, 2), ==, "three");
/* Terms from cloned lists should compare by pointers directly */
g_assert (dee_term_list_get_term (fix->terms, 0) ==
dee_term_list_get_term (clone, 0));
g_assert (dee_term_list_get_term (fix->terms, 1) ==
dee_term_list_get_term (clone, 1));
g_assert (dee_term_list_get_term (fix->terms, 2) ==
dee_term_list_get_term (clone, 2));
/* Clearing original should not affect clone*/
dee_term_list_clear (fix->terms);
g_assert_cmpint (dee_term_list_num_terms (clone), ==, 3);
g_assert_cmpint (dee_term_list_num_terms (fix->terms), ==, 0);
g_object_unref (clone);
}
void
test_term_list_create_suite (void)
{
#define DOMAIN "/Index/TermList"
g_test_add (DOMAIN"/Empty", Fixture, 0,
setup, test_empty, teardown);
g_test_add (DOMAIN"/One", Fixture, 0,
setup, test_one, teardown);
g_test_add (DOMAIN"/Two", Fixture, 0,
setup, test_two, teardown);
g_test_add (DOMAIN"/Clone", Fixture, 0,
setup, test_clone, teardown);
}
dee-1.2.7+15.04.20150304/tests/test-model-column.c 0000644 0000153 0000161 00000034054 12475676210 021503 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
* Neil Jagdish Patel
*
*/
#include
#include
#include
#include
typedef struct
{
DeeModel *model;
} ColumnFixture;
static void column_setup (ColumnFixture *fix, gconstpointer data);
static void column_teardown (ColumnFixture *fix, gconstpointer data);
static void proxy_column_setup (ColumnFixture *fix, gconstpointer data);
static void proxy_column_teardown (ColumnFixture *fix, gconstpointer data);
static void test_column_allocation (ColumnFixture *fix, gconstpointer data);
static void test_unmodified_and_get_value (ColumnFixture *fix, gconstpointer data);
static void test_modification_and_get_row (ColumnFixture *fix, gconstpointer data);
static void test_get_schema (ColumnFixture *fix, gconstpointer data);
static void test_no_schema (ColumnFixture *fix, gconstpointer data);
static void test_bad_schemas (void);
static void test_null_string (ColumnFixture *fix, gconstpointer data);
void
test_model_column_create_suite (void)
{
#define SEQ_DOMAIN "/Model/Sequence/Column"
#define PROXY_DOMAIN "/Model/Proxy/Column"
g_test_add (SEQ_DOMAIN"/Allocation", ColumnFixture, 0,
column_setup, test_column_allocation, column_teardown);
g_test_add (PROXY_DOMAIN"/Allocation", ColumnFixture, 0,
proxy_column_setup, test_column_allocation, proxy_column_teardown);
g_test_add (SEQ_DOMAIN"/UnmodifiedAndGetValue", ColumnFixture, 0,
column_setup, test_unmodified_and_get_value, column_teardown);
g_test_add (PROXY_DOMAIN"/UnmodifiedAndGetValue", ColumnFixture, 0,
proxy_column_setup, test_unmodified_and_get_value, proxy_column_teardown);
g_test_add (SEQ_DOMAIN"/ModificationAndGetRow", ColumnFixture, 0,
column_setup, test_modification_and_get_row, column_teardown);
g_test_add (PROXY_DOMAIN"/ModificationAndGetRow", ColumnFixture, 0,
proxy_column_setup, test_modification_and_get_row, proxy_column_teardown);
g_test_add (SEQ_DOMAIN"/Schemas", ColumnFixture, 0,
column_setup, test_get_schema, column_teardown);
g_test_add (PROXY_DOMAIN"/Schemas", ColumnFixture, 0,
proxy_column_setup, test_get_schema, proxy_column_teardown);
g_test_add (SEQ_DOMAIN"/NoSchemas", ColumnFixture, 0,
column_setup, test_no_schema, column_teardown);
g_test_add (PROXY_DOMAIN"/NoSchemas", ColumnFixture, 0,
proxy_column_setup, test_no_schema, proxy_column_teardown);
g_test_add_func ("/Model/Column/BadSchemas", test_bad_schemas);
g_test_add (SEQ_DOMAIN"/NullString", ColumnFixture, 0,
column_setup, test_null_string, column_teardown);
g_test_add (PROXY_DOMAIN"/NullString", ColumnFixture, 0,
proxy_column_setup, test_null_string, proxy_column_teardown);
}
static void
column_setup (ColumnFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model,
"b", "y", "i", "u", "x", "t", "d", "s", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
g_assert_cmpint (8, ==, dee_model_get_n_columns (fix->model));
g_assert_cmpstr ("b", ==, dee_model_get_column_schema (fix->model, 0));
g_assert_cmpstr ("y", ==, dee_model_get_column_schema(fix->model, 1));
g_assert_cmpstr ("i", ==, dee_model_get_column_schema (fix->model, 2));
g_assert_cmpstr ("u", ==, dee_model_get_column_schema (fix->model, 3));
g_assert_cmpstr ("x", ==, dee_model_get_column_schema (fix->model, 4));
g_assert_cmpstr ("t", ==, dee_model_get_column_schema (fix->model, 5));
g_assert_cmpstr ("d", ==, dee_model_get_column_schema (fix->model, 6));
g_assert_cmpstr ("s", ==, dee_model_get_column_schema (fix->model, 7));
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
}
static void
column_teardown (ColumnFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
}
static void
proxy_column_setup (ColumnFixture *fix, gconstpointer data)
{
column_setup (fix, data);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL,
"back-end", fix->model,
NULL);
g_assert (DEE_IS_PROXY_MODEL (fix->model));
}
static void
proxy_column_teardown (ColumnFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_PROXY_MODEL (fix->model));
g_object_unref (fix->model);
}
static void
test_column_allocation (ColumnFixture *fix, gconstpointer data)
{
g_assert (DEE_IS_MODEL (fix->model));
}
static void
test_unmodified_and_get_value (ColumnFixture *fix, gconstpointer data)
{
DeeModel *model = fix->model;
DeeModelIter *iter;
GVariant *value;
dee_model_append (fix->model,
TRUE,
'1',
G_MININT32,
G_MAXUINT32,
G_MAXINT64,
G_MAXUINT64,
G_MAXDOUBLE,
"Hello World");
g_assert (dee_model_get_n_rows (model) == 1);
iter = dee_model_get_first_iter (model);
value = dee_model_get_value (model, iter, 0);
g_assert_cmpint (TRUE, ==, g_variant_get_boolean (value));
g_assert_cmpint (TRUE, ==, dee_model_get_bool (model, iter, 0));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 1);
g_assert_cmpint ('1', ==, g_variant_get_byte (value));
g_assert_cmpint ('1', ==, dee_model_get_uchar (model, iter, 1));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 2);
g_assert_cmpint (G_MININT32, ==, g_variant_get_int32 (value));
g_assert_cmpint (G_MININT32, ==, dee_model_get_int32 (model, iter, 2));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 3);
g_assert (g_variant_get_uint32 (value) == G_MAXUINT32);
g_assert_cmpuint (G_MAXUINT32, ==, dee_model_get_uint32 (model, iter, 3));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 4);
g_assert (g_variant_get_int64 (value) == G_MAXINT64);
g_assert_cmpint (G_MAXINT64, ==, dee_model_get_int64 (model, iter, 4));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 5);
g_assert (g_variant_get_uint64 (value) == G_MAXUINT64);
g_assert_cmpuint (G_MAXUINT64, ==, dee_model_get_uint64 (model, iter, 5));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 6);
g_assert (g_variant_get_double (value) == G_MAXDOUBLE);
g_assert_cmpfloat (G_MAXDOUBLE, ==, dee_model_get_double (model, iter, 6));
g_variant_unref (value);
value = dee_model_get_value (model, iter, 7);
g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "Hello World");
g_assert_cmpstr ("Hello World", ==, dee_model_get_string (model, iter, 7));
g_variant_unref (value);
/* Assert that we don't mess up the string copying.
* Ie that dee_model_get_string() returns a const string */
const gchar *cp1 = dee_model_get_string (model, iter, 7);
const gchar *cp2 = dee_model_get_string (model, iter, 7);
g_assert_cmpstr ("Hello World", ==, cp1);
g_assert_cmpstr ("Hello World", ==, cp2);
g_assert (cp1 == cp2);
}
static void
test_modification_and_get_row (ColumnFixture *fix, gconstpointer data)
{
DeeModel *model = fix->model;
DeeModelIter *iter;
GVariant **heap, **stack, **_stack;
gint i;
dee_model_append (fix->model,
TRUE,
'1',
G_MININT,
G_MAXUINT,
G_MAXINT64,
G_MAXUINT64,
G_MAXDOUBLE,
"Hello World");
g_assert (dee_model_get_n_rows (model) == 1);
iter = dee_model_get_first_iter (model);
dee_model_set (model, iter,
FALSE,
'2',
G_MININT+5,
G_MAXUINT-5,
G_MAXINT64-5,
G_MAXUINT64-5,
G_MAXDOUBLE-5.0,
"World Hello");
/* Try filling a stack allocated array and assert
* that we get the same pointer back*/
stack = g_alloca (sizeof(gpointer) * dee_model_get_n_columns (model));
_stack = dee_model_get_row (model, iter, stack);
g_assert (stack == _stack);
/* Also try allocating a new array on the heap by passing in NULL for
* the destination */
heap = dee_model_get_row (model, iter, NULL);
g_assert (heap != NULL);
/* Now assert that both the stack- and heap allocated row
* contains the right data */
g_assert (!g_variant_get_boolean (stack[0]));
g_assert (!g_variant_get_boolean (heap[0]));
g_assert_cmpint (g_variant_get_byte (stack[1]), ==, '2');
g_assert_cmpint (g_variant_get_byte (heap[1]), ==, '2');
g_assert_cmpint (g_variant_get_int32 (stack[2]), ==, G_MININT+5);
g_assert_cmpint (g_variant_get_int32 (heap[2]), ==, G_MININT+5);
g_assert_cmpint (g_variant_get_uint32 (stack[3]), ==, G_MAXUINT-5);
g_assert_cmpint (g_variant_get_uint32 (heap[3]), ==, G_MAXUINT-5);
g_assert (g_variant_get_int64 (stack[4]) == G_MAXINT64-5);
g_assert (g_variant_get_int64 (heap[4]) == G_MAXINT64-5);
g_assert (g_variant_get_uint64 (stack[5]) == G_MAXUINT64-5);
g_assert (g_variant_get_uint64 (heap[5]) == G_MAXUINT64-5);
g_assert (g_variant_get_double (stack[6]) == G_MAXDOUBLE-5.0);
g_assert (g_variant_get_double (heap[6]) == G_MAXDOUBLE-5.0);
g_assert_cmpstr (g_variant_get_string (stack[7], NULL), ==, "World Hello");
g_assert_cmpstr (g_variant_get_string (heap[7], NULL), ==, "World Hello");
/* Unref the variants and free the heap allocated array */
for (i = 0; i < dee_model_get_n_columns (model); i++)
{
g_variant_unref (stack[i]);
g_variant_unref (heap[i]);
}
g_free (heap);
}
static void
test_get_schema (ColumnFixture *fix, gconstpointer data)
{
const gchar* const *schema;
guint n_cols;
/* First check we don't crash when passing NULL for num_columns */
schema = dee_model_get_schema (fix->model,
NULL);
schema = dee_model_get_schema (fix->model,
&n_cols);
g_assert_cmpint (8, ==, n_cols);
g_assert_cmpstr ("b", ==, schema[0]);
g_assert_cmpstr ("b", ==, dee_model_get_column_schema (fix->model, 0));
g_assert_cmpstr ("y", ==, schema[1]);
g_assert_cmpstr ("y", ==, dee_model_get_column_schema (fix->model, 1));
g_assert_cmpstr ("i", ==, schema[2]);
g_assert_cmpstr ("i", ==, dee_model_get_column_schema (fix->model, 2));
g_assert_cmpstr ("u", ==, schema[3]);
g_assert_cmpstr ("u", ==, dee_model_get_column_schema (fix->model, 3));
g_assert_cmpstr ("x", ==, schema[4]);
g_assert_cmpstr ("x", ==, dee_model_get_column_schema (fix->model, 4));
g_assert_cmpstr ("t", ==, schema[5]);
g_assert_cmpstr ("t", ==, dee_model_get_column_schema (fix->model, 5));
g_assert_cmpstr ("d", ==, schema[6]);
g_assert_cmpstr ("d", ==, dee_model_get_column_schema (fix->model, 6));
g_assert_cmpstr ("s", ==, schema[7]);
g_assert_cmpstr ("s", ==, dee_model_get_column_schema (fix->model, 7));
}
static void
test_no_schema (ColumnFixture *fix, gconstpointer data)
{
DeeModel *model;
/* Create a model without a schema and try to manipulate it */
model = dee_sequence_model_new ();
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
{
dee_model_append (model, "ignore this...");
exit (0); /* successful test run (which we shouldn't have) */
}
g_test_trap_assert_failed();
g_test_trap_assert_stderr ("*doesn't have a schema*");
}
static void
test_bad_schemas (void)
{
DeeModel *model = NULL;
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT
| G_TEST_TRAP_SILENCE_STDERR))
{
model = dee_sequence_model_new ();
dee_model_set_schema (model, "", NULL); // empty signature
}
g_test_trap_assert_failed ();
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT
| G_TEST_TRAP_SILENCE_STDERR))
{
model = dee_sequence_model_new ();
dee_model_set_schema (model, "as", "u", "(tt", NULL); // unclosed tuple
}
g_test_trap_assert_failed ();
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT
| G_TEST_TRAP_SILENCE_STDERR))
{
model = dee_sequence_model_new ();
dee_model_set_schema (model, "///", NULL); // illegal characters
}
g_test_trap_assert_failed ();
}
/* Inserting a NULL string should work */
static void
test_null_string (ColumnFixture *fix, gconstpointer data)
{
DeeModel *model = fix->model;
DeeModelIter *iter;
/* Test that we can add a NULL string and that it'll be treated as "" */
dee_model_append (fix->model,
TRUE,
'1',
(gint)0,
(guint)0,
G_GINT64_CONSTANT(0),
G_GUINT64_CONSTANT (0),
(gdouble)0.0,
NULL);
iter = dee_model_get_first_iter (model);
g_assert_cmpstr ("", ==, dee_model_get_string (model, iter, 7));
dee_model_set_value (model, iter, 7, g_variant_new_string ("foo"));
g_assert_cmpstr ("foo", ==, dee_model_get_string (model, iter, 7));
/* Test that we can modify a row in place and set a NULL string which
* is treated as a "" */
dee_model_set (model, iter,
TRUE,
'1',
(gint)0,
(guint)0,
G_GINT64_CONSTANT(0),
G_GUINT64_CONSTANT (0),
(gdouble)0.0,
NULL);
g_assert_cmpstr ("", ==, dee_model_get_string (model, iter, 7));
}
dee-1.2.7+15.04.20150304/tests/peer-helper-1peer.c 0000644 0000153 0000161 00000004161 12475676210 021351 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Mikkel Kamstrup Erlandsen
*
*/
#include "config.h"
#include
#include
#include
#include
static gint n_peers = 0;
static void
on_peer_found (DeePeer *peer)
{
n_peers++;
}
static void
on_peer_lost (DeePeer *peer)
{
n_peers--;
}
/* Expects a clone with 3 rows in it */
gint
main (gint argc, gchar *argv[])
{
DeePeer *peer;
unsigned num_peers;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
peer = dee_peer_new (argv[1]);
g_signal_connect (peer, "peer-found", G_CALLBACK (on_peer_found), NULL);
g_signal_connect (peer, "peer-lost", G_CALLBACK (on_peer_lost), NULL);
if (gtx_wait_for_signal (G_OBJECT (peer), 100000, "notify::swarm-leader", NULL))
g_error ("Peer helper timed out waiting for swarm leader");
/* The main process should be swarm leaders. Not us */
g_assert_cmpint (0, ==, dee_peer_is_swarm_leader (peer));
/* At this point we shouldn't have emitted 'peer-found' yet */
g_assert_cmpint (0, ==, n_peers);
if (gtx_wait_for_signal (G_OBJECT (peer), 100000, "peer-found", NULL))
g_error ("Peer helper timed out waiting for 'peer-found' signal");
g_assert_cmpint (1, ==, n_peers);
/* Listing of peers includes also self */
/* Listing of peers is in flaky state atm (should == 2), see lp:1076971 */
num_peers = g_strv_length (dee_peer_list_peers (peer));
g_assert_cmpint (2, >=, num_peers);
g_assert_cmpint (1, <=, num_peers);
return 0;
}
dee-1.2.7+15.04.20150304/tests/test-model-signals.c 0000644 0000153 0000161 00000012141 12475676210 021637 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Neil Jagdish Patel
* Mikkel Kamstrup Erlandsen
*
*/
#include
#include
#include
typedef struct
{
DeeModel *model;
} SignalsFixture;
static void rows_setup (SignalsFixture *fix, gconstpointer data);
static void rows_teardown (SignalsFixture *fix, gconstpointer data);
static void proxy_rows_setup (SignalsFixture *fix, gconstpointer data);
static void proxy_rows_teardown (SignalsFixture *fix, gconstpointer data);
static void test_signal_add (SignalsFixture *fix, gconstpointer data);
static void test_signal_remove (SignalsFixture *fix, gconstpointer data);
static void test_signal_changed (SignalsFixture *fix, gconstpointer data);
void
test_model_signals_create_suite (void)
{
#define SEQ_DOMAIN "/Model/Sequence/Signals"
#define PROXY_DOMAIN "/Model/Proxy/Signals"
g_test_add (SEQ_DOMAIN"/Add", SignalsFixture, 0,
rows_setup, test_signal_add, rows_teardown);
g_test_add (PROXY_DOMAIN"/Add", SignalsFixture, 0,
proxy_rows_setup, test_signal_add, proxy_rows_teardown);
g_test_add (SEQ_DOMAIN"/Remove", SignalsFixture, 0,
rows_setup, test_signal_remove, rows_teardown);
g_test_add (PROXY_DOMAIN"/Remove", SignalsFixture, 0,
proxy_rows_setup, test_signal_remove, proxy_rows_teardown);
g_test_add (SEQ_DOMAIN"/Changed", SignalsFixture, 0,
rows_setup, test_signal_changed, rows_teardown);
g_test_add (PROXY_DOMAIN"/Changed", SignalsFixture, 0,
proxy_rows_setup, test_signal_changed, proxy_rows_teardown);
}
static void
rows_setup (SignalsFixture *fix, gconstpointer data)
{
fix->model = dee_sequence_model_new ();
dee_model_set_schema (fix->model, "i", "s", NULL);
g_assert (DEE_IS_SEQUENCE_MODEL (fix->model));
}
static void
rows_teardown (SignalsFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
}
static void
proxy_rows_setup (SignalsFixture *fix, gconstpointer data)
{
rows_setup (fix, data);
fix->model = g_object_new (DEE_TYPE_PROXY_MODEL,
"back-end", fix->model,
NULL);
g_assert (DEE_IS_PROXY_MODEL (fix->model));
}
static void
proxy_rows_teardown (SignalsFixture *fix, gconstpointer data)
{
g_object_unref (fix->model);
}
static guint n_add_signals = 0;
static void
test_signal_add_callback (DeeModel *model, DeeModelIter *iter)
{
n_add_signals++;
}
static void
test_signal_add (SignalsFixture *fix, gconstpointer data)
{
gint i;
g_signal_connect (fix->model, "row-added",
G_CALLBACK (test_signal_add_callback), NULL);
n_add_signals = 0;
for (i = 0; i < 10000; i++)
{
dee_model_append (fix->model, i, "Test");
}
g_assert_cmpint (n_add_signals, ==, 10000);
}
static guint n_remove_signals = 0;
static void
test_signal_remove_callback (DeeModel *model, DeeModelIter *iter)
{
n_remove_signals++;
}
static void
test_signal_remove (SignalsFixture *fix, gconstpointer data)
{
gint i;
g_signal_connect (fix->model, "row-removed",
G_CALLBACK (test_signal_remove_callback), NULL);
for (i = 0; i < 10000; i++)
{
dee_model_append (fix->model, i, "Test");
}
n_remove_signals = i = 0;
dee_model_clear (fix->model);
g_assert_cmpint (n_remove_signals, ==, 10000);
}
static guint n_changed_signals = 0;
static void
test_signal_changed_callback (DeeModel *model, DeeModelIter *iter)
{
n_changed_signals++;
}
static void
test_signal_changed (SignalsFixture *fix, gconstpointer data)
{
DeeModelIter *iter;
gint i;
g_signal_connect (fix->model, "row-changed",
G_CALLBACK (test_signal_changed_callback), NULL);
for (i = 0; i < 10000; i++)
{
dee_model_append (fix->model, i, "Test");
}
n_changed_signals = 0;
iter = dee_model_get_first_iter (fix->model);
while (iter != NULL && !dee_model_is_last (fix->model, iter))
{
gint32 j = 0;
gchar *k = "ing";
dee_model_set (fix->model, iter, j, k);
iter = dee_model_next (fix->model, iter);
}
g_assert_cmpint (n_changed_signals, ==, 10000);
n_changed_signals = 0;
iter = dee_model_get_first_iter (fix->model);
while (iter != NULL && !dee_model_is_last (fix->model, iter))
{
dee_model_set_value (fix->model, iter, 0, g_variant_new_int32 (10));
iter = dee_model_next (fix->model, iter);
}
g_assert_cmpint (n_changed_signals, ==, 10000);
}
dee-1.2.7+15.04.20150304/tests/model-helper-append1.c 0000644 0000153 0000161 00000002633 12475676210 022034 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010-2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* 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, see .
*
* Authored by
* Michal Hruby
*
*/
#include "config.h"
#include
#include
#include
#include
/* Joins an existing model, and then tries to append a new row */
gint
main (gint argc, gchar *argv[])
{
DeeModel *model;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
if (argc == 2)
model = dee_shared_model_new (argv[1]);
else
model = dee_shared_model_new_for_peer ((DeePeer*) dee_client_new (argv[1]));
if (gtx_wait_for_signal (G_OBJECT (model), 300, "notify::synchronized", NULL))
{
g_critical ("Model never synchronized");
return 1;
}
dee_model_append (model, 68, "wumbo");
gtx_yield_main_loop (500);
gtx_assert_last_unref (model);
return 0;
}
dee-1.2.7+15.04.20150304/dee-icu-1.0.pc.in 0000644 0000153 0000161 00000000430 12475676210 017354 0 ustar pbuser pbgroup 0000000 0000000 prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: @PACKAGE_NAME@
Description: Dee ICU integration
Version: @VERSION@
Libs: -L${libdir} -ldee-1.0
Cflags: -I${includedir}/dee-1.0
Requires: glib-2.0 gthread-2.0 gobject-2.0 gio-2.0 gio-unix-2.0
dee-1.2.7+15.04.20150304/README 0000644 0000153 0000161 00000000002 12475676210 015467 0 ustar pbuser pbgroup 0000000 0000000
dee-1.2.7+15.04.20150304/src/ 0000755 0000153 0000161 00000000000 12475676370 015415 5 ustar pbuser pbgroup 0000000 0000000 dee-1.2.7+15.04.20150304/src/dee-filter-model.h 0000644 0000153 0000161 00000007712 12475676210 020704 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#if !defined (_DEE_H_INSIDE) && !defined (DEE_COMPILATION)
#error "Only can be included directly."
#endif
#ifndef _HAVE_DEE_FILTER_MODEL_H
#define _HAVE_DEE_FILTER_MODEL_H
#include
#include
#include
#include
G_BEGIN_DECLS
#define DEE_TYPE_FILTER_MODEL (dee_filter_model_get_type ())
#define DEE_FILTER_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
DEE_TYPE_FILTER_MODEL, DeeFilterModel))
#define DEE_FILTER_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
DEE_TYPE_FILTER_MODEL, DeeFilterModelClass))
#define DEE_IS_FILTER_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
DEE_TYPE_FILTER_MODEL))
#define DEE_IS_FILTER_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
DEE_TYPE_FILTER_MODEL))
#define DEE_FILTER_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
DBUS_TYPE_FILTER_MODEL, DeeFilterModelClass))
typedef struct _DeeFilterModel DeeFilterModel;
typedef struct _DeeFilterModelClass DeeFilterModelClass;
typedef struct _DeeFilterModelPrivate DeeFilterModelPrivate;
/* We need this one here to avoid circular refs */
typedef struct _DeeFilter DeeFilter;
/**
* DeeFilterModel:
*
* All fields in the DeeFilterModel structure are private and should never be
* accessed directly
*/
struct _DeeFilterModel
{
/*< private >*/
DeeProxyModel parent;
DeeFilterModelPrivate *priv;
};
struct _DeeFilterModelClass
{
/*< private >*/
DeeProxyModelClass parent_class;
/*< private >*/
void (*_dee_filter_model_1) (void);
void (*_dee_filter_model_2) (void);
void (*_dee_filter_model_3) (void);
void (*_dee_filter_model_4) (void);
};
/**
* dee_filter_model_get_type:
*
* The GType of #DeeFilterModel
*
* Return value: the #GType of #DeeFilterModel
**/
GType dee_filter_model_get_type (void);
DeeModel* dee_filter_model_new (DeeModel *orig_model,
DeeFilter *filter);
gboolean dee_filter_model_contains (DeeFilterModel *self,
DeeModelIter *iter);
DeeModelIter* dee_filter_model_append_iter (DeeFilterModel *self,
DeeModelIter *iter);
DeeModelIter* dee_filter_model_prepend_iter (DeeFilterModel *self,
DeeModelIter *iter);
DeeModelIter* dee_filter_model_insert_iter (DeeFilterModel *self,
DeeModelIter *iter,
guint pos);
DeeModelIter* dee_filter_model_insert_iter_before (DeeFilterModel *self,
DeeModelIter *iter,
DeeModelIter *pos);
DeeModelIter* dee_filter_model_insert_iter_with_original_order (DeeFilterModel *self,
DeeModelIter *iter);
G_END_DECLS
#endif /* _HAVE_DEE_FILTER_MODEL_H */
dee-1.2.7+15.04.20150304/src/dee-client.c 0000644 0000153 0000161 00000026560 12475676210 017574 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by: Michal Hruby
*
*/
/**
* SECTION:dee-client
* @short_description: Creates a client object you can use to connect
* to a #DeeServer.
* @include: dee.h
*
* #DeeClient is the endpoint for connecting to #DeeServer.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "dee-client.h"
#include "dee-server.h"
#include "dee-marshal.h"
#include "trace-log.h"
G_DEFINE_TYPE (DeeClient, dee_client, DEE_TYPE_PEER)
#define GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), DEE_TYPE_CLIENT, DeeClientPrivate))
/**
* DeeClientPrivate:
*
* Ignore this structure.
**/
struct _DeeClientPrivate
{
GDBusConnection *connection;
GCancellable *cancellable;
gchar *bus_address;
guint peer_found_timer_id;
gulong closed_signal_handler_id;
};
/* Globals */
enum
{
PROP_0,
PROP_BUS_ADDRESS
};
enum
{
LAST_SIGNAL
};
//static guint32 _server_signals[LAST_SIGNAL] = { 0 };
/* Forwards */
static gboolean dee_client_is_swarm_leader (DeePeer *peer);
static const gchar* dee_client_get_swarm_leader (DeePeer *peer);
static GSList* dee_client_get_connections (DeePeer *peer);
static gchar** dee_client_list_peers (DeePeer *peer);
static void connecting_finished (GObject *object,
GAsyncResult *res,
gpointer user_data);
static void connection_closed (GDBusConnection *connection,
gboolean remote_peer_vanished,
GError *error,
DeeClient *client);
/* GObject methods */
static void
dee_client_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
DeeClientPrivate *priv;
priv = DEE_CLIENT (object)->priv;
switch (property_id)
{
case PROP_BUS_ADDRESS:
g_value_set_string (value, priv->bus_address);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
dee_client_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
DeeClientPrivate *priv;
priv = DEE_CLIENT (object)->priv;
switch (property_id)
{
case PROP_BUS_ADDRESS:
if (priv->bus_address) g_free (priv->bus_address);
priv->bus_address = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
dee_client_constructed (GObject *self)
{
DeeClientPrivate *priv;
const gchar *swarm_name;
GDBusConnectionFlags flags;
priv = DEE_CLIENT (self)->priv;
/* we should chain up the constructed method here, but peer does things we
* don't want to, so not chaining up... */
swarm_name = dee_peer_get_swarm_name (DEE_PEER (self));
if (swarm_name == NULL)
{
g_critical ("DeeClient created without a swarm name. You must specify "
"a non-NULL swarm name");
return;
}
if (!priv->bus_address)
{
priv->bus_address = dee_server_bus_address_for_name (swarm_name, TRUE);
}
flags = G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT;
priv->cancellable = g_cancellable_new ();
g_dbus_connection_new_for_address (priv->bus_address,
flags,
NULL, // AuthObserver
priv->cancellable,
connecting_finished,
self);
}
static void
dee_client_finalize (GObject *object)
{
DeeClientPrivate *priv;
priv = DEE_CLIENT (object)->priv;
if (priv->cancellable)
{
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
}
if (priv->closed_signal_handler_id)
{
g_signal_handler_disconnect (priv->connection,
priv->closed_signal_handler_id);
priv->closed_signal_handler_id = 0;
}
if (priv->connection)
{
g_object_unref (priv->connection);
}
if (priv->peer_found_timer_id)
{
g_source_remove (priv->peer_found_timer_id);
priv->peer_found_timer_id = 0;
}
if (priv->bus_address)
{
g_free (priv->bus_address);
}
G_OBJECT_CLASS (dee_client_parent_class)->finalize (object);
}
static void
dee_client_class_init (DeeClientClass *klass)
{
GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
DeePeerClass *peer_class = DEE_PEER_CLASS (klass);
g_type_class_add_private (klass, sizeof (DeeClientPrivate));
object_class->constructed = dee_client_constructed;
object_class->get_property = dee_client_get_property;
object_class->set_property = dee_client_set_property;
object_class->finalize = dee_client_finalize;
peer_class->is_swarm_leader = dee_client_is_swarm_leader;
peer_class->get_swarm_leader = dee_client_get_swarm_leader;
peer_class->get_connections = dee_client_get_connections;
peer_class->list_peers = dee_client_list_peers;
/**
* DeeClient::bus-address:
*
* D-Bus address the client will connect to. If you do not specify this
* property #DeeClient will use dee_server_bus_address_for_name() using
* current swarm name to determine the value of this property.
*/
pspec = g_param_spec_string ("bus-address", "Bus address",
"Bus address to use for the connection",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_BUS_ADDRESS, pspec);
}
static void
dee_client_init (DeeClient *self)
{
self->priv = GET_PRIVATE (self);
}
/**
* dee_client_new:
* @swarm_name: Name of swarm to join.
*
* Creates a new instance of #DeeClient and tries to connect to #DeeServer
* created using dee_server_new(). The #DeePeer:swarm-leader property will
* be set once the client connects.
*
* Return value: (transfer full): A newly constructed #DeeClient.
*/
DeeClient*
dee_client_new (const gchar* swarm_name)
{
g_return_val_if_fail (swarm_name != NULL, NULL);
return DEE_CLIENT (g_object_new (DEE_TYPE_CLIENT,
"swarm-name", swarm_name, NULL));
}
/**
* dee_client_new_for_address:
* @swarm_name: Name of swarm to join.
* @bus_address: D-Bus address to use when connecting to the server.
*
* Creates a new instance of #DeeClient and tries to connect to @bus_address.
* The #DeePeer:swarm-leader property will be set once the client connects.
*
* Return value: (transfer full): A newly constructed #DeeClient.
*/
DeeClient*
dee_client_new_for_address (const gchar* swarm_name,
const gchar* bus_address)
{
g_return_val_if_fail (swarm_name != NULL, NULL);
return DEE_CLIENT (g_object_new (DEE_TYPE_CLIENT,
"swarm-name", swarm_name,
"bus-address", bus_address, NULL));
}
/* Private Methods */
static gboolean
dee_client_is_swarm_leader (DeePeer *peer)
{
return FALSE;
}
static const gchar*
dee_client_get_swarm_leader (DeePeer *peer)
{
DeeClientPrivate *priv;
priv = DEE_CLIENT (peer)->priv;
return priv->connection ? g_dbus_connection_get_guid (priv->connection) : NULL;
}
static GSList*
dee_client_get_connections (DeePeer *peer)
{
DeeClientPrivate *priv;
GSList *list = NULL;
priv = DEE_CLIENT (peer)->priv;
if (priv->connection)
{
list = g_slist_append (list, priv->connection);
}
return list;
}
static gchar**
dee_client_list_peers (DeePeer *peer)
{
DeeClientPrivate *priv;
gchar **result;
int i = 0;
priv = DEE_CLIENT (peer)->priv;
result = g_new (gchar*, priv->connection ? 2 : 1);
if (priv->connection)
{
result[i++] = g_strdup (g_dbus_connection_get_guid (priv->connection));
}
result[i] = NULL;
return result;
}
static gboolean
emit_peer_found (gpointer user_data)
{
g_return_val_if_fail (DEE_IS_CLIENT (user_data), FALSE);
DeeClientPrivate *priv = DEE_CLIENT (user_data)->priv;
g_signal_emit_by_name (user_data, "peer-found",
g_dbus_connection_get_guid (priv->connection));
priv->peer_found_timer_id = 0;
return FALSE;
}
static void
connecting_finished (GObject *object, GAsyncResult *res, gpointer user_data)
{
GDBusConnection *connection;
DeeClient *self;
DeeClientPrivate *priv;
GError *error = NULL;
connection = g_dbus_connection_new_for_address_finish (res, &error);
if (error)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("Unable to connect to server: %s", error->message);
// swarm-leader will be set to NULL for unsuccessful connections
g_object_notify (G_OBJECT (user_data), "swarm-leader");
}
/* Don't touch the object in case we were cancelled, it's most likely
* unreffed by now */
g_error_free (error);
return;
}
self = DEE_CLIENT (user_data);
priv = self->priv;
priv->connection = connection;
g_object_unref (priv->cancellable);
priv->cancellable = NULL;
priv->closed_signal_handler_id = g_signal_connect (connection, "closed",
G_CALLBACK (connection_closed), self);
g_object_notify (G_OBJECT (user_data), "swarm-leader");
g_signal_emit_by_name (user_data, "connection-acquired", connection);
// FIXME: we might want to call some List method (same as DeePeer), so far
// we'll just simulate an async method (tests expect this anyway)
priv->peer_found_timer_id = g_idle_add_full (G_PRIORITY_DEFAULT,
emit_peer_found, user_data,
NULL);
}
static void
connection_closed (GDBusConnection *connection, gboolean remote_peer_vanished,
GError *error, DeeClient *client)
{
DeeClientPrivate *priv;
g_return_if_fail (DEE_IS_CLIENT (client));
priv = client->priv;
priv->connection = NULL;
g_signal_handler_disconnect (connection, priv->closed_signal_handler_id);
priv->closed_signal_handler_id = 0;
trace_object (client, "Connection [%p] closed", connection);
/* Let's do reverse order of connecting_finished */
g_signal_emit_by_name (client, "peer-lost",
g_dbus_connection_get_guid (connection));
g_signal_emit_by_name (client, "connection-closed", connection);
g_object_notify (G_OBJECT (client), "swarm-leader");
g_object_unref (connection);
}
dee-1.2.7+15.04.20150304/src/dee-analyzer.c 0000644 0000153 0000161 00000036102 12475676210 020134 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-analyzer
* @short_description: Primary gateway for data indexing
* @include: dee.h
*
* A #DeeAnalyzer takes a text stream, splits it into tokens, and runs the
* tokens through a series of filtering steps. Optionally outputs collation
* keys for the terms.
*
* One of the important use cases of analyzers in Dee is as vessel for the
* indexing logic for creating a #DeeIndex from a #DeeModel.
*
* The recommended way to implement your own custom analyzers are by either
* adding term filters to a #DeeAnalyzer or #DeeTextAnalyzer instance with
* dee_analyzer_add_term_filter() and/or
* derive your own subclass that overrides the dee_analyzer_tokenize() method.
* Should you have very special requirements it is possible to reimplement
* all aspects of the analyzer class though.
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "dee-analyzer.h"
G_DEFINE_TYPE (DeeAnalyzer,
dee_analyzer,
G_TYPE_OBJECT);
#define DEE_ANALYZER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE(obj, DEE_TYPE_ANALYZER, DeeAnalyzerPrivate))
typedef struct {
DeeTermFilterFunc filter_func;
gpointer data;
GDestroyNotify destroy;
} DeeTermFilter;
/**
* DeeAnalyzerPrivate:
*
* Ignore this structure.
**/
struct _DeeAnalyzerPrivate
{
/* A list of DeeTermFilters */
GSList *term_filters;
DeeTermList *term_pool;
};
enum
{
PROP_0,
};
/*
* DeeAnalyzer forward declarations
*/
static void dee_analyzer_analyze_real (DeeAnalyzer *self,
const gchar *data,
DeeTermList *terms_out,
DeeTermList *colkeys_out);
static void dee_analyzer_tokenize_real (DeeAnalyzer *self,
const gchar *data,
DeeTermList *terms_out);
static void dee_analyzer_add_term_filter_real (DeeAnalyzer *self,
DeeTermFilterFunc filter_func,
gpointer filter_data,
GDestroyNotify filter_destroy);
static gchar* dee_analyzer_collate_key_real (DeeAnalyzer *self,
const gchar *data);
static gint dee_analyzer_collate_cmp_real (DeeAnalyzer *self,
const gchar *key1,
const gchar *key2);
/* Private forward declarations */
void _dee_analyzer_term_filter_free (DeeTermFilter *filter);
DeeTermFilter* _dee_analyzer_term_filter_new (DeeTermFilterFunc filter_func,
gpointer data,
GDestroyNotify destroy);
void
_dee_analyzer_term_filter_free (DeeTermFilter *filter)
{
if (filter->destroy)
filter->destroy (filter->data);
g_slice_free (DeeTermFilter, filter);
}
DeeTermFilter*
_dee_analyzer_term_filter_new (DeeTermFilterFunc filter_func,
gpointer data,
GDestroyNotify destroy)
{
DeeTermFilter *self;
self = g_slice_new (DeeTermFilter);
self->filter_func = filter_func;
self->data = data;
self->destroy = destroy;
return self;
}
/* GObject stuff */
static void
dee_analyzer_finalize (GObject *object)
{
DeeAnalyzerPrivate *priv = DEE_ANALYZER (object)->priv;
g_slist_free_full (priv->term_filters,
(GDestroyNotify) _dee_analyzer_term_filter_free);
priv->term_filters = NULL;
if (priv->term_pool)
{
g_object_unref (priv->term_pool);
priv->term_pool = NULL;
}
G_OBJECT_CLASS (dee_analyzer_parent_class)->finalize (object);
}
static void
dee_analyzer_set_property (GObject *object,
guint id,
const GValue *value,
GParamSpec *pspec)
{
//DeeAnalyzerPrivate *priv = DEE_ANALYZER (object)->priv;
switch (id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
break;
}
}
static void
dee_analyzer_get_property (GObject *object,
guint id,
GValue *value,
GParamSpec *pspec)
{
switch (id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
break;
}
}
static void
dee_analyzer_class_init (DeeAnalyzerClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
obj_class->finalize = dee_analyzer_finalize;
obj_class->get_property = dee_analyzer_get_property;
obj_class->set_property = dee_analyzer_set_property;
klass->analyze = dee_analyzer_analyze_real;
klass->tokenize = dee_analyzer_tokenize_real;
klass->add_term_filter = dee_analyzer_add_term_filter_real;
klass->collate_key = dee_analyzer_collate_key_real;
klass->collate_cmp = dee_analyzer_collate_cmp_real;
/* Add private data */
g_type_class_add_private (obj_class, sizeof (DeeAnalyzerPrivate));
}
static void
dee_analyzer_init (DeeAnalyzer *self)
{
DeeAnalyzerPrivate *priv;
priv = self->priv = DEE_ANALYZER_GET_PRIVATE (self);
priv->term_filters = NULL;
priv->term_pool = (DeeTermList*) g_object_new (DEE_TYPE_TERM_LIST, NULL);
}
/*
* Default implementations
*/
static void
dee_analyzer_analyze_real (DeeAnalyzer *self,
const gchar *data,
DeeTermList *terms_out,
DeeTermList *colkeys_out)
{
DeeAnalyzerPrivate *priv;
GSList *iter;
DeeTermList *in, *out, *tmp, *tmp_term_pool;
gint i;
gchar *colkey;
const gchar *term;
g_return_if_fail (DEE_IS_ANALYZER (self));
g_return_if_fail (data != NULL);
priv = self->priv;
dee_term_list_clear (priv->term_pool);
tmp_term_pool = dee_term_list_clone (priv->term_pool);
if (terms_out)
dee_term_list_clear (terms_out);
if (colkeys_out)
dee_term_list_clear (colkeys_out);
dee_analyzer_tokenize (self, data, priv->term_pool);
/* Run terms through all filters. Result is that we'll have
* the final terms in the 'in' term list */
in = priv->term_pool;
out = tmp_term_pool;
for (iter = priv->term_filters; iter; iter = iter->next)
{
DeeTermFilter *filter = (DeeTermFilter*) iter->data;
filter->filter_func (in, out, filter->data);
/* Clear and swap in/out buffers */
tmp = dee_term_list_clear (in);
in = out;
out = tmp;
}
/* Copy terms to output and generate colkeys if requested */
for (i = 0; i < dee_term_list_num_terms (in); i++)
{
term = dee_term_list_get_term (in, i);
if (terms_out)
dee_term_list_add_term (terms_out, term);
if (colkeys_out)
{
colkey = dee_analyzer_collate_key (self, term);
dee_term_list_add_term (colkeys_out, colkey);
g_free (colkey);
}
}
g_object_unref (tmp_term_pool);
}
/* Default tokenization is a no-op */
static void
dee_analyzer_tokenize_real (DeeAnalyzer *self,
const gchar *data,
DeeTermList *terms_out)
{
g_return_if_fail (DEE_IS_ANALYZER (self));
g_return_if_fail (data != NULL);
g_return_if_fail (DEE_IS_TERM_LIST (terms_out));
dee_term_list_add_term (terms_out, data);
}
static void
dee_analyzer_add_term_filter_real (DeeAnalyzer *self,
DeeTermFilterFunc filter_func,
gpointer filter_data,
GDestroyNotify filter_destroy)
{
DeeAnalyzerPrivate *priv;
g_return_if_fail (DEE_IS_ANALYZER (self));
g_return_if_fail (filter_func != NULL);
priv = self->priv;
priv->term_filters = g_slist_append (priv->term_filters,
_dee_analyzer_term_filter_new(filter_func,
filter_data,
filter_destroy));
}
static gchar*
dee_analyzer_collate_key_real (DeeAnalyzer *self,
const gchar *data)
{
g_return_val_if_fail (DEE_IS_ANALYZER (self), NULL);
g_return_val_if_fail (data != NULL, NULL);
return g_strdup (data);
}
gint
dee_analyzer_collate_cmp_real (DeeAnalyzer *self,
const gchar *key1,
const gchar *key2)
{
g_return_val_if_fail (DEE_IS_ANALYZER (self), 0);
g_return_val_if_fail (key1 != NULL, 0);
g_return_val_if_fail (key2 != NULL, 0);
return strcmp (key1, key2);
}
/*
* Public API
*/
/**
* dee_analyzer_analyze:
* @self: The analyzer to use
* @data: The input data to analyze
* @terms_out: (allow-none): A #DeeTermList to place the generated terms in.
* If %NULL to terms are generated
* @colkeys_out: (allow-none): A #DeeTermList to place generated collation keys in.
* If %NULL no collation keys are generated
*
* Extract terms and or collation keys from some input data (which is normally,
* but not necessarily, a UTF-8 string).
*
* The terms and corresponding collation keys will be written in order to the
* provided #DeeTermLists.
*
* Implementation notes for subclasses:
* The analysis process must call dee_analyzer_tokenize() and run the tokens
* through all term filters added with dee_analyzer_add_term_filter().
* Collation keys must be generated with dee_analyzer_collate_key().
*/
void
dee_analyzer_analyze (DeeAnalyzer *self,
const gchar *data,
DeeTermList *terms_out,
DeeTermList *colkeys_out)
{
DeeAnalyzerClass *klass;
g_return_if_fail (DEE_IS_ANALYZER (self));
klass = DEE_ANALYZER_GET_CLASS (self);
(* klass->analyze) (self, data, terms_out, colkeys_out);
}
/**
* dee_analyzer_tokenize:
* @self: The analyzer to use
* @data: The input data to analyze
* @terms_out: A #DeeTermList to place the generated tokens in.
*
* Tokenize some input data (which is normally, but not necessarily,
* a UTF-8 string).
*
* Tokenization splits the input data into constituents (in most cases words),
* but does not run it through any of the term filters set for the analyzer.
* It is undefined if the tokenization process itself does any normalization.
*/
void
dee_analyzer_tokenize (DeeAnalyzer *self,
const gchar *data,
DeeTermList *terms_out)
{
DeeAnalyzerClass *klass;
g_return_if_fail (DEE_IS_ANALYZER (self));
klass = DEE_ANALYZER_GET_CLASS (self);
(* klass->tokenize) (self, data, terms_out);
}
/**
* dee_analyzer_add_term_filter:
* @self: The analyzer to add a term filter to
* @filter_func: (scope notified): Function to call
* @filter_data: (closure): Data to pass to @filter_func when it is invoked
* @filter_destroy: (allow-none): Called on @filter_data when the #DeeAnalyzer
* owning the filter is destroyed
*
* Register a #DeeTermFilterFunc to be called whenever dee_analyzer_analyze()
* is called.
*
* Term filters can be used to normalize, add, or remove terms from an input
* data stream.
*/
void
dee_analyzer_add_term_filter (DeeAnalyzer *self,
DeeTermFilterFunc filter_func,
gpointer filter_data,
GDestroyNotify filter_destroy)
{
DeeAnalyzerClass *klass;
g_return_if_fail (DEE_IS_ANALYZER (self));
klass = DEE_ANALYZER_GET_CLASS (self);
(* klass->add_term_filter) (self, filter_func, filter_data, filter_destroy);
}
/**
* dee_analyzer_collate_key:
* @self: The analyzer to generate a collation key with
* @data: The input data to generate a collation key for
*
* Generate a collation key for a set of input data (usually a UTF-8 string
* passed through tokenization and term filters of the analyzer).
*
* The default implementation just calls g_strdup().
*
* Returns: A newly allocated collation key. Use dee_analyzer_collate_cmp() or
* dee_analyzer_collate_cmp_func() to compare collation keys. Free
* with g_free().
*/
gchar*
dee_analyzer_collate_key (DeeAnalyzer *self,
const gchar *data)
{
DeeAnalyzerClass *klass;
g_return_val_if_fail (DEE_IS_ANALYZER (self), NULL);
klass = DEE_ANALYZER_GET_CLASS (self);
return (* klass->collate_key) (self, data);
}
/**
* dee_analyzer_collate_cmp:
* @self: The analyzer to use when comparing collation keys
* @key1: The first collation key to compare
* @key2: The second collation key to compare
*
* Compare collation keys generated by dee_analyzer_collate_key() with similar
* semantics as strcmp(). See also dee_analyzer_collate_cmp_func() if you
* need a version of this function that works as a #GCompareDataFunc.
*
* The default implementation in #DeeAnalyzer just uses strcmp().
*
* Returns: -1, 0 or 1, if @key1 is <, == or > than @key2.
*/
gint
dee_analyzer_collate_cmp (DeeAnalyzer *self,
const gchar *key1,
const gchar *key2)
{
DeeAnalyzerClass *klass;
g_return_val_if_fail (DEE_IS_ANALYZER (self), 0);
klass = DEE_ANALYZER_GET_CLASS (self);
return (* klass->collate_cmp) (self, key1, key2);
}
/**
* dee_analyzer_collate_cmp_func:
* @key1: The first key to compare
* @key2: The second key to compare
* @analyzer: The #DeeAnalyzer to use for the comparison
*
* A #GCompareDataFunc using a #DeeAnalyzer to compare the keys. This is just
* a convenience wrapper around dee_analyzer_collate_cmp().
*
* Returns: -1, 0 or 1, if @key1 is <, == or > than @key2.
*/
gint
dee_analyzer_collate_cmp_func (const gchar *key1,
const gchar *key2,
gpointer analyzer)
{
return dee_analyzer_collate_cmp ((DeeAnalyzer*)analyzer, key1, key2);
}
DeeAnalyzer*
dee_analyzer_new (void)
{
return (DeeAnalyzer*) g_object_new (DEE_TYPE_ANALYZER, NULL);
}
dee-1.2.7+15.04.20150304/src/trace-log.c 0000644 0000153 0000161 00000002725 12475676210 017435 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#include
#include "trace-log.h"
void
trace_object_va (void *obj,
const gchar *format,
va_list args)
{
GString *tmp;
if (!G_IS_OBJECT(obj)) {
g_critical ("Failed to log '%s' for object. Not an object.", format);
return;
}
tmp = g_string_sized_new (512);
g_string_printf (tmp, "(%s@%p): ", g_type_name(G_OBJECT_TYPE(obj)), obj);
g_string_append (tmp, format);
g_logv (TRACE_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, tmp->str, args);
g_string_free (tmp, TRUE);
}
void
trace_object_real (void *obj,
const gchar *format,
...)
{
va_list args;
va_start (args, format);
trace_object_va (obj, format, args);
va_end (args);
}
dee-1.2.7+15.04.20150304/src/dee-sequence-model.c 0000644 0000153 0000161 00000112607 12475676210 021222 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-sequence-model
* @short_description: A #DeeModel implementation backed by a #GSequence
* @include: dee.h
*
* #DeeSequenceModel is an implementation of the #DeeModel interface
* backed by a #GSequence. It extends #DeeSerializableModel so that you may use
* it as back end model for a #DeeSharedModel.
*
* The implementation is backed by a #GSequence giving a good tradeoff between
* random access time versus random- insertion and deletion times. Notably the
* dee_model_insert_sorted() and dee_model_find_sorted() methods use the
* underlying tree structure to guarantee a O(log(N))
* profile.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include "dee-model.h"
#include "dee-serializable-model.h"
#include "dee-sequence-model.h"
#include "dee-marshal.h"
#include "trace-log.h"
static void dee_sequence_model_model_iface_init (DeeModelIface *iface);
G_DEFINE_TYPE_WITH_CODE (DeeSequenceModel,
dee_sequence_model,
DEE_TYPE_SERIALIZABLE_MODEL,
G_IMPLEMENT_INTERFACE (DEE_TYPE_MODEL,
dee_sequence_model_model_iface_init));
#define DEE_SEQUENCE_MODEL_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE(obj, DEE_TYPE_SEQUENCE_MODEL, DeeSequenceModelPrivate))
/* Signal ids for emitting row update signals a just a smidgeon faster */
static guint sigid_row_added;
static guint sigid_row_removed;
static guint sigid_row_changed;
/**
* DeeSequenceModelPrivate:
*
* Ignore this structure.
*/
struct _DeeSequenceModelPrivate
{
/* Row data is is an array of gpointers. The last pointer in the array
* points to the list of tags for the row. All items before are straight
* old GVariants */
GSequence *sequence;
/* The tag registry. The data members of the list simply contain the
* GDestroyNotify for the tag. The tag handle is the offset into the
* list + 1. We need the +1 to discern the first tag from a NULL pointer.
* We can use offsets as we expect only very few tags per model */
GSList *tags;
/* Flag marking if we are in a transaction */
gboolean setting_many;
};
/*
* DeeModel forward declarations
*/
static guint dee_sequence_model_get_n_rows (DeeModel *self);
static DeeModelIter* dee_sequence_model_append_row (DeeModel *self,
GVariant **row_members);
static DeeModelIter* dee_sequence_model_prepend_row (DeeModel *self,
GVariant **row_members);
static DeeModelIter* dee_sequence_model_insert_row_before (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members);
static DeeModelIter* dee_sequence_model_find_row_sorted (DeeModel *self,
GVariant **row_spec,
DeeCompareRowFunc cmp_func,
gpointer user_data,
gboolean *out_was_found);
static void dee_sequence_model_remove (DeeModel *self,
DeeModelIter *iter);
static void dee_sequence_model_set_row (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members);
static void dee_sequence_model_set_value (DeeModel *self,
DeeModelIter *iter,
guint column,
GVariant *value);
static void dee_sequence_model_set_value_silently (DeeModel *self,
DeeModelIter *iter,
guint column,
const gchar *col_schema,
GVariant *value);
static GVariant* dee_sequence_model_get_value (DeeModel *self,
DeeModelIter *iter,
guint column);
static GVariant** dee_sequence_model_get_row (DeeModel *self,
DeeModelIter *iter,
GVariant **out_row_members);
static DeeModelIter* dee_sequence_model_get_first_iter (DeeModel *self);
static DeeModelIter* dee_sequence_model_get_last_iter (DeeModel *self);
static DeeModelIter* dee_sequence_model_get_iter_at_row (DeeModel *self,
guint row);
static gboolean dee_sequence_model_get_bool (DeeModel *self,
DeeModelIter *iter,
guint column);
static guchar dee_sequence_model_get_uchar (DeeModel *self,
DeeModelIter *iter,
guint column);
static gint32 dee_sequence_model_get_int32 (DeeModel *self,
DeeModelIter *iter,
guint column);
static guint32 dee_sequence_model_get_uint32 (DeeModel *self,
DeeModelIter *iter,
guint column);
static gint64 dee_sequence_model_get_int64 (DeeModel *self,
DeeModelIter *iter,
guint column);
static guint64 dee_sequence_model_get_uint64 (DeeModel *self,
DeeModelIter *iter,
guint column);
static gdouble dee_sequence_model_get_double (DeeModel *self,
DeeModelIter *iter,
guint column);
static const gchar* dee_sequence_model_get_string (DeeModel *self,
DeeModelIter *iter,
guint column);
static DeeModelIter* dee_sequence_model_next (DeeModel *self,
DeeModelIter *iter);
static DeeModelIter* dee_sequence_model_prev (DeeModel *self,
DeeModelIter *iter);
static gboolean dee_sequence_model_is_first (DeeModel *self,
DeeModelIter *iter);
static gboolean dee_sequence_model_is_last (DeeModel *self,
DeeModelIter *iter);
static guint dee_sequence_model_get_position (DeeModel *self,
DeeModelIter *iter);
static DeeModelTag* dee_sequence_model_register_tag (DeeModel *self,
GDestroyNotify tag_destroy);
static gpointer dee_sequence_model_get_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag);
static void dee_sequence_model_set_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
gpointer value);
/*
* Private forwards
*/
static gpointer * dee_sequence_model_create_empty_row (DeeModel *self);
static void dee_sequence_model_free_row (DeeSequenceModel *self,
GSequenceIter *iter);
static void dee_sequence_model_find_tag (DeeSequenceModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
GSList **out_row_tag,
GSList **out_tag);
/* GObject Init */
static void
dee_sequence_model_finalize (GObject *object)
{
DeeSequenceModel *self = DEE_SEQUENCE_MODEL (object);
DeeSequenceModelPrivate *priv = self->priv;
GSequenceIter *iter, *end;
/* Free row data */
end = g_sequence_get_end_iter (priv->sequence);
iter = g_sequence_get_begin_iter (priv->sequence);
while (iter != end)
{
dee_sequence_model_free_row (self, iter);
iter = g_sequence_iter_next (iter);
}
/* Free our GSequence */
g_sequence_free (priv->sequence);
priv->sequence = NULL;
/* Free the tag registry. The list members need no freeing,
* they are just function pointers */
g_slist_free (priv->tags);
priv->tags = NULL;
G_OBJECT_CLASS (dee_sequence_model_parent_class)->finalize (object);
}
static void
dee_sequence_model_set_property (GObject *object,
guint id,
const GValue *value,
GParamSpec *pspec)
{
switch (id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
break;
}
}
static void
dee_sequence_model_get_property (GObject *object,
guint id,
GValue *value,
GParamSpec *pspec)
{
switch (id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
break;
}
}
static void
dee_sequence_model_class_init (DeeSequenceModelClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
obj_class->finalize = dee_sequence_model_finalize;
obj_class->set_property = dee_sequence_model_set_property;
obj_class->get_property = dee_sequence_model_get_property;
/* Find signal ids for the model modification signals */
sigid_row_added = g_signal_lookup ("row-added", DEE_TYPE_MODEL);
sigid_row_removed = g_signal_lookup ("row-removed", DEE_TYPE_MODEL);
sigid_row_changed = g_signal_lookup ("row-changed", DEE_TYPE_MODEL);
/* Add private data */
g_type_class_add_private (obj_class, sizeof (DeeSequenceModelPrivate));
}
static void
dee_sequence_model_model_iface_init (DeeModelIface *iface)
{
iface->get_n_rows = dee_sequence_model_get_n_rows;
iface->prepend_row = dee_sequence_model_prepend_row;
iface->append_row = dee_sequence_model_append_row;
iface->insert_row_before = dee_sequence_model_insert_row_before;
iface->find_row_sorted = dee_sequence_model_find_row_sorted;
iface->remove = dee_sequence_model_remove;
iface->set_row = dee_sequence_model_set_row;
iface->set_value = dee_sequence_model_set_value;
iface->get_value = dee_sequence_model_get_value;
iface->get_row = dee_sequence_model_get_row;
iface->get_first_iter = dee_sequence_model_get_first_iter;
iface->get_last_iter = dee_sequence_model_get_last_iter;
iface->get_iter_at_row = dee_sequence_model_get_iter_at_row;
iface->get_bool = dee_sequence_model_get_bool;
iface->get_uchar = dee_sequence_model_get_uchar;
iface->get_int32 = dee_sequence_model_get_int32;
iface->get_uint32 = dee_sequence_model_get_uint32;
iface->get_int64 = dee_sequence_model_get_int64;
iface->get_uint64 = dee_sequence_model_get_uint64;
iface->get_double = dee_sequence_model_get_double;
iface->get_string = dee_sequence_model_get_string;
iface->next = dee_sequence_model_next;
iface->prev = dee_sequence_model_prev;
iface->is_first = dee_sequence_model_is_first;
iface->is_last = dee_sequence_model_is_last;
iface->get_position = dee_sequence_model_get_position;
iface->register_tag = dee_sequence_model_register_tag;
iface->get_tag = dee_sequence_model_get_tag;
iface->set_tag = dee_sequence_model_set_tag;
}
static void
dee_sequence_model_init (DeeSequenceModel *model)
{
DeeSequenceModelPrivate *priv;
priv = model->priv = DEE_SEQUENCE_MODEL_GET_PRIVATE (model);
priv->sequence = g_sequence_new (NULL);
priv->tags = NULL;
priv->setting_many = FALSE;
}
/* Private Methods */
/*
* DeeModel Interface Implementation
*/
static guint
dee_sequence_model_get_n_rows (DeeModel *self)
{
DeeSequenceModelPrivate *priv;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), 0);
priv = ((DeeSequenceModel *) self)->priv;
return g_sequence_get_length (priv->sequence);
}
static DeeModelIter*
dee_sequence_model_prepend_row (DeeModel *self,
GVariant **row_members)
{
DeeSequenceModel *_self = (DeeSequenceModel *) self;
DeeSequenceModelPrivate *priv;
DeeModelIter *iter;
gpointer *row;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (_self), NULL);
g_return_val_if_fail (row_members != NULL, NULL);
priv = _self->priv;
row = dee_sequence_model_create_empty_row (self);
iter = (DeeModelIter*) g_sequence_prepend (priv->sequence, row);
priv->setting_many = TRUE;
dee_model_set_row (self, iter, row_members);
priv->setting_many = FALSE;
dee_serializable_model_inc_seqnum (self);
g_signal_emit (self, sigid_row_added, 0, iter);
return iter;
}
static DeeModelIter*
dee_sequence_model_append_row (DeeModel *self,
GVariant **row_members)
{
DeeSequenceModel *_self = (DeeSequenceModel *) self;
DeeSequenceModelPrivate *priv;
DeeModelIter *iter;
gpointer *row;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (_self), NULL);
g_return_val_if_fail (row_members != NULL, NULL);
priv = _self->priv;
row = dee_sequence_model_create_empty_row (self);
iter = (DeeModelIter*) g_sequence_append (priv->sequence, row);
priv->setting_many = TRUE;
dee_model_set_row (self, iter, row_members);
priv->setting_many = FALSE;
dee_serializable_model_inc_seqnum (self);
g_signal_emit (self, sigid_row_added, 0, iter);
return iter;
}
static DeeModelIter*
dee_sequence_model_insert_row_before (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members)
{
DeeSequenceModelPrivate *priv;
gpointer *row;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
g_return_val_if_fail (iter != NULL, NULL);
g_return_val_if_fail (row_members != NULL, NULL);
priv = DEE_SEQUENCE_MODEL (self)->priv;
row = dee_sequence_model_create_empty_row (self);
iter = (DeeModelIter*) g_sequence_insert_before ((GSequenceIter *) iter,
row);
priv->setting_many = TRUE;
dee_model_set_row (self, iter, row_members);
priv->setting_many = FALSE;
dee_serializable_model_inc_seqnum (self);
g_signal_emit (self, sigid_row_added, 0, iter);
return iter;
}
/* logN search using the tree structure of GSeq */
static DeeModelIter*
dee_sequence_model_find_row_sorted (DeeModel *self,
GVariant **row_spec,
DeeCompareRowFunc cmp_func,
gpointer user_data,
gboolean *out_was_found)
{
DeeSequenceModelPrivate *priv;
GSequenceIter *iter;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
g_return_val_if_fail (row_spec != NULL, NULL);
g_return_val_if_fail (cmp_func != NULL, NULL);
priv = DEE_SEQUENCE_MODEL (self)->priv;
iter = g_sequence_search (priv->sequence, row_spec,
(GCompareDataFunc)cmp_func, user_data);
/* Kinda awkward - if we did find the row then GSequence has placed just
* after the row we wanted. If we did not find it, then we're in the right
* place */
if (!g_sequence_iter_is_begin (iter))
{
GSequenceIter *jter = g_sequence_iter_prev (iter);
if (cmp_func (g_sequence_get (jter), row_spec, user_data) == 0)
{
if (out_was_found != NULL) *out_was_found = TRUE;
return (DeeModelIter *) jter;
}
}
if (out_was_found != NULL) *out_was_found = FALSE;
return (DeeModelIter *) iter;
}
static void
dee_sequence_model_remove (DeeModel *self,
DeeModelIter *iter_)
{
DeeSequenceModel *_self = (DeeSequenceModel *)self;
GSequenceIter *iter = (GSequenceIter *)iter_;
g_return_if_fail (DEE_IS_SEQUENCE_MODEL (_self));
g_return_if_fail (iter != NULL);
g_return_if_fail (!g_sequence_iter_is_end (iter));
if (iter)
{
/* Emit the removed signal while the iter is still valid,
* but after we increased the seqnum */
dee_serializable_model_inc_seqnum (self);
g_signal_emit (self, sigid_row_removed, 0, iter_);
dee_sequence_model_free_row (_self, iter);
g_sequence_remove (iter);
}
else
{
g_warning ("Unable to remove row '%p': does not exists", iter_);
}
}
static void
dee_sequence_model_set_value (DeeModel *self,
DeeModelIter *iter,
guint column,
GVariant *value)
{
DeeSequenceModel *_self = (DeeSequenceModel *)self;
DeeSequenceModelPrivate *priv;
g_return_if_fail (DEE_IS_SEQUENCE_MODEL (_self));
g_return_if_fail (iter != NULL);
g_return_if_fail (value != NULL);
g_return_if_fail (column < dee_model_get_n_columns (self));
priv = _self->priv;
dee_sequence_model_set_value_silently (self, iter, column,
dee_model_get_column_schema (self, column), value);
if (priv->setting_many == FALSE)
{
dee_serializable_model_inc_seqnum (self);
g_signal_emit (self, sigid_row_changed, 0, iter);
}
}
static void
dee_sequence_model_set_row (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members)
{
DeeSequenceModel *_self = (DeeSequenceModel *)self;
DeeSequenceModelPrivate *priv;
guint i, n_cols;
const gchar *const *schema;
g_return_if_fail (DEE_IS_SEQUENCE_MODEL (_self));
g_return_if_fail (iter != NULL);
g_return_if_fail (row_members != NULL);
priv = _self->priv;
schema = dee_model_get_schema (self, &n_cols);
for (i = 0; i < n_cols; i++)
{
dee_sequence_model_set_value_silently (self, iter, i, schema[i],
row_members[i]);
}
if (priv->setting_many == FALSE)
{
dee_serializable_model_inc_seqnum (self);
g_signal_emit (self, sigid_row_changed, 0, iter);
}
}
static void
dee_sequence_model_set_value_silently (DeeModel *self,
DeeModelIter *iter,
guint column,
const gchar *col_schema,
GVariant *value)
{
gpointer *row;
g_return_if_fail (g_variant_type_equal (g_variant_get_type (value),
G_VARIANT_TYPE (col_schema)));
row = g_sequence_get ((GSequenceIter *) iter);
if (G_UNLIKELY (row == NULL))
{
g_critical ("Unable to set value. NULL row data in DeeSequenceModel@%p "
"at position %u. The row has probably been removed",
self, dee_model_get_position (self, iter));
return;
}
if (row[column] != NULL)
g_variant_unref (row[column]);
row[column] = g_variant_ref_sink (value);
}
static GVariant*
dee_sequence_model_peek_value (DeeModel *self,
DeeModelIter *iter,
guint column)
{
gpointer *row;
row = g_sequence_get ((GSequenceIter *) iter);
if (G_UNLIKELY (row == NULL))
{
g_critical ("Unable to get value. NULL row data in DeeSequenceModel@%p "
"at position %u. The row has probably been removed",
self, dee_model_get_position (self, iter));
return NULL;
}
return row[column];
}
static GVariant*
dee_sequence_model_get_value (DeeModel *self,
DeeModelIter *iter,
guint column)
{
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
g_return_val_if_fail (iter != NULL, NULL);
g_return_val_if_fail (column < dee_model_get_n_columns (self), NULL);
GVariant *val = dee_sequence_model_peek_value (self, iter, column);
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get value. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return NULL;
}
return g_variant_ref (val);
}
static GVariant**
dee_sequence_model_get_row (DeeModel *self,
DeeModelIter *iter,
GVariant **out_row_members)
{
guint col, n_cols;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
n_cols = dee_model_get_n_columns (self);
if (out_row_members == NULL)
out_row_members = g_new0 (GVariant*, n_cols + 1);
/* We use peek_value() here because it saves us from some expensive checks
* compared to get_value(), that we can guarantee from this call site anyway
*/
for (col = 0; col < n_cols; col++)
out_row_members[col] = g_variant_ref (
dee_sequence_model_peek_value (self, iter, col));
return out_row_members;
}
static DeeModelIter*
dee_sequence_model_get_first_iter (DeeModel *self)
{
DeeSequenceModel *_self = (DeeSequenceModel *)self;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (_self), NULL);
return (DeeModelIter *) g_sequence_get_begin_iter (_self->priv->sequence);
}
static DeeModelIter*
dee_sequence_model_get_last_iter (DeeModel *self)
{
DeeSequenceModel *_self = (DeeSequenceModel *)self;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (_self), NULL);
return (DeeModelIter *) g_sequence_get_end_iter (_self->priv->sequence);
}
static DeeModelIter*
dee_sequence_model_get_iter_at_row (DeeModel *self, guint row)
{
DeeSequenceModel *_self = (DeeSequenceModel *)self;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
return (DeeModelIter *) g_sequence_get_iter_at_pos (_self->priv->sequence,
row);
}
static gboolean
dee_sequence_model_get_bool (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get boolean. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return FALSE;
}
return g_variant_get_boolean (val);
}
static guchar
dee_sequence_model_get_uchar (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get byte. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return '\0';
}
return g_variant_get_byte (val);
}
static gint32
dee_sequence_model_get_int32 (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get int32. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return 0;
}
return g_variant_get_int32 (val);
}
static guint32
dee_sequence_model_get_uint32 (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get uint32. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return 0;
}
return g_variant_get_uint32 (val);
}
static gint64
dee_sequence_model_get_int64 (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get int64. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return G_GINT64_CONSTANT (0);
}
return g_variant_get_int64 (val);
}
static guint64
dee_sequence_model_get_uint64 (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get uint64. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return G_GUINT64_CONSTANT (0);
}
return g_variant_get_uint64 (val);
}
static gdouble
dee_sequence_model_get_double (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get double. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return 0;
}
return g_variant_get_double (val);
}
static const gchar*
dee_sequence_model_get_string (DeeModel *self,
DeeModelIter *iter,
guint column)
{
GVariant *val = dee_sequence_model_peek_value (self, iter, column);;
if (G_UNLIKELY (val == NULL))
{
g_critical ("Unable to get string. Column %i in DeeSequenceModel@%p"
" holds a NULL value in row %u",
column, self, dee_model_get_position (self, iter));
return NULL;
}
return g_variant_get_string (val, NULL);
}
static DeeModelIter*
dee_sequence_model_next (DeeModel *self,
DeeModelIter *iter)
{
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
g_return_val_if_fail (iter, NULL);
g_return_val_if_fail (!g_sequence_iter_is_end ((GSequenceIter*) iter), NULL);
return (DeeModelIter *) g_sequence_iter_next ((GSequenceIter *)iter);
}
static DeeModelIter*
dee_sequence_model_prev (DeeModel *self,
DeeModelIter *iter)
{
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
g_return_val_if_fail (iter, NULL);
g_return_val_if_fail (!g_sequence_iter_is_begin ((GSequenceIter*) iter), NULL);
return (DeeModelIter *) g_sequence_iter_prev ((GSequenceIter *)iter);
}
static gboolean
dee_sequence_model_is_first (DeeModel *self,
DeeModelIter *iter)
{
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), FALSE);
g_return_val_if_fail (iter, FALSE);
return g_sequence_iter_is_begin ((GSequenceIter *)iter);
}
static gboolean
dee_sequence_model_is_last (DeeModel *self,
DeeModelIter *iter)
{
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), FALSE);
g_return_val_if_fail (iter, FALSE);
return g_sequence_iter_is_end ((GSequenceIter *)iter);
}
static guint
dee_sequence_model_get_position (DeeModel *self,
DeeModelIter *iter)
{
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), FALSE);
g_return_val_if_fail (iter, FALSE);
return g_sequence_iter_get_position ((GSequenceIter *)iter);
}
static DeeModelTag*
dee_sequence_model_register_tag (DeeModel *self,
GDestroyNotify tag_destroy)
{
DeeSequenceModelPrivate *priv;
GSequenceIter *iter, *end;
gpointer *row;
guint tag_handle, n_cols;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
priv = DEE_SEQUENCE_MODEL (self)->priv;
/* Register the tag. Multiple iterations of the tags list is not
* a big deal here because we only expect very few tags per model */
priv->tags = g_slist_append (priv->tags, tag_destroy);
tag_handle = g_slist_length (priv->tags);
/* Update all existing rows to have this tag */
n_cols = dee_model_get_n_columns (self);
end = g_sequence_get_end_iter (priv->sequence);
iter = g_sequence_get_begin_iter (priv->sequence);
while (iter != end)
{
row = g_sequence_get (iter);
row[n_cols] = g_slist_append (row[n_cols], NULL);
iter = g_sequence_iter_next (iter);
}
return (DeeModelTag *) GUINT_TO_POINTER (tag_handle);
}
static gpointer
dee_sequence_model_get_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag)
{
DeeSequenceModel *_self;
GSList *row_tag_l, *tag_l;
g_return_val_if_fail (DEE_IS_SEQUENCE_MODEL (self), NULL);
g_return_val_if_fail (iter != NULL, NULL);
g_return_val_if_fail (tag != NULL, NULL);
_self = DEE_SEQUENCE_MODEL (self);
dee_sequence_model_find_tag (_self, iter, tag, &row_tag_l, &tag_l);
if (row_tag_l == NULL || tag_l == NULL)
{
g_critical ("Failed to get tag %u on %s@%p",
GPOINTER_TO_UINT (tag), G_OBJECT_TYPE_NAME (self), self);
return NULL;
}
return row_tag_l->data;
}
void
dee_sequence_model_set_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
gpointer value)
{
DeeSequenceModel *_self;
GSList *row_tag_l, *tag_l;
GDestroyNotify destroy;
gpointer old_value;
g_return_if_fail (DEE_IS_SEQUENCE_MODEL (self));
g_return_if_fail (iter != NULL);
g_return_if_fail (tag != NULL);
_self = DEE_SEQUENCE_MODEL (self);
dee_sequence_model_find_tag (_self, iter, tag, &row_tag_l, &tag_l);
if (row_tag_l == NULL || tag_l == NULL)
{
g_critical ("Failed to set tag %u on %s@%p",
GPOINTER_TO_UINT (tag), G_OBJECT_TYPE_NAME (self), self);
return;
}
destroy = (GDestroyNotify) tag_l->data;
old_value = row_tag_l->data;
if (destroy && old_value)
{
destroy (old_value);
}
row_tag_l->data = value;
}
/*
* Private methods
*/
/* Create an array with the right amount of elements, all set to NULL */
static gpointer*
dee_sequence_model_create_empty_row (DeeModel *self)
{
DeeSequenceModelPrivate *priv;
gpointer *row;
guint n_columns;
GSList *tag_iter;
/* The row tags are stored as a GSList on the n_columns+1 index of the row.
* Zeroing the memory below is important since it gives us an empty GSList
* for the tags on the final position */
priv = ((DeeSequenceModel *)self)->priv;
n_columns = dee_model_get_n_columns (self);
row = g_slice_alloc0 (sizeof (gpointer) * (n_columns + 1));
/* Populate the row tag list to have the same length as our tag registry */
for (tag_iter = priv->tags; tag_iter; tag_iter = tag_iter->next)
{
row[n_columns] =
g_slist_prepend (row[n_columns], NULL);
}
return row;
}
static void
dee_sequence_model_free_row (DeeSequenceModel *self,
GSequenceIter *iter)
{
DeeSequenceModelPrivate *priv;
gpointer *row;
guint n_cols, i;
GSList *tag_iter, *row_tag_iter, *dum;
GDestroyNotify destroy;
priv = self->priv;
row = g_sequence_get (iter);
n_cols = dee_model_get_n_columns (DEE_MODEL (self));
/* Free the row data */
for (i = 0; i < n_cols; i++)
g_variant_unref (row[i]);
/* Free any row tags */
row_tag_iter = row[n_cols];
tag_iter = priv->tags;
while (row_tag_iter && tag_iter)
{
destroy = (GDestroyNotify) tag_iter->data;
if (destroy != NULL && row_tag_iter->data != NULL)
destroy (row_tag_iter->data);
/* Free the GSList element for the row tag while we're here anyway */
dum = row_tag_iter->next;
g_slist_free_1 (row_tag_iter);
row_tag_iter = dum;
tag_iter = tag_iter->next;
}
if (row_tag_iter != NULL)
{
g_critical ("Internal error: Row tags leaked. "
"More row tags for this row than there are registered tags.");
}
else if (tag_iter != NULL)
{
g_critical ("Internal error: Row tags leaked. "
"More tags registered than there are tags for this row.");
}
/* Free the row itself */
g_slice_free1 (sizeof (gpointer) * (n_cols + 1), row);
/* Set the row data to NULL to help debugging for consumers accessing
* removed rows*/
g_sequence_set (iter, NULL);
}
static void
dee_sequence_model_find_tag (DeeSequenceModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
GSList **out_row_tag,
GSList **out_tag)
{
DeeSequenceModelPrivate *priv;
gpointer *row;
guint tag_offset, i, n_cols;
GSList *row_tag_iter, *tag_iter;
priv = self->priv;
row = g_sequence_get ((GSequenceIter *) iter);
n_cols = dee_model_get_n_columns (DEE_MODEL (self));
tag_offset = GPOINTER_TO_UINT (tag);
if (G_UNLIKELY (priv->sequence == NULL))
{
g_critical ("Access to freed DeeSequenceModel detected "
"when looking up tag on DeeSequenceModel@%p", self);
goto not_found;
}
if (G_UNLIKELY (priv->tags == NULL))
{
g_critical ("Unable to look up tag. No tags registered on "
"DeeSequenceModel@%p", self);
goto not_found;
}
if (G_UNLIKELY (row == NULL))
{
g_critical ("Unable to look up tag. No row data. "
"The row has probably been removed ");
goto not_found;
}
/* Find tag at right offset */
row_tag_iter = row[n_cols];
tag_iter = priv->tags;
i = 1; // remember 1-based offset for tag handles
while (row_tag_iter && tag_iter && i < tag_offset)
{
row_tag_iter = row_tag_iter->next;
tag_iter = tag_iter->next;
i++;
}
if (i != tag_offset)
{
g_critical ("Unable to find tag %u for %s@%p",
tag_offset, G_OBJECT_TYPE_NAME (self), self);
goto not_found;
}
*out_row_tag = row_tag_iter;
*out_tag = tag_iter;
return;
not_found:
*out_row_tag = NULL;
*out_tag = NULL;
}
/*
* Constructors
*/
/**
* dee_sequence_model_new:
*
* Create a new #DeeSequenceModel. Before using it you must normally set a
* schema on it by calling dee_model_set_schema().
*
* Return value: (transfer full) (type DeeSequenceModel): A newly created
* #DeeSequenceModel. Free with g_object_unref().
*
*/
DeeModel*
dee_sequence_model_new ()
{
DeeModel *self;
self = DEE_MODEL (g_object_new (DEE_TYPE_SEQUENCE_MODEL, NULL));
return self;
}
dee-1.2.7+15.04.20150304/src/Makefile.am 0000644 0000153 0000161 00000007634 12475676210 017454 0 ustar pbuser pbgroup 0000000 0000000 NULL =
BUILT_SOURCES =
CLEANFILES =
EXTRA_DIST =
INTROSPECTION_GIRS =
INTROSPECTION_SCANNER_ARGS = --warn-all
-include $(INTROSPECTION_MAKEFILE)
##
# DBus introspection XML
##
# create a .h file containing the introspection data in a variable for gdbus
%-xml.h : dbus/%.xml
$(AM_V_GEN)name=`basename $< | sed -e 's/[-\.]/_/g' -e 's/.xml/_xml/g'`; \
echo "static const gchar $$name[] = " > $@; \
cat $< | tr \" \' | sed 's/^/\"/g' | sed 's/$$/\"/g' >> $@; \
echo ";" >> $@;
BUILT_SOURCES += \
com.canonical.Dee.Model-xml.h \
com.canonical.Dee.Peer-xml.h
EXTRA_DIST += \
dbus/com.canonical.Dee.Model.xml \
dbus/com.canonical.Dee.Peer.xml
##
# Development headers
##
devel_headersdir = $(includedir)/dee-1.0
devel_headers = \
dee.h \
dee-analyzer.h \
dee-file-resource-manager.h \
dee-filter-model.h \
dee-filter.h \
dee-hash-index.h \
dee-index.h \
dee-model.h \
dee-model-reader.h \
dee-peer.h \
dee-server.h \
dee-client.h \
dee-proxy-model.h \
dee-resource-manager.h \
dee-result-set.h \
dee-sequence-model.h \
dee-serializable.h \
dee-serializable-model.h \
dee-shared-model.h \
dee-term-list.h \
dee-text-analyzer.h \
dee-transaction.h \
dee-tree-index.h \
$(NULL)
devel_headers_HEADERS = \
$(devel_headers) \
$(NULL)
##
# Build libdee
##
lib_LTLIBRARIES = libdee-1.0.la
libdee_1_0_la_SOURCES = \
$(devel_headers) \
dee-analyzer.c \
dee-file-resource-manager.c \
dee-filter-model.c \
dee-filter.c \
dee-glist-result-set.h \
dee-glist-result-set.c \
dee-hash-index.c \
dee-index.c \
dee-model.c \
dee-model-reader.c \
dee-peer.c \
dee-server.c \
dee-client.c \
dee-proxy-model.c \
dee-resource-manager.c \
dee-result-set.c \
dee-sequence-model.c \
dee-serializable.c \
dee-serializable-model.c \
dee-shared-model.c \
dee-term-list.c \
dee-text-analyzer.c \
dee-transaction.c \
dee-tree-index.c \
trace-log.h \
$(BUILT_SOURCES) \
$(NULL)
libdee_1_0_la_LIBADD = \
$(DEE_LIBS)
libdee_1_0_la_LDFLAGS = \
$(DEE_LT_LDFLAGS) \
$(COVERAGE_LDFLAGS)
libdee_1_0_la_CPPFLAGS = \
-I$(srcdir) \
-I$(top_srcdir) \
-I$(top_builddir) \
-DG_LOG_DOMAIN=\"dee\" \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DDEE_COMPILATION \
$(GCC_FLAGS) \
$(DEE_CFLAGS) \
$(MAINTAINER_CFLAGS) \
$(COVERAGE_CFLAGS)
if HAVE_ICU
devel_headers += dee-icu.h
libdee_1_0_la_SOURCES += dee-icu-term-filter.c
libdee_1_0_la_LIBADD += $(ICU_LIBS)
endif
##
# If trace logging is not enabled
# all the macros are removed by the preprocessor
##
if ENABLE_TRACE_LOG
libdee_1_0_la_SOURCES += trace-log.c
endif
##
# Signal Marshallers
##
dee-marshal.h: $(srcdir)/dee-marshal.list
$(AM_V_GEN)$(GLIB_GENMARSHAL) --header \
--prefix=_dee_marshal $(srcdir)/dee-marshal.list \
> dee-marshal.h
dee-marshal.c: $(srcdir)/dee-marshal.list
$(AM_V_GEN)$(GLIB_GENMARSHAL) --body \
--prefix=_dee_marshal $(srcdir)/dee-marshal.list \
> dee-marshal.c
BUILT_SOURCES += \
dee-marshal.c \
dee-marshal.h
EXTRA_DIST += dee-marshal.list
CLEANFILES += \
$(BUILT_SOURCES)
##
# GObject Introspection
##
if HAVE_INTROSPECTION
irscanner_sources = $(libdee_1_0_la_SOURCES)
dee_gir = Dee-$(GIR_VERSION).gir
Dee-1.0.gir: $(lib_LTLIBRARIES) Makefile
Dee_1_0_gir_SCANNERFLAGS = --c-include="dee.h"
Dee_1_0_gir_INCLUDES = GObject-2.0 GLib-2.0 Gio-2.0
Dee_1_0_gir_LIBS = $(lib_LTLIBRARIES)
Dee_1_0_gir_FILES = $(irscanner_sources)
Dee_1_0_gir_CFLAGS = \
-I$(srcdir) \
-I$(top_srcdir) \
-I$(top_builddir) \
-DDEE_COMPILATION \
$(NULL)
Dee_1_0_gir_EXPORT_PACKAGES = dee-1.0
INTROSPECTION_GIRS += $(dee_gir)
# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to
# install anything - we need to install inside our prefix.
girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
typelibsdir = $(libdir)/girepository-1.0/
typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES += $(gir_DATA) $(typelibs_DATA)
endif
dee-1.2.7+15.04.20150304/src/dee-icu.h 0000644 0000153 0000161 00000004277 12475676210 017104 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#ifndef _HAVE_DEE_ICU_H
#define _HAVE_DEE_ICU_H
#include
#include
G_BEGIN_DECLS
/**
* DEE_ICU_ERROR:
*
* Error domain for the ICU extension to Dee. Error codes will be from the
* #DeeICUError enumeration
*/
#define DEE_ICU_ERROR dee_icu_error_quark()
/**
* DeeICUError:
*
* Error codes for the ICU extension to Dee. These codes will be set when the
* error domain is #DEE_ICU_ERROR.
*
* @DEE_ICU_ERROR_BAD_RULE: Error parsing a transliteration rule
* @DEE_ICU_ERROR_BAD_ID: Error parsing a transliterator system id
* @DEE_ICU_ERROR_UNKNOWN: The ICU subsystem returned an error that is not
* handled in Dee
*/
typedef enum {
DEE_ICU_ERROR_BAD_RULE,
DEE_ICU_ERROR_BAD_ID,
DEE_ICU_ERROR_UNKNOWN
} DeeICUError;
typedef struct _DeeICUTermFilter DeeICUTermFilter;
DeeICUTermFilter* dee_icu_term_filter_new (const gchar* system_id,
const gchar *rules,
GError **error);
DeeICUTermFilter* dee_icu_term_filter_new_ascii_folder ();
gchar* dee_icu_term_filter_apply (DeeICUTermFilter *self,
const gchar *text);
void dee_icu_term_filter_destroy (DeeICUTermFilter *filter);
GQuark dee_icu_error_quark (void);
G_END_DECLS
#endif /* _HAVE_DEE_ICU_H */
dee-1.2.7+15.04.20150304/src/dee-serializable-model.h 0000644 0000153 0000161 00000006521 12475676210 022062 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#if !defined (_DEE_H_INSIDE) && !defined (DEE_COMPILATION)
#error "Only can be included directly."
#endif
#ifndef _HAVE_DEE_SERIALIZABLE_MODEL_H
#define _HAVE_DEE_SERIALIZABLE_MODEL_H
#include
#include
#include
G_BEGIN_DECLS
#define DEE_TYPE_SERIALIZABLE_MODEL (dee_serializable_model_get_type ())
#define DEE_SERIALIZABLE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
DEE_TYPE_SERIALIZABLE_MODEL, DeeSerializableModel))
#define DEE_SERIALIZABLE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
DEE_TYPE_SERIALIZABLE_MODEL, DeeSerializableModelClass))
#define DEE_IS_SERIALIZABLE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
DEE_TYPE_SERIALIZABLE_MODEL))
#define DEE_IS_SERIALIZABLE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
DEE_TYPE_SERIALIZABLE_MODEL))
#define DEE_SERIALIZABLE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
DBUS_TYPE_ABSTRACT_MODEL, DeeSerializableModelClass))
typedef struct _DeeSerializableModel DeeSerializableModel;
typedef struct _DeeSerializableModelClass DeeSerializableModelClass;
typedef struct _DeeSerializableModelPrivate DeeSerializableModelPrivate;
/**
* DeeSerializableModel:
*
* All fields in the DeeSerializableModel structure are private and should never be
* accessed directly
*/
struct _DeeSerializableModel
{
/*< private >*/
GObject parent;
DeeSerializableModelPrivate *priv;
};
struct _DeeSerializableModelClass
{
/*< private >*/
GObjectClass parent_class;
/*< vatable >*/
guint64 (* get_seqnum) (DeeModel *self);
void (* set_seqnum) (DeeModel *self,
guint64 seqnum);
guint64 (* inc_seqnum) (DeeModel *self);
/*< private >*/
void (*_dee_serializable_model_1) (void);
void (*_dee_serializable_model_2) (void);
void (*_dee_serializable_model_3) (void);
void (*_dee_serializable_model_4) (void);
};
/**
* dee_serializable_model_get_type:
*
* The GType of #DeeSerializableModel
*
* Return value: the #GType of #DeeSerializableModel
**/
GType dee_serializable_model_get_type (void);
guint64 dee_serializable_model_get_seqnum (DeeModel *self);
void dee_serializable_model_set_seqnum (DeeModel *self,
guint64 seqnum);
guint64 dee_serializable_model_inc_seqnum (DeeModel *self);
G_END_DECLS
#endif /* _HAVE_DEE_SERIALIZABLE_MODEL_H */
dee-1.2.7+15.04.20150304/src/dee-result-set.h 0000644 0000153 0000161 00000006112 12475676210 020421 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#if !defined (_DEE_H_INSIDE) && !defined (DEE_COMPILATION)
#error "Only can be included directly."
#endif
#ifndef _DEE_RESULT_SET_H_
#define _DEE_RESULT_SET_H_
#include
#include
#include
G_BEGIN_DECLS
#define DEE_TYPE_RESULT_SET (dee_result_set_get_type ())
#define DEE_RESULT_SET(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), DEE_TYPE_RESULT_SET, DeeResultSet))
#define DEE_IS_RESULT_SET(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEE_TYPE_RESULT_SET))
#define DEE_RESULT_SET_GET_IFACE(obj) \
(G_TYPE_INSTANCE_GET_INTERFACE(obj, dee_result_set_get_type (), DeeResultSetIface))
typedef struct _DeeResultSetIface DeeResultSetIface;
typedef struct _DeeResultSet DeeResultSet;
struct _DeeResultSetIface
{
GTypeInterface g_iface;
/*< public >*/
guint (*get_n_rows) (DeeResultSet *self);
DeeModelIter* (*next) (DeeResultSet *self);
gboolean (*has_next) (DeeResultSet *self);
DeeModelIter* (*peek) (DeeResultSet *self);
void (*seek) (DeeResultSet *self,
guint pos);
guint (*tell) (DeeResultSet *self);
DeeModel* (*get_model) (DeeResultSet *self);
/*< private >*/
void (*_dee_result_set_1) (void);
void (*_dee_result_set_2) (void);
void (*_dee_result_set_3) (void);
void (*_dee_result_set_4) (void);
void (*_dee_result_set_5) (void);
};
GType dee_result_set_get_type (void);
guint dee_result_set_get_n_rows (DeeResultSet *self);
DeeModelIter* dee_result_set_next (DeeResultSet *self);
gboolean dee_result_set_has_next (DeeResultSet *self);
DeeModelIter* dee_result_set_peek (DeeResultSet *self);
void dee_result_set_seek (DeeResultSet *self,
guint pos);
guint dee_result_set_tell (DeeResultSet *self);
DeeModel* dee_result_set_get_model (DeeResultSet *self);
#define _vala_dee_result_set_next_value(rs) (dee_result_set_has_next(rs) ? dee_result_set_next(rs) : NULL)
#define _vala_dee_result_set_iterator(rs) ((DeeResultSet*)g_object_ref(rs))
G_END_DECLS
#endif /* _HAVE_DEE_RESULT_SET_H */
dee-1.2.7+15.04.20150304/src/dee-serializable.h 0000644 0000153 0000161 00000006337 12475676210 020771 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#if !defined (_DEE_H_INSIDE) && !defined (DEE_COMPILATION)
#error "Only can be included directly."
#endif
#ifndef _DEE_SERIALIZABLE_H_
#define _DEE_SERIALIZABLE_H_
#include
#include
#include
G_BEGIN_DECLS
#define DEE_TYPE_SERIALIZABLE (dee_serializable_get_type ())
#define DEE_SERIALIZABLE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), DEE_TYPE_SERIALIZABLE, DeeSerializable))
#define DEE_IS_SERIALIZABLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEE_TYPE_SERIALIZABLE))
#define DEE_SERIALIZABLE_GET_IFACE(obj) \
(G_TYPE_INSTANCE_GET_INTERFACE(obj, dee_serializable_get_type (), DeeSerializableIface))
typedef struct _DeeSerializableIface DeeSerializableIface;
typedef struct _DeeSerializable DeeSerializable;
/**
* DeeSerializableParseFunc:
* @data: A #GVariant with type signature as passed to
* dee_serializable_register_parser() when the parser was registered.
* The variant is not referenced.
*
* Return value: (transfer full): A newly constructed #GObject of the #GType
* used when registering the parser. Note that since
* the environment guarantees that the input data is valid
* according to the registration information this function
* can not fail. Thus %NULL is not a valid return value.
*/
typedef GObject* (*DeeSerializableParseFunc) (GVariant *data);
struct _DeeSerializableIface
{
GTypeInterface g_iface;
/*< public >*/
GVariant* (*serialize) (DeeSerializable *self);
/*< private >*/
void (*_dee_serializable_1) (void);
void (*_dee_serializable_2) (void);
void (*_dee_serializable_3) (void);
void (*_dee_serializable_4) (void);
void (*_dee_serializable_5) (void);
};
GType dee_serializable_get_type (void);
void dee_serializable_register_parser (GType type,
const GVariantType *vtype,
DeeSerializableParseFunc parse_func);
GObject* dee_serializable_parse (GVariant *data,
GType type);
GObject* dee_serializable_parse_external (GVariant *data);
GVariant* dee_serializable_externalize (DeeSerializable *self);
GVariant* dee_serializable_serialize (DeeSerializable *self);
G_END_DECLS
#endif /* _HAVE_DEE_SERIALIZABLE_H */
dee-1.2.7+15.04.20150304/src/dee-serializable.c 0000644 0000153 0000161 00000034462 12475676210 020764 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-serializable
* @short_description: Interface for classes that can serialize to and from #GVariants
* @include: dee.h
*
* Interface for classes that can serialize to and from #GVariants.
*
* There are two serialization concepts supported by this API:
* serialization and externalization.
* A serialized instance is created with dee_serializable_serialize() and can
* be read back with dee_serializable_parse() provided you know the correct
* #GType for the serialized data. The #GVariant representation of your
* serialized data is guaranteed to be exactly as you implement yourself in the
* @serialize vfunc of the #DeeSerializableIface.
*
* With externalized instances you don't have to know the correct GType to
* recreate the instance. The #GType is encoded in the data itself. When you're
* using dee_serializable_externalize() your data will be wrapped in a container
* format with the required object metadata to read it back. For this reason
* dee_serializable_parse_external() doesn't require you to pass in the #GType
* you want to deserialize.
*
*
* On Subclasses of DeeSerializable Types
*
* As a rule of thumb you need to re-implement the #DeeSerializable interface
* and install parse functions with dee_serializable_register_parser() every
* time you create a new class derived from a #DeeSerializable superclass.
*
*
* In case a subclass does not provide it's own serialization interface
* Dee will recurse upwards in the type hierarchy and use the serialization and
* parser implementations of the first superclass with the required behaviour.
* This means that the parsed instance will not be an
* instance of the subclass but only of the serializable superclass.
* Caveat emptor.
*
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include "dee-serializable.h"
#include "dee-serializable-model.h"
#include "dee-sequence-model.h"
#include "dee-shared-model.h"
#include "trace-log.h"
#define DEE_SERIALIZABLE_FORMAT_VERSION 1
typedef struct {
GType type;
GVariantType *vtype;
DeeSerializableParseFunc parse;
} Parser;
GHashTable *parsers_by_gtype = NULL;
typedef DeeSerializableIface DeeSerializableInterface;
G_DEFINE_INTERFACE (DeeSerializable, dee_serializable, G_TYPE_OBJECT)
static void
dee_serializable_default_init (DeeSerializableInterface *klass)
{
}
static void
init_parsers ()
{
gpointer *cls;
parsers_by_gtype = g_hash_table_new (g_str_hash, g_str_equal);
/* Call type initializers for built in DeeSerializables,
* we need to ref the classes as the parsers are registered in the
* class_init() functions */
cls = g_type_class_ref (dee_serializable_model_get_type ());
g_type_class_unref (cls);
cls = g_type_class_ref (dee_sequence_model_get_type ());
g_type_class_unref (cls);
cls = g_type_class_ref (dee_shared_model_get_type ());
g_type_class_unref (cls);
}
/**
* dee_serializable_register_parser:
* @type: The #GType of the object class to register a parser for
* @vtype: Variants to be converted must have this signature
* @parse_func: A function to convert #GVariant data into an instance of the
* given @type.
*
* Register a parser that can convert #GVariant data into an instance of
* a given #GType. Note that you can register more than one parser for the
* same #GType provided that you give them different variant type signatures.
*
* If there is already a parser registered for the given @type and @vtype
* it will be silently replaced.
*
* The recommended behaviour is that #GObject classes register their parsers in
* their respective class init functions.
*/
void
dee_serializable_register_parser (GType type,
const GVariantType *vtype,
DeeSerializableParseFunc parse_func)
{
GSList *parsers, *iter;
Parser *parser;
const gchar *gtype_name;
g_return_if_fail (G_TYPE_IS_OBJECT (type));
g_return_if_fail (vtype != NULL);
g_return_if_fail (parse_func != NULL);
if (G_UNLIKELY (parsers_by_gtype == NULL))
{
init_parsers ();
}
gtype_name = g_type_name (type);
parsers = g_hash_table_lookup (parsers_by_gtype, gtype_name);
trace ("Registering DeeSerializable parser for type %s with signature %s",
gtype_name, g_variant_type_peek_string (vtype));
/* Update existing parser if we have one */
for (iter = parsers; iter != NULL; iter = iter->next)
{
parser = (Parser *) iter->data;
if (g_variant_type_equal (parser->vtype, vtype))
{
/* Parser for this type-vtype combo already registered.
* Override the current parser as documented and return */
parser->parse = parse_func;
return;
}
}
/* Invariant: Beyond this point we don't have the parser registered */
parser = g_new0 (Parser, 1);
parser->type = type;
parser->vtype = g_variant_type_copy (vtype);
parser->parse = parse_func;
parsers = g_slist_prepend (parsers, parser);
g_hash_table_insert (parsers_by_gtype, g_strdup (gtype_name), parsers);
return;
}
static GObject*
_parse_type (GVariant *data,
GType type,
gboolean *found_parser)
{
GObject *object = NULL;
GSList *parsers, *iter;
Parser *parser;
const GVariantType *vtype;
const gchar *gtype_name = NULL;
g_return_val_if_fail (data != NULL, NULL);
vtype = g_variant_get_type (data);
gtype_name = g_type_name (type);
if (found_parser) *found_parser = FALSE;
trace ("Looking up parser for DeeSerializable of type %s with signature %s",
gtype_name, g_variant_type_peek_string (vtype));
/* Find the right parser and apply it */
parsers = g_hash_table_lookup (parsers_by_gtype, gtype_name);
for (iter = parsers; iter != NULL; iter = iter->next)
{
parser = (Parser *) iter->data;
if (g_variant_type_equal (parser->vtype, vtype))
{
if (found_parser) *found_parser = TRUE;
object = parser->parse (data);
if (G_UNLIKELY (object == NULL))
{
g_critical ("Parser for GType %s signature %s returned NULL. This is not allowed by the contract for DeeSerializableParseFunc.",
gtype_name, g_variant_type_peek_string (vtype));
}
else if (G_UNLIKELY (!g_type_is_a (G_OBJECT_TYPE (object), parser->type)))
{
g_critical ("Parser for GType %s signature %s returned instance of type %s which is not a subtype of %s",
gtype_name, g_variant_type_peek_string (vtype), G_OBJECT_TYPE_NAME (object), gtype_name);
g_object_unref (object);
object = NULL;
}
break;
}
}
if (object == NULL)
trace ("No parser registered for GType %s with signature %s",
gtype_name, g_variant_type_peek_string (vtype));
return object;
}
/**
* dee_serializable_parse_external:
* @data: The #GVariant data to parse
*
* Reconstruct a #DeeSerializable from #GVariant data. For this function
* to work you need to register a parser with
* dee_serializable_register_parser(). Any native Dee class will do so
* automatically.
*
* This method only works on data created with dee_serializable_externalize()
* and not with data from dee_serializable_serialize().
*
* Since a #DeeSerializableParseFunc is not allowed to fail - by contract -
* it can be guaranteed that this function only returns %NULL in case there
* is no known parser for the #GType or #GVariant signature of @data.
*
* Return value: (transfer full): A newly constructed #GObject build from @data
* or %NULL in case no parser has been registered for the given
* #GType or variant signature. Free with g_object_unref().
*/
GObject*
dee_serializable_parse_external (GVariant *data)
{
GObject *object = NULL;
guint32 *version;
GVariant *headers, *payload, *payloadv;
gchar *gtype_name = NULL;
GType gtype_id;
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (g_variant_type_equal (g_variant_get_type (data), G_VARIANT_TYPE ("(ua{sv}v)")), NULL);
if (G_UNLIKELY (parsers_by_gtype == NULL))
{
init_parsers ();
}
g_variant_ref_sink (data);
/* Unpack the serialized data */
g_variant_get_child (data, 0, "u", &version);
headers = g_variant_get_child_value (data, 1);
payloadv = g_variant_get_child_value (data, 2);
payload = g_variant_get_variant (payloadv);
if (!g_variant_lookup (headers, "GType", "s", >ype_name))
{
g_critical ("Unable to parse DeeSerializable data: 'GType' header not present in serialized data");
goto out;
}
gtype_id = g_type_from_name (gtype_name);
if (gtype_id == 0)
{
g_critical ("No known GType for type name %s. Perhaps it is not "
"registered with serialization subsystem yet?", gtype_name);
goto out;
}
object = dee_serializable_parse (payload, gtype_id);
out:
g_variant_unref (data);
g_variant_unref (headers);
g_variant_unref (payloadv);
g_variant_unref (payload);
g_free (gtype_name);
return object;
}
/**
* dee_serializable_parse:
* @data: The #GVariant data to parse. If this is a floating reference it will
* be consumed
* @type: The #GType of the class to instantiate from @data
*
* Reconstruct a #DeeSerializable from #GVariant data. For this function
* to work you need to register a parser with
* dee_serializable_register_parser(). Any native Dee class will do so
* automatically.
*
* This method only works on data created with dee_serializable_serialize()
* and not with data from dee_serializable_externalize().
*
* Since a #DeeSerializableParseFunc is not allowed to fail - by contract -
* it can be guaranteed that this function only returns %NULL in case there
* is no known parser for @type and #GVariant signature of @data.
*
* Return value: (transfer full): A newly constructed #GObject build from @data
* or %NULL in case no parser has been registered for the given
* #GType or variant signature. Free with g_object_unref().
*/
GObject*
dee_serializable_parse (GVariant *data,
GType type)
{
GObject *object = NULL;
GType orig_type;
gboolean parser_found = FALSE;
gboolean parsed = FALSE;
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (g_type_is_a (type, DEE_TYPE_SERIALIZABLE), NULL);
if (G_UNLIKELY (parsers_by_gtype == NULL))
{
init_parsers ();
}
orig_type = type;
g_variant_ref_sink (data);
while (g_type_is_a (type, DEE_TYPE_SERIALIZABLE))
{
object = _parse_type (data, type, &parser_found);
parsed |= parser_found;
if (object != NULL)
break;
type = g_type_parent (type);
}
if (!parsed)
g_critical ("No parser registered for GType %s with signature %s",
g_type_name (orig_type), g_variant_get_type_string (data));
g_variant_unref (data);
return object;
}
/**
* dee_serializable_externalize:
* @self: The instance to externalize
*
* Build an externalized form of @self which can be used together with
* dee_serializable_parse_external() to rebuild a copy of @self.
*
* It is important to note that the variant returned from this method does
* not have the same type signature as returned from a call to
* dee_serializable_serialize(). Externalization will wrap the serialized data
* in a container format with versioning information and headers with type
* information.
*
* Return value: A floating reference to a #GVariant with the externalized data.
*/
GVariant*
dee_serializable_externalize (DeeSerializable *self)
{
GVariant *payload;
GVariantBuilder b;
g_return_val_if_fail (DEE_IS_SERIALIZABLE (self), NULL);
payload = dee_serializable_serialize (self);
g_variant_builder_init (&b, G_VARIANT_TYPE ("(ua{sv}v)"));
g_variant_builder_add (&b, "u", DEE_SERIALIZABLE_FORMAT_VERSION);
g_variant_builder_open (&b, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&b, "{sv}", "GType", g_variant_new_string (G_OBJECT_TYPE_NAME (self)));
g_variant_builder_close (&b);
g_variant_builder_add_value (&b, g_variant_new_variant (payload));
g_variant_unref (payload);
return g_variant_builder_end (&b);
}
/**
* dee_serializable_serialize:
* @self: The instance to serialize
*
* Build a clean serialized representation of @self. The signature of the
* returned variant is entirely determined by the underlying implementation.
* You can recreate a serialized instance by calling dee_serializable_parse()
* provided that you know the correct #GType for the serialized instance.
*
* Return value: (transfer full): A reference to a #GVariant with
* the serialized data. The variants type signature is entirely
* dependent of the underlying implementation. Free using
* g_variant_unref().
*/
GVariant*
dee_serializable_serialize (DeeSerializable *self)
{
DeeSerializableIface *iface;
GVariant *result;
g_return_val_if_fail (DEE_IS_SERIALIZABLE (self), NULL);
iface = DEE_SERIALIZABLE_GET_IFACE (self);
result = iface->serialize (self);
/* Make sure we return a real reference
* FIXME: just use g_variant_take_ref once we depend on glib 2.30 */
if (g_variant_is_floating (result)) return g_variant_ref_sink (result);
return result;
}
dee-1.2.7+15.04.20150304/src/dee-tree-index.h 0000644 0000153 0000161 00000004655 12475676210 020370 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#if !defined (_DEE_H_INSIDE) && !defined (DEE_COMPILATION)
#error "Only can be included directly."
#endif
#ifndef _HAVE_DEE_TREE_INDEX_H
#define _HAVE_DEE_TREE_INDEX_H
#include
#include
#include
#include
#include
G_BEGIN_DECLS
#define DEE_TYPE_TREE_INDEX (dee_tree_index_get_type ())
#define DEE_TREE_INDEX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
DEE_TYPE_TREE_INDEX, DeeTreeIndex))
#define DEE_TREE_INDEX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
DEE_TYPE_TREE_INDEX, DeeTreeIndexClass))
#define DEE_IS_TREE_INDEX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
DEE_TYPE_TREE_INDEX))
#define DEE_IS_TREE_INDEX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
DEE_TYPE_TREE_INDEX))
#define DEE_TREE_INDEX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
DBUS_TYPE_TREE_INDEX, DeeTreeIndexClass))
typedef struct _DeeTreeIndexClass DeeTreeIndexClass;
typedef struct _DeeTreeIndex DeeTreeIndex;
typedef struct _DeeTreeIndexPrivate DeeTreeIndexPrivate;
/**
* DeeTreeIndex:
*
* All fields in the DeeTreeIndex structure are private and should never be
* accessed directly
*/
struct _DeeTreeIndex
{
/*< private >*/
DeeIndex parent;
DeeTreeIndexPrivate *priv;
};
struct _DeeTreeIndexClass
{
DeeIndexClass parent_class;
};
GType dee_tree_index_get_type (void);
DeeTreeIndex* dee_tree_index_new (DeeModel *model,
DeeAnalyzer *analyzer,
DeeModelReader *reader);
G_END_DECLS
#endif /* _HAVE_DEE_TREE_INDEX_H */
dee-1.2.7+15.04.20150304/src/dee-model-reader.c 0000644 0000153 0000161 00000013527 12475676210 020655 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2010 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-model-reader
* @title: Model Readers
* @short_description: Extracting strings from #DeeModels
* @include: dee.h
*
* The purpose of a #DeeModelReader is to extract string from a #DeeModel.
* These strings are usually passed through a #DeeAnalyzer on into a #DeeIndex.
*
* Most readers will extract a value of a given type from a given column,
* but it must be noted that this is not a requirement. The strings may be
* built from several columns.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include // memset()
#include "dee-model.h"
#include "dee-model-reader.h"
/**
* dee_model_reader_read:
* @self: The #DeeModelReader used to read @model
* @model: The #DeeModel to read a string from
* @iter: The row to read a string from
*
* Read data from a row in a #DeeModel and extract a string representation from
* it.
*
* Note that generally a #DeeModelReader need not be confined to reading from
* one specific column, although in practice most are.
*
* Returns: A newly allocated string. Free with g_free().
*/
gchar*
dee_model_reader_read (DeeModelReader *self,
DeeModel *model,
DeeModelIter *iter)
{
g_return_val_if_fail (self != NULL, NULL);
return self->reader_func (model, iter, self->userdata);
}
/**
* dee_model_reader_destroy:
* @reader: The reader to destroy
*
* Release resources associated with @reader, but does not free the
* #DeeModelReader structure itself.
*
* This will call the destroy() function registered with the reader
* if it is set.
*/
void
dee_model_reader_destroy (DeeModelReader *reader)
{
g_return_if_fail (reader != NULL);
if (reader->destroy)
reader->destroy (reader->userdata);
}
/**
* dee_model_reader_new:
* @reader_func: (scope notified): The #DeeModelReaderFunc to use for the reader
* @userdata: (closure) (allow-none): The user data to pass to @reader_func
* @destroy: (allow-none): The #GDestroyNotify to call on
* @userdata when disposing of the reader
* @out_reader: (out): A pointer to an uninitialized #DeeModelReader struct
*
* Create a new #DeeModelReader with the given parameters. This call will zero
* the @out_reader struct.
*
*/
void
dee_model_reader_new (DeeModelReaderFunc reader_func,
gpointer userdata,
GDestroyNotify destroy,
DeeModelReader *out_reader)
{
g_return_if_fail (reader_func != NULL);
g_return_if_fail (out_reader != NULL);
memset (out_reader, 0, sizeof (DeeModelReader));
out_reader->reader_func = reader_func;
out_reader->userdata = userdata;
out_reader->destroy = destroy;
}
static gchar*
_string_reader_func (DeeModel *model,
DeeModelIter *iter,
gpointer userdata)
{
return g_strdup (
dee_model_get_string (model, iter, GPOINTER_TO_UINT (userdata)));
}
/**
* dee_model_reader_new_for_string_column:
* @column: The column index to read a string from
* @out_reader: (out): A pointer to a #DeeModelReader instance which will have
* all fields initialized appropriately
*
* A #DeeModelReader reading a string from a #DeeModel at a given column
*/
void
dee_model_reader_new_for_string_column (guint column,
DeeModelReader *out_reader)
{
dee_model_reader_new (_string_reader_func, GUINT_TO_POINTER (column),
NULL, out_reader);
}
static gchar*
_int32_reader_func (DeeModel *model,
DeeModelIter *iter,
gpointer userdata)
{
return g_strdup_printf (
"%i", dee_model_get_int32 (model, iter, GPOINTER_TO_UINT (userdata)));
}
/**
* dee_model_reader_new_for_int32_column:
* @column: The column index to read a %gint32 from
* @out_reader: (out): A pointer to a #DeeModelReader instance which will have
* all fields initialized appropriately
*
* A #DeeModelReader reading a %gint32 from a #DeeModel at a given column
*/
void
dee_model_reader_new_for_int32_column (guint column,
DeeModelReader *out_reader)
{
dee_model_reader_new (_int32_reader_func, GUINT_TO_POINTER (column),
NULL, out_reader);
}
static gchar*
_uint32_reader_func (DeeModel *model,
DeeModelIter *iter,
gpointer userdata)
{
return g_strdup_printf ("%"G_GUINT32_FORMAT,
dee_model_get_uint32 (model, iter, GPOINTER_TO_UINT (userdata)));
}
/**
* dee_model_reader_new_for_uint32_column:
* @column: The column index to read a %guint32 from
* @out_reader: (out): A pointer to a #DeeModelReader instance which will have
* all fields initialized appropriately
*
* A #DeeModelReader reading a %guint32 from a #DeeModel at a given column
*/
void
dee_model_reader_new_for_uint32_column (guint column,
DeeModelReader *out_reader)
{
dee_model_reader_new (_uint32_reader_func, GUINT_TO_POINTER (column),
NULL, out_reader);
}
dee-1.2.7+15.04.20150304/src/dee-file-resource-manager.h 0000644 0000153 0000161 00000004711 12475676210 022471 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#ifndef _DEE_FILE_RESOURCE_MANAGER_H_
#define _DEE_FILE_RESOURCE_MANAGER_H_
#include
#include
#include
G_BEGIN_DECLS
#define DEE_TYPE_FILE_RESOURCE_MANAGER (dee_file_resource_manager_get_type ())
#define DEE_FILE_RESOURCE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
DEE_TYPE_FILE_RESOURCE_MANAGER, DeeFileResourceManager))
#define DEE_FILE_RESOURCE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
DEE_TYPE_FILE_RESOURCE_MANAGER, DeeFileResourceManagerClass))
#define DEE_IS_FILE_RESOURCE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
DEE_TYPE_FILE_RESOURCE_MANAGER))
#define DEE_IS_FILE_RESOURCE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
DEE_TYPE_FILE_RESOURCE_MANAGER))
#define DEE_FILE_RESOURCE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
DEE_TYPE_FILE_RESOURCE_MANAGER, DeeFileResourceManagerClass))
typedef struct _DeeFileResourceManager DeeFileResourceManager;
typedef struct _DeeFileResourceManagerClass DeeFileResourceManagerClass;
struct _DeeFileResourceManager
{
GObject parent_instance;
};
struct _DeeFileResourceManagerClass
{
GObjectClass parent_class;
};
GType dee_file_resource_manager_get_type (void);
DeeResourceManager* dee_file_resource_manager_new (const gchar *primary_path);
void dee_file_resource_manager_add_search_path (DeeResourceManager *self,
const gchar *path);
const gchar* dee_file_resource_manager_get_primary_path (DeeResourceManager *self);
G_END_DECLS
#endif /* _DEE_FILE_RESOURCE_MANAGER_H_ */
dee-1.2.7+15.04.20150304/src/dee-server.h 0000644 0000153 0000161 00000004524 12475676210 017625 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Michal Hruby
*/
#if !defined (_DEE_H_INSIDE) && !defined (DEE_COMPILATION)
#error "Only can be included directly."
#endif
#ifndef _HAVE_DEE_SERVER_H
#define _HAVE_DEE_SERVER_H
#include
#include
#include "dee-peer.h"
G_BEGIN_DECLS
#define DEE_TYPE_SERVER dee_server_get_type()
#define DEE_SERVER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), DEE_TYPE_SERVER, DeeServer))
#define DEE_SERVER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), DEE_TYPE_SERVER, DeeServerClass))
#define DEE_IS_SERVER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEE_TYPE_SERVER))
#define DEE_IS_SERVER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), DEE_TYPE_SERVER))
#define DEE_SERVER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), DEE_TYPE_SERVER, DeeServerClass))
typedef struct _DeeServerPrivate DeeServerPrivate;
typedef struct {
/*< private >*/
DeePeer parent;
DeeServerPrivate *priv;
} DeeServer;
typedef struct {
/*< private >*/
DeePeerClass parent_class;
} DeeServerClass;
/**
* dee_server_get_type:
*
* The GType of #DeeServer
*
* Return value: the #GType of #DeeServer
**/
GType dee_server_get_type (void);
DeeServer* dee_server_new (const gchar *swarm_name);
DeeServer* dee_server_new_for_address (const gchar *swarm_name,
const gchar *bus_address);
const gchar* dee_server_get_client_address (DeeServer *server);
gchar* dee_server_bus_address_for_name (const gchar *name,
gboolean include_username);
G_END_DECLS
#endif /* _HAVE_DEE_SERVER_H */
dee-1.2.7+15.04.20150304/src/dee-transaction.c 0000644 0000153 0000161 00000142722 12475676214 020646 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-transaction
* @short_description: A self contained change set for a #DeeModel
* @include: dee.h
*
* #DeeTransaction is a self contained change set related to some particular
* #DeeModel called the target model.
*
* The transaction instance itself implements the #DeeModel interface in a way
* that overlays the target model. In database terms the target model has
* isolation level READ_COMMITTED. Meaning that the target model is not modified
* until you call dee_transaction_commit().
*
* To flush the changes to the target model call dee_transaction_commit().
* After committing the transaction will become invalid and must be freed with
* g_object_unref(). It is a programming error to try and access a transaction
* that has been committed with the sole exception of calling
* dee_transaction_is_committed().
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include "dee-model.h"
#include "dee-transaction.h"
#include "dee-serializable-model.h"
#include "dee-marshal.h"
#include "trace-log.h"
/*
* IMPLEMENTATION NOTES
*
* The idea is to keep the transaction as light as possible by reusing the
* iters from the target model, letting them fall through to the target when
* unchanged in the transaction.
*
* This gives some overhead when reading stuff from a transaction model, but
* that is considered an acceptable tradeoff as the transaction is optimized
* for writing and not reading.
*
* The transaction keeps a "journal" of the changes it needs to apply and
* commit. The relevant data structure is the JournalIter. Journal iters
* are characterized in 2 ways. JournalIters are called 'jiters' for short.
*
* Firstly there is the ChangeType of a jiter.
*
* CHANGE_TYPE_REMOVE: The jiter is an 'override' for an iter in the
* target model that has been deleted. The jiter.overlay
* member points to the original
*
* CHANGE_TYPE_CHANGE: The jiter is an 'override' for an iter in the
* target model that has been changed. The jiter.overlay
* points to the original. The jiter.row_data member will
* contain all the values for the changed row
*
* CHANGE_TYPE_ADD: The jiter does not correspond to an iter in the target, and
* the jiter.override member will be unset. Additions are
* grouped together in "segments" and these segments points
* to an iter in the target they attach *before*
*
* To ease internal book keeping we also have the IterType enumeration which
* describes if a given pointer is a jiter or an iter.
*
* Segments
* Jiters that are additions are grouped into "segments" and each segment
* points to a row in the target model.
*
*/
typedef struct _JournalSegment JournalSegment;
typedef struct _JournalIter JournalIter;
typedef enum {
CHANGE_TYPE_REMOVE,
CHANGE_TYPE_CHANGE,
CHANGE_TYPE_ADD
} ChangeType;
typedef enum {
ITER_TYPE_TARGET,
ITER_TYPE_JOURNAL
} IterType;
struct _JournalSegment {
/* End points of the journal iters in the segment */
JournalIter *first_iter;
JournalIter *last_iter;
/* The row in the target model that this segment is attached before.
* Note that the target row may be changed or deleted */
DeeModelIter *target_iter;
/* The transaction owning the segment. It is mainly here as an optimization
* to allow fast access to the number of column sin the model for copying
* and freeing the row_data */
DeeTransaction *txn;
/* Used on commit() because we commit whole segments at a time,
* disregarding playback order */
gboolean is_committed;
};
/* Implements a two dimensional doubly linked list. One dimension is the
* playback queue and the other is the order of the iters (inside a segment).
* INVARIANT: Set if and only if change_type == CHANGE_TYPE_ADD */
struct _JournalIter {
/* Added rows all belong to a specific segment
* attached before a row in the target */
JournalSegment *segment;
/* Linked list for the playback queue */
JournalIter *next_playback;
JournalIter *prev_playback;
/* Linked list for the itersinside a segment */
JournalIter *next_iter;
JournalIter *prev_iter;
/* Points to a row in the targetmodel
* INVARIANT: Set if and only if change_type == CHANGE_TYPE_{CHANGE,REMOVE} */
DeeModelIter *override_iter;
/* FIXME: Not implemented. I am not even sure it's theoretically possible */
GSList *tags;
ChangeType change_type;
GVariant **row_data;
};
/**
* DeeTransactionPrivate:
*
* Ignore this structure.
*/
struct _DeeTransactionPrivate
{
/* The model the transaction applies against */
DeeModel *target;
/* The journal maps DeeModelIters from the target model to JournalIters.
* Also maps JournalIters to them selves.
* INAVARIANT: If an iter is not in the journal it
* it is an untouched iter from the target model
* NOTE: Different keys may point to the same jiter
*/
GHashTable *journal;
/* The segments map DeeModelIters from the target model,
* to JournalSegments that lie immediately before them.
* INVARIANT: A JournalIter that has a segment has change_type CHANGE_TYPE_ADD
* NOTE: different keys may correspond to the same segment
*/
GHashTable *segments;
/* The head and the tail of the queue of JournalIters constituting
* the changes we must play back on the target model.
* NOTE: jiters that become irrelevant must be unlinked from the
* playback queue and freed. We use the playback queue on finalize
* to walk and free the jiters and segments */
JournalIter *first_playback;
JournalIter *last_playback;
/* Signals handlers to check for the concurrent modification of the back end */
gulong target_row_added_handler;
gulong target_row_removed_handler;
gulong target_row_changed_handler;
/* canary to saniy check that no one sneaks changes into the target while
* the txn is open */
guint64 begin_seqnum;
/* DeeTransactionError code. If != 0 we have an error state set */
guint error_code;
/* Number of columns in target model (just a cache) */
guint n_cols;
};
static JournalIter*
journal_iter_new (ChangeType ct)
{
JournalIter *jent;
jent = g_slice_new0 (JournalIter);
jent->change_type = ct;
return jent;
}
static void
journal_iter_free (JournalIter *jiter)
{
GVariant **v;
if (jiter->row_data)
{
for (v = jiter->row_data; *v != NULL; v++)
{
g_variant_unref (*v);
*v = NULL;
}
g_free (jiter->row_data);
jiter->row_data = NULL;
}
// FIXME: free tags, when/if we implement tags
g_slice_free (JournalIter, jiter);
}
#define journal_iter_is_removed(jiter) (jiter->change_type == CHANGE_TYPE_REMOVE)
static JournalSegment*
journal_segment_new_before (DeeModelIter *iter, DeeTransaction *txn)
{
JournalSegment *jseg = g_slice_new0 (JournalSegment);
jseg->target_iter = iter;
jseg->txn = txn;
jseg->is_committed = FALSE;
return jseg;
}
static void
journal_segment_free (JournalSegment *segment)
{
g_slice_free (JournalSegment, segment);
}
static GVariant**
copy_row_data (GVariant **row_data, guint n_cols)
{
GVariant **iter, **copy;
guint i;
for (iter = row_data, i = 0; i < n_cols; iter++, i++)
{
g_variant_ref_sink (*iter);
}
copy = g_new (GVariant*, n_cols + 1);
memcpy (copy, row_data, n_cols * sizeof (GVariant*));
copy[n_cols] = NULL;
return copy;
}
static JournalIter*
journal_segment_append (JournalSegment *jseg, GVariant **row_data)
{
JournalIter *new_jiter;
g_assert ((jseg->last_iter == NULL && jseg->first_iter == NULL) ||
jseg->last_iter->next_iter == NULL);
new_jiter = journal_iter_new (CHANGE_TYPE_ADD);
new_jiter->segment = jseg;
new_jiter->row_data = copy_row_data (row_data, jseg->txn->priv->n_cols);
if (jseg->last_iter == NULL)
{
jseg->last_iter = new_jiter;
jseg->first_iter = new_jiter;
}
else
{
new_jiter->prev_iter = jseg->last_iter;
jseg->last_iter->next_iter = new_jiter;
jseg->last_iter = new_jiter;
}
return new_jiter;
}
static JournalIter*
journal_segment_prepend (JournalSegment *jseg, GVariant **row_data)
{
JournalIter *new_jiter;
g_assert ((jseg->last_iter == NULL && jseg->first_iter == NULL) ||
jseg->first_iter->prev_iter == NULL);
new_jiter = journal_iter_new (CHANGE_TYPE_ADD);
new_jiter->segment = jseg;
new_jiter->row_data = copy_row_data (row_data, jseg->txn->priv->n_cols);
if (jseg->first_iter == NULL)
{
jseg->last_iter = new_jiter;
jseg->first_iter = new_jiter;
}
else
{
new_jiter->next_iter = jseg->first_iter;
jseg->first_iter->prev_iter = new_jiter;
jseg->first_iter = new_jiter;
}
return new_jiter;
}
static JournalIter*
journal_segment_insert_before (JournalSegment *jseg,
JournalIter *jiter,
GVariant **row_data)
{
JournalIter *new_jiter;
g_assert ((jseg->first_iter == NULL && jseg->last_iter == NULL) ||
(jseg->first_iter != NULL && jseg->last_iter != NULL));
if (jiter == NULL)
{
return journal_segment_append (jseg, row_data);
}
else if (jiter == jseg->first_iter)
{
return journal_segment_prepend (jseg, row_data);
}
/* It's not a pre- or append(), but a genuine insertion */
new_jiter = journal_iter_new (CHANGE_TYPE_ADD);
new_jiter->segment = jseg;
new_jiter->row_data = copy_row_data (row_data, jseg->txn->priv->n_cols);
if (jseg->first_iter == NULL)
{
jseg->first_iter = new_jiter;
jseg->last_iter = new_jiter;
}
else
{
jiter->prev_iter->next_iter = new_jiter;
new_jiter->prev_iter = jiter->prev_iter;
new_jiter->next_iter = jiter;
jiter->prev_iter = new_jiter;
}
return new_jiter;
}
#define AS_TXN(ptr) ((DeeTransaction*)ptr)
#define get_journal_segment_before(iter) \
g_hash_table_lookup (priv->segments, iter)
#define set_journal_segment_before(iter,jseg) \
g_hash_table_insert (priv->segments, iter, jseg)
#define register_journal_iter(jiter) \
g_hash_table_insert (priv->journal, jiter, jiter); \
if (jiter->override_iter) g_hash_table_insert (priv->journal, jiter->override_iter, jiter);
#define unregister_journal_iter(jiter) \
g_hash_table_remove (priv->journal, jiter);
#define check_journal_iter(iter,jiter_p) \
g_hash_table_lookup_extended (priv->journal, iter, NULL, (void**)jiter_p)
#define JOURNAL_ITER(iter) \
((JournalIter*)iter)
#define MODEL_ITER(jiter) \
((DeeModelIter*)jiter)
#define append_to_playback(jiter) \
if (priv->first_playback == NULL) \
priv->first_playback = jiter; \
\
if (priv->last_playback) \
{ \
priv->last_playback->next_playback = jiter; \
jiter->prev_playback = priv->last_playback; \
} \
\
priv->last_playback = jiter;
static void dee_transaction_model_iface_init (DeeModelIface *iface);
G_DEFINE_TYPE_WITH_CODE (DeeTransaction,
dee_transaction,
DEE_TYPE_SERIALIZABLE_MODEL,
G_IMPLEMENT_INTERFACE (DEE_TYPE_MODEL,
dee_transaction_model_iface_init));
#define DEE_TRANSACTION_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE(obj, DEE_TYPE_TRANSACTION, DeeTransactionPrivate))
enum
{
PROP_0,
PROP_TARGET
};
/* INVARIANT: The end iter of the transaction is the same as the end iter
* of the target model */
#define DEE_TRANSACTION_TARGET(txn) (DEE_TRANSACTION(txn)->priv->target)
/*
* DeeModel forward declarations
*/
static DeeModelIter* dee_transaction_insert_row_before (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members);
static void dee_transaction_remove (DeeModel *self,
DeeModelIter *iter);
static void dee_transaction_set_value (DeeModel *self,
DeeModelIter *iter,
guint column,
GVariant *value);
static void dee_transaction_set_row (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members);
static GVariant* dee_transaction_get_value (DeeModel *self,
DeeModelIter *iter,
guint column);
static DeeModelIter* dee_transaction_get_first_iter (DeeModel *self);
static DeeModelIter* dee_transaction_get_last_iter (DeeModel *self);
static DeeModelIter* dee_transaction_next (DeeModel *self,
DeeModelIter *iter);
static DeeModelIter* dee_transaction_prev (DeeModel *self,
DeeModelIter *iter);
static DeeModelTag* dee_transaction_register_tag (DeeModel *self,
GDestroyNotify tag_destroy);
static gpointer dee_transaction_get_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag);
static void dee_transaction_set_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
gpointer value);
static void dee_transaction_set_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
gpointer value);
static const gchar* dee_transaction_get_field_schema (DeeModel *self,
const gchar *field_name,
guint *out_column);
static void on_target_modified (DeeTransaction *self,
DeeModelIter *iter);
/* GObject Init */
static void
dee_transaction_finalize (GObject *object)
{
DeeTransactionPrivate *priv = DEE_TRANSACTION (object)->priv;
if (priv->target)
{
g_signal_handler_disconnect (priv->target, priv->target_row_added_handler);
g_signal_handler_disconnect (priv->target, priv->target_row_removed_handler);
g_signal_handler_disconnect (priv->target, priv->target_row_changed_handler);
g_object_unref (priv->target);
}
if (priv->journal)
{
g_hash_table_unref (priv->journal);
priv->journal = NULL;
}
if (priv->segments)
{
g_hash_table_unref (priv->segments);
priv->segments = NULL;
}
if (priv->first_playback)
{
JournalIter *jiter, *free_jiter;
GHashTable *freed_segments = g_hash_table_new (g_direct_hash,
g_direct_equal);
for (jiter = priv->first_playback; jiter != NULL; )
{
if (jiter->segment &&
g_hash_table_lookup (freed_segments, jiter->segment))
{
g_hash_table_insert (freed_segments,jiter->segment, jiter->segment);
journal_segment_free (jiter->segment);
}
free_jiter = jiter;
jiter = jiter->next_playback;
journal_iter_free (free_jiter);
}
priv->first_playback = NULL;
priv->last_playback = NULL;
g_hash_table_destroy (freed_segments);
}
G_OBJECT_CLASS (dee_transaction_parent_class)->finalize (object);
}
/* GObject Post-Init. Properties have been set */
static void
dee_transaction_constructed (GObject *object)
{
const gchar* const *schema;
const gchar **column_names;
guint n_columns;
DeeTransactionPrivate *priv = DEE_TRANSACTION (object)->priv;
/* Chain up before we do too much, to make sure the parent class is ready */
if (G_OBJECT_CLASS (dee_transaction_parent_class)->constructed != NULL)
G_OBJECT_CLASS (dee_transaction_parent_class)->constructed (object);
if (priv->target == NULL)
{
g_critical ("You must set the 'target' property of "
"the DeeTransaction upon creation.");
return;
}
/* Adopt schema of target model */
schema = dee_model_get_schema (priv->target, &n_columns);
dee_model_set_schema_full (DEE_MODEL (object), schema, n_columns);
priv->n_cols = n_columns;
/* Also adopt column names of target model */
column_names = dee_model_get_column_names (priv->target, &n_columns);
if (column_names)
{
dee_model_set_column_names_full (DEE_MODEL (object),
column_names, n_columns);
}
/* Adopt seqnums of target model, if it has any */
if (DEE_IS_SERIALIZABLE_MODEL (priv->target))
{
priv->begin_seqnum = dee_serializable_model_get_seqnum (priv->target);
}
else
{
priv->begin_seqnum = 0;
}
dee_serializable_model_set_seqnum (DEE_MODEL (object), priv->begin_seqnum);
priv->target_row_added_handler =
g_signal_connect_swapped (priv->target, "row-added",
G_CALLBACK (on_target_modified), object);
priv->target_row_removed_handler =
g_signal_connect_swapped (priv->target, "row-removed",
G_CALLBACK (on_target_modified), object);
priv->target_row_changed_handler =
g_signal_connect_swapped (priv->target, "row-changed",
G_CALLBACK (on_target_modified), object);
}
static void
dee_transaction_set_property (GObject *object,
guint id,
const GValue *value,
GParamSpec *pspec)
{
DeeTransactionPrivate *priv = DEE_TRANSACTION (object)->priv;
switch (id)
{
case PROP_TARGET:
priv->target = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
break;
}
}
static void
dee_transaction_get_property (GObject *object,
guint id,
GValue *value,
GParamSpec *pspec)
{
switch (id)
{
case PROP_TARGET:
g_value_set_object (value, DEE_TRANSACTION (object)->priv->target);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
break;
}
}
static void
dee_transaction_class_init (DeeTransactionClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
obj_class->finalize = dee_transaction_finalize;
obj_class->constructed = dee_transaction_constructed;
obj_class->set_property = dee_transaction_set_property;
obj_class->get_property = dee_transaction_get_property;
/**
* DeeTransaction:back-end:
*
* The backend model used by this proxy model.
**/
pspec = g_param_spec_object ("target", "Target",
"Target model",
DEE_TYPE_MODEL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS);
g_object_class_install_property (obj_class, PROP_TARGET, pspec);
/* Add private data */
g_type_class_add_private (obj_class, sizeof (DeeTransactionPrivate));
}
static void
dee_transaction_model_iface_init (DeeModelIface *iface)
{
DeeModelIface *piface = g_type_interface_peek_parent (iface);
iface->set_schema_full = piface->set_schema_full;
iface->get_schema = piface->get_schema;
iface->get_field_schema = dee_transaction_get_field_schema;
iface->get_column_schema = piface->get_column_schema;
iface->get_n_columns = piface->get_n_columns;
iface->get_n_rows = piface->get_n_rows;
iface->clear = piface->clear;
iface->prepend_row = piface->prepend_row;
iface->append_row = piface->append_row;
iface->insert_row = piface->insert_row;
iface->insert_row_before = dee_transaction_insert_row_before;
iface->remove = dee_transaction_remove;
iface->set_value = dee_transaction_set_value;
iface->set_row = dee_transaction_set_row;
iface->get_value = dee_transaction_get_value;
iface->get_first_iter = dee_transaction_get_first_iter;
iface->get_last_iter = dee_transaction_get_last_iter;
iface->get_iter_at_row = piface->get_iter_at_row;
iface->get_bool = piface->get_bool;
iface->get_uchar = piface->get_uchar;
iface->get_int32 = piface->get_int32;
iface->get_uint32 = piface->get_uint32;
iface->get_int64 = piface->get_int64;
iface->get_uint64 = piface->get_uint64;
iface->get_double = piface->get_double;
iface->get_string = piface->get_string;
iface->next = dee_transaction_next;
iface->prev = dee_transaction_prev;
iface->is_first = piface->is_first;
iface->is_last = piface->is_last;
iface->get_position = piface->get_position;
iface->register_tag = dee_transaction_register_tag;
iface->get_tag = dee_transaction_get_tag;
iface->set_tag = dee_transaction_set_tag;
}
static void
dee_transaction_init (DeeTransaction *model)
{
DeeTransactionPrivate *priv;
priv = model->priv = DEE_TRANSACTION_GET_PRIVATE (model);
priv->target = NULL;
priv->journal = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->segments = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->target_row_added_handler = 0;
priv->target_row_removed_handler = 0;
priv->target_row_changed_handler = 0;
}
/*
* DeeModel Interface Implementation
*/
/* Inherited methods */
// dee_transaction_set_schema_full ()
// dee_transaction_get_schema ()
// dee_transaction_get_column_schema ()
// dee_transaction_get_n_columns ()
// dee_transaction_get_n_rows () (slow O(n))
// dee_transaction_clear () (slow O(n))
// dee_transaction_append_row ()
// dee_transaction_prepend_row ()
// dee_transaction_insert_row ()
static const gchar*
dee_transaction_get_field_schema (DeeModel *self,
const gchar *field_name,
guint *out_column)
{
DeeModelIface *piface;
const gchar *schema;
schema = dee_model_get_field_schema (DEE_TRANSACTION_TARGET (self),
field_name, out_column);
if (schema) return schema;
// maybe the names are registered just for the transaction instance?
piface = g_type_interface_peek_parent (DEE_MODEL_GET_IFACE (self));
return (* piface->get_field_schema) (self, field_name, out_column);
}
static DeeModelIter*
dee_transaction_insert_row_before (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members)
{
DeeTransactionPrivate *priv;
JournalIter *new_jiter, *jiter;
JournalSegment *jseg;
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_return_val_if_fail (iter != NULL, NULL);
g_return_val_if_fail (row_members != NULL, NULL);
g_return_val_if_fail (!dee_transaction_is_committed (AS_TXN (self)), NULL);
priv = DEE_TRANSACTION (self)->priv;
/* new_jiter is what we'll eventually return */
new_jiter = NULL;
if (check_journal_iter (iter, &jiter))
{
/* If the jiter has a segment it must be an added row and we wire
* into that segment */
if (jiter->segment)
{
g_assert (jiter->change_type == CHANGE_TYPE_ADD);
new_jiter = journal_segment_insert_before (jiter->segment,
jiter,
row_members);
}
else
{
g_assert (jiter->change_type == CHANGE_TYPE_CHANGE ||
jiter->change_type == CHANGE_TYPE_REMOVE);
/* Inserting relative to a removed row is a consumer error, but
* note we still want the assertion above to verify our own
* invariants */
if (G_UNLIKELY (jiter->change_type == CHANGE_TYPE_REMOVE))
{
g_critical ("Inserting new row relative to previously removed row");
return iter;
}
/* Note that on commit time we might have removed the iter we attach
* before. We handle that at that point by scanning forwards until we
* find a valid iter */
if ((jseg = get_journal_segment_before (iter)) != NULL)
{
new_jiter = journal_segment_append (jseg, row_members);
}
else
{
jseg = journal_segment_new_before (iter, DEE_TRANSACTION (self));
new_jiter = journal_segment_append (jseg, row_members);
set_journal_segment_before (iter, jseg);
}
}
}
else if ((jseg = get_journal_segment_before (iter)) != NULL)
{
/* This is an untouched row from the target model with a segment
* attached before it */
new_jiter = journal_segment_append (jseg, row_members);
}
else
{
/* This is an untouched row from the target model without any new rows
* attached before it.
* Set up a new segment before it and attach to that */
jseg = journal_segment_new_before (iter, DEE_TRANSACTION (self));
new_jiter = journal_segment_append (jseg, row_members);
set_journal_segment_before (iter, jseg);
}
/* We have b0rked up this function if new_jiter is not set by now */
g_assert (new_jiter != NULL);
append_to_playback (new_jiter);
register_journal_iter (new_jiter);
dee_serializable_model_inc_seqnum (self);
g_signal_emit_by_name (self, "row-added", new_jiter);
return MODEL_ITER (new_jiter);
}
static void
dee_transaction_remove (DeeModel *self,
DeeModelIter *iter)
{
DeeTransactionPrivate *priv;
JournalIter *jiter;
gboolean should_free_jiter;
g_return_if_fail (DEE_IS_TRANSACTION (self));
g_return_if_fail (!dee_transaction_is_committed (AS_TXN (self)));
priv = DEE_TRANSACTION (self)->priv;
should_free_jiter = FALSE;
if (check_journal_iter (iter, &jiter))
{
if (G_UNLIKELY (jiter->change_type == CHANGE_TYPE_REMOVE))
{
g_critical ("Row %p already removed from transaction", iter);
return;
}
/* If jiter is something we've added we can just unlink it from the
* playback queue and its segment and free it. If it's a change we
* can simply mark it as a removal in stead.
* Note that if a segment is attached to a removed row, we resolve
* that at commit() time by scanning forwards to the next non-removed
* row. */
if (jiter->change_type == CHANGE_TYPE_CHANGE)
{
jiter->change_type = CHANGE_TYPE_REMOVE;
}
else
{
g_assert (jiter->change_type == CHANGE_TYPE_ADD);
should_free_jiter = TRUE;
}
}
else
{
jiter = journal_iter_new (CHANGE_TYPE_REMOVE);
jiter->override_iter = iter;
register_journal_iter (jiter);
append_to_playback (jiter);
}
/* Emit the removed signal while the iter is still valid,
* but after we increased the seqnum */
dee_serializable_model_inc_seqnum (self);
g_signal_emit_by_name (self, "row-removed",
jiter->override_iter ? jiter->override_iter : MODEL_ITER (jiter));
if (should_free_jiter)
{
/* Detach from segment */
if (jiter->segment->first_iter == jiter)
jiter->segment->first_iter = jiter->next_iter;
if (jiter->segment->last_iter == jiter)
jiter->segment->last_iter = jiter->prev_iter;
/* If our host segment is empty we must get rid of it,
* else we unlink our selves from the internal list */
if (jiter->segment->first_iter == NULL)
{
g_assert (jiter->segment->last_iter == NULL);
g_hash_table_remove (priv->segments, jiter->segment->target_iter);
}
else{
if (jiter->prev_iter)
jiter->prev_iter->next_iter = jiter->next_iter;
if (jiter->next_iter)
jiter->next_iter->prev_iter = jiter->prev_iter;
}
/* Remove from playback queue */
if (jiter->prev_playback)
jiter->prev_playback->next_playback = jiter->next_playback;
if (jiter->next_playback)
jiter->next_playback->prev_playback = jiter->prev_playback;
unregister_journal_iter (jiter);
}
}
static void
dee_transaction_set_row (DeeModel *self,
DeeModelIter *iter,
GVariant **row_members)
{
DeeTransactionPrivate *priv;
JournalIter *jiter;
GVariant **v;
g_return_if_fail (DEE_IS_TRANSACTION (self));
g_return_if_fail (!dee_transaction_is_committed (AS_TXN (self)));
priv = DEE_TRANSACTION (self)->priv;
if (check_journal_iter (iter, &jiter))
{
if (G_UNLIKELY (jiter->change_type == CHANGE_TYPE_REMOVE))
{
g_critical ("Trying to update row which have been removed from "
"the transaction");
return;
}
g_assert (jiter->row_data != NULL);
for (v = jiter->row_data; *v != NULL; v++)
{
g_variant_unref (*v);
}
g_free (jiter->row_data);
jiter->row_data = copy_row_data (row_members, priv->n_cols);
}
else
{
/* A simple check to raise the probability of iter being a valid
* iter in the target */
if (strcmp (g_variant_get_type_string (row_members[0]),
g_variant_get_type_string (dee_model_get_value (priv->target,
iter, 0)))
!= 0)
{
g_critical ("Error setting row in transaction %p. The iter is "
"probably not in the target model", self);
return;
}
jiter = journal_iter_new (CHANGE_TYPE_CHANGE);
jiter->row_data = copy_row_data (row_members, priv->n_cols);
jiter->override_iter = iter;
register_journal_iter (jiter);
append_to_playback (jiter);
}
g_assert (jiter != NULL);
g_assert ( (jiter->override_iter != NULL && jiter->change_type == CHANGE_TYPE_CHANGE)
|| (jiter->override_iter == NULL && jiter->change_type == CHANGE_TYPE_ADD));
dee_serializable_model_inc_seqnum (self);
g_signal_emit_by_name (self, "row-changed",
jiter->override_iter ? jiter->override_iter : MODEL_ITER (jiter));
}
static void
dee_transaction_set_value (DeeModel *self,
DeeModelIter *iter,
guint column,
GVariant *value)
{
DeeTransactionPrivate *priv;
JournalIter *jiter;
g_return_if_fail (DEE_IS_TRANSACTION (self));
g_return_if_fail (iter != NULL);
g_return_if_fail (value != NULL);
g_return_if_fail (!dee_transaction_is_committed (AS_TXN (self)));
priv = DEE_TRANSACTION (self)->priv;
g_return_if_fail (column < priv->n_cols);
if (check_journal_iter (iter, &jiter))
{
if (G_UNLIKELY (jiter->change_type == CHANGE_TYPE_REMOVE))
{
g_critical ("Trying to change value of removed row");
return;
}
g_variant_unref (jiter->row_data[column]);
jiter->row_data[column] = g_variant_ref_sink (value);
}
else
{
/* We haven't touched this row before, which guarantees that the iter
* must point to a row in the target model */
jiter = journal_iter_new (CHANGE_TYPE_CHANGE);
jiter->override_iter = iter;
/* Assume row data */
jiter->row_data = dee_model_get_row (priv->target, iter, NULL);
g_variant_unref (jiter->row_data[column]);
jiter->row_data[column] = g_variant_ref_sink (value);
register_journal_iter (jiter);
append_to_playback (jiter);
}
g_assert (jiter != NULL);
g_assert ( (jiter->override_iter != NULL && jiter->change_type == CHANGE_TYPE_CHANGE)
|| (jiter->override_iter == NULL && jiter->change_type == CHANGE_TYPE_ADD));
dee_serializable_model_inc_seqnum (self);
g_signal_emit_by_name (self, "row-changed",
jiter->override_iter ? jiter->override_iter : MODEL_ITER (jiter));
}
static GVariant*
dee_transaction_get_value (DeeModel *self,
DeeModelIter *iter,
guint column)
{
DeeTransactionPrivate *priv;
JournalIter *jiter;
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_return_val_if_fail (!dee_transaction_is_committed (AS_TXN (self)), NULL);
priv = DEE_TRANSACTION (self)->priv;
if(check_journal_iter (iter, &jiter))
{
if (G_UNLIKELY (jiter->change_type == CHANGE_TYPE_REMOVE))
{
g_critical ("Trying to get value from a row that has been removed "
"from the transaction");
return NULL;
}
g_return_val_if_fail (column < priv->n_cols, NULL);
return g_variant_ref (jiter->row_data[column]);
}
else
{
return dee_model_get_value (priv->target, iter, column);
}
}
/* Inherited methods */
// dee_transaction_get_bool ()
// dee_transaction_get_uchar ()
// dee_transaction_get_int32 ()
// dee_transaction_get_uint32 ()
// dee_transaction_get_int64 ()
// dee_transaction_get_uint64 ()
// dee_transaction_get_double ()
// dee_transaction_get_string ()
/* This method returns the next logical iter, which may be a removal */
static DeeModelIter*
dee_transaction_next_raw (DeeModel *self,
DeeModelIter *iter,
IterType *out_iter_type)
{
DeeTransactionPrivate *priv;
JournalIter *jiter, *jiter_next;
JournalSegment *jseg;
DeeModelIter *end;
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
priv = DEE_TRANSACTION (self)->priv;
end = dee_model_get_last_iter (self); /* end shared with target */
g_return_val_if_fail (iter != end, (*out_iter_type = ITER_TYPE_TARGET, end));
if (check_journal_iter(iter, &jiter))
{
*out_iter_type = ITER_TYPE_JOURNAL;
/* If jiter points to a next jiter we're somewhere inside a segment and
* that's well and good.
*
* Otherwise we reached the end of the segment and we return
* the iter the segment was attached before (which may have
* an override jiter, mind you). Or we wheren't in a segment to
* begin with */
if (jiter->next_iter)
{
return MODEL_ITER (jiter->next_iter);
}
else if (jiter->segment)
{
if (check_journal_iter (jiter->segment->target_iter, &jiter_next))
{
return MODEL_ITER (jiter_next);
}
else
{
*out_iter_type = ITER_TYPE_TARGET;
return jiter->segment->target_iter;
}
}
else
{
/* This was an overlay jiter, either CHANGE or REMOVE.
* We use the structure of the target model to step.
* If there's a segment before the next iter in the target model,
* step into the segment. Otherwise just step normally on the target
* */
g_assert (jiter->override_iter != NULL);
iter = dee_model_next (priv->target, jiter->override_iter);
jseg = get_journal_segment_before (iter);
if (jseg != NULL)
{
return MODEL_ITER (jseg->first_iter);
}
else
{
if (check_journal_iter (iter, &jiter_next))
{
return MODEL_ITER (jiter_next);
}
else
{
*out_iter_type = ITER_TYPE_TARGET;
return iter;
}
}
}
g_assert_not_reached ();
}
/* If we get here, then this was not a journal iter,
* but an unmodifed row from the target model */
/* We share end iter with the target model, so it's an error to hit that */
if (iter == end)
{
g_critical ("Trying to step past end of transaction model");
return iter;
}
/* If there's a segment before the next iter in the target model,
* step into the segment. Otherwise just step normally on the target */
iter = dee_model_next (priv->target, iter);
jseg = get_journal_segment_before (iter);
if (jseg != NULL)
{
*out_iter_type = ITER_TYPE_JOURNAL;
return MODEL_ITER (jseg->first_iter);
}
else
{
*out_iter_type = ITER_TYPE_TARGET;
return iter;
}
}
static DeeModelIter*
dee_transaction_get_first_iter (DeeModel *self)
{
DeeTransactionPrivate *priv;
JournalSegment *jseg;
JournalIter *jiter;
DeeModelIter *iter;
IterType itype;
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_return_val_if_fail (!dee_transaction_is_committed (AS_TXN (self)), NULL);
priv = DEE_TRANSACTION (self)->priv;
iter = dee_model_get_first_iter (priv->target);
if ((jseg = get_journal_segment_before (iter)) != NULL)
{
g_assert (jseg->first_iter != NULL);
itype = ITER_TYPE_JOURNAL;
jiter = jseg->first_iter;
iter = MODEL_ITER (jseg->first_iter);
}
else if (check_journal_iter (iter, &jiter))
{
/* Since iter is from the target, then jiter must
* be an overlay and not in a segment (ie. not an addition) */
g_assert (jiter->segment == NULL);
g_assert (jiter->override_iter == iter);
itype = ITER_TYPE_JOURNAL;
iter = MODEL_ITER (jiter);
}
else
{
/* The first target iter is untouched */
itype = ITER_TYPE_TARGET;
}
/* Now scan forwards until we have something which is not deleted.
* This is complicated by the fact that we may have attached segments
* before iters that have been marked removed */
while (itype == ITER_TYPE_JOURNAL && journal_iter_is_removed (jiter))
{
iter = dee_transaction_next_raw (self, iter, &itype);
if (itype == ITER_TYPE_JOURNAL)
{
jiter = JOURNAL_ITER (iter);
}
if ((jseg = get_journal_segment_before (iter)) != NULL)
{
return MODEL_ITER (jseg->first_iter);
}
}
/* Finally - for override iters (changes, this shouldn't be a removal),
* we return the original iter from the target model */
if (itype == ITER_TYPE_JOURNAL && jiter->override_iter != NULL)
{
g_assert (!journal_iter_is_removed (jiter));
iter = jiter->override_iter;
itype = ITER_TYPE_TARGET;
}
return iter;
}
static DeeModelIter*
dee_transaction_get_last_iter (DeeModel *self)
{
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_return_val_if_fail (!dee_transaction_is_committed (AS_TXN (self)), NULL);
/* We share end iter with the target model */
return dee_model_get_last_iter (DEE_TRANSACTION_TARGET (self));
}
// dee_transaction_get_iter_at_row () // Fall through to O(n) scan
static DeeModelIter*
dee_transaction_next (DeeModel *self,
DeeModelIter *iter)
{
DeeTransactionPrivate *priv;
IterType itype;
JournalIter *jiter;
JournalSegment *jseg;
// FIXME: Strictly - this method will work even if 'iter' has been marked
// removed. It might be nice to complain if anyone does this...
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_return_val_if_fail (!dee_transaction_is_committed (AS_TXN (self)), NULL);
priv = DEE_TRANSACTION (self)->priv;
iter = dee_transaction_next_raw (self, iter, &itype);
/* Now scan forwards until we have something which is not deleted.
* This is complicated by the fact that we may have attached segments
* before iters that have been marked removed */
jiter = JOURNAL_ITER (iter);
while (itype == ITER_TYPE_JOURNAL && journal_iter_is_removed (jiter))
{
iter = dee_transaction_next_raw (self, iter, &itype);
if (itype == ITER_TYPE_JOURNAL)
{
jiter = JOURNAL_ITER (iter);
}
if ((jseg = get_journal_segment_before (iter)) != NULL)
{
return MODEL_ITER (jseg->first_iter);
}
}
return iter;
}
static DeeModelIter*
dee_transaction_prev (DeeModel *self,
DeeModelIter *iter)
{
DeeTransactionPrivate *priv;
JournalIter *jiter, *jiter_prev;
JournalSegment *jseg;
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_return_val_if_fail (!dee_transaction_is_committed (AS_TXN (self)), NULL);
priv = DEE_TRANSACTION (self)->priv;
if (check_journal_iter(iter, &jiter))
{
if (jiter->prev_iter)
{
return MODEL_ITER (jiter->prev_iter);
}
else if (dee_model_is_first (priv->target, jiter->segment->target_iter))
{
g_critical ("Trying to step before beginning of transaction model");
return MODEL_ITER (jiter);
}
else
{
iter = dee_model_prev (priv->target, jiter->segment->target_iter);
if (check_journal_iter (iter, &jiter_prev))
return MODEL_ITER (jiter_prev);
else
return iter;
}
g_assert_not_reached ();
}
/* If there's a segment before the current iter in the target model,
* step into that segment. Otherwise just step normally on the target */
jseg = get_journal_segment_before (iter);
if (jseg != NULL)
return MODEL_ITER (jseg->last_iter);
else
return dee_model_prev (priv->target, iter);
}
/* Inherited methods */
// dee_transaction_is_first ()
// dee_transaction_is_last ()
// dee_transaction_get_position () // Generic O(n) traversal
static DeeModelTag*
dee_transaction_register_tag (DeeModel *self,
GDestroyNotify tag_destroy)
{
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
g_critical ("DeeTransaction models can not create new tags, "
"only re-use those of the target model");
return NULL;
}
static gpointer
dee_transaction_get_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag)
{
g_return_val_if_fail (DEE_IS_TRANSACTION (self), NULL);
// FIXME: Read through, or fetch from journal
g_error ("Not implemented");
return NULL;
}
static void
dee_transaction_set_tag (DeeModel *self,
DeeModelIter *iter,
DeeModelTag *tag,
gpointer value)
{
g_return_if_fail (DEE_IS_TRANSACTION (self));
// FIXME: Write through or to journal
g_error ("Not implemented");
}
/*
* Signal handlers on the target model.
* Used to detect concurrent changes - which we do not support
*/
static void
on_target_modified (DeeTransaction *self,
DeeModelIter *iter)
{
if (self->priv->error_code != DEE_TRANSACTION_ERROR_COMMITTED)
self->priv->error_code = DEE_TRANSACTION_ERROR_CONCURRENT_MODIFICATION;
}
/*
* PUBLIC API
*/
/**
* dee_transaction_new:
* @target: The #DeeModel the transaction applies against
*
* Returns: (transfer full) (type Dee.Transaction):
* A newly allocated #DeeTransaction. Free with g_object_unref() when
* done using it - no matter if you call dee_transaction_commit() or not.
*/
DeeModel*
dee_transaction_new (DeeModel *target)
{
g_return_val_if_fail (DEE_IS_MODEL (target), NULL);
return DEE_MODEL (g_object_new (DEE_TYPE_TRANSACTION,
"target", target,
NULL));
}
/**
* dee_transaction_get_target:
* @self: The transaction to retrieve the target model for
*
* Get the target model of a transaction. This is just a convenience method
* for accessing the :target property.
*
* Returns: (transfer none): The target model
*/
DeeModel*
dee_transaction_get_target (DeeTransaction *self)
{
g_return_val_if_fail (DEE_IS_TRANSACTION (self), FALSE);
return self->priv->target;
}
/**
* dee_transaction_is_committed:
* @self: The transaction to inspect
*
* Check if a #DeeTransaction has been committed. This method is mainly for
* debugging and testing purposes.
*
* Returns: %TRUE if and only if dee_transaction_commit() has completed
* successfully on the transaction.
*/
gboolean
dee_transaction_is_committed (DeeTransaction *self)
{
g_return_val_if_fail (DEE_IS_TRANSACTION (self), FALSE);
return self->priv->error_code == DEE_TRANSACTION_ERROR_COMMITTED;
}
static const gchar*
get_txn_error_string (guint error_code)
{
switch (error_code)
{
case DEE_TRANSACTION_ERROR_COMMITTED:
return "Already committed";
case DEE_TRANSACTION_ERROR_CONCURRENT_MODIFICATION:
return "Target model has been concurrently modified";
default:
return "Unknown error";
}
}
/**
* dee_transaction_commit:
* @self: The transaction to commit
* @error: (allow-none): Location to return a #GError in or %NULL to disregard
* errors
*
* Apply a transaction to its target model. After this call the transaction
* is invalidated and must be freed with g_object_unref().
*
* Returns: %TRUE if and only if the transaction successfully applies to :target.
*/
gboolean
dee_transaction_commit (DeeTransaction *self, GError **error)
{
DeeTransactionPrivate *priv;
JournalIter *jiter, *seg_iter, *free_jiter;
GSList *segments_to_free;
DeeModelIter *iter;
g_return_val_if_fail (DEE_IS_TRANSACTION (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
priv = self->priv;
if (priv->error_code != 0)
{
g_set_error (error,
DEE_TRANSACTION_ERROR,
priv->error_code,
"Error committing transaction. %s",
get_txn_error_string (priv->error_code));
return FALSE;
}
if (DEE_IS_SERIALIZABLE_MODEL (priv->target) &&
priv->begin_seqnum != dee_serializable_model_get_seqnum (priv->target))
{
g_set_error (error,
DEE_TRANSACTION_ERROR,
DEE_TRANSACTION_ERROR_CONCURRENT_MODIFICATION,
"Target model seqnum has changed during the transaction");
return FALSE;
}
/* Because we have many criss crossing references to the segments we need
* to collect them carefully to free all of them; and each only once! */
segments_to_free = NULL;
/* To avoid an extra traversal on finalize() we free the journal iters
* as we traverse them now. The txn is illegal after commit() by API
* contract anyway */
for (jiter = priv->first_playback; jiter != NULL; )
{
switch (jiter->change_type)
{
case CHANGE_TYPE_ADD:
/* We can commit the whole segment since a segment is comprised
* purely of additions */
if (jiter->segment->is_committed)
break;
for (seg_iter = jiter->segment->first_iter,
iter = jiter->segment->target_iter;
seg_iter;
seg_iter = seg_iter->next_iter)
{
dee_model_insert_row_before (priv->target,
iter,
seg_iter->row_data);
}
jiter->segment->is_committed = TRUE;
segments_to_free = g_slist_prepend (segments_to_free, jiter->segment);
break;
case CHANGE_TYPE_REMOVE:
dee_model_remove (priv->target, jiter->override_iter);
break;
case CHANGE_TYPE_CHANGE:
dee_model_set_row (priv->target,
jiter->override_iter,
jiter->row_data);
break;
default:
g_critical ("Unexpected change type %u", jiter->change_type);
break;
}
free_jiter = jiter;
jiter = jiter->next_playback;
journal_iter_free (free_jiter);
}
/* By now all jiters have been freed. Remaining is to free the segments */
g_slist_free_full (segments_to_free, (GDestroyNotify) journal_segment_free);
priv->first_playback = NULL;
priv->last_playback = NULL;
priv->error_code = DEE_TRANSACTION_ERROR_COMMITTED;
return TRUE;
}
GQuark
dee_transaction_error_quark (void)
{
return g_quark_from_static_string ("dee-transaction-error-quark");
}
dee-1.2.7+15.04.20150304/src/dee-glist-result-set.c 0000644 0000153 0000161 00000013775 12475676210 021551 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2009 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-glist-result-set
* @short_description: Internal API do not use
*
* GList implementation of a #DeeResultSet on top of a #GList
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include "dee-glist-result-set.h"
static void dee_glist_result_set_result_set_iface_init (DeeResultSetIface *iface);
G_DEFINE_TYPE_WITH_CODE (DeeGListResultSet,
dee_glist_result_set,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (DEE_TYPE_RESULT_SET,
dee_glist_result_set_result_set_iface_init))
#define DEE_GLIST_RESULT_SET_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE(obj, DEE_TYPE_GLIST_RESULT_SET, DeeGListResultSetPrivate))
typedef struct
{
GList *rows;
DeeModel *model;
GList *cursor;
GObject *row_owner;
guint pos;
guint n_rows;
gboolean n_rows_calculated;
} DeeGListResultSetPrivate;
/* GObject Init */
static void
dee_glist_result_set_finalize (GObject *object)
{
DeeGListResultSetPrivate *priv;
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (object);
if (priv->model)
g_object_unref (priv->model);
if (priv->row_owner)
g_object_unref (priv->row_owner);
G_OBJECT_CLASS (dee_glist_result_set_parent_class)->finalize (object);
}
static void
dee_glist_result_set_class_init (DeeGListResultSetClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
obj_class->finalize = dee_glist_result_set_finalize;
/* Add private data */
g_type_class_add_private (obj_class, sizeof (DeeGListResultSetPrivate));
}
static void
dee_glist_result_set_init (DeeGListResultSet *self)
{
DeeGListResultSetPrivate *priv;
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
priv->pos = 0;
priv->n_rows_calculated = FALSE;
}
static guint
dee_glist_result_set_get_n_rows (DeeResultSet *self)
{
DeeGListResultSetPrivate *priv;
g_return_val_if_fail (DEE_IS_GLIST_RESULT_SET (self), 0);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
if (!priv->n_rows_calculated)
{
priv->n_rows_calculated = TRUE;
priv->n_rows = g_list_length (priv->rows);
}
return priv->n_rows;
}
static DeeModelIter*
dee_glist_result_set_next (DeeResultSet *self)
{
DeeGListResultSetPrivate *priv;
DeeModelIter *next;
g_return_val_if_fail (DEE_IS_GLIST_RESULT_SET (self), NULL);
g_return_val_if_fail (dee_result_set_has_next (self), NULL);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
next = dee_result_set_peek (self);
priv->cursor = priv->cursor->next;
priv->pos++;
return next;
}
static gboolean
dee_glist_result_set_has_next (DeeResultSet *self)
{
DeeGListResultSetPrivate *priv;
g_return_val_if_fail (DEE_IS_GLIST_RESULT_SET (self), FALSE);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
return priv->cursor != NULL;
}
static DeeModelIter*
dee_glist_result_set_peek (DeeResultSet *self)
{
DeeGListResultSetPrivate *priv;
g_return_val_if_fail (DEE_IS_GLIST_RESULT_SET (self), NULL);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
if (priv->cursor == NULL)
return NULL;
return (DeeModelIter*) (priv->cursor->data);
}
static void
dee_glist_result_set_seek (DeeResultSet *self,
guint pos)
{
DeeGListResultSetPrivate *priv;
g_return_if_fail (DEE_IS_GLIST_RESULT_SET (self));
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
priv->cursor = g_list_nth (priv->rows, pos);
priv->pos = pos;
if (priv->cursor == NULL && pos != 0)
{
g_warning ("Illegal seek in DeeGListResultSet. Seeking 0");
priv->cursor = priv->rows;
priv->pos = 0;
}
}
static guint
dee_glist_result_set_tell (DeeResultSet *self)
{
DeeGListResultSetPrivate *priv;
g_return_val_if_fail (DEE_IS_GLIST_RESULT_SET (self), 0);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
return priv->pos;
}
static DeeModel*
dee_glist_result_set_get_model (DeeResultSet *self)
{
DeeGListResultSetPrivate *priv;
g_return_val_if_fail (DEE_IS_GLIST_RESULT_SET (self), NULL);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
return priv->model;
}
static void
dee_glist_result_set_result_set_iface_init (DeeResultSetIface *iface)
{
iface->get_n_rows = dee_glist_result_set_get_n_rows;
iface->next = dee_glist_result_set_next;
iface->has_next = dee_glist_result_set_has_next;
iface->peek = dee_glist_result_set_peek;
iface->seek = dee_glist_result_set_seek;
iface->tell = dee_glist_result_set_tell;
iface->get_model = dee_glist_result_set_get_model;
}
/* Internal constructor. Takes a ref on @model, @rows are implicitly reffed
* by reffing @row_owner. Row owner may be NULL, in which case we cross fingers
* and trust the caller that @rows are not freed */
DeeResultSet*
dee_glist_result_set_new (GList *rows,
DeeModel *model,
GObject *row_owner)
{
GObject *self;
DeeGListResultSetPrivate *priv;
self = g_object_new (DEE_TYPE_GLIST_RESULT_SET, NULL);
priv = DEE_GLIST_RESULT_SET_GET_PRIVATE (self);
priv->rows = rows;
priv->cursor = rows;
priv->model = g_object_ref (model);
if (row_owner != NULL)
priv->row_owner = g_object_ref (row_owner);
return (DeeResultSet*)self;
}
dee-1.2.7+15.04.20150304/src/dee-filter.c 0000644 0000153 0000161 00000044747 12475676210 017612 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by:
* Mikkel Kamstrup Erlandsen
*/
/**
* SECTION:dee-filter
* @title: Filters
* @short_description: A suite of simple #DeeFilters for use with #DeeFilterModels
* @include: dee.h
*
* #DeeFilters are used together with #DeeFilterModels to build
* "views" of some original #DeeModel. An example could be to build a view
* of a model that exposes the rows of the original model sorted by a given
* column (leaving the original model unaltered):
* |[
* DeeModel *model, *view;
* DeeFilter *collator;
*
* // Create and populate a model with some unsorted rows
* model = dee_sequence_model_new ();
* dee_model_set_schema (model, "i", "s", NULL);
* dee_model_append (model, 27, "Foo");
* dee_model_append (model, 68, "Bar");
*
* // Create a collator for column 1
* collator = dee_filter_new_collator (1);
*
* // Create the sorted view
* view = dee_filter_model_new (collator, model);
* g_free (collator);
*
* // When accessing the view the row with 'Bar' will be first
* ]|
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include // memset()
#include "dee-filter-model.h"
#include "dee-filter.h"
#include "trace-log.h"
typedef struct {
guint n_cols;
DeeCompareRowFunc cmp;
gpointer user_data;
GDestroyNotify destroy;
GVariant **row_buf;
} SortFilter;
/* The CollatorFilter stores collation keys for the columns in a DeeModelTag */
typedef struct {
guint column;
DeeModelTag *collation_key_tag;
} CollatorFilter;
typedef struct {
guint column;
gchar *key;
} KeyFilter;
typedef struct {
guint column;
GRegex *regex;
} RegexFilter;
typedef struct {
guint column;
GVariant *value;
} ValueFilter;
/*
* Private impl
*/
static gboolean
_dee_filter_sort_map_notify (DeeModel *orig_model,
DeeModelIter *orig_iter,
DeeFilterModel *filter_model,
gpointer user_data)
{
DeeModelIter *pos_iter;
SortFilter *filter;
guint i;
gboolean was_found;
g_return_val_if_fail (user_data != NULL, FALSE);
filter = (SortFilter *) user_data;
dee_model_get_row (orig_model, orig_iter, filter->row_buf);
pos_iter = dee_model_find_row_sorted (DEE_MODEL (filter_model),
filter->row_buf,
filter->cmp,
filter->user_data,
&was_found);
dee_filter_model_insert_iter_before (filter_model, orig_iter, pos_iter);
for (i = 0; i < filter->n_cols; i++) g_variant_unref (filter->row_buf[i]);
return was_found;
}
static void
_dee_filter_sort_map_func (DeeModel *orig_model,
DeeFilterModel *filter_model,
gpointer user_data)
{
DeeModelIter *iter, *end;
SortFilter *filter;
g_return_if_fail (user_data != NULL);
filter = (SortFilter *) user_data;
filter->n_cols = dee_model_get_n_columns (orig_model);
filter->row_buf = g_new0(GVariant*, filter->n_cols);
iter = dee_model_get_first_iter (orig_model);
end = dee_model_get_last_iter (orig_model);
while (iter != end)
{
_dee_filter_sort_map_notify (orig_model, iter, filter_model, filter);
iter = dee_model_next (orig_model, iter);
}
}
static gint
_cmp_collate_asc (GVariant **row1, GVariant **row2, gpointer user_data)
{
guint col = GPOINTER_TO_UINT (user_data);
return g_utf8_collate (g_variant_get_string (row1[col], NULL),
g_variant_get_string (row2[col], NULL));
}
static gint
_cmp_collate_desc (GVariant **row1, GVariant **row2, gpointer user_data)
{
guint col = GPOINTER_TO_UINT (user_data);
return - g_utf8_collate (g_variant_get_string (row1[col], NULL),
g_variant_get_string (row2[col], NULL));
}
static void
_dee_filter_key_map_func (DeeModel *orig_model,
DeeFilterModel *filter_model,
gpointer user_data)
{
DeeModelIter *iter, *end;
KeyFilter *filter;
guint column;
const gchar *key, *val;
g_return_if_fail (user_data != NULL);
filter = (KeyFilter *) user_data;
key = filter->key;
column = filter->column;
iter = dee_model_get_first_iter (orig_model);
end = dee_model_get_last_iter (orig_model);
while (iter != end)
{
val = dee_model_get_string (orig_model, iter, column);
if (g_strcmp0 (key, val) == 0)
{
dee_filter_model_append_iter (filter_model, iter);
}
iter = dee_model_next (orig_model, iter);
}
}
static gboolean
_dee_filter_key_map_notify (DeeModel *orig_model,
DeeModelIter *orig_iter,
DeeFilterModel *filter_model,
gpointer user_data)
{
KeyFilter *filter;
const gchar *val;
g_return_val_if_fail (user_data != NULL, FALSE);
filter = (KeyFilter *) user_data;
val = dee_model_get_string (orig_model, orig_iter, filter->column);
/* Ignore rows that don't match the key */
if (g_strcmp0 (filter->key, val) != 0)
return FALSE;
dee_filter_model_insert_iter_with_original_order (filter_model, orig_iter);
return TRUE;
}
static void
_dee_filter_value_map_func (DeeModel *orig_model,
DeeFilterModel *filter_model,
gpointer user_data)
{
DeeModelIter *iter, *end;
ValueFilter *filter;
GVariant *val;
g_return_if_fail (user_data != NULL);
filter = (ValueFilter *) user_data;
iter = dee_model_get_first_iter (orig_model);
end = dee_model_get_last_iter (orig_model);
while (iter != end)
{
val = dee_model_get_value (orig_model, iter, filter->column);
if (g_variant_equal (filter->value, val))
{
dee_filter_model_append_iter (filter_model, iter);
}
iter = dee_model_next (orig_model, iter);
}
}
static gboolean
_dee_filter_value_map_notify (DeeModel *orig_model,
DeeModelIter *orig_iter,
DeeFilterModel *filter_model,
gpointer user_data)
{
ValueFilter *filter;
GVariant *val;
g_return_val_if_fail (user_data != NULL, FALSE);
filter = (ValueFilter *) user_data;
val = dee_model_get_value (orig_model, orig_iter, filter->column);
/* Ignore rows that don't match the value */
if (!g_variant_equal (filter->value, val))
return FALSE;
dee_filter_model_insert_iter_with_original_order (filter_model, orig_iter);
return TRUE;
}
static void
_dee_filter_regex_map_func (DeeModel *orig_model,
DeeFilterModel *filter_model,
gpointer user_data)
{
DeeModelIter *iter, *end;
RegexFilter *filter;
guint column;
GRegex *regex;
const gchar *val;
g_return_if_fail (user_data != NULL);
filter = (RegexFilter *) user_data;
regex = filter->regex;
column = filter->column;
iter = dee_model_get_first_iter (orig_model);
end = dee_model_get_last_iter (orig_model);
while (iter != end)
{
val = dee_model_get_string (orig_model, iter, column);
if (g_regex_match (regex, val, 0, NULL))
{
dee_filter_model_append_iter (filter_model, iter);
}
iter = dee_model_next (orig_model, iter);
}
}
static gboolean
_dee_filter_regex_map_notify (DeeModel *orig_model,
DeeModelIter *orig_iter,
DeeFilterModel *filter_model,
gpointer user_data)
{
RegexFilter *filter;
const gchar *val;
g_return_val_if_fail (user_data != NULL, FALSE);
filter = (RegexFilter *) user_data;
val = dee_model_get_string (orig_model, orig_iter, filter->column);
/* Ignore rows that don't match the key */
if (!g_regex_match (filter->regex, val, 0, NULL))
return FALSE;
dee_filter_model_insert_iter_with_original_order (filter_model, orig_iter);
return TRUE;
}
static void
sort_filter_free (SortFilter *filter)
{
if (filter->destroy != NULL)
filter->destroy (filter->user_data);
g_free (filter->row_buf);
g_free (filter);
}
static void
key_filter_free (KeyFilter *filter)
{
g_free (filter->key);
g_free (filter);
}
static void
value_filter_free (ValueFilter *filter)
{
g_variant_unref (filter->value);
g_free (filter);
}
static void
regex_filter_free (RegexFilter *filter)
{
g_regex_unref (filter->regex);
g_free (filter);
}
/*
* API
*/
/**
* dee_filter_notify:
* @filter: The filter to apply
* @orig_iter: The #DeeModelIter added to @orig_model
* @orig_model: The model that is being filtered
* @filter_model: The #DeeFilterModel that holds the
* filtered subset of @orig_model
*
* Call the #DeeFilterMapNotify function of a #DeeFilter.
* When using a #DeeFilterModel you should not call this method yourself.
*
* Returns: The return value from the #DeeFilterMapNotify. That is; %TRUE
* if @orig_iter was added to @filter_model
*/
gboolean
dee_filter_notify (DeeFilter *filter,
DeeModelIter *orig_iter,
DeeModel *orig_model,
DeeFilterModel *filter_model)
{
g_return_val_if_fail (filter != NULL, FALSE);
return filter->map_notify (orig_model, orig_iter,
filter_model, filter->userdata);
}
/**
* dee_filter_map:
* @filter: The filter to apply
* @orig_model: The model that is being filtered
* @filter_model: The #DeeFilterModel that holds the
* filtered subset of @orig_model
*
* Call the #DeeFilterMapFunc function of a #DeeFilter.
* When using a #DeeFilterModel you should not call this method yourself.
*/
void
dee_filter_map (DeeFilter *filter,
DeeModel *orig_model,
DeeFilterModel *filter_model)
{
g_return_if_fail (filter != NULL);
filter->map_func (orig_model, filter_model, filter->userdata);
}
/**
* dee_filter_destroy:
* @filter: The filter to destroy
*
* Call the #GDestroyNotify function on the userdata pointer of a #DeeFilter
* (if the destroy member is set, that is).
*
* When using a #DeeFilterModel you should not call this method yourself.
*
* This method will not free the memory allocated for @filter.
*/
void
dee_filter_destroy (DeeFilter *filter)
{
g_return_if_fail (filter != NULL);
if (filter->destroy)
filter->destroy (filter->userdata);
}
/**
* dee_filter_new:
* @map_func: (scope notified): The #DeeFilterMapFunc to use for the filter
* @map_notify: (scope notified): The #DeeFilterMapNotify to use for the filter
* @userdata: (closure): The user data to pass to @map_func and @map_notify
* @destroy: (allow-none): The #GDestroyNotify to call on
* @userdata when disposing of the filter
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a new #DeeFilter with the given parameters. This call will zero
* the @out_filter struct.
*
*/
void
dee_filter_new (DeeFilterMapFunc map_func,
DeeFilterMapNotify map_notify,
gpointer userdata,
GDestroyNotify destroy,
DeeFilter *out_filter)
{
g_return_if_fail (map_func != NULL);
g_return_if_fail (map_notify != NULL);
g_return_if_fail (out_filter != NULL);
memset (out_filter, 0, sizeof (DeeFilter));
out_filter->map_func = map_func;
out_filter->map_notify = map_notify;
out_filter->userdata = userdata;
out_filter->destroy = destroy;
}
/**
* dee_filter_new_sort:
* @cmp_row: (scope notified): A #DeeCompareRowFunc to use for sorting
* @cmp_user_data: (closure): User data passed to @cmp_row
* @cmp_destroy: (allow-none): The #GDestroyNotify to call on
* @cmp_user_data when disposing of the filter
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a new #DeeFilter sorting a model according to a #DeeCompareRowFunc.
*
*/
void
dee_filter_new_sort (DeeCompareRowFunc cmp_row,
gpointer cmp_user_data,
GDestroyNotify cmp_destroy,
DeeFilter *out_filter)
{
SortFilter *filter;
filter = g_new0 (SortFilter, 1);
filter->cmp = cmp_row;
filter->user_data = cmp_user_data;
filter->destroy = cmp_destroy;
dee_filter_new (_dee_filter_sort_map_func,
_dee_filter_sort_map_notify,
filter,
(GDestroyNotify) sort_filter_free,
out_filter);
}
/**
* dee_filter_new_collator:
* @column: The index of a column containing the strings to sort after
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a #DeeFilter that takes string values from a column in the model
* and builds a #DeeFilterModel with the rows sorted according to the
* collation rules of the current locale.
*/
void
dee_filter_new_collator (guint column,
DeeFilter *out_filter)
{
dee_filter_new_sort (_cmp_collate_asc, GUINT_TO_POINTER (column),
NULL, out_filter);
}
/**
* dee_filter_new_collator_desc:
* @column: The index of a column containing the strings to sort after
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a #DeeFilter that takes string values from a column in the model
* and builds a #DeeFilterModel with the rows sorted descending according to the
* collation rules of the current locale.
*/
void
dee_filter_new_collator_desc (guint column,
DeeFilter *out_filter)
{
dee_filter_new_sort (_cmp_collate_desc, GUINT_TO_POINTER (column),
NULL, out_filter);
}
/**
* dee_filter_new_for_key_column:
* @column: The index of a column containing the string key to match
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a #DeeFilter that only includes rows from the original model
* which has an exact match on some string column. A #DeeFilterModel created
* with this filter will be ordered in accordance with its parent model.
*/
void
dee_filter_new_for_key_column (guint column,
const gchar *key,
DeeFilter *out_filter)
{
KeyFilter *key_filter;
g_return_if_fail (key != NULL);
key_filter = g_new0 (KeyFilter, 1);
key_filter->column = column;
key_filter->key = g_strdup (key);
dee_filter_new (_dee_filter_key_map_func,
_dee_filter_key_map_notify,
key_filter,
(GDestroyNotify) key_filter_free,
out_filter);
}
/**
* dee_filter_new_for_any_column:
* @column: The index of a column containing the string to match
* @value: (transfer none): A #GVariant value columns must match exactly.
* The matching semantics are those of g_variant_equal(). If @value
* is floating the ownership will be transfered to the filter
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a #DeeFilter that only includes rows from the original model
* which match a variant value in a given column. A #DeeFilterModel
* created with this filter will be ordered in accordance with its parent model.
*
* This method will work on any column, disregarding its schema, since the
* value comparison is done using g_variant_equal(). This means you can use
* this filter as a convenient fallback when there is no predefined filter
* for your column type if raw performance is not paramount.
*/
void
dee_filter_new_for_any_column (guint column,
GVariant *value,
DeeFilter *out_filter)
{
ValueFilter *v_filter;
g_return_if_fail (value != NULL);
v_filter = g_new0 (ValueFilter, 1);
v_filter->column = column;
v_filter->value = g_variant_ref_sink (value);
dee_filter_new (_dee_filter_value_map_func,
_dee_filter_value_map_notify,
v_filter,
(GDestroyNotify) value_filter_free,
out_filter);
}
/**
* dee_filter_new_regex:
* @column: The index of a column containing the string to match
* @regex: (transfer none):The regular expression @column must match
* @out_filter: (out): A pointer to an uninitialized #DeeFilter struct.
* This struct will zeroed and configured with the filter
* parameters
*
* Create a #DeeFilter that only includes rows from the original model
* which match a regular expression on some string column. A #DeeFilterModel
* created with this filter will be ordered in accordance with its parent model.
*/
void
dee_filter_new_regex (guint column,
GRegex *regex,
DeeFilter *out_filter)
{
RegexFilter *r_filter;
g_return_if_fail (regex != NULL);
r_filter = g_new0 (RegexFilter, 1);
r_filter->column = column;
r_filter->regex = g_regex_ref (regex);
dee_filter_new (_dee_filter_regex_map_func,
_dee_filter_regex_map_notify,
r_filter,
(GDestroyNotify) regex_filter_free,
out_filter);
}
dee-1.2.7+15.04.20150304/src/dee-icu-term-filter.c 0000644 0000153 0000161 00000017067 12475676210 021330 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* 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 version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
*