Compare commits

...
27 Commits
Author SHA1 Message Date
Stanislav Angelovic 6e8e5aadb6 Bump up to v0.8.3 2020-09-11 22:29:15 +02:00
Stanislav Angelovič 3b735bf1aa Introduce CI workflow based on GitHub Actions (#114)
This introduces GitHub CI which runs builds and tests in a matrix configuration. It also changes the systemd repo to stable one. And puts the CI badge (plus a few more badges) to the README page.

Fixes #44
2020-07-22 16:35:42 +02:00
Stanislav Angelovic 2f7b35c5a8 Fix unused variable warnings for release builds 2020-07-21 15:44:16 +02:00
Stanislav Angelovic d5867e1197 Fix unused variable warning for release builds 2020-07-21 15:32:31 +02:00
Stanislav Angelovic 250aa2bbe3 Add additional messages to CMake build for optional parts 2020-07-21 12:12:14 +02:00
Stanislav Angelovic e63357b222 Remove non-virtual-dtor warnings by making classes final 2020-07-21 11:12:57 +02:00
Stanislav Angelovič 2c6be0307f Update CMake configuration flag names 2020-07-19 18:23:19 +02:00
sangelovic 138a437b22 Fix #112: Address a few inconsistencies and make code more idiomatic 2020-07-18 20:47:05 +02:00
sangelovic cc8d88cc64 Fix GetObjectPath() in integration tests 2020-07-18 20:30:51 +02:00
sangelovic bded067496 Fix #43: Clean up integration tests 2020-07-18 20:21:47 +02:00
Tomas Pecka c1c4512f9f Fix build with gcc8.3
sdbus::ObjectPath and sdbus::Signature copy constructors are implicitly
declared as deleted when compiling with Linaro's ARM toolchain [1] gcc8.3.
Explicitly listing the copy constructors for affected classes fixes the problem.

[1] https://www.linaro.org/
2020-07-16 18:53:18 +02:00
Stanislav Angelovic 175c43ec53 Bump revision up to v0.8.2 2020-06-17 15:29:46 +02:00
Stanislav Angelovic c137dfa213 Fix potential data race in Proxy's condition variable 2020-06-17 09:13:30 +02:00
Stanislav Angelovic a0dadcc6fe Fix integration tests after getObjectPath() introduction failed them 2020-06-16 17:25:01 +02:00
Jan Kundrát 0d010440c5 Fix build with clang 9.0.1 and libcxx
This should not be required in C++17 because there is an appropriate
class template deduction rule [1] which infers that it's going to be a
weak_ptr<T> when constructing from a shared_ptr<T>. However, in
clang/LLVM's libcxx C++ STL implementation this only got implemented in
May 2020 [2].

[1] https://en.cppreference.com/w/cpp/memory/weak_ptr/deduction_guides
[2] https://reviews.llvm.org/D69603
2020-06-16 16:51:53 +02:00
ChristianS99andChristian Schneider ae8849e545 Implement #104: add getObjectPath() for classes (#105)
* Implement #104: add getObjectPath() for classes

* Implement #104: changes requested in review

Co-authored-by: Christian Schneider <cschneider@radiodata.biz>
2020-05-28 15:36:58 +02:00
sangelovic fb35a9a196 Fix integration test cases failing in specific situations 2020-05-17 15:06:29 +02:00
sangelovic 6cbd49ddaa Install proper public sd-bus headers in internal libsystemd build 2020-05-17 15:05:24 +02:00
ChristianS99andChristian Schneider fb0a70a831 Fix #101: sanitize names of namespaces/methods/signals/properties/arguments (#102)
- add a list of c++ keywords and common defines
- sanitize names so that there are no functions/args with names that are reserved in c++

Co-authored-by: Christian Schneider <cschneider@radiodata.biz>
2020-05-16 22:57:37 +02:00
Viliam Lejcik 9af20af001 Fixed integration tests for libsystemd older than 242 2020-05-09 22:02:57 +02:00
Benjamin Kaufmann 63bbb07ef0 Fixup for 00d0837d98
* Add PendingAsyncCall return value to all relevant overloads of
  IProxy::callMethod().
2020-04-08 16:41:29 +02:00
sangelovic 00d0837d98 Introduce support for cancellable async calls 2020-04-04 16:30:56 +02:00
sangelovic e91bedd4cb Fix #92: CallData race condition in Proxy::callMethod 2020-04-02 20:46:38 +02:00
Oliver Tappe dc66efbbcb Fix #93: Get signals working for multiple proxies.
* Proxy::sdbus_signal_handler() needs to return 0 instead of 1 in
  order to allow multiple proxies listening to a signal all being
  triggered.
* Add test for emitting a signal to multiple proxies on same
  connection.
2020-03-26 21:19:18 +01:00
Stanislav Angelovič a23aadbe5e Fix required CMake version to v3.13
Fixes #86
2020-02-14 14:31:14 +01:00
Viliam Lejcik ae57c6760b sdbus-c++-xml2cpp: fixed file existence condition
fixes issue: https://github.com/Kistler-Group/sdbus-cpp/issues/83
2020-02-04 12:18:50 +01:00
Stanislav Angelovič 21820f7529 Update using-sdbus-c++.md 2020-02-02 23:03:24 +01:00
53 changed files with 2784 additions and 1101 deletions
+68
View File
@@ -0,0 +1,68 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04, ubuntu-20.04]
compiler: [g++, clang]
build: [shared-libsystemd]
include:
- os: ubuntu-20.04
compiler: g++
build: embedded-static-libsystemd
steps:
- uses: actions/checkout@v2
- name: install-libsystemd-toolchain
if: matrix.build == 'embedded-static-libsystemd'
run: |
sudo apt-get update -y
sudo apt-get install -y meson ninja-build libcap-dev libmount-dev m4 gperf
- name: install-libsystemd-dev
if: matrix.build == 'shared-libsystemd'
run: |
sudo apt-get update -y
sudo apt-get install -y libsystemd-dev
- name: install-clang
if: matrix.compiler == 'clang'
run: |
sudo apt-get install -y clang
sudo update-alternatives --remove-all cc
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang 10
sudo update-alternatives --remove-all c++
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 10
- name: configure-debug
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-18.04'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-O0 -g -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
- name: configure-release
if: matrix.build == 'shared-libsystemd' && matrix.os == 'ubuntu-20.04'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -W -Wextra -Wall -Wnon-virtual-dtor -Werror" -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON ..
- name: configure-with-embedded-libsystemd
if: matrix.build == 'embedded-static-libsystemd'
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DENABLE_PERF_TESTS=ON -DENABLE_STRESS_TESTS=ON -DBUILD_CODE_GEN=ON -DBUILD_LIBSYSTEMD=ON -DLIBSYSTEMD_VERSION=244 ..
- name: make
run: |
cd build
make -j2
- name: verify
run: |
cd build
sudo make install
ctest
+5 -2
View File
@@ -2,9 +2,9 @@
# PROJECT INFORMATION
#-------------------------------
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.13)
project(sdbus-c++ VERSION 0.8.1 LANGUAGES C CXX)
project(sdbus-c++ VERSION 0.8.3 LANGUAGES C CXX)
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
@@ -141,6 +141,7 @@ install(TARGETS ${EXPORT_SET}
option(BUILD_TESTS "Build and install tests (default OFF)" OFF)
if(BUILD_TESTS)
message(STATUS "Building with tests")
enable_testing()
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/tests")
endif()
@@ -152,6 +153,7 @@ endif()
option(BUILD_CODE_GEN "Build and install interface stub code generator (default OFF)" OFF)
if(BUILD_CODE_GEN)
message(STATUS "Building with code generator tool")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/tools")
endif()
@@ -162,6 +164,7 @@ endif()
option(BUILD_DOC "Build documentation for sdbus-c++" ON)
if(BUILD_DOC)
message(STATUS "Building with documentation")
option(BUILD_DOXYGEN_DOC "Build doxygen documentation for sdbus-c++ API" OFF)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/docs")
install(FILES README README.md NEWS COPYING ChangeLog AUTHORS DESTINATION ${CMAKE_INSTALL_DOCDIR})
+22
View File
@@ -147,3 +147,25 @@ v0.8.1
- Switch to full C++17 support
- Switch to more modern CMake (>=3.12)
- Provide better names to event loop-related IConnection methods, keep old ones marked as deprecated for backwards compatibility
v0.8.2
- Introduce support for cancellable async calls
- Add getObjectPath() for proxy and object classes
- Sanitize names of namespaces/methods/signals/properties/arguments in sdbus-c++-xml2cpp
- Fix delivery of signals to multiple proxies subscribed to them
- Fix file existence condition in sdbus-c++-xml2cpp
- Fix CallData race condition in Proxy::callMethod
- Fix integration tests for libsystemd older than 242
- Fix installation of public sd-bus headers in internal libsystemd build
- Fix integration test cases failing in specific situations
- Fix build with clang 9.0.1 and libcxx
- Fix potential data race in Proxy's condition variable
v0.8.3
- Fix build with gcc 8.3
- Address a few inconsistencies and make code more idiomatic
- Clean up integration tests
- Remove non-virtual-dtor warnings by making classes final
- Update CMake configuration flag names
- Fix unused variable warning for release builds
- Introduce CI workflow based on GitHub Actions
+6 -2
View File
@@ -1,6 +1,10 @@
sdbus-c++
=========
![ci](https://github.com/Kistler-Group/sdbus-cpp/workflows/CI/badge.svg)
![license](https://img.shields.io/github/license/Kistler-Group/sdbus-cpp)
![release](https://img.shields.io/github/v/release/Kistler-Group/sdbus-cpp)
sdbus-c++ is a high-level C++ D-Bus library for Linux designed to provide expressive, easy-to-use API in modern C++. It adds another layer of abstraction on top of sd-bus, a nice, fresh C D-Bus implementation by systemd.
sdbus-c++ has been written primarily as a replacement of dbus-c++, which currently suffers from a number of (unresolved) bugs, concurrency issues and inherent design complexities and limitations. sdbus-c++ has learned from dbus-c++ and has chosen a different path, a path of simple yet powerful design that is intuitive and friendly to the user and inherently free of those bugs.
@@ -38,11 +42,11 @@ $ sudo make install
Option for building sdbus-c++ unit and integration tests, invokable by `make test`. That incorporates downloading and building static libraries of Google Test. Default value: `OFF`. Use `-DBUILD_TESTS=ON` to enable building the tests. With this option turned on, you may also enable/disable the following options:
* `BUILD_PERF_TESTS` [boolean]
* `ENABLE_PERF_TESTS` [boolean]
Option for building sdbus-c++ performance tests. Default value: `OFF`.
* `BUILD_STRESS_TESTS` [boolean]
* `ENABLE_STRESS_TESTS` [boolean]
Option for building sdbus-c++ stress tests. Default value: `OFF`.
+8 -6
View File
@@ -30,19 +30,21 @@ if(LIBSYSTEMD_VERSION GREATER "240")
set(BUILD_VERSION_H ${NINJA} -C <BINARY_DIR> version.h)
endif()
message(STATUS "Building with embedded libsystemd v${LIBSYSTEMD_VERSION}")
include(ExternalProject)
ExternalProject_Add(LibsystemdBuildProject
PREFIX libsystemd-v${LIBSYSTEMD_VERSION}
GIT_REPOSITORY https://github.com/systemd/systemd.git
GIT_TAG v${LIBSYSTEMD_VERSION}
GIT_REPOSITORY https://github.com/systemd/systemd-stable.git
GIT_TAG v${LIBSYSTEMD_VERSION}-stable
GIT_SHALLOW 1
UPDATE_COMMAND ""
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove <BINARY_DIR>/*
COMMAND ${MESON} --prefix=<INSTALL_DIR> --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Dstatic-libsystemd=pic <SOURCE_DIR> <BINARY_DIR>
COMMAND ${MESON} --prefix=<INSTALL_DIR> --buildtype=${LIBSYSTEMD_BUILD_TYPE} -Dstatic-libsystemd=pic -Dselinux=false <SOURCE_DIR> <BINARY_DIR>
BUILD_COMMAND ${BUILD_VERSION_H}
COMMAND ${NINJA} -C <BINARY_DIR> libsystemd.a
BUILD_ALWAYS 1
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/src/libsystemd <INSTALL_DIR>/include
BUILD_ALWAYS 0
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/src/systemd <INSTALL_DIR>/include/systemd
LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1)
ExternalProject_Get_property(LibsystemdBuildProject SOURCE_DIR)
@@ -51,6 +53,6 @@ ExternalProject_Get_property(LibsystemdBuildProject INSTALL_DIR)
add_library(Systemd::Libsystemd STATIC IMPORTED)
set_target_properties(Systemd::Libsystemd PROPERTIES IMPORTED_LOCATION ${BINARY_DIR}/libsystemd.a)
file(MAKE_DIRECTORY ${INSTALL_DIR}/include) # Trick for CMake to stop complaining about non-existent ${INSTALL_DIR}/include directory
file(MAKE_DIRECTORY ${INSTALL_DIR}/include/systemd) # Trick for CMake to stop complaining about non-existent ${INSTALL_DIR}/include directory
target_include_directories(Systemd::Libsystemd INTERFACE ${INSTALL_DIR}/include)
target_link_libraries(Systemd::Libsystemd INTERFACE ${CAP_LIBRARIES} ${GLIBC_RT_LIBRARY} ${MOUNT_LIBRARIES})
+1 -1
View File
@@ -26,7 +26,7 @@ Introduction
sdbus-c++ is a C++ D-Bus library built on top of [sd-bus](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html), a lightweight D-Bus client library implemented within [systemd](https://github.com/systemd/systemd) project. It provides D-Bus functionality on a higher level of abstraction, trying to employ C++ type system to shift as much work as possible from the developer to the compiler.
sdbus-c++ does not cover the entire sd-bus API, but provides tools for implementing the most common functionality - RPC method calls, signals and properties. There is room for additions and improvements, as needed and when needed.
Although sdbus-c++ covers most of sd-bus API, it does not (yet) fully cover every sd-bus API detail. The focus is put on the most widely used functionality: D-Bus connections, object, proxies, synchronous and asynchronous method calls, signals, and properties. If you are missing a desired functionality, you are welcome to submit an issue, or, best, to contribute to sdbus-c++ by submitting a pull request.
Integrating sdbus-c++ into your project
---------------------------------------
+9
View File
@@ -131,8 +131,17 @@ namespace sdbus {
getObject().unregister();
}
/*!
* @brief Returns object path of the underlying DBus object
*/
const std::string& getObjectPath() const
{
return getObject().getObjectPath();
}
protected:
using base_type = AdaptorInterfaces;
~AdaptorInterfaces() = default;
};
}
+2 -1
View File
@@ -42,6 +42,7 @@ namespace sdbus {
class IProxy;
class Variant;
class Error;
class PendingAsyncCall;
}
namespace sdbus {
@@ -193,7 +194,7 @@ namespace sdbus {
template <typename _Rep, typename _Period>
AsyncMethodInvoker& withTimeout(const std::chrono::duration<_Rep, _Period>& timeout);
template <typename... _Args> AsyncMethodInvoker& withArguments(_Args&&... args);
template <typename _Function> void uponReplyInvoke(_Function&& callback);
template <typename _Function> PendingAsyncCall uponReplyInvoke(_Function&& callback);
private:
IProxy& proxy_;
+2 -2
View File
@@ -576,7 +576,7 @@ namespace sdbus {
}
template <typename _Function>
void AsyncMethodInvoker::uponReplyInvoke(_Function&& callback)
PendingAsyncCall AsyncMethodInvoker::uponReplyInvoke(_Function&& callback)
{
assert(method_.isValid()); // onInterface() must be placed/called prior to this function
@@ -594,7 +594,7 @@ namespace sdbus {
sdbus::apply(callback, error, args);
};
proxy_.callMethod(method_, std::move(asyncReplyHandler), timeout_);
return proxy_.callMethod(method_, std::move(asyncReplyHandler), timeout_);
}
/*** ---------------- ***/
+5
View File
@@ -435,6 +435,11 @@ namespace sdbus {
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] SignalEmitter emitSignal(const std::string& signalName);
/*!
* @brief Returns object path of the underlying DBus object
*/
virtual const std::string& getObjectPath() const = 0;
};
// Out-of-line member definitions
+54 -4
View File
@@ -38,6 +38,10 @@ namespace sdbus {
class MethodCall;
class MethodReply;
class IConnection;
class PendingAsyncCall;
namespace internal {
class Proxy;
}
}
namespace sdbus {
@@ -108,6 +112,7 @@ namespace sdbus {
* @param[in] message Message representing an async method call
* @param[in] asyncReplyCallback Handler for the async reply
* @param[in] timeout Timeout for dbus call in microseconds
* @return Cookie for the the pending asynchronous call
*
* The call is non-blocking. It doesn't wait for the reply. Once the reply arrives,
* the provided async reply handler will get invoked from the context of the connection
@@ -117,13 +122,13 @@ namespace sdbus {
*
* @throws sdbus::Error in case of failure
*/
virtual void callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout = 0) = 0;
virtual PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout = 0) = 0;
/*!
* @copydoc IProxy::callMethod(const MethodCall&,async_reply_handler,uint64_t)
*/
template <typename _Rep, typename _Period>
void callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout);
PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout);
/*!
* @brief Registers a handler for the desired signal emitted by the proxied D-Bus object
@@ -261,6 +266,51 @@ namespace sdbus {
* @throws sdbus::Error in case of failure
*/
[[nodiscard]] PropertySetter setProperty(const std::string& propertyName);
/*!
* @brief Returns object path of the underlying DBus object
*/
virtual const std::string& getObjectPath() const = 0;
};
/********************************************//**
* @class PendingAsyncCall
*
* PendingAsyncCall represents a simple handle type to cancel the delivery
* of the asynchronous D-Bus call result to the application.
*
* The handle is lifetime-independent from the originating Proxy object.
* It's safe to call its methods even after the Proxy has gone.
*
***********************************************/
class PendingAsyncCall
{
public:
/*!
* @brief Cancels the delivery of the pending asynchronous call result
*
* This function effectively removes the callback handler registered to the
* async D-Bus method call result delivery. Does nothing if the call was
* completed already, or if the originating Proxy object has gone meanwhile.
*/
void cancel();
/*!
* @brief Answers whether the asynchronous call is still pending
*
* @return True if the call is pending, false if the call has been fully completed
*
* Pending call in this context means a call whose results have not arrived, or
* have arrived and are currently being processed by the callback handler.
*/
bool isPending() const;
private:
friend internal::Proxy;
PendingAsyncCall(std::weak_ptr<void> callData);
private:
std::weak_ptr<void> callData_;
};
// Out-of-line member definitions
@@ -273,10 +323,10 @@ namespace sdbus {
}
template <typename _Rep, typename _Period>
inline void IProxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout)
inline PendingAsyncCall IProxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, const std::chrono::duration<_Rep, _Period>& timeout)
{
auto microsecs = std::chrono::duration_cast<std::chrono::microseconds>(timeout);
callMethod(message, std::move(asyncReplyCallback), microsecs.count());
return callMethod(message, std::move(asyncReplyCallback), microsecs.count());
}
inline MethodInvoker IProxy::callMethod(const std::string& methodName)
+1 -1
View File
@@ -44,7 +44,7 @@ namespace sdbus {
class ObjectPath;
class Signature;
template <typename... _ValueTypes> class Struct;
struct UnixFd;
class UnixFd;
class MethodReply;
namespace internal {
class ISdBus;
+9
View File
@@ -165,8 +165,17 @@ namespace sdbus {
getProxy().unregister();
}
/*!
* @brief Returns object path of the underlying DBus object
*/
const std::string& getObjectPath() const
{
return getProxy().getObjectPath();
}
protected:
using base_type = ProxyInterfaces;
~ProxyInterfaces() = default;
};
}
+1 -1
View File
@@ -41,7 +41,7 @@ namespace sdbus {
template <typename... _ValueTypes> class Struct;
class ObjectPath;
class Signature;
struct UnixFd;
class UnixFd;
class MethodCall;
class MethodReply;
class Signal;
+2
View File
@@ -154,6 +154,7 @@ namespace sdbus {
public:
using std::string::string;
ObjectPath() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
ObjectPath(const ObjectPath&) = default; // Fixes gcc 8.3 error (deleted copy constructor)
ObjectPath(std::string path)
: std::string(std::move(path))
{}
@@ -171,6 +172,7 @@ namespace sdbus {
public:
using std::string::string;
Signature() = default; // Fixes gcc 6.3 error (default c-tor is not imported in above using declaration)
Signature(const Signature&) = default; // Fixes gcc 8.3 error (deleted copy constructor)
Signature(std::string path)
: std::string(std::move(path))
{}
+1 -3
View File
@@ -393,9 +393,7 @@ bool Connection::processPendingRequest()
bool Connection::waitForNextRequest()
{
auto bus = bus_.get();
assert(bus != nullptr);
assert(bus_ != nullptr);
assert(loopExitFd_.fd != 0);
auto sdbusPollData = getEventLoopPollData();
+5
View File
@@ -225,6 +225,11 @@ sdbus::IConnection& Object::getConnection() const
return dynamic_cast<sdbus::IConnection&>(connection_);
}
const std::string& Object::getObjectPath() const
{
return objectPath_;
}
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
{
auto& vtable = interfaceData.vtable;
+1
View File
@@ -101,6 +101,7 @@ namespace sdbus::internal {
bool hasObjectManager() const override;
sdbus::IConnection& getConnection() const override;
const std::string& getObjectPath() const override;
private:
using InterfaceName = std::string;
+51 -11
View File
@@ -93,16 +93,20 @@ MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout)
return sendMethodCallMessageAndWaitForReply(message, timeout);
}
void Proxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout)
PendingAsyncCall Proxy::callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout)
{
SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL);
auto callback = (void*)&Proxy::sdbus_async_reply_handler;
auto callData = std::make_unique<AsyncCalls::CallData>(AsyncCalls::CallData{*this, std::move(asyncReplyCallback), {}});
auto callData = std::make_shared<AsyncCalls::CallData>(AsyncCalls::CallData{*this, std::move(asyncReplyCallback), {}});
auto weakData = std::weak_ptr<AsyncCalls::CallData>{callData};
callData->slot = message.send(callback, callData.get(), timeout);
pendingAsyncCalls_.addCall(callData->slot.get(), std::move(callData));
auto slotPtr = callData->slot.get();
pendingAsyncCalls_.addCall(slotPtr, std::move(callData));
return {weakData};
}
MethodReply Proxy::sendMethodCallMessageAndWaitForReply(const MethodCall& message, uint64_t timeout)
@@ -123,8 +127,8 @@ MethodReply Proxy::sendMethodCallMessageAndWaitForReply(const MethodCall& messag
void Proxy::SyncCallReplyData::sendMethodReplyToWaitingThread(MethodReply& reply, const Error* error)
{
SCOPE_EXIT{ cond_.notify_one(); };
std::unique_lock<std::mutex> lock{mutex_};
std::unique_lock lock{mutex_};
SCOPE_EXIT{ cond_.notify_one(); }; // This must happen before unlocking the mutex to avoid potential data race on spurious wakeup in the waiting thread
SCOPE_EXIT{ arrived_ = true; };
//error_ = nullptr; // Necessary if SyncCallReplyData instance is thread_local
@@ -137,7 +141,7 @@ void Proxy::SyncCallReplyData::sendMethodReplyToWaitingThread(MethodReply& reply
MethodReply Proxy::SyncCallReplyData::waitForMethodReply()
{
std::unique_lock<std::mutex> lock{mutex_};
std::unique_lock lock{mutex_};
cond_.wait(lock, [this](){ return arrived_; });
//arrived_ = false; // Necessary if SyncCallReplyData instance is thread_local
@@ -194,19 +198,27 @@ void Proxy::unregister()
interfaces_.clear();
}
const std::string& Proxy::getObjectPath() const
{
return objectPath_;
}
int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
{
auto* asyncCallData = static_cast<AsyncCalls::CallData*>(userData);
assert(asyncCallData != nullptr);
assert(asyncCallData->callback);
auto& proxy = asyncCallData->proxy;
auto slot = asyncCallData->slot.get();
// We are removing the CallData item at the complete scope exit, after the callback has been invoked.
// We can't do it earlier (before callback invocation for example), because CallBack data (slot release)
// is the synchronization point between callback invocation and Proxy::unregister.
SCOPE_EXIT
{
// Slot may be null if we're doing blocking synchronous call implemented by means of asynchronous call,
// because in that case the call data is still alive on the stack, we don't need to manage it separately.
if (asyncCallData->slot)
proxy.pendingAsyncCalls_.removeCall(asyncCallData->slot.get());
// Remove call meta-data if it's a real async call (a sync call done in terms of async has slot == nullptr)
if (slot)
proxy.pendingAsyncCalls_.removeCall(slot);
};
auto message = Message::Factory::create<MethodReply>(sdbusMessage, &proxy.connection_->getSdBusInterface());
@@ -238,7 +250,35 @@ int Proxy::sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd
callback(message);
return 1;
return 0;
}
}
namespace sdbus {
PendingAsyncCall::PendingAsyncCall(std::weak_ptr<void> callData)
: callData_(std::move(callData))
{
}
void PendingAsyncCall::cancel()
{
if (auto ptr = callData_.lock(); ptr != nullptr)
{
auto* callData = static_cast<internal::Proxy::AsyncCalls::CallData*>(ptr.get());
callData->proxy.pendingAsyncCalls_.removeCall(callData->slot.get());
// At this point, the callData item is being deleted, leading to the release of the
// sd-bus slot pointer. This release locks the global sd-bus mutex. If the async
// callback is currently being processed, the sd-bus mutex is locked by the event
// loop thread, thus access to the callData item is synchronized and thread-safe.
}
}
bool PendingAsyncCall::isPending() const
{
return !callData_.expired();
}
}
+26 -9
View File
@@ -52,7 +52,7 @@ namespace sdbus::internal {
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
MethodReply callMethod(const MethodCall& message, uint64_t timeout) override;
void callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) override;
PendingAsyncCall callMethod(const MethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) override;
void registerSignalHandler( const std::string& interfaceName
, const std::string& signalName
@@ -60,6 +60,8 @@ namespace sdbus::internal {
void finishRegistration() override;
void unregister() override;
const std::string& getObjectPath() const override;
private:
class SyncCallReplyData
{
@@ -81,6 +83,8 @@ namespace sdbus::internal {
static int sdbus_signal_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
private:
friend PendingAsyncCall;
std::unique_ptr< sdbus::internal::IConnection
, std::function<void(sdbus::internal::IConnection*)>
> connection_;
@@ -119,29 +123,42 @@ namespace sdbus::internal {
clear();
}
bool addCall(void* slot, std::unique_ptr<CallData>&& asyncCallData)
bool addCall(void* slot, std::shared_ptr<CallData> asyncCallData)
{
std::lock_guard lock(mutex_);
return calls_.emplace(slot, std::move(asyncCallData)).second;
}
bool removeCall(void* slot)
void removeCall(void* slot)
{
std::lock_guard lock(mutex_);
return calls_.erase(slot) > 0;
std::unique_lock lock(mutex_);
if (auto it = calls_.find(slot); it != calls_.end())
{
auto callData = std::move(it->second);
calls_.erase(it);
lock.unlock();
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
// out of the `mutex_' critical section here, because if the `removeCall` is called by some
// thread and at the same time Proxy's async reply handler (which already holds global sd-bus
// mutex) is in progress in a different thread, we get double-mutex deadlock.
}
}
void clear()
{
std::unique_lock<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
auto asyncCallSlots = std::move(calls_);
// Perform releasing of sd-bus slots outside of the calls_ critical section which avoids
// double mutex dead lock when the async reply handler is invoked at the same time.
lock.unlock();
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
// out of the `mutex_' critical section here, because if the `clear` is called by some thread
// and at the same time Proxy's async reply handler (which already holds global sd-bus
// mutex) is in progress in a different thread, we get double-mutex deadlock.
}
private:
std::unordered_map<void*, std::unique_ptr<CallData>> calls_;
std::unordered_map<void*, std::shared_ptr<CallData>> calls_;
std::mutex mutex_;
} pendingAsyncCalls_;
};
+19 -8
View File
@@ -39,14 +39,23 @@ set(UNITTESTS_SRCS
set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests)
set(INTEGRATIONTESTS_SRCS
${INTEGRATIONTESTS_SOURCE_DIR}/AdaptorAndProxy_test.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/Connection_test.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/adaptor-glue.h
${INTEGRATIONTESTS_SOURCE_DIR}/defs.h
${INTEGRATIONTESTS_SOURCE_DIR}/proxy-glue.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestingAdaptor.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestingProxy.h)
${INTEGRATIONTESTS_SOURCE_DIR}/DBusConnectionTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusGeneralTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusMethodsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusAsyncMethodsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusSignalsTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusPropertiesTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/DBusStandardInterfacesTests.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/Defs.h
${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-adaptor.h
${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-proxy.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.h
${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.cpp
${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp)
set(PERFTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/perftests)
set(STRESSTESTS_CLIENT_SRCS
@@ -93,6 +102,7 @@ if(ENABLE_PERF_TESTS OR ENABLE_STRESS_TESTS)
find_package(Threads REQUIRED)
if(ENABLE_PERF_TESTS)
message(STATUS "Building with performance tests")
add_executable(sdbus-c++-perf-tests-client ${STRESSTESTS_CLIENT_SRCS})
target_link_libraries(sdbus-c++-perf-tests-client sdbus-c++ Threads::Threads)
add_executable(sdbus-c++-perf-tests-server ${STRESSTESTS_SERVER_SRCS})
@@ -100,6 +110,7 @@ if(ENABLE_PERF_TESTS OR ENABLE_STRESS_TESTS)
endif()
if(ENABLE_STRESS_TESTS)
message(STATUS "Building with stress tests")
add_executable(sdbus-c++-stress-tests ${STRESSTESTS_SRCS})
target_link_libraries(sdbus-c++-stress-tests sdbus-c++ Threads::Threads)
endif()
+99 -78
View File
@@ -24,25 +24,19 @@
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
// Own
#include "TestingAdaptor.h"
#include "TestingProxy.h"
// sdbus
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
// gmock
#include <gtest/gtest.h>
#include <gmock/gmock.h>
// STL
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
@@ -52,63 +46,9 @@ using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
namespace
{
class AdaptorAndProxyFixture : public ::testing::Test
{
public:
static void SetUpTestCase()
{
s_connection->requestName(INTERFACE_NAME);
s_connection->enterEventLoopAsync();
}
static void TearDownTestCase()
{
s_connection->leaveEventLoop();
s_connection->releaseName(INTERFACE_NAME);
}
static bool waitUntil(std::atomic<bool>& flag, std::chrono::milliseconds timeout = 5s)
{
std::chrono::milliseconds elapsed{};
std::chrono::milliseconds step{5ms};
do {
std::this_thread::sleep_for(step);
elapsed += step;
if (elapsed > timeout)
return false;
} while (!flag);
return true;
}
private:
void SetUp() override
{
m_adaptor = std::make_unique<TestingAdaptor>(*s_connection);
m_proxy = std::make_unique<TestingProxy>(INTERFACE_NAME, OBJECT_PATH);
std::this_thread::sleep_for(50ms); // Give time for the proxy to start listening to signals
}
void TearDown() override
{
m_proxy.reset();
m_adaptor.reset();
}
public:
static std::unique_ptr<sdbus::IConnection> s_connection;
std::unique_ptr<TestingAdaptor> m_adaptor;
std::unique_ptr<TestingProxy> m_proxy;
};
std::unique_ptr<sdbus::IConnection> AdaptorAndProxyFixture::s_connection = sdbus::createSystemBusConnection();
}
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -119,16 +59,14 @@ TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
auto connection = sdbus::createConnection();
connection->requestName(INTERFACE_NAME);
ASSERT_NO_THROW(TestingAdaptor adaptor(*connection));
ASSERT_NO_THROW(TestingProxy proxy(INTERFACE_NAME, OBJECT_PATH));
ASSERT_NO_THROW(TestAdaptor adaptor(*connection));
ASSERT_NO_THROW(TestProxy proxy(INTERFACE_NAME, OBJECT_PATH));
connection->releaseName(INTERFACE_NAME);
}
// Methods
using SdbusTestObject = AdaptorAndProxyFixture;
TEST_F(SdbusTestObject, CallsEmptyMethodSuccesfully)
{
ASSERT_NO_THROW(m_proxy->noArgNoReturn());
@@ -210,7 +148,7 @@ TEST_F(SdbusTestObject, CallsMethodWithSignatureSuccesfully)
TEST_F(SdbusTestObject, CallsMethodWithObjectPathSuccesfully)
{
auto resObjectPath = m_proxy->getObjectPath();
auto resObjectPath = m_proxy->getObjPath();
ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE));
}
@@ -273,7 +211,7 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
});
m_proxy->doOperationClientSideAsyncWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
future.get(), Eq(100);
future.get();
FAIL() << "Expected sdbus::Error exception";
}
@@ -322,7 +260,7 @@ TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
std::atomic<int> startedCount{};
auto call = [&](uint32_t param)
{
TestingProxy proxy{INTERFACE_NAME, OBJECT_PATH};
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
auto result = proxy.doOperationAsync(param);
@@ -345,7 +283,7 @@ TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
std::atomic<int> startedCount{};
auto call = [&]()
{
TestingProxy proxy{INTERFACE_NAME, OBJECT_PATH};
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
@@ -385,6 +323,51 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
ASSERT_THAT(future.get(), Eq(100));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
{
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
auto call = m_proxy->doOperationClientSideAsync(100);
ASSERT_TRUE(call.isPending());
}
TEST_F(SdbusTestObject, CancelsPendingAsyncCallOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(100);
call.cancel();
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(100);
call.cancel();
ASSERT_FALSE(call.isPending());
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(0);
(void) future.get(); // Wait for the call to finish
ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); }));
}
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
@@ -414,17 +397,17 @@ TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentInterface)
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination)
{
TestingProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
{
TestingProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist");
TestProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist");
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
TEST_F(SdbusTestObject, ReceivesTwoSignalsWhileMakingMethodCall)
TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall)
{
m_proxy->emitTwoSimpleSignals();
@@ -455,6 +438,18 @@ TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully)
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
{
auto proxy1 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully)
{
m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}});
@@ -490,7 +485,7 @@ TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully)
TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty)
{
ASSERT_THROW(m_proxy->state("new_value"), sdbus::Error);
ASSERT_THROW(m_proxy->setStateProperty("new_value"), sdbus::Error);
}
TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
@@ -622,7 +617,20 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(1));
EXPECT_THAT(interfacesAndProperties.count(INTERFACE_NAME), Eq(1));
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#else
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
// So in this specific instance, `action' property is no more added to the list.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#endif
signalReceived = true;
};
@@ -639,7 +647,20 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); // 3 properties under INTERFACE_NAME
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#else
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
// So in this specific instance, `action' property is no more added to the list.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#endif
signalReceived = true;
};
@@ -0,0 +1,219 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusAsyncMethodsTests.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
{
try
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doOperationClientSideAsyncWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
future.get();
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply"));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out"));
}
catch(...)
{
FAIL() << "Expected sdbus::Error exception";
}
}
TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
{
// Yeah, this is kinda timing-dependent test, but times should be safe...
std::mutex mtx;
std::vector<uint32_t> results;
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
auto call = [&](uint32_t param)
{
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
auto result = proxy.doOperationAsync(param);
std::lock_guard<std::mutex> guard(mtx);
results.push_back(result);
};
std::thread invocations[]{std::thread{call, 1500}, std::thread{call, 1000}, std::thread{call, 500}};
while (startedCount != 3) ;
invoke = true;
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
ASSERT_THAT(results, ElementsAre(500, 1000, 1500));
}
TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
{
std::atomic<size_t> resultCount{};
std::atomic<bool> invoke{};
std::atomic<int> startedCount{};
auto call = [&]()
{
TestProxy proxy{INTERFACE_NAME, OBJECT_PATH};
++startedCount;
while (!invoke) ;
size_t localResultCount{};
for (size_t i = 0; i < 500; ++i)
{
auto result = proxy.doOperationAsync(i % 2);
if (result == (i % 2)) // Correct return value?
localResultCount++;
}
resultCount += localResultCount;
};
std::thread invocations[]{std::thread{call}, std::thread{call}, std::thread{call}};
while (startedCount != 3) ;
invoke = true;
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
ASSERT_THAT(resultCount, Eq(1500));
}
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doOperationClientSideAsync(100);
ASSERT_THAT(future.get(), Eq(100));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress)
{
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){});
auto call = m_proxy->doOperationClientSideAsync(100);
ASSERT_TRUE(call.isPending());
}
TEST_F(SdbusTestObject, CancelsPendingAsyncCallOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(100);
call.cancel();
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(100);
call.cancel();
ASSERT_FALSE(call.isPending());
}
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); });
auto call = m_proxy->doOperationClientSideAsync(0);
(void) future.get(); // Wait for the call to finish
ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); }));
}
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doErroneousOperationClientSideAsync();
ASSERT_THROW(future.get(), sdbus::Error);
}
@@ -1,8 +1,8 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file Connection_test.cpp
* @file DBusConnectionTests.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
@@ -25,7 +25,7 @@
*/
// Own
#include "defs.h"
#include "Defs.h"
// sdbus
#include <sdbus-c++/Error.h>
@@ -39,7 +39,7 @@
#include <thread>
using ::testing::Eq;
using namespace sdbus::test;
/*-------------------------------------*/
/* -- TEST CASES -- */
@@ -0,0 +1,56 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusGeneralTests.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using namespace sdbus::test;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST(AdaptorAndProxy, CanBeConstructedSuccesfully)
{
auto connection = sdbus::createConnection();
connection->requestName(INTERFACE_NAME);
ASSERT_NO_THROW(TestAdaptor adaptor(*connection));
ASSERT_NO_THROW(TestProxy proxy(INTERFACE_NAME, OBJECT_PATH));
connection->releaseName(INTERFACE_NAME);
}
+253
View File
@@ -0,0 +1,253 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusMethodsTests.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST_F(SdbusTestObject, CallsEmptyMethodSuccesfully)
{
ASSERT_NO_THROW(m_proxy->noArgNoReturn());
}
TEST_F(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully)
{
auto resInt = m_proxy->getInt();
ASSERT_THAT(resInt, Eq(INT32_VALUE));
auto multiplyRes = m_proxy->multiply(INT64_VALUE, DOUBLE_VALUE);
ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodsWithTuplesSuccesfully)
{
auto resTuple = m_proxy->getTuple();
ASSERT_THAT(std::get<0>(resTuple), Eq(UINT32_VALUE));
ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodsWithStructSuccesfully)
{
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{};
auto vectorRes = m_proxy->getInts16FromStruct(a);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{0})); // because second item is by default initialized to 0
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{
UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE}
};
vectorRes = m_proxy->getInts16FromStruct(b);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE}));
}
TEST_F(SdbusTestObject, CallsMethodWithVariantSuccesfully)
{
sdbus::Variant v{DOUBLE_VALUE};
auto variantRes = m_proxy->processVariant(v);
ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
}
TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
{
std::vector<int32_t> x{-2, 0, 2};
sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true};
auto mapOfVariants = m_proxy->getMapOfVariants(x, y);
decltype(mapOfVariants) res{{-2, false}, {0, false}, {2, true}};
ASSERT_THAT(mapOfVariants[-2].get<bool>(), Eq(res[-2].get<bool>()));
ASSERT_THAT(mapOfVariants[0].get<bool>(), Eq(res[0].get<bool>()));
ASSERT_THAT(mapOfVariants[2].get<bool>(), Eq(res[2].get<bool>()));
}
TEST_F(SdbusTestObject, CallsMethodWithStructInStructSuccesfully)
{
auto val = m_proxy->getStructInStruct();
ASSERT_THAT(val.get<0>(), Eq(STRING_VALUE));
ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully)
{
auto val = m_proxy->sumStructItems({1, 2}, {3, 4});
ASSERT_THAT(val, Eq(1 + 2 + 3 + 4));
}
TEST_F(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully)
{
auto val = m_proxy->sumVectorItems({1, 7}, {2, 3});
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3));
}
TEST_F(SdbusTestObject, CallsMethodWithSignatureSuccesfully)
{
auto resSignature = m_proxy->getSignature();
ASSERT_THAT(resSignature, Eq(SIGNATURE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithObjectPathSuccesfully)
{
auto resObjectPath = m_proxy->getObjPath();
ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithUnixFdSuccesfully)
{
auto resUnixFd = m_proxy->getUnixFd();
ASSERT_THAT(resUnixFd.get(), Gt(UNIX_FD_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
{
auto resComplex = m_proxy->getComplex();
ASSERT_THAT(resComplex.count(0), Eq(1));
}
TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag)
{
m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE);
ASSERT_TRUE(waitUntil(m_adaptor->m_wasMultiplyCalled));
ASSERT_THAT(m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE));
}
TEST_F(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully)
{
auto res = m_proxy->doOperationWith500msTimeout(20); // The operation will take 20ms, but the timeout is 500ms, so we are fine
ASSERT_THAT(res, Eq(20));
}
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut)
{
try
{
m_proxy->doOperationWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply"));
ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out"));
}
catch(...)
{
FAIL() << "Expected sdbus::Error exception";
}
}
TEST_F(SdbusTestObject, CallsMethodThatThrowsError)
{
try
{
m_proxy->throwError();
FAIL() << "Expected sdbus::Error exception";
}
catch (const sdbus::Error& e)
{
ASSERT_THAT(e.getName(), Eq("org.freedesktop.DBus.Error.AccessDenied"));
ASSERT_THAT(e.getMessage(), Eq("A test error occurred (Operation not permitted)"));
}
catch(...)
{
FAIL() << "Expected sdbus::Error exception";
}
}
TEST_F(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet)
{
ASSERT_NO_THROW(m_proxy->throwErrorWithNoReply());
ASSERT_TRUE(waitUntil(m_adaptor->m_wasThrowErrorCalled));
}
TEST_F(SdbusTestObject, FailsCallingNonexistentMethod)
{
ASSERT_THROW(m_proxy->callNonexistentMethod(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentInterface)
{
ASSERT_THROW(m_proxy->callMethodOnNonexistentInterface(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination)
{
TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
{
TestProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist");
ASSERT_THROW(proxy.getInt(), sdbus::Error);
}
TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall)
{
m_proxy->emitTwoSimpleSignals();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
}
#if LIBSYSTEMD_VERSION>=240
TEST_F(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239)
{
s_connection->setMethodCallTimeout(5000000);
ASSERT_THAT(s_connection->getMethodCallTimeout(), Eq(5000000));
}
#else
TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240)
{
ASSERT_THROW(s_connection->setMethodCallTimeout(5000000), sdbus::Error);
ASSERT_THROW(s_connection->getMethodCallTimeout(), sdbus::Error);
}
#endif
@@ -0,0 +1,74 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusPropertiesTests.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully)
{
ASSERT_THAT(m_proxy->state(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty)
{
ASSERT_THROW(m_proxy->setStateProperty("new_value"), sdbus::Error);
}
TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
{
uint32_t newActionValue = 5678;
m_proxy->action(newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
@@ -0,0 +1,94 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file AdaptorAndProxy_test.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully)
{
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
{
auto proxy1 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_connection, INTERFACE_NAME, OBJECT_PATH);
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully)
{
m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}});
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap));
ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("zero"));
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one"));
}
TEST_F(SdbusTestObject, EmitsSignalWithVariantSuccesfully)
{
double d = 3.14;
m_adaptor->emitSignalWithVariant(d);
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithVariant));
ASSERT_THAT(m_proxy->m_variantFromSignal, DoubleEq(d));
}
TEST_F(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully)
{
m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}});
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithSignature));
ASSERT_THAT(m_proxy->m_signatureFromSignal["platform"], Eq("av"));
}
@@ -0,0 +1,259 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2020 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file DBusStandardInterfacesTests.cpp
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "sdbus-c++/sdbus-c++.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <string>
#include <thread>
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
#include <unistd.h>
using ::testing::Eq;
using ::testing::DoubleEq;
using ::testing::Gt;
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/
/* -- TEST CASES -- */
/*-------------------------------------*/
TEST_F(SdbusTestObject, PingsViaPeerInterface)
{
ASSERT_NO_THROW(m_proxy->Ping());
}
TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface)
{
// If /etc/machine-id does not exist in your system (which is very likely because you have
// a non-systemd Linux), org.freedesktop.DBus.Peer.GetMachineId() will not work. To solve
// this, you can create /etc/machine-id yourself as symlink to /var/lib/dbus/machine-id,
// and then org.freedesktop.DBus.Peer.GetMachineId() will start to work.
if (::access("/etc/machine-id", F_OK) == -1)
GTEST_SKIP() << "/etc/machine-id file does not exist, GetMachineId() will not work";
ASSERT_NO_THROW(m_proxy->GetMachineId());
}
// TODO: Adjust expected xml and uncomment this test
//TEST_F(SdbusTestObject, AnswersXmlApiDescriptionViaIntrospectableInterface)
//{
// ASSERT_THAT(m_proxy->Introspect(), Eq(m_adaptor->getExpectedXmlApiDescription()));
//}
TEST_F(SdbusTestObject, GetsPropertyViaPropertiesInterface)
{
ASSERT_THAT(m_proxy->Get(INTERFACE_NAME, "state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, SetsPropertyViaPropertiesInterface)
{
uint32_t newActionValue = 2345;
m_proxy->Set(INTERFACE_NAME, "action", newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
{
const auto properties = m_proxy->GetAll(INTERFACE_NAME);
ASSERT_THAT(properties, SizeIs(3));
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
}
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& /*invalidatedProperties*/ )
{
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
EXPECT_THAT(changedProperties, SizeIs(1));
EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(!DEFAULT_BLOCKING_VALUE));
signalReceived = true;
};
m_proxy->blocking(!DEFAULT_BLOCKING_VALUE);
m_proxy->action(DEFAULT_ACTION_VALUE*2);
m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"});
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties )
{
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
EXPECT_THAT(changedProperties, SizeIs(1));
EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
ASSERT_THAT(invalidatedProperties, SizeIs(1));
EXPECT_THAT(invalidatedProperties[0], Eq("action"));
signalReceived = true;
};
m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME);
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects)
{
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0));
}
TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully)
{
auto subObject1 = sdbus::createObject(*s_connection, "/sub/path1");
subObject1->registerProperty("aProperty1").onInterface("org.sdbuscpp.integrationtests.iface1").withGetter([]{return uint8_t{123};});
subObject1->finishRegistration();
auto subObject2 = sdbus::createObject(*s_connection, "/sub/path2");
subObject2->registerProperty("aProperty2").onInterface("org.sdbuscpp.integrationtests.iface2").withGetter([]{return "hi";});
subObject2->finishRegistration();
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path1").at("org.sdbuscpp.integrationtests.iface1").at("aProperty1").get<uint8_t>(), Eq(123));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path2").at("org.sdbuscpp.integrationtests.iface2").at("aProperty2").get<std::string>(), Eq("hi"));
}
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(1));
EXPECT_THAT(interfacesAndProperties.count(INTERFACE_NAME), Eq(1));
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#else
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
// So in this specific instance, `action' property is no more added to the list.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#endif
signalReceived = true;
};
m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME});
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
#if LIBSYSTEMD_VERSION<=244
// Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#else
// Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only
// for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal.
// So in this specific instance, `action' property is no more added to the list.
EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state"));
EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking"));
#endif
signalReceived = true;
};
m_adaptor->emitInterfacesAddedSignal();
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
ASSERT_THAT(interfaces, SizeIs(1));
EXPECT_THAT(interfaces[0], Eq(INTERFACE_NAME));
signalReceived = true;
};
m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME});
ASSERT_TRUE(waitUntil(signalReceived));
}
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
{
std::atomic<bool> signalReceived{false};
m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces )
{
EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
ASSERT_THAT(interfaces, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces
signalReceived = true;
};
m_adaptor->emitInterfacesRemovedSignal();
ASSERT_TRUE(waitUntil(signalReceived));
}
@@ -2,7 +2,7 @@
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file defs.h
* @file Defs.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
@@ -29,6 +29,8 @@
#include "sdbus-c++/Types.h"
namespace sdbus { namespace test {
const std::string INTERFACE_NAME{"org.sdbuscpp.integrationtests"};
const std::string OBJECT_PATH{"/"};
@@ -49,4 +51,6 @@ const bool DEFAULT_BLOCKING_VALUE{true};
constexpr const double DOUBLE_VALUE{3.24L};
}}
#endif /* SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_ */
+416
View File
@@ -0,0 +1,416 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.cpp
*
* Created on: May 23, 2020
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestAdaptor.h"
#include <thread>
#include <chrono>
#include <atomic>
namespace sdbus { namespace test {
TestAdaptor::TestAdaptor(sdbus::IConnection& connection) :
AdaptorInterfaces(connection, OBJECT_PATH)
{
registerAdaptor();
}
TestAdaptor::~TestAdaptor()
{
unregisterAdaptor();
}
void TestAdaptor::noArgNoReturn()
{
}
int32_t TestAdaptor::getInt()
{
return INT32_VALUE;
}
std::tuple<uint32_t, std::string> TestAdaptor::getTuple()
{
return std::make_tuple(UINT32_VALUE, STRING_VALUE);
}
double TestAdaptor::multiply(const int64_t& a, const double& b)
{
return a * b;
}
void TestAdaptor::multiplyWithNoReply(const int64_t& a, const double& b)
{
m_multiplyResult = a * b;
m_wasMultiplyCalled = true;
}
std::vector<int16_t> TestAdaptor::getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
{
std::vector<int16_t> res{x.get<1>()};
auto y = std::get<std::vector<int16_t>>(x);
res.insert(res.end(), y.begin(), y.end());
return res;
}
sdbus::Variant TestAdaptor::processVariant(const sdbus::Variant& v)
{
sdbus::Variant res = static_cast<int32_t>(v.get<double>());
return res;
}
std::map<int32_t, sdbus::Variant> TestAdaptor::getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
{
std::map<int32_t, sdbus::Variant> res;
for (auto item : x)
{
res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y);
}
return res;
}
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> TestAdaptor::getStructInStruct()
{
return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}));
}
int32_t TestAdaptor::sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)
{
int32_t res{0};
res += std::get<0>(a) + std::get<1>(a);
res += std::get<0>(b) + std::get<1>(b);
return res;
}
uint32_t TestAdaptor::sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b)
{
uint32_t res{0};
for (auto x : a)
{
res += x;
}
for (auto x : b)
{
res += x;
}
return res;
}
uint32_t TestAdaptor::doOperation(const uint32_t& param)
{
std::this_thread::sleep_for(std::chrono::milliseconds(param));
return param;
}
void TestAdaptor::doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t param)
{
if (param == 0)
{
// Don't sleep and return the result from this thread
result.returnResults(param);
}
else
{
// Process asynchronously in another thread and return the result from there
std::thread([param, result = std::move(result)]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(param));
result.returnResults(param);
}).detach();
}
}
sdbus::Signature TestAdaptor::getSignature()
{
return SIGNATURE_VALUE;
}
sdbus::ObjectPath TestAdaptor::getObjPath()
{
return OBJECT_PATH_VALUE;
}
sdbus::UnixFd TestAdaptor::getUnixFd()
{
return sdbus::UnixFd{UNIX_FD_VALUE};
}
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> TestAdaptor::getComplex()
{
return { // map
{
0, // uint_64_t
{ // struct
{ // map
{
23, // uint8_t
{ // vector
{ // struct
"/object/path", // object path
false,
Variant{3.14},
{ // map
{0, "zero"}
}
}
}
}
},
"a{t(a{ya(obva{is})}gs)}", // signature
std::string{}
}
}
};
}
void TestAdaptor::throwError()
{
m_wasThrowErrorCalled = true;
throw sdbus::createError(1, "A test error occurred");
}
void TestAdaptor::throwErrorWithNoReply()
{
TestAdaptor::throwError();
}
void TestAdaptor::doPrivilegedStuff()
{
// Intentionally left blank
}
void TestAdaptor::emitTwoSimpleSignals()
{
emitSimpleSignal();
emitSignalWithMap({});
}
std::string TestAdaptor::state()
{
return m_state;
}
uint32_t TestAdaptor::action()
{
return m_action;
}
void TestAdaptor::action(const uint32_t& value)
{
m_action = value;
}
bool TestAdaptor::blocking()
{
return m_blocking;
}
void TestAdaptor::blocking(const bool& value)
{
m_blocking = value;
}
void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
{
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(s);
}
std::string TestAdaptor::getExpectedXmlApiDescription() const
{
return
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" type="s" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="GetAll">
<arg name="interface" direction="in" type="s"/>
<arg name="properties" direction="out" type="a{sv}"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.ObjectManager">
<method name="GetManagedObjects">
<arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
</method>
<signal name="InterfacesAdded">
<arg type="o" name="object_path"/>
<arg type="a{sa{sv}}" name="interfaces_and_properties"/>
</signal>
<signal name="InterfacesRemoved">
<arg type="o" name="object_path"/>
<arg type="as" name="interfaces"/>
</signal>
</interface>
<interface name="org.sdbuscpp.integrationtests">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<method name="doOperation">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doOperationAsync">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doPrivilegedStuff">
<annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
</method>
<method name="emitTwoSimpleSignals">
</method>
<method name="getComplex">
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</method>
<method name="getInt">)delimiter"
#if LIBSYSTEMD_VERSION>=242
R"delimiter(
<arg type="i" name="anInt" direction="out"/>)delimiter"
#else
R"delimiter(
<arg type="i" direction="out"/>)delimiter"
#endif
R"delimiter(
</method>
<method name="getInts16FromStruct">
<arg type="(yndsan)" direction="in"/>
<arg type="an" direction="out"/>
</method>
<method name="getMapOfVariants">)delimiter"
#if LIBSYSTEMD_VERSION>=242
R"delimiter(
<arg type="ai" name="x" direction="in"/>
<arg type="(vv)" name="y" direction="in"/>
<arg type="a{iv}" name="aMapOfVariants" direction="out"/>)delimiter"
#else
R"delimiter(
<arg type="ai" direction="in"/>
<arg type="(vv)" direction="in"/>
<arg type="a{iv}" direction="out"/>)delimiter"
#endif
R"delimiter(
</method>
<method name="getObjPath">
<arg type="o" direction="out"/>
</method>
<method name="getSignature">
<arg type="g" direction="out"/>
</method>
<method name="getStructInStruct">
<arg type="(s(a{ii}))" direction="out"/>
</method>
<method name="getTuple">
<arg type="u" direction="out"/>
<arg type="s" direction="out"/>
</method>
<method name="getUnixFd">
<arg type="h" direction="out"/>
</method>
<method name="multiply">)delimiter"
#if LIBSYSTEMD_VERSION>=242
R"delimiter(
<arg type="x" name="a" direction="in"/>
<arg type="d" name="b" direction="in"/>
<arg type="d" name="result" direction="out"/>)delimiter"
#else
R"delimiter(
<arg type="x" direction="in"/>
<arg type="d" direction="in"/>
<arg type="d" direction="out"/>)delimiter"
#endif
R"delimiter(
</method>
<method name="multiplyWithNoReply">
<arg type="x" direction="in"/>
<arg type="d" direction="in"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<method name="noArgNoReturn">
</method>
<method name="processVariant">
<arg type="v" direction="in"/>
<arg type="v" direction="out"/>
</method>
<method name="sumStructItems">
<arg type="(yq)" direction="in"/>
<arg type="(ix)" direction="in"/>
<arg type="i" direction="out"/>
</method>
<method name="sumVectorItems">
<arg type="aq" direction="in"/>
<arg type="at" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="throwError">
</method>
<method name="throwErrorWithNoReply">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<signal name="signalWithMap">
<arg type="a{is}"/>
</signal>
<signal name="signalWithVariant">
<arg type="v"/>
</signal>
<signal name="simpleSignal">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</signal>
<property name="action" type="u" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="blocking" type="b" access="readwrite">
</property>
<property name="state" type="s" access="read">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
</interface>
</node>
)delimiter";
}
}}
+93
View File
@@ -0,0 +1,93 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTADAPTOR_H_
#define SDBUS_CPP_INTEGRATIONTESTS_TESTADAPTOR_H_
#include "integrationtests-adaptor.h"
#include "Defs.h"
#include <thread>
#include <chrono>
#include <atomic>
namespace sdbus { namespace test {
class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integrationtests_adaptor
, sdbus::Properties_adaptor
, sdbus::ObjectManager_adaptor >
{
public:
TestAdaptor(sdbus::IConnection& connection);
~TestAdaptor();
protected:
void noArgNoReturn() override;
int32_t getInt() override;
std::tuple<uint32_t, std::string> getTuple() override;
double multiply(const int64_t& a, const double& b) override;
void multiplyWithNoReply(const int64_t& a, const double& b) override;
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0) override;
sdbus::Variant processVariant(const sdbus::Variant& variant) override;
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) override;
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() override;
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1) override;
uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1) override;
uint32_t doOperation(const uint32_t& arg0) override;
void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) override;
sdbus::Signature getSignature() override;
sdbus::ObjectPath getObjPath() override;
sdbus::UnixFd getUnixFd() override;
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() override;
void throwError() override;
void throwErrorWithNoReply() override;
void doPrivilegedStuff() override;
void emitTwoSimpleSignals() override;
uint32_t action() override;
void action(const uint32_t& value) override;
bool blocking() override;
void blocking(const bool& value) override;
std::string state() override;
public:
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
std::string getExpectedXmlApiDescription() const;
private:
const std::string m_state{DEFAULT_STATE_VALUE};
uint32_t m_action{DEFAULT_ACTION_VALUE};
bool m_blocking{DEFAULT_BLOCKING_VALUE};
public: // for tests
// For dont-expect-reply method call verifications
mutable std::atomic<bool> m_wasMultiplyCalled{false};
mutable double m_multiplyResult{};
mutable std::atomic<bool> m_wasThrowErrorCalled{false};
};
}}
#endif /* INTEGRATIONTESTS_TESTADAPTOR_H_ */
+33
View File
@@ -0,0 +1,33 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.cpp
*
* Created on: May 23, 2020
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestFixture.h"
namespace sdbus { namespace test {
std::unique_ptr<sdbus::IConnection> TestFixture::s_connection = sdbus::createSystemBusConnection();
}}
+104
View File
@@ -0,0 +1,104 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_
#define SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_
#include "TestAdaptor.h"
#include "TestProxy.h"
#include "Defs.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <thread>
#include <chrono>
#include <atomic>
#include <chrono>
namespace sdbus { namespace test {
class TestFixture : public ::testing::Test
{
public:
static void SetUpTestCase()
{
s_connection->requestName(INTERFACE_NAME);
s_connection->enterEventLoopAsync();
}
static void TearDownTestCase()
{
s_connection->leaveEventLoop();
s_connection->releaseName(INTERFACE_NAME);
}
template <typename _Fnc>
static bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
using namespace std::chrono_literals;
std::chrono::milliseconds elapsed{};
std::chrono::milliseconds step{5ms};
do {
std::this_thread::sleep_for(step);
elapsed += step;
if (elapsed > timeout)
return false;
} while (!fnc());
return true;
}
static bool waitUntil(std::atomic<bool>& flag, std::chrono::milliseconds timeout = std::chrono::seconds(5))
{
return waitUntil([&flag]() -> bool { return flag; }, timeout);
}
private:
void SetUp() override
{
m_adaptor = std::make_unique<TestAdaptor>(*s_connection);
m_proxy = std::make_unique<TestProxy>(INTERFACE_NAME, OBJECT_PATH);
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy to start listening to signals
}
void TearDown() override
{
m_proxy.reset();
m_adaptor.reset();
}
public:
static std::unique_ptr<sdbus::IConnection> s_connection;
std::unique_ptr<TestAdaptor> m_adaptor;
std::unique_ptr<TestProxy> m_proxy;
};
}}
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */
+170
View File
@@ -0,0 +1,170 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestAdaptor.cpp
*
* Created on: May 23, 2020
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestProxy.h"
#include <thread>
#include <chrono>
#include <atomic>
namespace sdbus { namespace test {
TestProxy::TestProxy(std::string destination, std::string objectPath)
: ProxyInterfaces(std::move(destination), std::move(objectPath))
{
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
registerProxy();
}
TestProxy::TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
{
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s){ this->onSignalWithoutRegistration(s); });
registerProxy();
}
TestProxy::~TestProxy()
{
unregisterProxy();
}
void TestProxy::onSimpleSignal()
{
m_gotSimpleSignal = true;
}
void TestProxy::onSignalWithMap(const std::map<int32_t, std::string>& aMap)
{
m_mapFromSignal = aMap;
m_gotSignalWithMap = true;
}
void TestProxy::onSignalWithVariant(const sdbus::Variant& aVariant)
{
m_variantFromSignal = aVariant.get<double>();
m_gotSignalWithVariant = true;
}
void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
{
m_signatureFromSignal[std::get<0>(s)] = static_cast<std::string>(std::get<0>(std::get<1>(s)));
m_gotSignalWithSignature = true;
}
void TestProxy::onDoOperationReply(uint32_t returnValue, const sdbus::Error* error)
{
if (m_DoOperationClientSideAsyncReplyHandler)
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
}
void TestProxy::onPropertiesChanged( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties )
{
if (m_onPropertiesChangedHandler)
m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties);
}
void TestProxy::onInterfacesAdded(const sdbus::ObjectPath& objectPath, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties)
{
if (m_onInterfacesAddedHandler)
m_onInterfacesAddedHandler(objectPath, interfacesAndProperties);
}
void TestProxy::onInterfacesRemoved(const sdbus::ObjectPath& objectPath, const std::vector<std::string>& interfaces)
{
if (m_onInterfacesRemovedHandler)
m_onInterfacesRemovedHandler(objectPath, interfaces);
}
void TestProxy::installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler)
{
m_DoOperationClientSideAsyncReplyHandler = std::move(handler);
}
uint32_t TestProxy::doOperationWith500msTimeout(uint32_t param)
{
using namespace std::chrono_literals;
uint32_t result;
getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(500000us).withArguments(param).storeResultsTo(result);
return result;
}
sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param)
{
return getProxy().callMethodAsync("doOperation")
.onInterface(sdbus::test::INTERFACE_NAME)
.withArguments(param)
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
{
this->onDoOperationReply(returnValue, error);
});
}
void TestProxy::doErroneousOperationClientSideAsync()
{
getProxy().callMethodAsync("throwError")
.onInterface(sdbus::test::INTERFACE_NAME)
.uponReplyInvoke([this](const sdbus::Error* error)
{
this->onDoOperationReply(0, error);
});
}
void TestProxy::doOperationClientSideAsyncWith500msTimeout(uint32_t param)
{
using namespace std::chrono_literals;
getProxy().callMethodAsync("doOperation")
.onInterface(sdbus::test::INTERFACE_NAME)
.withTimeout(500000us)
.withArguments(param)
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
{
this->onDoOperationReply(returnValue, error);
});
}
int32_t TestProxy::callNonexistentMethod()
{
int32_t result;
getProxy().callMethod("callNonexistentMethod").onInterface(sdbus::test::INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t TestProxy::callMethodOnNonexistentInterface()
{
int32_t result;
getProxy().callMethod("someMethod").onInterface("sdbuscpp.interface.that.does.not.exist").storeResultsTo(result);
return result;
}
void TestProxy::setStateProperty(const std::string& value)
{
getProxy().setProperty("state").onInterface(sdbus::test::INTERFACE_NAME).toValue(value);
}
}}
@@ -2,7 +2,7 @@
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestingProxy.h
* @file TestAdaptor.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
@@ -24,87 +24,53 @@
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTINGPROXY_H_
#define SDBUS_CPP_INTEGRATIONTESTS_TESTINGPROXY_H_
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_
#define SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_
#include "proxy-glue.h"
#include "integrationtests-proxy.h"
#include "Defs.h"
#include <thread>
#include <chrono>
#include <atomic>
class TestingProxy : public sdbus::ProxyInterfaces< ::testing_proxy
, sdbus::Peer_proxy
, sdbus::Introspectable_proxy
, sdbus::Properties_proxy
, sdbus::ObjectManager_proxy >
namespace sdbus { namespace test {
class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy
, sdbus::Peer_proxy
, sdbus::Introspectable_proxy
, sdbus::Properties_proxy
, sdbus::ObjectManager_proxy >
{
public:
TestingProxy(std::string destination, std::string objectPath)
: ProxyInterfaces(std::move(destination), std::move(objectPath))
{
registerProxy();
}
~TestingProxy()
{
unregisterProxy();
}
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler)
{
m_DoOperationClientSideAsyncReplyHandler = handler;
}
TestProxy(std::string destination, std::string objectPath);
TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath);
~TestProxy();
protected:
void onSimpleSignal() override
{
m_gotSimpleSignal = true;
}
void onSimpleSignal() override;
void onSignalWithMap(const std::map<int32_t, std::string>& aMap) override;
void onSignalWithVariant(const sdbus::Variant& aVariant) override;
void onSignalWithMap(const std::map<int32_t, std::string>& m) override
{
m_mapFromSignal = m;
m_gotSignalWithMap = true;
}
void onSignalWithVariant(const sdbus::Variant& v) override
{
m_variantFromSignal = v.get<double>();
m_gotSignalWithVariant = true;
}
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s) override
{
m_signatureFromSignal[std::get<0>(s)] = static_cast<std::string>(std::get<0>(std::get<1>(s)));
m_gotSignalWithSignature = true;
}
void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) override
{
if (m_DoOperationClientSideAsyncReplyHandler)
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
}
void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s);
void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error);
// Signals of standard D-Bus interfaces
void onPropertiesChanged( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties ) override
{
if (m_onPropertiesChangedHandler)
m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties);
}
, const std::vector<std::string>& invalidatedProperties ) override;
void onInterfacesAdded( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override
{
if (m_onInterfacesAddedHandler)
m_onInterfacesAddedHandler(objectPath, interfacesAndProperties);
}
void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces) override
{
if (m_onInterfacesRemovedHandler)
m_onInterfacesRemovedHandler(objectPath, interfaces);
}
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override;
void onInterfacesRemoved( const sdbus::ObjectPath& objectPath, const std::vector<std::string>& interfaces) override;
public:
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler);
uint32_t doOperationWith500msTimeout(uint32_t param);
sdbus::PendingAsyncCall doOperationClientSideAsync(uint32_t param);
void doErroneousOperationClientSideAsync();
void doOperationClientSideAsyncWith500msTimeout(uint32_t param);
int32_t callNonexistentMethod();
int32_t callMethodOnNonexistentInterface();
void setStateProperty(const std::string& value);
//private:
public: // for tests
@@ -123,4 +89,6 @@ public: // for tests
std::function<void(const sdbus::ObjectPath&, const std::vector<std::string>&)> m_onInterfacesRemovedHandler;
};
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTINGPROXY_H_ */
}}
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ */
-246
View File
@@ -1,246 +0,0 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file TestingAdaptor.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTINGADAPTOR_H_
#define SDBUS_CPP_INTEGRATIONTESTS_TESTINGADAPTOR_H_
#include "adaptor-glue.h"
#include <thread>
#include <chrono>
#include <atomic>
class TestingAdaptor : public sdbus::AdaptorInterfaces< testing_adaptor
, sdbus::Properties_adaptor
, sdbus::ObjectManager_adaptor >
{
public:
TestingAdaptor(sdbus::IConnection& connection) :
AdaptorInterfaces(connection, OBJECT_PATH)
{
registerAdaptor();
}
~TestingAdaptor()
{
unregisterAdaptor();
}
protected:
void noArgNoReturn() const override
{
}
int32_t getInt() const override
{
return INT32_VALUE;
}
std::tuple<uint32_t, std::string> getTuple() const override
{
return std::make_tuple(UINT32_VALUE, STRING_VALUE);
}
double multiply(const int64_t& a, const double& b) const override
{
return a * b;
}
void multiplyWithNoReply(const int64_t& a, const double& b) const override
{
m_multiplyResult = a * b;
m_wasMultiplyCalled = true;
}
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x) const override
{
std::vector<int16_t> res{x.get<1>()};
auto y = std::get<std::vector<int16_t>>(x);
res.insert(res.end(), y.begin(), y.end());
return res;
}
sdbus::Variant processVariant(sdbus::Variant& v) override
{
sdbus::Variant res = static_cast<int32_t>(v.get<double>());
return res;
}
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) const override
{
std::map<int32_t, sdbus::Variant> res;
for (auto item : x)
{
res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y);
}
return res;
}
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() const override
{
return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}));
}
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b) override
{
int32_t res{0};
res += std::get<0>(a) + std::get<1>(a);
res += std::get<0>(b) + std::get<1>(b);
return res;
}
uint32_t sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b) override
{
uint32_t res{0};
for (auto x : a)
{
res += x;
}
for (auto x : b)
{
res += x;
}
return res;
}
uint32_t doOperation(uint32_t param) override
{
std::this_thread::sleep_for(std::chrono::milliseconds(param));
return param;
}
void doOperationAsync(uint32_t param, sdbus::Result<uint32_t> result) override
{
if (param == 0)
{
// Don't sleep and return the result from this thread
result.returnResults(param);
}
else
{
// Process asynchronously in another thread and return the result from there
std::thread([param, result = std::move(result)]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(param));
result.returnResults(param);
}).detach();
}
}
sdbus::Signature getSignature() const override
{
return SIGNATURE_VALUE;
}
sdbus::ObjectPath getObjectPath() const override
{
return OBJECT_PATH_VALUE;
}
sdbus::UnixFd getUnixFd() const override
{
return sdbus::UnixFd{UNIX_FD_VALUE};
}
ComplexType getComplex() const override
{
return { // map
{
0, // uint_64_t
{ // struct
{ // map
{
'a', // uint8_t
{ // vector
{ // struct
"/object/path", // object path
false,
3.14,
{ // map
{0, "zero"}
}
}
}
}
},
"a{t(a{ya(obva{is})}gs)}", // signature
""
}
}
};
}
void throwError() const override
{
m_wasThrowErrorCalled = true;
throw sdbus::createError(1, "A test error occurred");
}
void emitTwoSimpleSignals() override
{
emitSimpleSignal();
emitSignalWithMap({});
}
std::string state() override
{
return m_state;
}
uint32_t action() override
{
return m_action;
}
void action(const uint32_t& value) override
{
m_action = value;
}
bool blocking() override
{
return m_blocking;
}
void blocking(const bool& value) override
{
m_blocking = value;
}
private:
const std::string m_state{DEFAULT_STATE_VALUE};
uint32_t m_action{DEFAULT_ACTION_VALUE};
bool m_blocking{DEFAULT_BLOCKING_VALUE};
public: // for tests
// For dont-expect-reply method call verifications
mutable std::atomic<bool> m_wasMultiplyCalled{false};
mutable double m_multiplyResult{};
mutable std::atomic<bool> m_wasThrowErrorCalled{false};
};
#endif /* INTEGRATIONTESTS_TESTINGADAPTOR_H_ */
-341
View File
@@ -1,341 +0,0 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file adaptor-glue.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CPP_INTEGRATIONTESTS_ADAPTOR_GLUE_H_
#define SDBUS_CPP_INTEGRATIONTESTS_ADAPTOR_GLUE_H_
#include "defs.h"
// sdbus
#include "sdbus-c++/sdbus-c++.h"
using ComplexType = std::map<
uint64_t,
sdbus::Struct<
std::map<
uint8_t,
std::vector<
sdbus::Struct<
sdbus::ObjectPath,
bool,
sdbus::Variant,
std::map<int, std::string>
>
>
>,
sdbus::Signature,
std::string // char* leads to type and memory issues, std::string is best choice
>
>;
class testing_adaptor
{
protected:
testing_adaptor(sdbus::IObject& object) :
object_(object)
{
object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); });
object_.registerMethod("getInt").onInterface(INTERFACE_NAME).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getTuple(); });
object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).implementedAs([this](
const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x){ return this->getInts16FromStruct(x); });
object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Variant& v){ return this->processVariant(v); });
object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME)
.withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](
const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x ,y); });
object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getStructInStruct(); });
object_.registerMethod("sumStructItems").onInterface(INTERFACE_NAME).implementedAs([this](
const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b){
return this->sumStructItems(a, b);
});
object_.registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).implementedAs([this](
const std::vector<uint16_t>& a, const std::vector<uint64_t>& b){
return this->sumVectorItems(a, b);
});
object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).implementedAs([this](uint32_t param)
{
return this->doOperation(param);
});
object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result<uint32_t> result, uint32_t param)
{
this->doOperationAsync(param, std::move(result));
});
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getSignature(); });
object_.registerMethod("getObjectPath").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getObjectPath(); });
object_.registerMethod("getUnixFd").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getUnixFd(); });
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getComplex(); }).markAsDeprecated();
object_.registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); });
object_.registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ this->throwError(); }).withNoReply();
object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([](){}).markAsPrivileged();
object_.registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ this->emitTwoSimpleSignals(); });
// registration of signals is optional, it is useful because of introspection
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
// Note: sd-bus of libsystemd up to v244 has a bug where it doesn't generate signal parameter names in introspection XML. Signal param names commented temporarily.
object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>(/*"aMap"*/);
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>(/*"aVariant"*/);
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
//object_.registerProperty("blocking").onInterface(INTERFACE_NAME)./*withGetter([this](){ return this->blocking(); }).*/withSetter([this](const bool& value){ this->blocking(value); });
object_.registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
}
~testing_adaptor() = default;
public:
void emitSimpleSignal()
{
object_.emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
}
void emitSignalWithMap(const std::map<int32_t, std::string>& map)
{
object_.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(map);
}
void emitSignalWithVariant(const sdbus::Variant& v)
{
object_.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(v);
}
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
{
object_.emitSignal("signalWithoutRegistration").onInterface(INTERFACE_NAME).withArguments(s);
}
void emitSignalOnNonexistentInterface()
{
object_.emitSignal("simpleSignal").onInterface("sdbuscpp.interface.that.does.not.exist");
}
private:
sdbus::IObject& object_;
protected:
virtual void noArgNoReturn() const = 0;
virtual int32_t getInt() const = 0;
virtual std::tuple<uint32_t, std::string> getTuple() const = 0;
virtual double multiply(const int64_t& a, const double& b) const = 0;
virtual void multiplyWithNoReply(const int64_t& a, const double& b) const = 0;
virtual std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x) const = 0;
virtual sdbus::Variant processVariant(sdbus::Variant& v) = 0;
virtual std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) const = 0;
virtual sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() const = 0;
virtual int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b) = 0;
virtual uint32_t sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b) = 0;
virtual uint32_t doOperation(uint32_t param) = 0;
virtual void doOperationAsync(uint32_t param, sdbus::Result<uint32_t> result) = 0;
virtual sdbus::Signature getSignature() const = 0;
virtual sdbus::ObjectPath getObjectPath() const = 0;
virtual sdbus::UnixFd getUnixFd() const = 0;
virtual ComplexType getComplex() const = 0;
virtual void throwError() const = 0;
virtual void emitTwoSimpleSignals() = 0;
virtual std::string state() = 0;
virtual uint32_t action() = 0;
virtual void action(const uint32_t& value) = 0;
virtual bool blocking() = 0;
virtual void blocking(const bool& value) = 0;
public: // For testing purposes
std::string getExpectedXmlApiDescription()
{
return
R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Peer">
<method name="Ping"/>
<method name="GetMachineId">
<arg type="s" name="machine_uuid" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" type="s" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="GetAll">
<arg name="interface" direction="in" type="s"/>
<arg name="properties" direction="out" type="a{sv}"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="property" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
</signal>
</interface>
<interface name="org.freedesktop.DBus.ObjectManager">
<method name="GetManagedObjects">
<arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
</method>
<signal name="InterfacesAdded">
<arg type="o" name="object_path"/>
<arg type="a{sa{sv}}" name="interfaces_and_properties"/>
</signal>
<signal name="InterfacesRemoved">
<arg type="o" name="object_path"/>
<arg type="as" name="interfaces"/>
</signal>
</interface>
<interface name="org.sdbuscpp.integrationtests">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<method name="doOperation">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doOperationAsync">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doPrivilegedStuff">
<annotation name="org.freedesktop.systemd1.Privileged" value="true"/>
</method>
<method name="emitTwoSimpleSignals">
</method>
<method name="getComplex">
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</method>
<method name="getInt">
<arg type="i" name="anInt" direction="out"/>
</method>
<method name="getInts16FromStruct">
<arg type="(yndsan)" direction="in"/>
<arg type="an" direction="out"/>
</method>
<method name="getMapOfVariants">
<arg type="ai" name="x" direction="in"/>
<arg type="(vv)" name="y" direction="in"/>
<arg type="a{iv}" name="aMapOfVariants" direction="out"/>
</method>
<method name="getObjectPath">
<arg type="o" direction="out"/>
</method>
<method name="getSignature">
<arg type="g" direction="out"/>
</method>
<method name="getStructInStruct">
<arg type="(s(a{ii}))" direction="out"/>
</method>
<method name="getTuple">
<arg type="u" direction="out"/>
<arg type="s" direction="out"/>
</method>
<method name="getUnixFd">
<arg type="h" direction="out"/>
</method>
<method name="multiply">
<arg type="x" name="a" direction="in"/>
<arg type="d" name="b" direction="in"/>
<arg type="d" name="result" direction="out"/>
</method>
<method name="multiplyWithNoReply">
<arg type="x" direction="in"/>
<arg type="d" direction="in"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<method name="noArgNoReturn">
</method>
<method name="processVariant">
<arg type="v" direction="in"/>
<arg type="v" direction="out"/>
</method>
<method name="sumStructItems">
<arg type="(yq)" direction="in"/>
<arg type="(ix)" direction="in"/>
<arg type="i" direction="out"/>
</method>
<method name="sumVectorItems">
<arg type="aq" direction="in"/>
<arg type="at" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="throwError">
</method>
<method name="throwErrorWithNoReply">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<signal name="signalWithMap">
<arg type="a{is}"/>
</signal>
<signal name="signalWithVariant">
<arg type="v"/>
</signal>
<signal name="simpleSignal">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</signal>
<property name="action" type="u" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="blocking" type="b" access="readwrite">
</property>
<property name="state" type="s" access="read">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
</interface>
</node>
)delimiter";
}
};
#endif /* SDBUS_CPP_INTEGRATIONTESTS_ADAPTOR_GLUE_H_ */
@@ -0,0 +1,109 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__integrationtests_adaptor_h__adaptor__H__
#define __sdbuscpp__integrationtests_adaptor_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace sdbuscpp {
class integrationtests_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.integrationtests";
protected:
integrationtests_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); });
object_.registerMethod("getInt").onInterface(INTERFACE_NAME).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); });
object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); });
object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); });
object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply();
object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0){ return this->getInts16FromStruct(arg0); });
object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); });
object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y){ return this->getMapOfVariants(x, y); });
object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); });
object_.registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1){ return this->sumStructItems(arg0, arg1); });
object_.registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1){ return this->sumVectorItems(arg0, arg1); });
object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); });
object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result<uint32_t>&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); });
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); });
object_.registerMethod("getObjPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjPath(); });
object_.registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); });
object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getComplex(); }).markAsDeprecated();
object_.registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); });
object_.registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwErrorWithNoReply(); }).withNoReply();
object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged();
object_.registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); });
object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated();
object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters<std::map<int32_t, std::string>>("aMap");
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>("aVariant");
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
object_.registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
}
~integrationtests_adaptor() = default;
public:
void emitSimpleSignal()
{
object_.emitSignal("simpleSignal").onInterface(INTERFACE_NAME);
}
void emitSignalWithMap(const std::map<int32_t, std::string>& aMap)
{
object_.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap);
}
void emitSignalWithVariant(const sdbus::Variant& aVariant)
{
object_.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant);
}
private:
virtual void noArgNoReturn() = 0;
virtual int32_t getInt() = 0;
virtual std::tuple<uint32_t, std::string> getTuple() = 0;
virtual double multiply(const int64_t& a, const double& b) = 0;
virtual void multiplyWithNoReply(const int64_t& a, const double& b) = 0;
virtual std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0) = 0;
virtual sdbus::Variant processVariant(const sdbus::Variant& variant) = 0;
virtual std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y) = 0;
virtual sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() = 0;
virtual int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1) = 0;
virtual uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1) = 0;
virtual uint32_t doOperation(const uint32_t& arg0) = 0;
virtual void doOperationAsync(sdbus::Result<uint32_t>&& result, uint32_t arg0) = 0;
virtual sdbus::Signature getSignature() = 0;
virtual sdbus::ObjectPath getObjPath() = 0;
virtual sdbus::UnixFd getUnixFd() = 0;
virtual std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex() = 0;
virtual void throwError() = 0;
virtual void throwErrorWithNoReply() = 0;
virtual void doPrivilegedStuff() = 0;
virtual void emitTwoSimpleSignals() = 0;
private:
virtual uint32_t action() = 0;
virtual void action(const uint32_t& value) = 0;
virtual bool blocking() = 0;
virtual void blocking(const bool& value) = 0;
virtual std::string state() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -0,0 +1,204 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__integrationtests_proxy_h__proxy__H__
#define __sdbuscpp__integrationtests_proxy_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace sdbuscpp {
class integrationtests_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.integrationtests";
protected:
integrationtests_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
proxy_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
proxy_.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& aMap){ this->onSignalWithMap(aMap); });
proxy_.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); });
}
~integrationtests_proxy() = default;
virtual void onSimpleSignal() = 0;
virtual void onSignalWithMap(const std::map<int32_t, std::string>& aMap) = 0;
virtual void onSignalWithVariant(const sdbus::Variant& aVariant) = 0;
public:
void noArgNoReturn()
{
proxy_.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
}
int32_t getInt()
{
int32_t result;
proxy_.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::tuple<uint32_t, std::string> getTuple()
{
std::tuple<uint32_t, std::string> result;
proxy_.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
double multiply(const int64_t& a, const double& b)
{
double result;
proxy_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
return result;
}
void multiplyWithNoReply(const int64_t& a, const double& b)
{
proxy_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
}
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& arg0)
{
std::vector<int16_t> result;
proxy_.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
return result;
}
sdbus::Variant processVariant(const sdbus::Variant& variant)
{
sdbus::Variant result;
proxy_.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result);
return result;
}
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
{
std::map<int32_t, sdbus::Variant> result;
proxy_.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
return result;
}
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct()
{
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> result;
proxy_.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& arg0, const sdbus::Struct<int32_t, int64_t>& arg1)
{
int32_t result;
proxy_.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
return result;
}
uint32_t sumVectorItems(const std::vector<uint16_t>& arg0, const std::vector<uint64_t>& arg1)
{
uint32_t result;
proxy_.callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result);
return result;
}
uint32_t doOperation(const uint32_t& arg0)
{
uint32_t result;
proxy_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
return result;
}
uint32_t doOperationAsync(const uint32_t& arg0)
{
uint32_t result;
proxy_.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result);
return result;
}
sdbus::Signature getSignature()
{
sdbus::Signature result;
proxy_.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::ObjectPath getObjPath()
{
sdbus::ObjectPath result;
proxy_.callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::UnixFd getUnixFd()
{
sdbus::UnixFd result;
proxy_.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> getComplex()
{
std::map<uint64_t, sdbus::Struct<std::map<uint8_t, std::vector<sdbus::Struct<sdbus::ObjectPath, bool, sdbus::Variant, std::map<int32_t, std::string>>>>, sdbus::Signature, std::string>> result;
proxy_.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void throwError()
{
proxy_.callMethod("throwError").onInterface(INTERFACE_NAME);
}
void throwErrorWithNoReply()
{
proxy_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
}
void doPrivilegedStuff()
{
proxy_.callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME);
}
void emitTwoSimpleSignals()
{
proxy_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
}
public:
uint32_t action()
{
return proxy_.getProperty("action").onInterface(INTERFACE_NAME);
}
void action(const uint32_t& value)
{
proxy_.setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
}
bool blocking()
{
return proxy_.getProperty("blocking").onInterface(INTERFACE_NAME);
}
void blocking(const bool& value)
{
proxy_.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
}
std::string state()
{
return proxy_.getProperty("state").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/org/sdbuscpp/integrationtest">
<interface name="org.sdbuscpp.integrationtests">
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false" />
<method name="noArgNoReturn">
</method>
<method name="getInt">
<arg type="i" name="anInt" direction="out" />
</method>
<method name="getTuple">
<arg type="u" direction="out" />
<arg type="s" direction="out" />
</method>
<method name="multiply">
<arg type="x" name="a" direction="in" />
<arg type="d" name="b" direction="in" />
<arg type="d" name="result" direction="out" />
</method>
<method name="multiplyWithNoReply">
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true" />
<arg type="x" name="a" direction="in" />
<arg type="d" name="b" direction="in" />
</method>
<method name="getInts16FromStruct">
<arg type="(yndsan)" direction="in" />
<arg type="an" direction="out" />
</method>
<method name="processVariant">
<arg type="v" name="variant" direction="in" />
<arg type="v" name="result" direction="out" />
</method>
<method name="getMapOfVariants">
<arg type="ai" name="x" direction="in" />
<arg type="(vv)" name="y" direction="in" />
<arg type="a{iv}" name="aMapOfVariants" direction="out" />
</method>
<method name="getStructInStruct">
<arg type="(s(a{ii}))" name="aMapOfVariants" direction="out" />
</method>
<method name="sumStructItems">
<arg type="(yq)" direction="in" />
<arg type="(ix)" direction="in" />
<arg type="i" direction="out" />
</method>
<method name="sumVectorItems">
<arg type="aq" direction="in" />
<arg type="at" direction="in" />
<arg type="u" direction="out" />
</method>
<method name="doOperation">
<arg type="u" direction="in" />
<arg type="u" direction="out" />
</method>
<method name="doOperationAsync">
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
<arg type="u" direction="in" />
<arg type="u" direction="out" />
</method>
<method name="getSignature">
<arg type="g" direction="out" />
</method>
<method name="getObjPath">
<arg type="o" direction="out" />
</method>
<method name="getUnixFd">
<arg type="h" direction="out" />
</method>
<method name="getComplex">
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
<arg type="a{t(a{ya(obva{is})}gs)}" direction="out" />
</method>
<method name="throwError">
</method>
<method name="throwErrorWithNoReply">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true" />
</method>
<method name="doPrivilegedStuff">
<annotation name="org.freedesktop.systemd1.Privileged" value="true" />
</method>
<method name="emitTwoSimpleSignals">
</method>
<signal name="simpleSignal">
<annotation name="org.freedesktop.DBus.Deprecated" value="true" />
</signal>
<signal name="signalWithMap">
<arg type="a{is}" name="aMap" />
</signal>
<signal name="signalWithVariant">
<arg type="v" name="aVariant" />
</signal>
<property name="action" type="u" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="blocking" type="b" access="readwrite">
</property>
<property name="state" type="s" access="read">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
</interface>
</node>
-282
View File
@@ -1,282 +0,0 @@
/**
* (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com>
*
* @file proxy-glue.h
*
* Created on: Jan 2, 2017
* Project: sdbus-c++
* Description: High-level D-Bus IPC C++ library based on sd-bus
*
* This file is part of sdbus-c++.
*
* sdbus-c++ 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.1 of the License, or
* (at your option) any later version.
*
* sdbus-c++ 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 sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CPP_INTEGRATIONTESTS_PROXY_GLUE_H_
#define SDBUS_CPP_INTEGRATIONTESTS_PROXY_GLUE_H_
#include "defs.h"
// sdbus
#include "sdbus-c++/sdbus-c++.h"
class testing_proxy
{
protected:
testing_proxy(sdbus::IProxy& object) :
object_(object)
{
object_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
object_.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map<int32_t, std::string>& map){ this->onSignalWithMap(map); });
object_.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& v){ this->onSignalWithVariant(v); });
object_.uponSignal("signalWithoutRegistration").onInterface(INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s)
{ this->onSignalWithoutRegistration(s); });
}
~testing_proxy() = default;
virtual void onSimpleSignal() = 0;
virtual void onSignalWithMap(const std::map<int32_t, std::string>& map) = 0;
virtual void onSignalWithVariant(const sdbus::Variant& v) = 0;
virtual void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s) = 0;
virtual void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) = 0;
public:
void emitTwoSimpleSignals()
{
object_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
}
void noArgNoReturn()
{
object_.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME);
}
int32_t getInt()
{
int32_t result;
object_.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::tuple<uint32_t, std::string> getTuple()
{
std::tuple<uint32_t, std::string> result;
object_.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
double multiply(const int64_t& a, const double& b)
{
double result;
object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
return result;
}
void multiplyWithNoReply(const int64_t& a, const double& b)
{
object_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply();
}
std::vector<int16_t> getInts16FromStruct(const sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>>& x)
{
std::vector<int16_t> result;
object_.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(x).storeResultsTo(result);
return result;
}
sdbus::Variant processVariant(const sdbus::Variant& v)
{
sdbus::Variant result;
object_.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(v).storeResultsTo(result);
return result;
}
std::map<int32_t, sdbus::Variant> getMapOfVariants(const std::vector<int32_t>& x, const sdbus::Struct<sdbus::Variant, sdbus::Variant>& y)
{
std::map<int32_t, sdbus::Variant> result;
object_.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result);
return result;
}
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct()
{
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> result;
object_.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).withArguments().storeResultsTo(result);
return result;
}
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)
{
int32_t result;
object_.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
return result;
}
uint32_t sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b)
{
uint32_t result;
object_.callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result);
return result;
}
uint32_t doOperation(uint32_t param)
{
uint32_t result;
object_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result);
return result;
}
uint32_t doOperationWith500msTimeout(uint32_t param)
{
using namespace std::chrono_literals;
uint32_t result;
object_.callMethod("doOperation").onInterface(INTERFACE_NAME).withTimeout(500000us).withArguments(param).storeResultsTo(result);
return result;
}
uint32_t doOperationAsync(uint32_t param)
{
uint32_t result;
object_.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result);
return result;
}
void doOperationClientSideAsync(uint32_t param)
{
object_.callMethodAsync("doOperation")
.onInterface(INTERFACE_NAME)
.withArguments(param)
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
{
this->onDoOperationReply(returnValue, error);
});
}
void doErroneousOperationClientSideAsync()
{
object_.callMethodAsync("throwError")
.onInterface(INTERFACE_NAME)
.uponReplyInvoke([this](const sdbus::Error* error)
{
this->onDoOperationReply(0, error);
});
}
void doOperationClientSideAsyncWith500msTimeout(uint32_t param)
{
using namespace std::chrono_literals;
object_.callMethodAsync("doOperation")
.onInterface(INTERFACE_NAME)
.withTimeout(500000us)
.withArguments(param)
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
{
this->onDoOperationReply(returnValue, error);
});
}
sdbus::Signature getSignature()
{
sdbus::Signature result;
object_.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::ObjectPath getObjectPath()
{
sdbus::ObjectPath result;
object_.callMethod("getObjectPath").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::UnixFd getUnixFd()
{
sdbus::UnixFd result;
object_.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
ComplexType getComplex()
{
ComplexType result;
object_.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void throwError()
{
object_.callMethod("throwError").onInterface(INTERFACE_NAME);
}
void throwErrorWithNoReply()
{
object_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply();
}
int32_t callNonexistentMethod()
{
int32_t result;
object_.callMethod("callNonexistentMethod").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t callMethodOnNonexistentInterface()
{
int32_t result;
object_.callMethod("someMethod").onInterface("sdbuscpp.interface.that.does.not.exist").storeResultsTo(result);
return result;
}
std::string state()
{
return object_.getProperty("state").onInterface(INTERFACE_NAME);
}
void state(const std::string& value)
{
object_.setProperty("state").onInterface(INTERFACE_NAME).toValue(value);
}
uint32_t action()
{
return object_.getProperty("action").onInterface(INTERFACE_NAME);
}
void action(const uint32_t& value)
{
object_.setProperty("action").onInterface(INTERFACE_NAME).toValue(value);
}
bool blocking()
{
return object_.getProperty("blocking").onInterface(INTERFACE_NAME);
}
void blocking(const bool& value)
{
object_.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value);
}
private:
sdbus::IProxy& object_;
};
#endif /* SDBUS_CPP_INTEGRATIONTESTS_PROXY_GLUE_H_ */
+2 -2
View File
@@ -39,7 +39,7 @@ using namespace std::chrono_literals;
uint64_t totalDuration = 0;
class PerftestProxy : public sdbus::ProxyInterfaces<org::sdbuscpp::perftests_proxy>
class PerftestProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::perftests_proxy>
{
public:
PerftestProxy(std::string destination, std::string objectPath)
@@ -54,7 +54,7 @@ public:
}
protected:
virtual void onDataSignal(const std::string& data) override
virtual void onDataSignal([[maybe_unused]] const std::string& data) override
{
static unsigned int counter = 0;
static std::chrono::time_point<std::chrono::steady_clock> startTime;
+1 -1
View File
@@ -36,7 +36,7 @@ using namespace std::chrono_literals;
std::string createRandomString(size_t length);
class PerftestAdaptor : public sdbus::AdaptorInterfaces<org::sdbuscpp::perftests_adaptor>
class PerftestAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::perftests_adaptor>
{
public:
PerftestAdaptor(sdbus::IConnection& connection, std::string objectPath)
+2 -2
View File
@@ -33,9 +33,9 @@ protected:
virtual void onConcatenateReply(const std::string& result, const sdbus::Error* error) = 0;
public:
void concatenate(const std::map<std::string, sdbus::Variant>& params)
sdbus::PendingAsyncCall concatenate(const std::map<std::string, sdbus::Variant>& params)
{
proxy_.callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](const sdbus::Error* error, const std::string& result){ this->onConcatenateReply(result, error); });
return proxy_.callMethodAsync("concatenate").onInterface(INTERFACE_NAME).withArguments(params).uponReplyInvoke([this](const sdbus::Error* error, const std::string& result){ this->onConcatenateReply(result, error); });
}
private:
+7 -7
View File
@@ -53,7 +53,7 @@ using namespace std::string_literals;
#define FAHRENHEIT_THERMOMETER_OBJECT_PATH "/org/sdbuscpp/stresstests/fahrenheit/thermometer"s
#define CONCATENATOR_OBJECT_PATH "/org/sdbuscpp/stresstests/concatenator"s
class CelsiusThermometerAdaptor : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::celsius::thermometer_adaptor>
class CelsiusThermometerAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::celsius::thermometer_adaptor>
{
public:
CelsiusThermometerAdaptor(sdbus::IConnection& connection, std::string objectPath)
@@ -92,8 +92,8 @@ public:
}
};
class FahrenheitThermometerAdaptor : public sdbus::AdaptorInterfaces< org::sdbuscpp::stresstests::fahrenheit::thermometer_adaptor
, org::sdbuscpp::stresstests::fahrenheit::thermometer::factory_adaptor >
class FahrenheitThermometerAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::stresstests::fahrenheit::thermometer_adaptor
, org::sdbuscpp::stresstests::fahrenheit::thermometer::factory_adaptor >
{
public:
FahrenheitThermometerAdaptor(sdbus::IConnection& connection, std::string objectPath, bool isDelegate)
@@ -222,7 +222,7 @@ public:
}
};
class ConcatenatorAdaptor : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::concatenator_adaptor>
class ConcatenatorAdaptor final : public sdbus::AdaptorInterfaces<org::sdbuscpp::stresstests::concatenator_adaptor>
{
public:
ConcatenatorAdaptor(sdbus::IConnection& connection, std::string objectPath)
@@ -294,7 +294,7 @@ private:
std::atomic<bool> exit_{};
};
class ConcatenatorProxy : public sdbus::ProxyInterfaces<org::sdbuscpp::stresstests::concatenator_proxy>
class ConcatenatorProxy final : public sdbus::ProxyInterfaces<org::sdbuscpp::stresstests::concatenator_proxy>
{
public:
ConcatenatorProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath)
@@ -309,7 +309,7 @@ public:
}
private:
virtual void onConcatenateReply(const std::string& result, const sdbus::Error* error) override
virtual void onConcatenateReply(const std::string& result, [[maybe_unused]] const sdbus::Error* error) override
{
assert(error == nullptr);
@@ -457,7 +457,7 @@ int main(int argc, char *argv[])
FahrenheitThermometerProxy thermometer(con, SERVICE_1_BUS_NAME, FAHRENHEIT_THERMOMETER_OBJECT_PATH);
uint32_t localCounter{};
uint32_t previousTemperature{};
[[maybe_unused]] uint32_t previousTemperature{};
while (!stopClients)
{
+9 -6
View File
@@ -164,6 +164,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
for (const auto& method : methods)
{
auto methodName = method->get("name");
auto methodNameSafe = mangle_name(methodName);
auto annotations = getAnnotations(*method);
bool async{false};
@@ -219,7 +220,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
<< "[this]("
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "")
<< argTypeStr
<< "){ " << (async ? "" : "return ") << "this->" << methodName << "("
<< "){ " << (async ? "" : "return ") << "this->" << methodNameSafe << "("
<< (async ? "std::move(result)"s + (argTypeStr.empty() ? "" : ", ") : "")
<< argStr << "); })"
<< annotationRegistration << ";" << endl;
@@ -227,7 +228,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processMethods(const Node
declarationSS << tab
<< "virtual "
<< (async ? "void" : outArgsToType(outArgs))
<< " " << methodName
<< " " << methodNameSafe
<< "("
<< (async ? "sdbus::Result<" + outArgsToType(outArgs, true) + ">&& result" + (argTypeStr.empty() ? "" : ", ") : "")
<< argTypeStr
@@ -279,6 +280,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processSignals(const Node
auto nameWithCapFirstLetter = name;
nameWithCapFirstLetter[0] = std::toupper(nameWithCapFirstLetter[0]);
nameWithCapFirstLetter = mangle_name(nameWithCapFirstLetter);
signalMethodSS << tab << "void emit" << nameWithCapFirstLetter << "(" << argTypeStr << ")" << endl
<< tab << "{" << endl
@@ -305,6 +307,7 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
for (const auto& property : properties)
{
auto propertyName = property->get("name");
auto propertyNameSafe = mangle_name(propertyName);
auto propertyAccess = property->get("access");
auto propertySignature = property->get("type");
@@ -336,23 +339,23 @@ std::tuple<std::string, std::string> AdaptorGenerator::processProperties(const N
if (propertyAccess == "read" || propertyAccess == "readwrite")
{
registrationSS << ".withGetter([this](){ return this->" << propertyName << "(); })";
registrationSS << ".withGetter([this](){ return this->" << propertyNameSafe << "(); })";
}
if (propertyAccess == "readwrite" || propertyAccess == "write")
{
registrationSS
<< ".withSetter([this](" << propertyTypeArg << ")"
"{ this->" << propertyName << "(" << propertyArg << "); })";
"{ this->" << propertyNameSafe << "(" << propertyArg << "); })";
}
registrationSS << annotationRegistration;
registrationSS << ";" << endl;
if (propertyAccess == "read" || propertyAccess == "readwrite")
declarationSS << tab << "virtual " << propertyType << " " << propertyName << "() = 0;" << endl;
declarationSS << tab << "virtual " << propertyType << " " << propertyNameSafe << "() = 0;" << endl;
if (propertyAccess == "readwrite" || propertyAccess == "write")
declarationSS << tab << "virtual void " << propertyName << "(" << propertyTypeArg << ") = 0;" << endl;
declarationSS << tab << "virtual void " << propertyNameSafe << "(" << propertyTypeArg << ") = 0;" << endl;
}
return std::make_tuple(registrationSS.str(), declarationSS.str());
+6 -4
View File
@@ -96,6 +96,7 @@ std::tuple<unsigned, std::string> BaseGenerator::generateNamespaces(const std::s
{
std::string nspace;
getline(ss, nspace, '.');
nspace = mangle_name(nspace);
body << "namespace " << nspace << " {" << endl;
++count;
}
@@ -125,17 +126,18 @@ std::tuple<std::string, std::string, std::string, std::string> BaseGenerator::ar
{
argName = "arg" + std::to_string(i);
}
auto argNameSafe = mangle_name(argName);
auto type = signature_to_type(arg->get("type"));
argStringsSS << "\"" << argName << "\"";
if (!async)
{
argSS << argName;
argTypeSS << "const " << type << "& " << argName;
argSS << argNameSafe;
argTypeSS << "const " << type << "& " << argNameSafe;
}
else
{
argSS << "std::move(" << argName << ")";
argTypeSS << type << " " << argName;
argSS << "std::move(" << argNameSafe << ")";
argTypeSS << type << " " << argNameSafe;
}
typeSS << type;
}
+8 -5
View File
@@ -135,6 +135,7 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
for (const auto& method : methods)
{
auto name = method->get("name");
auto nameSafe = mangle_name(name);
Nodes args = (*method)["arg"];
Nodes inArgs = args.select("direction" , "in");
Nodes outArgs = args.select("direction" , "out");
@@ -173,7 +174,8 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
std::string outArgStr, outArgTypeStr;
std::tie(outArgStr, outArgTypeStr, std::ignore, std::ignore) = argsToNamesAndTypes(outArgs);
definitionSS << tab << (async ? "void" : retType) << " " << name << "(" << inArgTypeStr << ")" << endl
const std::string realRetType = (async && !dontExpectReply ? "sdbus::PendingAsyncCall" : async ? "void" : retType);
definitionSS << tab << realRetType << " " << nameSafe << "(" << inArgTypeStr << ")" << endl
<< tab << "{" << endl;
if (!timeoutValue.empty())
@@ -186,8 +188,8 @@ std::tuple<std::string, std::string> ProxyGenerator::processMethods(const Nodes&
definitionSS << tab << tab << retType << " result;" << endl;
}
definitionSS << tab << tab << "proxy_.callMethod" << (async ? "Async" : "") << "(\"" << name << "\")"
".onInterface(INTERFACE_NAME)";
definitionSS << tab << tab << (async && !dontExpectReply ? "return " : "")
<< "proxy_.callMethod" << (async ? "Async" : "") << "(\"" << name << "\").onInterface(INTERFACE_NAME)";
if (!timeoutValue.empty())
{
@@ -259,6 +261,7 @@ std::string ProxyGenerator::processProperties(const Nodes& properties) const
for (const auto& property : properties)
{
auto propertyName = property->get("name");
auto propertyNameSafe = mangle_name(propertyName);
auto propertyAccess = property->get("access");
auto propertySignature = property->get("type");
@@ -268,7 +271,7 @@ std::string ProxyGenerator::processProperties(const Nodes& properties) const
if (propertyAccess == "read" || propertyAccess == "readwrite")
{
propertySS << tab << propertyType << " " << propertyName << "()" << endl
propertySS << tab << propertyType << " " << propertyNameSafe << "()" << endl
<< tab << "{" << endl;
propertySS << tab << tab << "return proxy_.getProperty(\"" << propertyName << "\")"
".onInterface(INTERFACE_NAME)";
@@ -277,7 +280,7 @@ std::string ProxyGenerator::processProperties(const Nodes& properties) const
if (propertyAccess == "readwrite" || propertyAccess == "write")
{
propertySS << tab << "void " << propertyName << "(" << propertyTypeArg << ")" << endl
propertySS << tab << "void " << propertyNameSafe << "(" << propertyTypeArg << ")" << endl
<< tab << "{" << endl;
propertySS << tab << tab << "proxy_.setProperty(\"" << propertyName << "\")"
".onInterface(INTERFACE_NAME)"
@@ -7,6 +7,7 @@
#include <map>
#include "generator_utils.h"
#include "reserved_names.h"
std::string underscorize(const std::string& str)
@@ -142,3 +143,11 @@ std::string signature_to_type(const std::string& signature)
_parse_signature(signature, type, i);
return type;
}
std::string mangle_name(const std::string& name)
{
if (reserved_names.find(name) != reserved_names.end())
return name + "_";
else
return name;
}
+2
View File
@@ -19,4 +19,6 @@ std::string underscorize(const std::string& str);
constexpr const char* getHeaderComment() noexcept { return "\n/*\n * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!\n */\n\n"; }
std::string mangle_name (const std::string& name);
#endif //__SDBUSCPP_TOOLS_GENERATOR_UTILS_H
+104
View File
@@ -0,0 +1,104 @@
#include <set>
static const std::set<std::string> reserved_names = {
// c++ keywords taken from https://en.cppreference.com/w/cpp/keyword
"alignas",
"alignof",
"and",
"and_eq",
"asm",
"atomic_cancel",
"atomic_commit",
"atomic_noexcept",
"auto",
"bitand",
"bitor",
"bool",
"break",
"case",
"catch",
"char",
"char8_t",
"char16_t",
"char32_t",
"class",
"compl",
"concept",
"const",
"consteval",
"constexpr",
"constinit",
"const_cast",
"continue",
"co_await",
"co_return",
"co_yield",
"decltype",
"default",
"delete",
"do",
"double",
"dynamic_cast",
"else",
"enum",
"explicit",
"export",
"extern",
"false",
"float",
"for",
"friend",
"goto",
"if",
"inline",
"int",
"long",
"mutable",
"namespace",
"new",
"noexcept",
"not",
"not_eq",
"nullptr",
"operator",
"or",
"or_eq",
"private",
"protected",
"public",
"reflexpr",
"register",
"reinterpret_cast",
"requires",
"return",
"short",
"signed",
"sizeof",
"static",
"static_assert",
"static_cast",
"struct",
"switch",
"synchronized",
"template",
"this",
"thread_local",
"throw",
"true",
"try",
"typedef",
"typeid",
"typename",
"union",
"unsigned",
"using",
"virtual",
"void",
"volatile",
"wchar_t",
"while",
"xor",
"xor_eq",
// common defines
"NULL"
};
+1 -1
View File
@@ -149,7 +149,7 @@ int main(int argc, char **argv)
std::ifstream input(xmlFile);
if (input.bad())
if (input.fail())
{
std::cerr << "Unable to open file " << xmlFile << endl;
return 1;