From 8cbaee1c341b97d81fc597a4571b459baaac5c11 Mon Sep 17 00:00:00 2001 From: Daniel Playfair Cal Date: Mon, 7 Jan 2019 22:33:15 +1100 Subject: Tests: replace usage of dlsym with separate modules containing functions that need to be mocked out --- engine/dconf-engine-mockable.c | 39 +++++++++++++++++++++++++++++++++++++++ engine/dconf-engine-mockable.h | 30 ++++++++++++++++++++++++++++++ engine/dconf-engine-profile.c | 9 +++++---- engine/meson.build | 20 +++++++++++++++++++- shm/dconf-shm-mockable.c | 40 ++++++++++++++++++++++++++++++++++++++++ shm/dconf-shm-mockable.h | 31 +++++++++++++++++++++++++++++++ shm/dconf-shm.c | 5 +++-- shm/meson.build | 22 +++++++++++++++++++++- tests/engine.c | 9 +++------ tests/meson.build | 4 ++-- tests/shm.c | 16 +++------------- 11 files changed, 196 insertions(+), 29 deletions(-) create mode 100644 engine/dconf-engine-mockable.c create mode 100644 engine/dconf-engine-mockable.h create mode 100644 shm/dconf-shm-mockable.c create mode 100644 shm/dconf-shm-mockable.h diff --git a/engine/dconf-engine-mockable.c b/engine/dconf-engine-mockable.c new file mode 100644 index 0000000..dce2f43 --- /dev/null +++ b/engine/dconf-engine-mockable.c @@ -0,0 +1,39 @@ +/* + * Copyright © 2019 Daniel Playfair Cal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Daniel Playfair Cal + */ + +/** + * This module contains the production implementations of methods used in + * dconf_shm that need to be mocked out for tests. + * + * In some cases, external methods are wrapped with a different name. This is + * done so that it is not necessary to redefine the external functions in + * unit tests in order to mock them out, and therefore easy to also call the + * non mocked versions in tests if necessary. + */ + +#include "config.h" + +#include "dconf-engine-mockable.h" + + +FILE * +dconf_engine_fopen (const char *pathname, const char *mode) +{ + return fopen (pathname, mode); +} diff --git a/engine/dconf-engine-mockable.h b/engine/dconf-engine-mockable.h new file mode 100644 index 0000000..091f6d3 --- /dev/null +++ b/engine/dconf-engine-mockable.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2019 Daniel Playfair Cal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Daniel Playfair Cal + */ + +#ifndef __dconf_engine_mockable_h__ +#define __dconf_engine_mockable_h__ + +#include +#include + +G_GNUC_INTERNAL +FILE *dconf_engine_fopen (const char *pathname, + const char *mode); + +#endif diff --git a/engine/dconf-engine-profile.c b/engine/dconf-engine-profile.c index b204bb4..6474248 100644 --- a/engine/dconf-engine-profile.c +++ b/engine/dconf-engine-profile.c @@ -21,6 +21,7 @@ #include "config.h" #include "dconf-engine-profile.h" +#include "dconf-engine-mockable.h" #include #include @@ -207,7 +208,7 @@ dconf_engine_open_profile_file (const gchar *profile) gchar *filename; filename = g_build_filename (prefix, "dconf/profile", profile, NULL); - fp = fopen (filename, "r"); + fp = dconf_engine_fopen (filename, "r"); /* If it wasn't ENOENT then we don't want to continue on to check * other paths. Fail immediately. @@ -236,7 +237,7 @@ dconf_engine_open_mandatory_profile (void) memcpy (path, MANDATORY_DIR, mdlen); snprintf (path + mdlen, 20, "%u", (guint) getuid ()); - return fopen (path, "r"); + return dconf_engine_fopen (path, "r"); } static FILE * @@ -253,7 +254,7 @@ dconf_engine_open_runtime_profile (void) memcpy (path, runtime_dir, rdlen); memcpy (path + rdlen, RUNTIME_PROFILE, sizeof RUNTIME_PROFILE); - return fopen (path, "r"); + return dconf_engine_fopen (path, "r"); } DConfEngineSource ** @@ -311,7 +312,7 @@ dconf_engine_profile_open (const gchar *profile, if (profile[0] != '/') file = dconf_engine_open_profile_file (profile); else - file = fopen (profile, "r"); + file = dconf_engine_fopen (profile, "r"); } if (file != NULL) diff --git a/engine/meson.build b/engine/meson.build index d1a959d..ca46b60 100644 --- a/engine/meson.build +++ b/engine/meson.build @@ -1,4 +1,4 @@ -sources = files( +testable_sources = files( 'dconf-engine.c', 'dconf-engine-profile.c', 'dconf-engine-source.c', @@ -8,6 +8,10 @@ sources = files( 'dconf-engine-source-system.c', ) +sources = testable_sources + files( + 'dconf-engine-mockable.c', +) + engine_deps = [ libdconf_common_dep, libgvdb_dep, @@ -26,3 +30,17 @@ libdconf_engine_dep = declare_dependency( dependencies: engine_deps, link_with: libdconf_engine, ) + +libdconf_engine_test = static_library( + 'dconf-engine-test', + sources: testable_sources, + include_directories: top_inc, + dependencies: engine_deps + [libdconf_shm_dep], + c_args: dconf_c_args, + pic: true, +) + +libdconf_engine_test_dep = declare_dependency( + dependencies: engine_deps, + link_with: libdconf_engine_test, +) diff --git a/shm/dconf-shm-mockable.c b/shm/dconf-shm-mockable.c new file mode 100644 index 0000000..6adf7d5 --- /dev/null +++ b/shm/dconf-shm-mockable.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2019 Daniel Playfair Cal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Daniel Playfair Cal + */ + +/** + * This module contains the production implementations of methods used in + * dconf_shm that need to be mocked out for tests. + * + * In some cases, external methods are wrapped with a different name. This is + * done so that it is not necessary to redefine the external functions in + * unit tests in order to mock them out, and therefore easy to also call the + * non mocked versions in tests if necessary. + */ + +#include "config.h" + +#include "dconf-shm-mockable.h" + +#include + +ssize_t +dconf_shm_pwrite (int fd, const void *buf, size_t count, off_t offset) +{ + return pwrite (fd, buf, count, offset); +} diff --git a/shm/dconf-shm-mockable.h b/shm/dconf-shm-mockable.h new file mode 100644 index 0000000..98ff33f --- /dev/null +++ b/shm/dconf-shm-mockable.h @@ -0,0 +1,31 @@ +/* + * Copyright © 2019 Daniel Playfair Cal + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Daniel Playfair Cal + */ + +#ifndef __dconf_shm_mockable_h__ +#define __dconf_shm_mockable_h__ + +#include + +G_GNUC_INTERNAL +ssize_t dconf_shm_pwrite (int fd, + const void *buf, + size_t count, + off_t offset); + +#endif /* __dconf_shm_mockable_h__ */ diff --git a/shm/dconf-shm.c b/shm/dconf-shm.c index ae8c1c7..dbde759 100644 --- a/shm/dconf-shm.c +++ b/shm/dconf-shm.c @@ -21,6 +21,7 @@ #include "config.h" #include "dconf-shm.h" +#include "dconf-shm-mockable.h" #include #include @@ -82,7 +83,7 @@ dconf_shm_open (const gchar *name) * By writing to the second byte in the file we ensure we don't * overwrite the first byte (which is the one we care about). */ - if (pwrite (fd, "", 1, 1) != 1) + if (dconf_shm_pwrite (fd, "", 1, 1) != 1) { g_critical ("failed to allocate file '%s': %s. dconf will not work properly.", filename, g_strerror (errno)); goto out; @@ -124,7 +125,7 @@ dconf_shm_flag (const gchar *name) * If this fails then it will probably fail for the client too. * If it doesn't then there's not really much we can do... */ - if (pwrite (fd, "", 1, 1) == 1) + if (dconf_shm_pwrite (fd, "", 1, 1) == 1) { guint8 *shm; diff --git a/shm/meson.build b/shm/meson.build index 5fb9fe2..07f77d0 100644 --- a/shm/meson.build +++ b/shm/meson.build @@ -1,6 +1,11 @@ +sources = files( + 'dconf-shm.c', + 'dconf-shm-mockable.c', +) + libdconf_shm = static_library( 'dconf-shm', - sources: 'dconf-shm.c', + sources: sources, include_directories: top_inc, dependencies: glib_dep, c_args: dconf_c_args, @@ -11,3 +16,18 @@ libdconf_shm_dep = declare_dependency( dependencies: glib_dep, link_with: libdconf_shm, ) + + +libdconf_shm_test = static_library( + 'dconf-shm-test', + sources: 'dconf-shm.c', + include_directories: top_inc, + dependencies: glib_dep, + c_args: dconf_c_args, + pic: true, +) + +libdconf_shm_test_dep = declare_dependency( + dependencies: glib_dep, + link_with: libdconf_shm, +) diff --git a/tests/engine.c b/tests/engine.c index 7f2a748..fd2a348 100644 --- a/tests/engine.c +++ b/tests/engine.c @@ -2,6 +2,7 @@ #include "../engine/dconf-engine.h" #include "../engine/dconf-engine-profile.h" +#include "../engine/dconf-engine-mockable.h" #include "../common/dconf-enums.h" #include "dconf-mock.h" @@ -17,13 +18,9 @@ static const gchar *filename_to_replace; static const gchar *filename_to_replace_it_with; FILE * -fopen (const char *filename, +dconf_engine_fopen (const char *filename, const char *mode) { - static FILE * (*real_fopen) (const char *, const char *); - - if (!real_fopen) - real_fopen = dlsym (RTLD_NEXT, "fopen"); if (filename_to_replace && g_str_equal (filename, filename_to_replace)) { @@ -32,7 +29,7 @@ fopen (const char *filename, filename = filename_to_replace_it_with; } - return (* real_fopen) (filename, mode); + return fopen (filename, mode); } static void assert_no_messages (void); diff --git a/tests/meson.build b/tests/meson.build index 247ad76..8aa5837 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -24,11 +24,11 @@ unit_tests = [ # [name, sources, c_args, dependencies, link_with] ['paths', 'paths.c', [], libdconf_common_dep, []], ['changeset', 'changeset.c', [], libdconf_common_dep, []], - ['shm', ['shm.c', 'tmpdir.c'], [], [dl_dep, libdconf_common_dep, libdconf_shm_dep], []], + ['shm', ['shm.c', 'tmpdir.c'], [], [dl_dep, libdconf_common_dep, libdconf_shm_test_dep], []], ['gvdb', 'gvdb.c', '-DSRCDIR="@0@"'.format(test_dir), libgvdb_dep, []], ['gdbus-thread', 'dbus.c', '-DDBUS_BACKEND="/gdbus/thread"', libdconf_gdbus_thread_dep, []], ['gdbus-filter', 'dbus.c', '-DDBUS_BACKEND="/gdbus/filter"', libdconf_gdbus_filter_dep, []], - ['engine', 'engine.c', '-DSRCDIR="@0@"'.format(test_dir), [dl_dep, libdconf_engine_dep, m_dep], libdconf_mock], + ['engine', 'engine.c', '-DSRCDIR="@0@"'.format(test_dir), [dl_dep, libdconf_engine_test_dep, m_dep], libdconf_mock], ['client', 'client.c', '-DSRCDIR="@0@"'.format(test_dir), [libdconf_client_dep, libdconf_engine_dep], libdconf_mock], ['writer', 'writer.c', '-DSRCDIR="@0@"'.format(test_dir), [glib_dep, dl_dep, m_dep, libdconf_service_dep], [libdconf_mock]], ] diff --git a/tests/shm.c b/tests/shm.c index 26c5160..69d683f 100644 --- a/tests/shm.c +++ b/tests/shm.c @@ -10,6 +10,7 @@ #include #include "../shm/dconf-shm.h" +#include "../shm/dconf-shm-mockable.h" #include "tmpdir.h" static void @@ -87,29 +88,18 @@ test_flag_nonexistent (void) dconf_shm_flag ("does-not-exist"); } -#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 -#define PWRITE_SYM "pwrite64" -#else -#define PWRITE_SYM "pwrite" -#endif - static gboolean should_fail_pwrite; /* interpose */ ssize_t -pwrite (int fd, const void *buf, size_t count, off_t offset) +dconf_shm_pwrite (int fd, const void *buf, size_t count, off_t offset) { - static ssize_t (* real_pwrite) (int, const void *, size_t, off_t); - - if (!real_pwrite) - real_pwrite = dlsym (RTLD_NEXT, PWRITE_SYM); - if (should_fail_pwrite) { errno = ENOSPC; return -1; } - return (* real_pwrite) (fd, buf, count, offset); + return pwrite (fd, buf, count, offset); } static void -- cgit v1.2.1