From a09fa130053f5ab86c2c22d97e93486d407f811f Mon Sep 17 00:00:00 2001 From: Vitalii Arteev Date: Wed, 14 Oct 2020 17:35:24 +0200 Subject: [PATCH] Add auxiliary API for Proxy --- src/ipc/ipc-common/CMakeLists.txt | 1 + src/ipc/ipc-common/IPCProxyBase.h | 4 +- src/ipc/ipc-common/observer.h | 107 ++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/unittest_observer/CMakeLists.txt | 24 ++++ .../FaceliftObserverTest.cpp | 72 ++++++++++++ 6 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/ipc/ipc-common/observer.h create mode 100644 tests/unittest_observer/CMakeLists.txt create mode 100644 tests/unittest_observer/FaceliftObserverTest.cpp diff --git a/src/ipc/ipc-common/CMakeLists.txt b/src/ipc/ipc-common/CMakeLists.txt index 42413c67..c3b3283d 100644 --- a/src/ipc/ipc-common/CMakeLists.txt +++ b/src/ipc/ipc-common/CMakeLists.txt @@ -23,6 +23,7 @@ facelift_add_library(FaceliftIPCCommonLib IPCServiceAdapterBase.h NewIPCServiceAdapterBase.h IPCAttachedPropertyFactory.h + observer.h HEADERS_NO_MOC AppendDBUSSignatureFunction.h ipc-serialization.h diff --git a/src/ipc/ipc-common/IPCProxyBase.h b/src/ipc/ipc-common/IPCProxyBase.h index 25701b8d..cef22db4 100644 --- a/src/ipc/ipc-common/IPCProxyBase.h +++ b/src/ipc/ipc-common/IPCProxyBase.h @@ -33,7 +33,7 @@ #include "ipc-common.h" #include "IPCProxyBaseBase.h" #include "IPCProxyBinderBase.h" - +#include "observer.h" #if defined(FaceliftIPCCommonLib_LIBRARY) # define FaceliftIPCCommonLib_EXPORT Q_DECL_EXPORT @@ -49,10 +49,12 @@ class IPCProxyBase : public AdapterType, protected IPCProxyBaseBase public: using InterfaceType = AdapterType; + IsReadyObserver m_readyObserver{}; public: IPCProxyBase(QObject *parent) : AdapterType(parent) { + QObject::connect(this, &InterfaceBase::readyChanged, &m_readyObserver, &IsReadyObserver::onReadyChanged); } template diff --git a/src/ipc/ipc-common/observer.h b/src/ipc/ipc-common/observer.h new file mode 100644 index 00000000..40c05eca --- /dev/null +++ b/src/ipc/ipc-common/observer.h @@ -0,0 +1,107 @@ +/********************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** +** This file is part of the FaceLift project +** +** Permission is hereby granted, freIPCServiceAdapterBasee of charge, to any person +** obtaining a copy of this software and associated documentation files +** (the "Software"), to deal in the Software without restriction, +** including without limitation the rights to use, copy, modify, merge, +** publish, distribute, sublicense, and/or sell copies of the Software, +** and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +** +** SPDX-License-Identifier: MIT +** +**********************************************************************/ + +#pragma once + +#include +#include +#include + +namespace facelift { + +class IObserver : public QObject +{ + Q_OBJECT +public: + virtual void onReadyChanged(std::shared_ptr connection) = 0; +}; + + +class IsReadyObserver: public QObject +{ + Q_OBJECT + + QVector m_observers{}; +public: + IsReadyObserver() {} + + // Set observers + void setObservers(const QVector &observers) { + m_observers = observers; + for(auto observer: observers){ + auto connection = std::make_shared(); + *connection = QObject::connect(this, &IsReadyObserver::readyChanged, observer, [observer, connection](){ + observer->onReadyChanged( connection ); + }); + } + } + + // Get observers + const QVector &getObservers() const { + return m_observers; + } + + Q_SIGNAL void readyChanged(); + + void onReadyChanged() { + emit readyChanged(); + } +}; + +// Single-time observer which will unregister itself when done +template +class SingleTimeObserver : public IObserver +{ + F m_func; +public: + explicit SingleTimeObserver(F func) : m_func{func} {} + ~SingleTimeObserver() = default; + + void onReadyChanged(std::shared_ptr connection) override { + m_func(); + QObject::disconnect(*connection); + } +}; + +// Standard observer which will work for each signal +template +class StandartObserver : public IObserver +{ + F m_func; +public: + explicit StandartObserver(F func) : m_func{func} {} + ~StandartObserver() = default; + + void onReadyChanged(std::shared_ptr ) override { + m_func(); + } +}; + +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6dafed20..bb95e7f6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -76,6 +76,7 @@ add_test(NAME benchmarking-inprocess.cpp COMMAND test-driver.sh benchmarking/tst if(NOT ${FACELIFT_DISABLE_GTEST}) add_subdirectory(unittest) + add_subdirectory(unittest_observer) endif() add_subdirectory(objectregistry) diff --git a/tests/unittest_observer/CMakeLists.txt b/tests/unittest_observer/CMakeLists.txt new file mode 100644 index 00000000..3d0c0bbb --- /dev/null +++ b/tests/unittest_observer/CMakeLists.txt @@ -0,0 +1,24 @@ + +find_package(GTest) +if(${GTEST_FOUND}) + find_library(GMOCK_LIBRARY gmock REQUIRED HINTS "${CMAKE_SYSTEM_PREFIX_PATH}") + if(NOT ${GMOCK_LIBRARY} STREQUAL "GMOCK_LIBRARY-NOTFOUND") + add_library(GTest::GMock UNKNOWN IMPORTED) + set_target_properties(GTest::GMock PROPERTIES IMPORTED_LOCATION ${GMOCK_LIBRARY}) + else() + message(WARNING "Google test/mock not found.") + endif() + + find_package(Qt5 COMPONENTS Test REQUIRED) + find_package(Threads REQUIRED) + set(FACELIFT_GTEST_LIBRARIES ${GTEST_BOTH_LIBRARIES} GTest::GMock Qt5::Test Threads::Threads) + include_directories(${GTEST_INCLUDE_DIRS}) + + facelift_add_test(UnitTestsObserver + SOURCES FaceliftObserverTest.cpp + LINK_LIBRARIES ${FACELIFT_GTEST_LIBRARIES} FaceliftIPCCommonLib FaceliftModelLib) + +else() + message(WARNING "Required package google test not found!") +endif() + diff --git a/tests/unittest_observer/FaceliftObserverTest.cpp b/tests/unittest_observer/FaceliftObserverTest.cpp new file mode 100644 index 00000000..7b553a56 --- /dev/null +++ b/tests/unittest_observer/FaceliftObserverTest.cpp @@ -0,0 +1,72 @@ +#include +#include "IPCProxyBase.h" +#include "InterfaceBase.h" +#include + +namespace { + +using namespace facelift; + +class Counter +{ +public: + Counter() { m_value = 0; } + + void incValue() { + m_value++; + } + int getValue() const { + return m_value; + } +private: + int m_value; +}; + +class IPCProxyBaseTest : public ::testing::Test +{ +public: + Counter c1; + Counter c2; + StandartObserver < std::function > * obs1 = new StandartObserver < std::function > (std::bind(&Counter::incValue, &c1) ); + SingleTimeObserver< std::function > * obs2 = new SingleTimeObserver< std::function > (std::bind(&Counter::incValue, &c2) ); + + IPCProxyBase proxyBase{nullptr}; + + ~IPCProxyBaseTest() { + delete obs1; + obs1 = nullptr; + delete obs2; + obs2 = nullptr; + } +}; + +TEST_F(IPCProxyBaseTest, testObservers) +{ + // Set observers to proxy + const auto expected = QVector{obs1, obs2,}; + proxyBase.m_readyObserver.setObservers(expected); + const auto actual = proxyBase.m_readyObserver.getObservers(); + + // Check installed observers + EXPECT_EQ(expected.size(), actual.size()); + EXPECT_EQ(expected[0], actual[0]); + EXPECT_EQ(expected[1], actual[1]); + + // Check handle of signal + QSignalSpy spy(&proxyBase.m_readyObserver, &IsReadyObserver::readyChanged ); + ASSERT_EQ( spy.isValid(), true); + spy.clear(); + + // Generate signal + ASSERT_EQ(spy.count(), 0); + proxyBase.readyChanged(); + proxyBase.readyChanged(); + proxyBase.readyChanged(); + ASSERT_EQ(spy.count(), 3); + + // Check called function + ASSERT_EQ(c1.getValue(), 3); // for StandartObserver + ASSERT_EQ(c2.getValue(), 1); // for SingleTimeObserver +} + +} // end namespace