diff options
| author | William A. Kennington III <wak@google.com> | 2018-07-17 14:40:14 -0700 |
|---|---|---|
| committer | William A. Kennington III <wak@google.com> | 2018-07-17 14:40:14 -0700 |
| commit | 8f90e28b500d384fbabcf97119879c7ba3c88724 (patch) | |
| tree | 8c68ef24d7b8ec3e36b8c3d793d4dd3fe763b030 | |
| download | sdeventplus-8f90e28b500d384fbabcf97119879c7ba3c88724.tar.gz sdeventplus-8f90e28b500d384fbabcf97119879c7ba3c88724.zip | |
Initial Commit
| -rw-r--r-- | .clang-format | 85 | ||||
| -rw-r--r-- | .gitignore | 46 | ||||
| -rw-r--r-- | LICENSE | 201 | ||||
| -rw-r--r-- | MAINTAINERS | 45 | ||||
| -rw-r--r-- | Makefile.am | 4 | ||||
| -rw-r--r-- | README.md | 29 | ||||
| -rwxr-xr-x | bootstrap.sh | 4 | ||||
| -rw-r--r-- | configure.ac | 154 | ||||
| -rw-r--r-- | example/Makefile.am | 11 | ||||
| -rw-r--r-- | example/follow.cpp | 14 | ||||
| -rw-r--r-- | src/Makefile.am | 22 | ||||
| -rw-r--r-- | src/sdeventplus.pc.in | 11 | ||||
| -rw-r--r-- | src/sdeventplus/event.cpp | 53 | ||||
| -rw-r--r-- | src/sdeventplus/event.hpp | 27 | ||||
| -rw-r--r-- | src/sdeventplus/exception.cpp | 12 | ||||
| -rw-r--r-- | src/sdeventplus/exception.hpp | 14 | ||||
| -rw-r--r-- | src/sdeventplus/sdevent.cpp | 6 | ||||
| -rw-r--r-- | src/sdeventplus/sdevent.hpp | 52 | ||||
| -rw-r--r-- | src/sdeventplus/sdref.hpp | 89 | ||||
| -rw-r--r-- | src/sdeventplus/test/sdevent.hpp | 21 | ||||
| -rw-r--r-- | test/Makefile.am | 26 | ||||
| -rw-r--r-- | test/event.cpp | 96 | ||||
| -rw-r--r-- | test/exception.cpp | 25 | ||||
| -rw-r--r-- | test/sdref.cpp | 198 |
24 files changed, 1245 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..bbc1bb1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,85 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..511c641 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# Test suite logs +*.log + +# Code Coverage +*.gcda +*.gcno +*.trs +*-coverage* + +# CC / CXX Compiler +*.ii +*.i +*.o +*.s + +# Libtool +*.la +*.lo + +# Autotools +.deps +.dirstamp +.libs +/aclocal.m4 +/autom4te.cache +/build-aux +/config.h +/config.h.in +/config.h.in~ +/config.log +/config.status +/configure +/m4 +/libtool +Makefile +Makefile.in +/stamp-h1 + +# Custom generated files +/src/sdeventplus.pc + +# Output binaries +/example/follow +/test/event +/test/exception +/test/sdref @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000..3934d40 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,45 @@ +How to use this list: + Find the most specific section entry (described below) that matches where + your change lives and add the reviewers (R) and maintainers (M) as + reviewers. You can use the same method to track down who knows a particular + code base best. + + Your change/query may span multiple entries; that is okay. + + If you do not find an entry that describes your request at all, someone + forgot to update this list; please at least file an issue or send an email + to a maintainer, but preferably you should just update this document. + +Description of section entries: + + Section entries are structured according to the following scheme: + + X: NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!> + X: ... + . + . + . + + Where REPO_NAME is the name of the repository within the OpenBMC GitHub + organization; FILE_PATH is a file path within the repository, possibly with + wildcards; X is a tag of one of the following types: + + M: Denotes maintainer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; + if omitted from an entry, assume one of the maintainers from the + MAINTAINERS entry. + R: Denotes reviewer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; + these people are to be added as reviewers for a change matching the repo + path. + F: Denotes forked from an external repository; has fields URL. + + Line comments are to be denoted "# SOME COMMENT" (typical shell style + comment); it is important to follow the correct syntax and semantics as we + may want to use automated tools with this file in the future. + + A change cannot be added to an OpenBMC repository without a MAINTAINER's + approval; thus, a MAINTAINER should always be listed as a reviewer. + +START OF MAINTAINERS LIST +------------------------- + +M: William A. Kenngton III <wak@google.com> <wak-work!> diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..9bddc5e --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +ACLOCAL_AMFLAGS = -I m4 + +EXTRA_DIST = LICENSE MAINTAINERS README.md +SUBDIRS = src example test diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bbb9e8 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# sdeventplus + +sdeventplus is a c++ wrapper around the systemd sd_event apis meant +to provide c++ ergonomics to their usage. + +## Dependencies + +The sdeventplus library requires libsystemd for sd-event. + +Test cases require google{test,mock}, valgrind, and lcov. + +## Building +For a standard release build, you want something like: +``` +./bootstrap.sh +./configure --disable-tests +make +make install +``` + +For a test / debug build, a typical configuration is +``` +./bootstrap.sh +./configure --enable-tests --enable-coverage --enable-valgrind +make +make check +make check-valgrind +make check-code-coverage +``` diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..30ef75a --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -e +set -x +autoreconf -v -f -i diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..67566fc --- /dev/null +++ b/configure.ac @@ -0,0 +1,154 @@ +# Initialization +AC_PREREQ([2.69]) +AC_INIT([sdeventplus], [0.1], [https://github.com/openbmc/sdeventplus/issues]) +AC_LANG([C++]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIRS([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror dist-xz tar-ustar]) +AM_SILENT_RULES([yes]) + +# Make sure the default CFLAGS of `-O2 -g` don't override CODE_COVERAGE_CFLAGS +# It is important that this comes before AC_PROG_C{C,XX}, as we are attempting +# to stop them from populating default CFLAGS and CXXFLAGS. +AS_IF([test "x$enable_code_coverage" != "xno"], [ + AS_IF([test "x${CXXFLAGS+set}" != "xset"], [ + AC_SUBST(CXXFLAGS, [""]) + ]) + AS_IF([test "x${CFLAGS+set}" != "xset"], [ + AC_SUBST(CFLAGS, [""]) + ]) +]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC +AM_PROG_AR +AC_PROG_INSTALL +AC_PROG_MAKE_SET + +# Checks for libtool +LT_INIT # Removes 'unrecognized options: --with-libtool-sysroot' + +# Make sure the pkgconfigdata is configured for automake +PKG_INSTALLDIR + +# Checks for typedefs, structures, and compiler characteristics. +AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory]) +AX_APPEND_COMPILE_FLAGS([-Wall -Wextra -Wpedantic], [CFLAGS]) +AX_APPEND_COMPILE_FLAGS([-Wall -Wextra -Wpedantic], [CXXFLAGS]) + +# We require systemd unconditionally +AX_PKG_CHECK_MODULES([SYSTEMD], [libsystemd >= 218]) + +AX_SAVE_FLAGS_WITH_PREFIX(OLD, [CPPFLAGS]) +AX_APPEND_COMPILE_FLAGS([$SYSTEMD_CFLAGS], [CPPFLAGS]) +AC_CHECK_HEADERS([systemd/sd-event.h], [], + [AC_MSG_ERROR([Could not find systemd/sd-event.h])]) +AX_RESTORE_FLAGS_WITH_PREFIX(OLD, [CPPFLAGS]) + +AX_SAVE_FLAGS_WITH_PREFIX(OLD, [LDFLAGS]) +AX_APPEND_COMPILE_FLAGS([$SYSTEMD_LIBS], [LDFLAGS]) +AC_CHECK_LIB([systemd], [sd_event_default], [], [ + AC_MSG_ERROR([Could not find sd_event_default in libsystemd]) +]) +AX_RESTORE_FLAGS_WITH_PREFIX(OLD, [LDFLAGS]) + +# Make it possible for users to choose if they want test support +# explicitly or not at all +AC_ARG_ENABLE([tests], [Whether we should build test cases]) + +# Check/set gtest specific functions. +AS_IF([test "x$enable_tests" != "xno"], [ + PKG_CHECK_MODULES([GTEST], [gtest], [], [true]) + PKG_CHECK_MODULES([GMOCK], [gmock], [], [true]) + AX_PTHREAD + + AX_SAVE_FLAGS_WITH_PREFIX(OLD, [CPPFLAGS]) + AX_APPEND_COMPILE_FLAGS([$GTEST_CFLAGS], [CPPFLAGS]) + AC_LANG_PUSH([C++]) + AC_CHECK_HEADERS([gtest/gtest.h], [ + AS_IF([test "x$GTEST_CFLAGS" = "x"], [ + AS_IF([test "x$PTHREAD_CFLAGS" = "x"], [ + AX_APPEND_COMPILE_FLAGS(["-DGTEST_HAS_PTHREAD=0"], [GTEST_CFLAGS]) + ], [ + AX_APPEND_COMPILE_FLAGS(["-DGTEST_HAS_PTHREAD=1"], [GTEST_CFLAGS]) + AX_APPEND_COMPILE_FLAGS([$PTHREAD_CFLAGS], [GTEST_CFLAGS]) + ]) + ]) + ], [ + AS_IF([test "x$enable_tests" = "xyes"], [ + AC_MSG_ERROR([Testing enabled but could not find gtest/gtest.h]) + ]) + ]) + AC_LANG_POP([C++]) + AX_RESTORE_FLAGS_WITH_PREFIX(OLD, [CPPFLAGS]) + + AX_SAVE_FLAGS_WITH_PREFIX(OLD, [CPPFLAGS]) + AX_APPEND_COMPILE_FLAGS([$GMOCK_CFLAGS], [CPPFLAGS]) + AC_LANG_PUSH([C++]) + AC_CHECK_HEADERS([gmock/gmock.h], [], [ + AS_IF([test "x$enable_tests" = "xyes"], [ + AC_MSG_ERROR([Testing enabled but could not find gmock/gmock.h]) + ]) + ]) + AC_LANG_POP([C++]) + AX_RESTORE_FLAGS_WITH_PREFIX(OLD, [CPPFLAGS]) + + AX_SAVE_FLAGS_WITH_PREFIX(OLD, [LDFLAGS]) + AX_APPEND_COMPILE_FLAGS([$GTEST_LIBS], [LDFLAGS]) + AC_CHECK_LIB([gtest], [main], [ + AS_IF([test "x$GTEST_LIBS" = "x"], [ + AX_APPEND_COMPILE_FLAGS([-lgtest], [GTEST_LIBS]) + ]) + ], [ + AS_IF([test "x$enable_tests" = "xyes"], [ + AC_MSG_ERROR([Testing enabled but couldn't find gtest libs]) + ]) + ]) + AX_RESTORE_FLAGS_WITH_PREFIX(OLD, [LDFLAGS]) + + AX_SAVE_FLAGS_WITH_PREFIX(OLD, [LDFLAGS]) + AX_APPEND_COMPILE_FLAGS([$GMOCK_LIBS], [LDFLAGS]) + AC_CHECK_LIB([gmock], [main], [ + AS_IF([test "x$GMOCK_LIBS" = "x"], [ + AX_APPEND_COMPILE_FLAGS([-lgmock], [GMOCK_LIBS]) + ]) + ], [ + AS_IF([test "x$enable_tests" = "xyes"], [ + AC_MSG_ERROR([Testing enabled but couldn't find gmock libs]) + ]) + ]) + AX_RESTORE_FLAGS_WITH_PREFIX(OLD, [LDFLAGS]) +]) + +# Check for valgrind +AS_IF([test "x$enable_tests" != "xno"], [ + m4_foreach([vgtool], [valgrind_tool_list], + [AX_VALGRIND_DFLT(vgtool, [off])]) + AX_VALGRIND_DFLT([memcheck], [on]) + AX_VALGRIND_CHECK + AM_EXTRA_RECURSIVE_TARGETS([check-valgrind]) + m4_foreach([vgtool], [valgrind_tool_list], + [AM_EXTRA_RECURSIVE_TARGETS([check-valgrind-]vgtool)]) +]) + +# Code coverage +AS_IF([test "x$enable_tests" != "xno"], [ + AX_CODE_COVERAGE + AM_EXTRA_RECURSIVE_TARGETS([check-code-coverage]) +]) + +# Append -Werror after doing autoconf compiler checks +# Otherwise some perfectly valid checks can fail and cause our +# final configuratin to be broken. +AC_ARG_ENABLE([werror], [Whether to automatically add -Werror CFLAGS]) +AS_IF([test "x$enable_tests" != "xno"], [ + AX_APPEND_COMPILE_FLAGS([-Werror], [CFLAGS]) + AX_APPEND_COMPILE_FLAGS([-Werror], [CXXFLAGS]) +]) + +# Create configured output +AC_CONFIG_FILES([Makefile example/Makefile src/Makefile test/Makefile]) +AC_CONFIG_FILES([src/sdeventplus.pc]) +AC_OUTPUT diff --git a/example/Makefile.am b/example/Makefile.am new file mode 100644 index 0000000..3fad73a --- /dev/null +++ b/example/Makefile.am @@ -0,0 +1,11 @@ +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src \ + $(SYSTEMD_CFLAGS) $(CODE_COVERAGE_CPPFLAGS) +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) +common_ldadd = $(top_builddir)/src/libsdeventplus.la + +noinst_PROGRAMS = + +noinst_PROGRAMS += follow +follow_SOURCES = follow.cpp +follow_LDADD = $(common_ldadd) diff --git a/example/follow.cpp b/example/follow.cpp new file mode 100644 index 0000000..36cd44b --- /dev/null +++ b/example/follow.cpp @@ -0,0 +1,14 @@ +#include <cstdio> +#include <sdeventplus/event.hpp> + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + fprintf(stderr, "Usage: %s [file]\n", argv[0]); + return 1; + } + + sdeventplus::Event event = sdeventplus::Event::get_default(); + return event.loop(); +} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..5379c0a --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,22 @@ +AM_CPPFLAGS = $(SYSTEMD_CFLAGS) $(CODE_COVERAGE_CPPFLAGS) +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) + +nobase_include_HEADERS = +pkgconfig_DATA = sdeventplus.pc +lib_LTLIBRARIES = libsdeventplus.la +libsdeventplus_la_SOURCES = +libsdeventplus_la_LIBADD = $(SYSTEMD_LIBS) $(CODE_COVERAGE_LIBS) + +nobase_include_HEADERS += sdeventplus/event.hpp +libsdeventplus_la_SOURCES += sdeventplus/event.cpp + +nobase_include_HEADERS += sdeventplus/exception.hpp +libsdeventplus_la_SOURCES += sdeventplus/exception.cpp + +nobase_include_HEADERS += sdeventplus/sdevent.hpp +libsdeventplus_la_SOURCES += sdeventplus/sdevent.cpp + +nobase_include_HEADERS += sdeventplus/sdref.hpp + +nobase_include_HEADERS += sdeventplus/test/sdevent.hpp diff --git a/src/sdeventplus.pc.in b/src/sdeventplus.pc.in new file mode 100644 index 0000000..3d67d40 --- /dev/null +++ b/src/sdeventplus.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: sdeventplus +Version: @VERSION@ +Requires: @AX_PACKAGE_REQUIRES@ +Requires.private: @AX_PACKAGE_REQUIRES_PRIVATE@ +Cflags: -I${includedir} +Libs: -L${libdir} -lsdeventplus diff --git a/src/sdeventplus/event.cpp b/src/sdeventplus/event.cpp new file mode 100644 index 0000000..1baca16 --- /dev/null +++ b/src/sdeventplus/event.cpp @@ -0,0 +1,53 @@ +#include <functional> +#include <sdeventplus/event.hpp> +#include <sdeventplus/exception.hpp> + +namespace sdeventplus +{ + +Event::Event(sd_event* event, SdEventInterface* intf) : + intf(intf), event(event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, intf) +{ +} + +Event::Event(sd_event* event, std::false_type, SdEventInterface* intf) : + intf(intf), + event(event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), intf) +{ +} + +Event Event::get_new(SdEventInterface* intf) +{ + sd_event* event = nullptr; + int r = intf->sd_event_new(&event); + if (r < 0) + { + throw SdEventError(-r, "sd_event_new"); + } + return Event(event, std::false_type(), intf); +} + +Event Event::get_default(SdEventInterface* intf) +{ + sd_event* event = nullptr; + int r = intf->sd_event_default(&event); + if (r < 0) + { + throw SdEventError(-r, "sd_event_default"); + } + return Event(event, std::false_type(), intf); +} + +int Event::loop() +{ + int r = intf->sd_event_loop(event.get()); + if (r < 0) + { + throw SdEventError(-r, "sd_event_loop"); + } + return r; +} + +} // namespace sdeventplus diff --git a/src/sdeventplus/event.hpp b/src/sdeventplus/event.hpp new file mode 100644 index 0000000..e2372bb --- /dev/null +++ b/src/sdeventplus/event.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <memory> +#include <sdeventplus/sdevent.hpp> +#include <sdeventplus/sdref.hpp> +#include <systemd/sd-event.h> + +namespace sdeventplus +{ + +class Event +{ + public: + Event(sd_event* event, SdEventInterface* intf = &sdevent_impl); + Event(sd_event* event, std::false_type, + SdEventInterface* intf = &sdevent_impl); + static Event get_new(SdEventInterface* intf = &sdevent_impl); + static Event get_default(SdEventInterface* intf = &sdevent_impl); + + int loop(); + + private: + SdEventInterface* intf; + SdRef<sd_event> event; +}; + +} // namespace sdeventplus diff --git a/src/sdeventplus/exception.cpp b/src/sdeventplus/exception.cpp new file mode 100644 index 0000000..1cfba4f --- /dev/null +++ b/src/sdeventplus/exception.cpp @@ -0,0 +1,12 @@ +#include <sdeventplus/exception.hpp> +#include <system_error> + +namespace sdeventplus +{ + +SdEventError::SdEventError(int r, const char *prefix) : + std::system_error(r, std::generic_category(), prefix) +{ +} + +} // namespace sdeventplus diff --git a/src/sdeventplus/exception.hpp b/src/sdeventplus/exception.hpp new file mode 100644 index 0000000..eb88649 --- /dev/null +++ b/src/sdeventplus/exception.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <system_error> + +namespace sdeventplus +{ + +class SdEventError final : public std::system_error +{ + public: + SdEventError(int r, const char *prefix); +}; + +} // namespace sdeventplus diff --git a/src/sdeventplus/sdevent.cpp b/src/sdeventplus/sdevent.cpp new file mode 100644 index 0000000..d145f38 --- /dev/null +++ b/src/sdeventplus/sdevent.cpp @@ -0,0 +1,6 @@ +#include <sdeventplus/sdevent.hpp> + +namespace sdeventplus +{ +SdEventImpl sdevent_impl; +} diff --git a/src/sdeventplus/sdevent.hpp b/src/sdeventplus/sdevent.hpp new file mode 100644 index 0000000..129e67f --- /dev/null +++ b/src/sdeventplus/sdevent.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include <systemd/sd-event.h> + +namespace sdeventplus +{ + +class SdEventInterface +{ + public: + virtual ~SdEventInterface() = default; + + virtual int sd_event_default(sd_event **event) const = 0; + virtual int sd_event_new(sd_event **event) const = 0; + virtual sd_event *sd_event_ref(sd_event *event) const = 0; + virtual sd_event *sd_event_unref(sd_event *event) const = 0; + + virtual int sd_event_loop(sd_event *event) const = 0; +}; + +class SdEventImpl : public SdEventInterface +{ + public: + int sd_event_default(sd_event **event) const override + { + return ::sd_event_default(event); + } + + int sd_event_new(sd_event **event) const override + { + return ::sd_event_default(event); + } + + sd_event *sd_event_ref(sd_event *event) const override + { + return ::sd_event_ref(event); + } + + sd_event *sd_event_unref(sd_event *event) const override + { + return ::sd_event_unref(event); + } + + int sd_event_loop(sd_event *event) const override + { + return ::sd_event_loop(event); + } +}; + +extern SdEventImpl sdevent_impl; + +} // namespace sdeventplus diff --git a/src/sdeventplus/sdref.hpp b/src/sdeventplus/sdref.hpp new file mode 100644 index 0000000..492ae70 --- /dev/null +++ b/src/sdeventplus/sdref.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include <functional> +#include <memory> +#include <sdeventplus/sdevent.hpp> +#include <type_traits> + +namespace sdeventplus +{ + +template <typename T> class SdRef +{ + public: + using Func = std::function<T*(SdEventInterface*, T*)>; + + SdRef(T* ref, Func take_ref, Func release_ref, + SdEventInterface* intf = sdevent_impl) : + SdRef(take_ref(intf, ref), take_ref, release_ref, std::false_type(), + intf) + { + } + + SdRef(T* ref, Func take_ref, Func release_ref, std::false_type, + SdEventInterface* intf = sdevent_impl) : + intf(intf), + take_ref(take_ref), release_ref(release_ref), ref(ref) + { + } + + SdRef(const SdRef& other) : + intf(other.intf), take_ref(other.take_ref), + release_ref(other.release_ref), ref(take_ref(intf, other.ref)) + { + } + + SdRef& operator=(const SdRef& other) + { + if (this != &other) + { + // release_ref will be invalid if moved + if (release_ref) + release_ref(intf, ref); + + intf = other.intf; + take_ref = other.take_ref; + release_ref = other.release_ref; + ref = take_ref(intf, other.ref); + } + return *this; + } + + SdRef(SdRef&& other) = default; + + SdRef& operator=(SdRef&& other) + { + if (this != &other) + { + // release_ref will be invalid if move + if (release_ref) + release_ref(intf, ref); + + intf = std::move(other.intf); + take_ref = std::move(other.take_ref); + release_ref = std::move(other.release_ref); + ref = std::move(other.ref); + } + return *this; + } + + virtual ~SdRef() + { + // release_ref will be invalid after a move + if (release_ref) + release_ref(intf, ref); + } + + T* get() const + { + return ref; + } + + private: + SdEventInterface* intf; + Func take_ref; + Func release_ref; + T* ref; +}; + +} // namespace sdeventplus diff --git a/src/sdeventplus/test/sdevent.hpp b/src/sdeventplus/test/sdevent.hpp new file mode 100644 index 0000000..b467647 --- /dev/null +++ b/src/sdeventplus/test/sdevent.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <gmock/gmock.h> +#include <sdeventplus/sdevent.hpp> +#include <systemd/sd-event.h> + +namespace sdeventplus +{ + +class SdEventMock : public SdEventInterface +{ + public: + MOCK_CONST_METHOD1(sd_event_default, int(sd_event **)); + MOCK_CONST_METHOD1(sd_event_new, int(sd_event **)); + MOCK_CONST_METHOD1(sd_event_ref, sd_event *(sd_event *)); + MOCK_CONST_METHOD1(sd_event_unref, sd_event *(sd_event *)); + + MOCK_CONST_METHOD1(sd_event_loop, int(sd_event *)); +}; + +} // namespace sdeventplus diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..7efd9b2 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,26 @@ +@VALGRIND_CHECK_RULES@ +@CODE_COVERAGE_RULES@ + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src \ + $(GTEST_CFLAGS) $(GMOCK_CFLAGS) $(SYSTEMD_CFLAGS) \ + $(CODE_COVERAGE_CPPFLAGS) +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) +test_ldadd = $(top_builddir)/src/libsdeventplus.la $(SYSTEMD_LIBS) \ + $(CODE_COVERAGE_LIBS) +gtest_ldadd = $(test_ldadd) $(GTEST_LIBS) $(GMOCK_LIBS) -lgmock_main + +check_PROGRAMS = +TESTS = $(check_PROGRAMS) + +check_PROGRAMS += event +event_SOURCES = event.cpp +event_LDADD = $(gtest_ldadd) + +check_PROGRAMS += exception +exception_SOURCES = exception.cpp +exception_LDADD = $(gtest_ldadd) + +check_PROGRAMS += sdref +sdref_SOURCES = sdref.cpp +sdref_LDADD = $(gtest_ldadd) diff --git a/test/event.cpp b/test/event.cpp new file mode 100644 index 0000000..da935cf --- /dev/null +++ b/test/event.cpp @@ -0,0 +1,96 @@ +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <sdeventplus/event.hpp> +#include <sdeventplus/exception.hpp> +#include <sdeventplus/test/sdevent.hpp> +#include <type_traits> + +namespace sdeventplus +{ +namespace +{ + +using testing::DoAll; +using testing::Return; +using testing::SetArgPointee; + +class EventTest : public testing::Test +{ + protected: + testing::StrictMock<SdEventMock> mock; + sd_event *const expected_event = reinterpret_cast<sd_event *>(1234); +}; + +TEST_F(EventTest, NewEventRef) +{ + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(Return(expected_event)); + Event event(expected_event, &mock); + + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); +} + +TEST_F(EventTest, NewEventNoRef) +{ + Event event(expected_event, std::false_type(), &mock); + + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); +} + +TEST_F(EventTest, GetNewEvent) +{ + EXPECT_CALL(mock, sd_event_new(testing::_)) + .WillOnce(DoAll(SetArgPointee<0>(expected_event), Return(0))); + Event event = Event::get_new(&mock); + + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); +} + +TEST_F(EventTest, GetNewEventFail) +{ + EXPECT_CALL(mock, sd_event_new(testing::_)).WillOnce(Return(-EINVAL)); + EXPECT_THROW(Event::get_new(&mock), SdEventError); +} + +TEST_F(EventTest, GetDefaultEvent) +{ + EXPECT_CALL(mock, sd_event_default(testing::_)) + .WillOnce(DoAll(SetArgPointee<0>(expected_event), Return(0))); + Event event = Event::get_default(&mock); + + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); +} + +TEST_F(EventTest, GetDefaultEventFail) +{ + EXPECT_CALL(mock, sd_event_default(testing::_)).WillOnce(Return(-EINVAL)); + EXPECT_THROW(Event::get_default(&mock), SdEventError); +} + +TEST_F(EventTest, LoopSuccess) +{ + EXPECT_CALL(mock, sd_event_loop(expected_event)).WillOnce(Return(0)); + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); + EXPECT_EQ(0, Event(expected_event, std::false_type(), &mock).loop()); +} + +TEST_F(EventTest, LoopUserError) +{ + const int user_error = 10; + EXPECT_CALL(mock, sd_event_loop(expected_event)) + .WillOnce(Return(user_error)); + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); + EXPECT_EQ(user_error, + Event(expected_event, std::false_type(), &mock).loop()); +} + +TEST_F(EventTest, LoopInternalError) +{ + EXPECT_CALL(mock, sd_event_loop(expected_event)).WillOnce(Return(-EINVAL)); + EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); + EXPECT_THROW(Event(expected_event, std::false_type(), &mock).loop(), + SdEventError); +} + +} // namespace +} // namespace sdeventplus diff --git a/test/exception.cpp b/test/exception.cpp new file mode 100644 index 0000000..050513c --- /dev/null +++ b/test/exception.cpp @@ -0,0 +1,25 @@ +#include <gtest/gtest.h> +#include <sdeventplus/exception.hpp> +#include <string> +#include <system_error> + +namespace sdeventplus +{ +namespace +{ + +TEST(ExceptionTest, Construct) +{ + const int code = EINTR; + const char *const prefix = "construct_test"; + + std::system_error expected(code, std::generic_category(), prefix); + SdEventError err(code, prefix); + + EXPECT_EQ(std::string{expected.what()}, err.what()); + EXPECT_EQ(code, err.code().value()); + EXPECT_EQ(std::generic_category(), err.code().category()); +} + +} // namespace +} // namespace sdeventplus diff --git a/test/sdref.cpp b/test/sdref.cpp new file mode 100644 index 0000000..6bb5410 --- /dev/null +++ b/test/sdref.cpp @@ -0,0 +1,198 @@ +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <sdeventplus/sdevent.hpp> +#include <sdeventplus/sdref.hpp> +#include <sdeventplus/test/sdevent.hpp> +#include <systemd/sd-event.h> +#include <type_traits> +#include <utility> + +namespace sdeventplus +{ +namespace +{ + +class SdRefTest : public testing::Test +{ + protected: + sd_event *const expected_event = reinterpret_cast<sd_event *>(1234); + sd_event *const expected_event2 = reinterpret_cast<sd_event *>(2345); + testing::StrictMock<SdEventMock> mock; + testing::StrictMock<SdEventMock> mock2; +}; + +TEST_F(SdRefTest, ConstructRef) +{ + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(testing::Return(expected_event)); + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, &mock); + EXPECT_EQ(expected_event, event.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, ConstructNoRef) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, CopyConstruct) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(testing::Return(expected_event)); + SdRef<sd_event> event2(event); + EXPECT_EQ(expected_event, event2.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .Times(2) + .WillRepeatedly(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, MoveConstruct) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + + SdRef<sd_event> event2(std::move(event)); + EXPECT_EQ(expected_event, event2.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, CopyAssignOverValid) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + SdRef<sd_event> event2(expected_event2, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock2); + EXPECT_EQ(expected_event2, event2.get()); + + EXPECT_CALL(mock2, sd_event_unref(expected_event2)) + .WillOnce(testing::Return(nullptr)); + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(testing::Return(expected_event)); + event2 = event; + EXPECT_EQ(expected_event, event2.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .Times(2) + .WillRepeatedly(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, CopyAssignOverMoved) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + SdRef<sd_event> event2(expected_event2, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock2); + EXPECT_EQ(expected_event2, event2.get()); + { + SdRef<sd_event> event_mover(std::move(event2)); + EXPECT_EQ(expected_event2, event_mover.get()); + + EXPECT_CALL(mock2, sd_event_unref(expected_event2)) + .WillOnce(testing::Return(nullptr)); + } + + EXPECT_CALL(mock, sd_event_ref(expected_event)) + .WillOnce(testing::Return(expected_event)); + event2 = event; + EXPECT_EQ(expected_event, event2.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .Times(2) + .WillRepeatedly(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, CopySelf) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + + event = event; + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, MoveAssignOverValid) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + SdRef<sd_event> event2(expected_event2, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock2); + EXPECT_EQ(expected_event2, event2.get()); + + EXPECT_CALL(mock2, sd_event_unref(expected_event2)) + .WillOnce(testing::Return(nullptr)); + event2 = std::move(event); + EXPECT_EQ(expected_event, event2.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, MoveAssignOverMoved) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + SdRef<sd_event> event2(expected_event2, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock2); + EXPECT_EQ(expected_event2, event2.get()); + { + SdRef<sd_event> event_mover(std::move(event2)); + EXPECT_EQ(expected_event2, event_mover.get()); + + EXPECT_CALL(mock2, sd_event_unref(expected_event2)) + .WillOnce(testing::Return(nullptr)); + } + + event2 = std::move(event); + EXPECT_EQ(expected_event, event2.get()); + + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +TEST_F(SdRefTest, MoveSelf) +{ + SdRef<sd_event> event(expected_event, &SdEventInterface::sd_event_ref, + &SdEventInterface::sd_event_unref, std::false_type(), + &mock); + EXPECT_EQ(expected_event, event.get()); + event = std::move(event); + EXPECT_CALL(mock, sd_event_unref(expected_event)) + .WillOnce(testing::Return(nullptr)); +} + +} // namespace +} // namespace sdeventplus |

