From 38e625da7f47e457d150efedc598437e2e867ef7 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Thu, 20 Dec 2018 13:01:29 -0500 Subject: tests: shm: fix pwrite wrapper with -D_FILE_OFFSET_BITS=64 Due to the hacks used for large file support, wrapping pwrite is error prone and can end up calling the wrong function. Currently, "pwrite" is called instead of "pwrite64" on 32-bit ARM, causing the test to fail. This commit attempts to determine the correct symbol to call from the wrapper. --- tests/shm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/shm.c b/tests/shm.c index a0cf67e..26c5160 100644 --- a/tests/shm.c +++ b/tests/shm.c @@ -87,6 +87,12 @@ 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 @@ -95,7 +101,7 @@ 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"); + real_pwrite = dlsym (RTLD_NEXT, PWRITE_SYM); if (should_fail_pwrite) { -- cgit v1.2.1 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