diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..024e8fd --- /dev/null +++ b/conanfile.py @@ -0,0 +1,40 @@ +from conans import ConanFile, CMake, tools + + +class CsSignalConan(ConanFile): + name = "cs_signal" + version = "1.2.3" + license = "BSD2" + author = "Paul M. Bendixen paulbendixen@gmail.com" + url = "" + description = "A library for thread aware Signal/Slot delivery" + topics = ("CopperSpice", "Signal", "Slot") + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True], "fPIC": [True, False]} + default_options = {"shared": True, "fPIC": True} + generators = "cmake" + exports_sources = "*" + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def validate(self): + tools.check_min_cppstd(self,"17") + + def _configure(self): + cmake = CMake(self) + cmake.configure() + return cmake + + def build(self): + cmake = self._configure() + cmake.build() + + def package(self): + cmake = self._configure() + cmake.install() + + def package_info(self): + self.cpp_info.libs = ["CsSignal"] + diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt new file mode 100644 index 0000000..9fc2a59 --- /dev/null +++ b/test_package/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.1) +project(PackageTest CXX) + +find_package( Threads REQUIRED ) +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +add_executable(example main.cpp peach.cpp ) +target_link_libraries(example ${CONAN_LIBS} Threads::Threads) + +# CTest is a testing tool that can be used to test your project. +# enable_testing() +# add_test(NAME example +# WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin +# COMMAND example) diff --git a/test_package/conanfile.py b/test_package/conanfile.py new file mode 100644 index 0000000..6f75432 --- /dev/null +++ b/test_package/conanfile.py @@ -0,0 +1,25 @@ +import os + +from conans import ConanFile, CMake, tools + + +class CsSignalTestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "cmake" + + def build(self): + cmake = CMake(self) + # Current dir is "test_package/build/" and CMakeLists.txt is + # in "test_package" + cmake.configure() + cmake.build() + + def imports(self): + self.copy("*.dll", dst="bin", src="bin") + self.copy("*.dylib*", dst="bin", src="lib") + self.copy('*.so*', dst='bin', src='lib') + + def test(self): + if not tools.cross_building(self): + os.chdir("bin") + self.run(".%sexample" % os.sep) diff --git a/test_package/main.cpp b/test_package/main.cpp new file mode 100644 index 0000000..156e176 --- /dev/null +++ b/test_package/main.cpp @@ -0,0 +1,377 @@ +/*********************************************************************** +* +* Copyright (c) 2016-2021 Barbara Geller +* Copyright (c) 2016-2021 Ansel Sermersheim +* +* This file is part of CsSignal. +* +* CsSignal is free software, released under the BSD 2-Clause license. +* For license details refer to LICENSE provided with this project. +* +* CopperSpice 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. +* +* https://opensource.org/licenses/BSD-2-Clause +* +***********************************************************************/ + +#include + +#include + +#include "peach.h" + +bool g_unitTest = true; + +void test_1(); +void test_2(); +void test_3(); +void test_4(); +void test_5(); +void test_6(); +void test_7(); +void test_8(); + +int main() +{ + printf("\n\n%s\n\n", "** CsSignal Library - Start of Unit Test **"); + + test_1(); + test_2(); + test_3(); + test_4(); + test_5(); + test_6(); + test_7(); + test_8(); + + printf("\n\n"); + + if (! g_unitTest) { + return 1; + } +} + +void test_1() +{ + bool ok = true; + printf("Begin Unit Test One\n"); + + TestPushButton okButton; + Peach obj = Peach{}; + + connect(okButton, &TestPushButton::pressed, obj, &Peach::methodPressed); + + if (obj.m_slotPressed != 0) { + // ensure slot has not been accidentally called + ok = false; + } + + // call the signal + okButton.pressed(); + + if (obj.m_slotPressed != 1) { + // ensure slot has been called once + ok = false; + } + + if (ok) { + printf("End Unit Test One - PASSED\n\n"); + + } else { + printf("End Unit Test One - Failed\n\n"); + g_unitTest = false; + + } +} + +void funcPressed() +{ + printf(" SLOT: pressed (slot is a function pointer)\n"); +} + +void test_2() +{ + bool ok = true; + printf("Begin Unit Test Two\n"); + + TestPushButton okButton; + Peach obj = Peach{}; + + connect(okButton, &TestPushButton::pressed, obj, &funcPressed); + + // call the signal + okButton.pressed(); + + if (ok) { + printf("End Unit Test Two - PASSED\n\n"); + + } else { + printf("End Unit Test Two - Failed\n\n"); + g_unitTest = false; + + } +} + +void test_3() +{ + bool ok = true; + printf("Begin Unit Test Three\n"); + + int slotPressed = 0; + + TestPushButton okButton; + Peach obj = Peach{}; + + connect(okButton, &TestPushButton::pressed, obj, [&slotPressed]() + { + printf(" SLOT: pressed (slot is a lambda)\n"); + slotPressed++; + } ); + + if (slotPressed != 0) { + // ensure slot has not been accidentally called + ok = false; + } + + // call the signal + okButton.pressed(); + + if (slotPressed != 1) { + // ensure slot has been called once + ok = false; + } + + if (ok) { + printf("End Unit Test Three - PASSED\n\n"); + + } else { + printf("End Unit Test Three - Failed\n\n"); + g_unitTest = false; + + } +} + +void test_4() +{ + bool ok = true; + printf("Begin Unit Test Four\n"); + + TestPushButton okButton; + Peach obj = Peach{}; + + connect(okButton, &TestPushButton::pressed, obj, &Peach::templatePressed ); + + if (obj.m_slotPressed != 0) { + // ensure slot has not been accidentally called + ok = false; + } + + // call the signal + okButton.pressed(); + + if (obj.m_slotPressed != 1) { + // ensure slot has been called once + ok = false; + } + + if (ok) { + printf("End Unit Test Four - PASSED\n\n"); + + } else { + printf("End Unit Test Fout - Failed\n\n"); + g_unitTest = false; + + } +} + +void callBack(std::atomic &running, std::deque &array, std::mutex &mutex, + std::condition_variable &alarm) +{ + printf(" Test 5: Message from thread\n"); + + while (true) { + std::unique_lock lock(mutex); + + if (! array.empty()) { + auto data = std::move(array.front()); + array.pop_front(); + lock.unlock(); + + // call the slot + data(); + continue; + + } else if (! running) { + break; + + } + + alarm.wait(lock); + } +} + +void test_5() +{ + bool ok = true; + printf("Begin Unit Test Five\n"); + + // set up threads + std::atomic running; + running = true; + + std::deque array; + std::mutex mutex; + std::condition_variable alarm; + + std::thread thread1(callBack, std::ref(running), std::ref(array), std::ref(mutex), std::ref(alarm)); + + Peach obj; + obj.m_array = &array; + obj.m_mutex = &mutex; + obj.m_alarm = &alarm; + + TestPushButton okButton; + + connect(okButton, &TestPushButton::pressed, obj, &Peach::threadPressed, CsSignal::ConnectionKind::QueuedConnection); + + if (obj.m_slotPressed != 0) { + // ensure the slots were not been accidentally called + ok = false; + } + + // emit the signal + okButton.pressed(); + + running = false; + + // wake up the thread + alarm.notify_one(); + + thread1.join(); + + if (obj.m_slotPressed != 1) { + // ensure slot has been called once + ok = false; + } + + if (ok) { + printf("End Unit Test Five - PASSED\n\n"); + + } else { + printf("End Unit Test Five - Failed\n\n"); + g_unitTest = false; + + } +} + +void test_6() +{ + bool ok = true; + printf("Begin Unit Test Six\n"); + + TestPushButton okButton; + Peach obj = Peach{}; + + connect(okButton, &TestPushButton::pressed, obj, &Peach::methodPressed); + + if (obj.m_slotPressed != 0) { + // ensure slot has not been accidentally called + ok = false; + } + + // call the signal + okButton.pressed(); + + // + printf(" Disconnect() then emit signal again\n"); + disconnect(okButton, &TestPushButton::pressed, obj, &Peach::methodPressed); + okButton.pressed(); + + if (obj.m_slotPressed == 1) { + printf(" Signal emitted after disconnect(), did nothing\n"); + + } else { + // ensure slot has been called once + ok = false; + } + + if (ok) { + printf("End Unit Test Six - PASSED\n\n"); + + } else { + printf("End Unit Test Six - Failed\n\n"); + g_unitTest = false; + + } +} + +void test_7() +{ + bool ok = true; + printf("Begin Unit Test Seven\n"); + + TestPushButton okButton; + Peach obj = Peach{}; + + // testing a signal with a parameter + connect(okButton, &TestPushButton::toggled, obj, &Peach::toggled); + + if (obj.m_slotPressed != 0) { + // ensure slot has not been accidentally called + ok = false; + } + + // call the signal + okButton.toggled(true); + + if (obj.m_slotPressed != 1) { + // ensure slot has been called once + ok = false; + } + + if (ok) { + printf("End Unit Test Seven - PASSED\n\n"); + + } else { + printf("End Unit Test Seven - Failed\n\n"); + g_unitTest = false; + + } +} + +void test_8() +{ + bool ok = true; + printf("Begin Unit Test Eight\n"); + + if (true) { + + TestPushButton okButton; + Peach obj = Peach{}; + + // sender is an rvalue + connect(TestPushButton{}, &TestPushButton::pressed, obj, &funcPressed); + + // receiver is an rvalue + // connect(okButton, &TestPushButton::pressed, Peach{}, &funcPressed); + + // sender and receiver are rvalues + // connect(TestPushButton{}, &TestPushButton::pressed, Peach{}, &funcPressed); + + } else { + printf(" Not enabled, used to test for compile issues\n"); + + } + + if (ok) { + printf("End Unit Test Eight - PASSED\n\n"); + + } else { + printf("End Unit Test Eight - Failed\n\n"); + g_unitTest = false; + + } +} + diff --git a/test_package/peach.cpp b/test_package/peach.cpp new file mode 100644 index 0000000..0d16b5d --- /dev/null +++ b/test_package/peach.cpp @@ -0,0 +1,59 @@ +/*********************************************************************** +* +* Copyright (c) 2016-2021 Barbara Geller +* Copyright (c) 2016-2021 Ansel Sermersheim +* +* This file is part of CsSignal. +* +* CsSignal is free software, released under the BSD 2-Clause license. +* For license details refer to LICENSE provided with this project. +* +* CopperSpice 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. +* +* https://opensource.org/licenses/BSD-2-Clause +* +***********************************************************************/ + +#include + +#include "peach.h" + +Peach::Peach() +{ +} + +void Peach::toggled(bool onOff) +{ + printf(" Peach SLOT: pushButton toggled is (0 or 1) %d\n", onOff); + m_slotPressed++; +} + +void Peach::methodPressed() +{ + printf(" Peach SLOT: pressed (slot is a method pointer)\n"); + m_slotPressed++; +} + +void Peach::threadPressed() +{ + printf(" Peach SLOT: pressed (slot is from a thread)\n"); + m_slotPressed++; +} + +void Peach::queueSlot(CsSignal::PendingSlot data, CsSignal::ConnectionKind) +{ + SlotBase *receiver = data.receiver(); + printf(" queueSlot(): receiver is %s\n", typeid(*receiver).name()); + + std::lock_guard lock(*m_mutex); + m_array->push_back(std::move(data)); + + // wake up the thread + m_alarm->notify_one(); +} + + + + diff --git a/test_package/peach.h b/test_package/peach.h new file mode 100644 index 0000000..a92ee6a --- /dev/null +++ b/test_package/peach.h @@ -0,0 +1,70 @@ +/*********************************************************************** +* +* Copyright (c) 2016-2021 Barbara Geller +* Copyright (c) 2016-2021 Ansel Sermersheim +* +* This file is part of CsSignal. +* +* CsSignal is free software, released under the BSD 2-Clause license. +* For license details refer to LICENSE provided with this project. +* +* CopperSpice 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. +* +* https://opensource.org/licenses/BSD-2-Clause +* +***********************************************************************/ + +#ifndef TEST_PEACH_H +#define TEST_PEACH_H + +#include +#include + +#include +#include + +class TestPushButton : public CsSignal::SignalBase +{ + public: + SIGNAL_1(void pressed()) + SIGNAL_2(pressed) + + SIGNAL_1(void clicked(bool checked = false)) + SIGNAL_2(clicked, checked) + + SIGNAL_1(void toggled(bool checked)) + SIGNAL_2(toggled, checked) +}; + +class Peach : public CsSignal::SlotBase +{ + public: + Peach(); + + void toggled(bool onOff); + void methodPressed(); + void threadPressed(); + + template + void templatePressed(); + + int m_slotPressed = 0; + + std::deque *m_array; + std::mutex *m_mutex; + std::condition_variable *m_alarm; + + private: + void queueSlot(CsSignal::PendingSlot data, CsSignal::ConnectionKind type) override; +}; + +template +void Peach::templatePressed() +{ + printf(" Peach SLOT: pressed (slot is a template method)\n"); + m_slotPressed++; +} + +#endif \ No newline at end of file