diff -Nru libgom-0.3.3/bindings/python/meson.build libgom-0.4/bindings/python/meson.build --- libgom-0.3.3/bindings/python/meson.build 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/bindings/python/meson.build 2020-02-17 19:00:10.000000000 +0000 @@ -1,10 +1,10 @@ -python3 = import('python3').find_python() +pygobject_override_dir = get_option('pygobject-override-dir') get_overridedir = ''' import os import sysconfig -libdir = sysconfig.get_config_var('LIBDIR') +libdir = sysconfig.get_config_var('SCRIPTDIR') if not libdir: libdir = '/usr/lib' @@ -22,12 +22,17 @@ print(overridedir) ''' -ret = run_command([python3, '-c', get_overridedir]) +if pygobject_override_dir == '' + python3 = import('python3').find_python() + + ret = run_command([python3, '-c', get_overridedir]) + + if ret.returncode() != 0 + error('Failed to determine pygobject override directory') + else + pygobject_override_dir = join_paths(get_option('libdir'), ret.stdout().strip()) + endif -if ret.returncode() != 0 - error('Failed to determine pygobject overridedir') -else - pygobject_override_dir = join_paths(get_option('libdir'), ret.stdout().strip()) endif install_data('gi/overrides/Gom.py', install_dir: pygobject_override_dir) diff -Nru libgom-0.3.3/debian/changelog libgom-0.4/debian/changelog --- libgom-0.3.3/debian/changelog 2018-12-28 02:26:02.000000000 +0000 +++ libgom-0.4/debian/changelog 2020-03-02 12:57:22.000000000 +0000 @@ -1,3 +1,15 @@ +libgom (0.4-1) unstable; urgency=medium + + * New upstream release + - Bump build-dependency against meson + * debian/control.in: Bump Standards-Version to 4.5.0 (no further changes) + * Bump debherlper version to 12 + * debian/control.in Add libglib2.0-doc to B-D-I and mark the -doc package + with Build-Profiles: + * debian/control.in: Add Rules-Requires-Root: no + + -- Laurent Bigonville Mon, 02 Mar 2020 13:57:22 +0100 + libgom (0.3.3-5) unstable; urgency=medium * Add dh_makeshlibs -- -c4 diff -Nru libgom-0.3.3/debian/compat libgom-0.4/debian/compat --- libgom-0.3.3/debian/compat 2018-12-28 02:26:02.000000000 +0000 +++ libgom-0.4/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -11 diff -Nru libgom-0.3.3/debian/control libgom-0.4/debian/control --- libgom-0.3.3/debian/control 2018-12-28 02:26:02.000000000 +0000 +++ libgom-0.4/debian/control 2020-03-02 12:57:22.000000000 +0000 @@ -7,7 +7,7 @@ Priority: optional Maintainer: Debian GNOME Maintainers Uploaders: Jeremy Bicha , Laurent Bigonville , Michael Biebl -Build-Depends: debhelper (>= 11), +Build-Depends: debhelper-compat (= 12), gnome-pkg-tools, gobject-introspection, gtk-doc-tools, @@ -16,10 +16,12 @@ libgirepository1.0-dev, libglib2.0-dev (>= 2.36), libsqlite3-dev (>= 3.7), - meson (>= 0.38.1), + meson (>= 0.48), python-gi-dev, python3 (>= 3.4) -Standards-Version: 4.3.0 +Build-Depends-Indep: libglib2.0-doc +Standards-Version: 4.5.0 +Rules-Requires-Root: no Homepage: https://wiki.gnome.org/Projects/Gom Vcs-Browser: https://salsa.debian.org/gnome-team/libgom Vcs-Git: https://salsa.debian.org/gnome-team/libgom.git @@ -58,6 +60,7 @@ Architecture: all Multi-Arch: foreign Depends: ${misc:Depends} +Build-Profiles: Description: libgom API documentation Gom provides an object mapper from GObjects to SQLite. It helps you write applications that need to store structured data diff -Nru libgom-0.3.3/debian/control.in libgom-0.4/debian/control.in --- libgom-0.3.3/debian/control.in 2018-12-28 02:26:02.000000000 +0000 +++ libgom-0.4/debian/control.in 2020-03-02 12:57:22.000000000 +0000 @@ -3,7 +3,7 @@ Priority: optional Maintainer: Debian GNOME Maintainers Uploaders: @GNOME_TEAM@ -Build-Depends: debhelper (>= 11), +Build-Depends: debhelper-compat (= 12), gnome-pkg-tools, gobject-introspection, gtk-doc-tools, @@ -12,10 +12,12 @@ libgirepository1.0-dev, libglib2.0-dev (>= 2.36), libsqlite3-dev (>= 3.7), - meson (>= 0.38.1), + meson (>= 0.48), python-gi-dev, python3 (>= 3.4) -Standards-Version: 4.3.0 +Build-Depends-Indep: libglib2.0-doc +Standards-Version: 4.5.0 +Rules-Requires-Root: no Homepage: https://wiki.gnome.org/Projects/Gom Vcs-Browser: https://salsa.debian.org/gnome-team/libgom Vcs-Git: https://salsa.debian.org/gnome-team/libgom.git @@ -54,6 +56,7 @@ Architecture: all Multi-Arch: foreign Depends: ${misc:Depends} +Build-Profiles: Description: libgom API documentation Gom provides an object mapper from GObjects to SQLite. It helps you write applications that need to store structured data diff -Nru libgom-0.3.3/gom/gom-command.c libgom-0.4/gom/gom-command.c --- libgom-0.3.3/gom/gom-command.c 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/gom/gom-command.c 2020-02-17 19:00:10.000000000 +0000 @@ -106,13 +106,13 @@ break; default: if (G_VALUE_TYPE(value) == G_TYPE_DATE_TIME) { - GTimeVal tv = { 0 }; GDateTime *dt = g_value_get_boxed(value); - gchar *iso8601; + gchar *iso8601 = NULL; if (dt) { + GTimeVal tv = { 0 }; g_date_time_to_timeval(dt, &tv); + iso8601 = g_time_val_to_iso8601(&tv); } - iso8601 = g_time_val_to_iso8601(&tv); sqlite3_bind_text(priv->stmt, param, iso8601, -1, g_free); break; } else if (G_VALUE_TYPE(value) == G_TYPE_STRV) { diff -Nru libgom-0.3.3/gom/gom-cursor.c libgom-0.4/gom/gom-cursor.c --- libgom-0.3.3/gom/gom-cursor.c 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/gom/gom-cursor.c 2020-02-17 19:00:10.000000000 +0000 @@ -86,13 +86,13 @@ break; default: if (G_VALUE_TYPE(value) == G_TYPE_DATE_TIME) { - GTimeVal tv = { 0 }; - GDateTime *dt; const gchar *iso8601 = (gchar *)sqlite3_column_text(priv->stmt, column); + GDateTime *dt = NULL; if (iso8601) { + GTimeVal tv = { 0 }; g_time_val_from_iso8601(iso8601, &tv); + dt = g_date_time_new_from_timeval_utc(&tv); } - dt = g_date_time_new_from_timeval_utc(&tv); g_value_take_boxed(value, dt); break; } diff -Nru libgom-0.3.3/gom/gom-resource.c libgom-0.4/gom/gom-resource.c --- libgom-0.3.3/gom/gom-resource.c 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/gom/gom-resource.c 2020-02-17 19:00:10.000000000 +0000 @@ -26,6 +26,7 @@ #include "gom-repository.h" #include "gom-resource.h" #include "gom-resource-priv.h" +#include "reserved-keywords.h" G_DEFINE_ABSTRACT_TYPE(GomResource, gom_resource, G_TYPE_OBJECT) @@ -200,6 +201,19 @@ g_strdup(ref_property_name), g_free); } +static gboolean +is_valid_table_name (const gchar *table) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (reserved_keywords); i++) { + if (g_ascii_strcasecmp (reserved_keywords[i], table) == 0) + return FALSE; + } + + return TRUE; +} + void gom_resource_class_set_table (GomResourceClass *resource_class, const gchar *table) @@ -207,6 +221,7 @@ g_return_if_fail(GOM_IS_RESOURCE_CLASS(resource_class)); g_return_if_fail(table != NULL); g_return_if_fail(strlen(table) <= sizeof(resource_class->table)); + g_return_if_fail(is_valid_table_name(table)); g_snprintf(resource_class->table, sizeof(resource_class->table), @@ -1033,6 +1048,36 @@ } } +static void +pkey_changed_cb (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + GomResource *resource = (GomResource *) gobject; + + /* Did the developer reset the primary key? */ + if (!has_primary_key(GOM_RESOURCE(resource))) { + resource->priv->is_from_table = FALSE; + } +} + +static void +gom_resource_constructed (GObject *object) +{ + char *pkey_signal; + GomResourceClass *klass; + + /* Monitor the primary key */ + klass = GOM_RESOURCE_CLASS (G_OBJECT_GET_CLASS(object)); + g_assert (klass->primary_key[0] != '\0'); + pkey_signal = g_strdup_printf("notify::%s", klass->primary_key); + g_signal_connect (G_OBJECT (object), pkey_signal, + G_CALLBACK (pkey_changed_cb), NULL); + g_free(pkey_signal); + + G_OBJECT_CLASS (gom_resource_parent_class)->constructed (object); +} + /** * gom_resource_class_init: * @klass: (in): A #GomResourceClass. @@ -1048,6 +1093,7 @@ object_class->finalize = gom_resource_finalize; object_class->get_property = gom_resource_get_property; object_class->set_property = gom_resource_set_property; + object_class->constructed = gom_resource_constructed; g_type_class_add_private(object_class, sizeof(GomResourcePrivate)); gParamSpecs[PROP_REPOSITORY] = @@ -1060,19 +1106,6 @@ gParamSpecs[PROP_REPOSITORY]); } -static void -pkey_changed_cb (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) -{ - GomResource *resource = (GomResource *) gobject; - - /* Did the developer reset the primary key? */ - if (!has_primary_key(GOM_RESOURCE(resource))) { - resource->priv->is_from_table = FALSE; - } -} - /** * gom_resource_init: * @resource: (in): A #GomResource. @@ -1082,20 +1115,10 @@ static void gom_resource_init (GomResource *resource) { - char *pkey_signal; - GomResourceClass *klass; - resource->priv = G_TYPE_INSTANCE_GET_PRIVATE(resource, GOM_TYPE_RESOURCE, GomResourcePrivate); - - /* Monitor the primary key */ - klass = GOM_RESOURCE_CLASS (G_OBJECT_GET_CLASS(resource)); - pkey_signal = g_strdup_printf("notify::%s", klass->primary_key); - g_signal_connect (G_OBJECT (resource), pkey_signal, - G_CALLBACK (pkey_changed_cb), NULL); - g_free(pkey_signal); } gboolean diff -Nru libgom-0.3.3/gom/meson.build libgom-0.4/gom/meson.build --- libgom-0.3.3/gom/meson.build 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/gom/meson.build 2020-02-17 19:00:10.000000000 +0000 @@ -28,6 +28,7 @@ gom_private_headers = [ 'gom-resource-priv.h', + 'reserved-keywords.h', ] install_headers(gom_headers, diff -Nru libgom-0.3.3/gom/reserved-keywords.h libgom-0.4/gom/reserved-keywords.h --- libgom-0.3.3/gom/reserved-keywords.h 1970-01-01 00:00:00.000000000 +0000 +++ libgom-0.4/gom/reserved-keywords.h 2020-02-17 19:00:10.000000000 +0000 @@ -0,0 +1,130 @@ +/* Partially generated with the very brittle: + * for i in `wget -O- https://sqlite.org/lang_keywords.html | grep '
  • ' | sed 's,
  • ,,' | sed 's,
  • ,,' | grep -v '<'` ; do printf '\t"%s",\n' $i >> gom/reserved-keywords.h ; done + */ + +static const char* reserved_keywords[] = { + "ABORT", + "ACTION", + "ADD", + "AFTER", + "ALL", + "ALTER", + "ANALYZE", + "AND", + "AS", + "ASC", + "ATTACH", + "AUTOINCREMENT", + "BEFORE", + "BEGIN", + "BETWEEN", + "BY", + "CASCADE", + "CASE", + "CAST", + "CHECK", + "COLLATE", + "COLUMN", + "COMMIT", + "CONFLICT", + "CONSTRAINT", + "CREATE", + "CROSS", + "CURRENT_DATE", + "CURRENT_TIME", + "CURRENT_TIMESTAMP", + "DATABASE", + "DEFAULT", + "DEFERRABLE", + "DEFERRED", + "DELETE", + "DESC", + "DETACH", + "DISTINCT", + "DROP", + "EACH", + "ELSE", + "END", + "ESCAPE", + "EXCEPT", + "EXCLUSIVE", + "EXISTS", + "EXPLAIN", + "FAIL", + "FOR", + "FOREIGN", + "FROM", + "FULL", + "GLOB", + "GROUP", + "HAVING", + "IF", + "IGNORE", + "IMMEDIATE", + "IN", + "INDEX", + "INDEXED", + "INITIALLY", + "INNER", + "INSERT", + "INSTEAD", + "INTERSECT", + "INTO", + "IS", + "ISNULL", + "JOIN", + "KEY", + "LEFT", + "LIKE", + "LIMIT", + "MATCH", + "NATURAL", + "NO", + "NOT", + "NOTNULL", + "NULL", + "OF", + "OFFSET", + "ON", + "OR", + "ORDER", + "OUTER", + "PLAN", + "PRAGMA", + "PRIMARY", + "QUERY", + "RAISE", + "RECURSIVE", + "REFERENCES", + "REGEXP", + "REINDEX", + "RELEASE", + "RENAME", + "REPLACE", + "RESTRICT", + "RIGHT", + "ROLLBACK", + "ROW", + "SAVEPOINT", + "SELECT", + "SET", + "TABLE", + "TEMP", + "TEMPORARY", + "THEN", + "TO", + "TRANSACTION", + "TRIGGER", + "UNION", + "UNIQUE", + "UPDATE", + "USING", + "VACUUM", + "VALUES", + "VIEW", + "VIRTUAL", + "WHEN", + "WHERE", + "WITH", + "WITHOUT" +}; diff -Nru libgom-0.3.3/gom.doap libgom-0.4/gom.doap --- libgom-0.3.3/gom.doap 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/gom.doap 2020-02-17 19:00:10.000000000 +0000 @@ -5,12 +5,13 @@ xmlns="http://usefulinc.com/ns/doap#"> Gom + A GObject to SQLite object mapper. A GObject to SQLite object mapper. - + - + @@ -19,4 +20,11 @@ chergert + + + Bastien Nocera + + hadess + + diff -Nru libgom-0.3.3/meson.build libgom-0.4/meson.build --- libgom-0.3.3/meson.build 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/meson.build 2020-02-17 19:00:10.000000000 +0000 @@ -1,7 +1,7 @@ project('gom', 'c', - version: '0.3.3', + version: '0.4', license: 'LGPL-2.1+', - meson_version: '>= 0.38.1') + meson_version: '>= 0.48') version = meson.project_version().split('.') soversion = 0 diff -Nru libgom-0.3.3/meson_options.txt libgom-0.4/meson_options.txt --- libgom-0.3.3/meson_options.txt 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/meson_options.txt 2020-02-17 19:00:10.000000000 +0000 @@ -1,2 +1,3 @@ option('enable-gtk-doc', type: 'boolean', value: false, description: 'Enable generating the API reference') option('enable-introspection', type: 'boolean', value: true, description: 'Enable GObject Introspection') +option('pygobject-override-dir', type : 'string', value : '', description: 'Path to pygobject overrides directory') diff -Nru libgom-0.3.3/NEWS libgom-0.4/NEWS --- libgom-0.3.3/NEWS 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/NEWS 2020-02-17 19:00:10.000000000 +0000 @@ -1,5 +1,14 @@ Major changes in version +0.4 +--- +- Fix primary-keys never being monitored, which triggered crashes + with GLib 2.63 +- Test for invalid table names +- Install Python overrides in correct location +- Fix storage of NULL GDateTime values +- Fix constraints test under older versions of SQLite + 0.3.3 ----- - Replace hardcoded values in pkg-config file diff -Nru libgom-0.3.3/tests/meson.build libgom-0.4/tests/meson.build --- libgom-0.3.3/tests/meson.build 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/tests/meson.build 2020-02-17 19:00:10.000000000 +0000 @@ -6,7 +6,9 @@ 'test-gom-migration', 'test-gom-repository', 'test-gom-sorting', + 'test-gom-table-name', 'test-gom-update', + 'test-gom-datetime', ] foreach test_name: tests diff -Nru libgom-0.3.3/tests/test-gom-constraints.c libgom-0.4/tests/test-gom-constraints.c --- libgom-0.3.3/tests/test-gom-constraints.c 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/tests/test-gom-constraints.c 2020-02-17 19:00:10.000000000 +0000 @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -229,8 +230,8 @@ NULL); gom_resource_save_sync(GOM_RESOURCE(item), &error); g_assert_error(error, GOM_ERROR, GOM_ERROR_COMMAND_SQLITE); - g_assert (strstr (error->message, "UNIQUE") != NULL); - g_assert (strstr (error->message, "items.email") != NULL); + g_assert (strcasestr (error->message, "UNIQUE") != NULL); + g_assert (strstr (error->message, "email") != NULL); g_object_unref(item); g_clear_error(&error); @@ -266,8 +267,8 @@ NULL); gom_resource_save_sync(GOM_RESOURCE(item), &error); g_assert_error(error, GOM_ERROR, GOM_ERROR_COMMAND_SQLITE); - g_assert (strstr (error->message, "NOT NULL") != NULL); - g_assert (strstr (error->message, "items.name") != NULL); + g_assert (strstr (error->message, "NULL") != NULL); + g_assert (strstr (error->message, "name") != NULL); g_clear_error(&error); g_object_unref(item); @@ -277,8 +278,8 @@ NULL); gom_resource_save_sync(GOM_RESOURCE(item), &error); g_assert_error(error, GOM_ERROR, GOM_ERROR_COMMAND_SQLITE); - g_assert (strstr (error->message, "NOT NULL") != NULL); - g_assert (strstr (error->message, "items.email") != NULL); + g_assert (strstr (error->message, "NULL") != NULL); + g_assert (strstr (error->message, "email") != NULL); g_clear_error(&error); g_object_unref(item); diff -Nru libgom-0.3.3/tests/test-gom-datetime.c libgom-0.4/tests/test-gom-datetime.c --- libgom-0.3.3/tests/test-gom-datetime.c 1970-01-01 00:00:00.000000000 +0000 +++ libgom-0.4/tests/test-gom-datetime.c 2020-02-17 19:00:10.000000000 +0000 @@ -0,0 +1,252 @@ +/* Copied from test-gom-update.c */ + +#include +#include + +/* Common for both resource objects */ + +enum { + PROP_0, + PROP_ID, + PROP_START, + PROP_END, + LAST_PROP +}; + +/* ItemResource object */ + +#define ITEM_TYPE_RESOURCE (item_resource_get_type()) +#define ITEM_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ITEM_TYPE_RESOURCE, ItemResource)) +#define ITEM_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ITEM_TYPE_RESOURCE, ItemResourceClass)) +#define ITEM_IS_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ITEM_TYPE_RESOURCE)) +#define ITEM_IS_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ITEM_TYPE_RESOURCE)) +#define ITEM_RESOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ITEM_TYPE_RESOURCE, ItemResourceClass)) + +typedef struct { + char *id; + GDateTime *start; + GDateTime *end; +} ItemResourcePrivate; + +typedef struct { + GomResource parent; + ItemResourcePrivate *priv; +} ItemResource; + +typedef struct { + GomResourceClass parent_class; +} ItemResourceClass; + +GType item_resource_get_type(void); + +G_DEFINE_TYPE(ItemResource, item_resource, GOM_TYPE_RESOURCE) + +static GParamSpec *item_specs[LAST_PROP]; + +static void +item_resource_finalize (GObject *object) +{ + ItemResource *resource = ITEM_RESOURCE(object); + g_clear_pointer(&resource->priv->id, g_free); + g_clear_pointer(&resource->priv->start, g_date_time_unref); + g_clear_pointer(&resource->priv->end, g_date_time_unref); +} + +static void +item_resource_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ItemResource *resource = ITEM_RESOURCE(object); + + switch (prop_id) { + case PROP_ID: + g_value_set_string(value, resource->priv->id); + break; + case PROP_START: + g_value_set_boxed(value, resource->priv->start); + break; + case PROP_END: + g_value_set_boxed(value, resource->priv->end); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +item_resource_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ItemResource *resource = ITEM_RESOURCE(object); + + switch (prop_id) { + case PROP_ID: + g_clear_pointer(&resource->priv->id, g_free); + resource->priv->id = g_value_dup_string(value); + break; + case PROP_START: + g_clear_pointer(&resource->priv->start, g_free); + resource->priv->start = g_date_time_ref (g_value_get_boxed(value)); + break; + case PROP_END: { + g_clear_pointer(&resource->priv->end, g_free); + + gpointer boxed = g_value_get_boxed(value); + if (boxed) + { + resource->priv->end = g_date_time_ref (boxed); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +item_resource_class_init (ItemResourceClass *klass) +{ + GObjectClass *object_class; + GomResourceClass *resource_class; + + object_class = G_OBJECT_CLASS(klass); + object_class->finalize = item_resource_finalize; + object_class->get_property = item_resource_get_property; + object_class->set_property = item_resource_set_property; + g_type_class_add_private(object_class, sizeof(ItemResourcePrivate)); + + resource_class = GOM_RESOURCE_CLASS(klass); + gom_resource_class_set_table(resource_class, "items"); + + item_specs[PROP_ID] = g_param_spec_string("id", + "ID", + "The ID for the item.", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_ID, + item_specs[PROP_ID]); + gom_resource_class_set_primary_key(resource_class, "id"); + + item_specs[PROP_START] = g_param_spec_boxed("start", + "Start", + "The start point of the item.", + G_TYPE_DATE_TIME, + G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_START, + item_specs[PROP_START]); + + item_specs[PROP_END] = g_param_spec_boxed("end", + "End", + "The end point for the item.", + G_TYPE_DATE_TIME, + G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_END, + item_specs[PROP_END]); +} + +static void +item_resource_init (ItemResource *resource) +{ + resource->priv = G_TYPE_INSTANCE_GET_PRIVATE(resource, + ITEM_TYPE_RESOURCE, + ItemResourcePrivate); +} + +static void +update (void) +{ + GomAdapter *adapter; + GError *error = NULL; + gboolean ret; + GomRepository *repository; + GList *object_types; + ItemResource *it; + GTimeVal tv = { 0 }; + gchar *iso8601; + GDateTime *start, *end; + GValue value = { 0, }; + GomFilter *filter; + + adapter = gom_adapter_new(); + //ret = gom_adapter_open_sync(adapter, "file:test.db", &error); + ret = gom_adapter_open_sync(adapter, ":memory:", &error); + g_assert_no_error(error); + g_assert(ret); + + repository = gom_repository_new(adapter); + + object_types = g_list_prepend(NULL, GINT_TO_POINTER(ITEM_TYPE_RESOURCE)); + ret = gom_repository_automatic_migrate_sync(repository, 1, object_types, &error); + g_assert_no_error(error); + g_assert(ret); + + + iso8601 = g_time_val_to_iso8601(&tv); + g_assert_cmpstr(iso8601, ==, "1970-01-01T00:00:00Z"); + g_free (iso8601); + + start = g_date_time_new_from_timeval_utc(&tv); + g_assert(g_date_time_to_unix(start) == 0); + + it = g_object_new (ITEM_TYPE_RESOURCE, + "repository", repository, + "id", "My identifier", + "start", start, + "end", NULL, + NULL); + ret = gom_resource_save_sync(GOM_RESOURCE(it), &error); + g_assert(ret); + g_assert_no_error(error); + + g_object_unref(it); + g_date_time_unref(start); + + + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, "My identifier"); + filter = gom_filter_new_eq(ITEM_TYPE_RESOURCE, "id", &value); + g_value_unset(&value); + + it = ITEM_RESOURCE (gom_repository_find_one_sync(repository, + ITEM_TYPE_RESOURCE, + filter, + &error)); + g_assert_no_error(error); + g_assert(it); + g_object_unref(filter); + + g_object_get(it, + "start", &start, + "end", &end, + NULL); + g_object_unref(it); + + g_date_time_to_timeval(start, &tv); + g_date_time_unref (start); + + iso8601 = g_time_val_to_iso8601(&tv); + g_assert_cmpstr(iso8601, ==, "1970-01-01T00:00:00Z"); + g_free (iso8601); + + g_assert(end == NULL); + + + ret = gom_adapter_close_sync(adapter, &error); + g_assert_no_error(error); + g_assert(ret); + + g_object_unref(repository); + g_object_unref(adapter); +} + +gint +main (int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/GomRepository/datetime", update); + return g_test_run(); +} diff -Nru libgom-0.3.3/tests/test-gom-stress.c libgom-0.4/tests/test-gom-stress.c --- libgom-0.3.3/tests/test-gom-stress.c 2017-06-21 14:41:17.000000000 +0000 +++ libgom-0.4/tests/test-gom-stress.c 2020-02-17 19:00:10.000000000 +0000 @@ -37,7 +37,7 @@ LAST_PROP }; -#define NUM_RECORDS 100000 +#define NUM_RECORDS 15000 #define ITEM_TO_GET (NUM_RECORDS/2) static GParamSpec *specs[LAST_PROP]; diff -Nru libgom-0.3.3/tests/test-gom-table-name.c libgom-0.4/tests/test-gom-table-name.c --- libgom-0.3.3/tests/test-gom-table-name.c 1970-01-01 00:00:00.000000000 +0000 +++ libgom-0.4/tests/test-gom-table-name.c 2020-02-17 19:00:10.000000000 +0000 @@ -0,0 +1,228 @@ +#include +#include + +enum { + PROP_0, + PROP_ID, + PROP_FIRST_NAME, + PROP_SURNAME, + LAST_PROP +}; + +#define ITEM_TYPE_RESOURCE (item_resource_get_type()) +#define ITEM_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ITEM_TYPE_RESOURCE, ItemResource)) +#define ITEM_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ITEM_TYPE_RESOURCE, ItemResourceClass)) +#define ITEM_IS_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ITEM_TYPE_RESOURCE)) +#define ITEM_IS_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ITEM_TYPE_RESOURCE)) +#define ITEM_RESOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ITEM_TYPE_RESOURCE, ItemResourceClass)) + +typedef struct { + int id; + char *first_name; + char *surname; +} ItemResourcePrivate; + +typedef struct { + GomResource parent; + ItemResourcePrivate *priv; +} ItemResource; + +typedef struct { + GomResourceClass parent_class; +} ItemResourceClass; + +GType item_resource_get_type(void); + +G_DEFINE_TYPE(ItemResource, item_resource, GOM_TYPE_RESOURCE) + +static GParamSpec *item_specs[LAST_PROP]; + +static void +item_resource_finalize (GObject *object) +{ + ItemResource *resource = ITEM_RESOURCE(object); + g_clear_pointer(&resource->priv->first_name, g_free); + g_clear_pointer(&resource->priv->surname, g_free); +} + +static void +item_resource_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ItemResource *resource = ITEM_RESOURCE(object); + + switch (prop_id) { + case PROP_ID: + g_value_set_int(value, resource->priv->id); + break; + case PROP_FIRST_NAME: + g_value_set_string(value, resource->priv->first_name); + break; + case PROP_SURNAME: + g_value_set_string(value, resource->priv->surname); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +item_resource_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ItemResource *resource = ITEM_RESOURCE(object); + + switch (prop_id) { + case PROP_ID: + resource->priv->id = g_value_get_int(value); + break; + case PROP_FIRST_NAME: + g_clear_pointer(&resource->priv->first_name, g_free); + resource->priv->first_name = g_value_dup_string(value); + break; + case PROP_SURNAME: + g_clear_pointer(&resource->priv->surname, g_free); + resource->priv->surname = g_value_dup_string(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +item_resource_class_init (ItemResourceClass *klass) +{ + GObjectClass *object_class; + GomResourceClass *resource_class; + + object_class = G_OBJECT_CLASS(klass); + object_class->finalize = item_resource_finalize; + object_class->get_property = item_resource_get_property; + object_class->set_property = item_resource_set_property; + g_type_class_add_private(object_class, sizeof(ItemResourcePrivate)); + + resource_class = GOM_RESOURCE_CLASS(klass); + /* Invalid table name */ + gom_resource_class_set_table(resource_class, "insert"); + + item_specs[PROP_ID] = g_param_spec_int("id", + "ID", + "The ID for the item.", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_ID, + item_specs[PROP_ID]); + gom_resource_class_set_primary_key(resource_class, "id"); + + item_specs[PROP_FIRST_NAME] = g_param_spec_string("first-name", + "First name", + "The First name for the item.", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_FIRST_NAME, + item_specs[PROP_FIRST_NAME]); + + item_specs[PROP_SURNAME] = g_param_spec_string("surname", + "Surname", + "The Surname for the item.", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_SURNAME, + item_specs[PROP_SURNAME]); +} + +static void +item_resource_init (ItemResource *resource) +{ + resource->priv = G_TYPE_INSTANCE_GET_PRIVATE(resource, + ITEM_TYPE_RESOURCE, + ItemResourcePrivate); +} + +static void +table_name (void) +{ + GomAdapter *adapter; + GError *error = NULL; + gboolean ret; + GomRepository *repository; + GList *object_types; + GValue value = { 0, }; + GomFilter *filter; + char *s1, *s2; + ItemResource *it; + + if (!g_test_subprocess ()) { + /* Rerun this same test in a subprocess */ + g_test_trap_subprocess (NULL, 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*CRITICAL*is_valid_table_name*failed*"); + return; + } + + adapter = gom_adapter_new(); + //ret = gom_adapter_open_sync(adapter, "file:test.db", &error); + ret = gom_adapter_open_sync(adapter, ":memory:", &error); + g_assert_no_error(error); + g_assert(ret); + + repository = gom_repository_new(adapter); + + object_types = g_list_prepend(NULL, GINT_TO_POINTER(ITEM_TYPE_RESOURCE)); + ret = gom_repository_automatic_migrate_sync(repository, 1, object_types, &error); + g_assert_no_error(error); + g_assert(ret); + + it = g_object_new (ITEM_TYPE_RESOURCE, + "repository", repository, + "first-name", "First name", + "surname", "Surname", + NULL); + ret = gom_resource_save_sync(GOM_RESOURCE(it), &error); + g_assert(ret); + g_assert_no_error(error); + g_object_unref(it); + + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, "First name"); + filter = gom_filter_new_eq(ITEM_TYPE_RESOURCE, "first-name", &value); + g_value_unset(&value); + + it = ITEM_RESOURCE (gom_repository_find_one_sync(repository, + ITEM_TYPE_RESOURCE, + filter, + &error)); + g_assert_no_error(error); + g_assert(it); + g_object_unref(filter); + + g_object_get(it, + "first-name", &s1, + "surname", &s2, + NULL); + g_object_unref(it); + + g_assert_cmpstr(s1, ==, "First name"); + g_assert_cmpstr(s2, ==, "Surname"); + g_free(s1); + g_free(s2); + + ret = gom_adapter_close_sync(adapter, &error); + g_assert_no_error(error); + g_assert(ret); + + g_object_unref(repository); + g_object_unref(adapter); +} + +gint +main (int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/GomRepository/table_name", table_name); + return g_test_run(); +}