├── cmake ├── mac.cmake ├── policies.cmake ├── platform.cmake ├── failtest.cmake ├── target.cmake └── compilation.cmake ├── .gitignore ├── tests ├── main.cc ├── failtests │ ├── SignalBlockerNonSignal.cc │ ├── SignalBlockerFakeSignal.cc │ ├── VoidSignalNonVoidRetFunc.cc │ └── CMakeLists.txt ├── CMakeLists.txt ├── CustomTypes.cc ├── gtest │ ├── include │ │ └── gtest │ │ │ ├── internal │ │ │ ├── custom │ │ │ │ ├── gtest.h │ │ │ │ ├── gtest-port.h │ │ │ │ └── gtest-printers.h │ │ │ ├── gtest-port-arch.h │ │ │ ├── gtest-string.h │ │ │ ├── gtest-type-util.h │ │ │ ├── gtest-filepath.h │ │ │ └── gtest-death-test-internal.h │ │ │ ├── gtest_prod.h │ │ │ ├── gtest-test-part.h │ │ │ ├── gtest-assertion-result.h │ │ │ ├── gtest-message.h │ │ │ ├── gtest-spi.h │ │ │ └── gtest_pred_impl.h │ └── src │ │ ├── gtest-all.cc │ │ ├── gtest_main.cc │ │ ├── gtest-assertion-result.cc │ │ ├── gtest-matchers.cc │ │ ├── gtest-typed-test.cc │ │ └── gtest-test-part.cc ├── Interface.cc ├── SignalBlocker.cc └── General.cc ├── .clang-tidy ├── examples ├── CMakeLists.txt ├── Button.cc ├── Interface.cc └── ReturnValues.cc ├── .github └── workflows │ ├── codeql-analysis.yml │ ├── test-sanitizers.yml │ └── test.yml ├── LICENSE ├── .clang-format ├── .travis.yml ├── CMakeLists.txt ├── README.md ├── sigs17.h └── sigs.h /cmake/mac.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | build*/ 4 | /.cache/ 5 | /compile_commands.json 6 | -------------------------------------------------------------------------------- /cmake/policies.cmake: -------------------------------------------------------------------------------- 1 | # Only interpret if() arguments as variables or keywords when unquoted. 2 | if (POLICY CMP0054) 3 | cmake_policy(SET CMP0054 NEW) 4 | endif() 5 | -------------------------------------------------------------------------------- /tests/main.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) 4 | { 5 | testing::InitGoogleTest(&argc, argv); 6 | return RUN_ALL_TESTS(); 7 | } 8 | -------------------------------------------------------------------------------- /cmake/platform.cmake: -------------------------------------------------------------------------------- 1 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 2 | set(LINUX 1) 3 | endif() 4 | 5 | include(compilation) 6 | 7 | if (APPLE) 8 | include(mac) 9 | endif() 10 | -------------------------------------------------------------------------------- /tests/failtests/SignalBlockerNonSignal.cc: -------------------------------------------------------------------------------- 1 | #include "sigs.h" 2 | 3 | class Foo { 4 | }; 5 | 6 | int main() 7 | { 8 | Foo foo; 9 | sigs::SignalBlocker sb(foo); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /tests/failtests/SignalBlockerFakeSignal.cc: -------------------------------------------------------------------------------- 1 | #include "sigs.h" 2 | 3 | class FakeSignal { 4 | public: 5 | using RetArgs = void(); 6 | using LockType = int; 7 | }; 8 | 9 | int main() 10 | { 11 | FakeSignal fake; 12 | sigs::SignalBlocker sb(fake); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/failtests/VoidSignalNonVoidRetFunc.cc: -------------------------------------------------------------------------------- 1 | #include "sigs.h" 2 | 3 | int main() 4 | { 5 | sigs::Signal s; 6 | s.connect([] { /* do nothing */ }); 7 | 8 | // Must trigger static assertion because return type is void and not int! 9 | s([](int retVal) {}); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/failtests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(failtest) 2 | 3 | add_failtest( 4 | VoidSignalNonVoidRetFunc 5 | VoidSignalNonVoidRetFunc.cc 6 | ) 7 | 8 | add_failtest( 9 | SignalBlockerNonSignal 10 | SignalBlockerNonSignal.cc 11 | ) 12 | 13 | add_failtest( 14 | SignalBlockerFakeSignal 15 | SignalBlockerFakeSignal.cc 16 | ) 17 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: '-*,clang-analyzer-*,cppcoreguidelines-*,performance-*,portability-*,readability-*,-readability-identifier-length,bugprone-*,modernize-*,-modernize-use-trailing-return-type,misc-*' 3 | FormatStyle: file 4 | CheckOptions: 5 | - key: readability-braces-around-statements.ShortStatementLines 6 | value: '1' 7 | ... 8 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories( 2 | ${CMAKE_SOURCE_DIR} 3 | ) 4 | 5 | add_executable( 6 | button 7 | Button.cc 8 | ) 9 | 10 | add_executable( 11 | interface 12 | Interface.cc 13 | ) 14 | 15 | add_executable( 16 | return_values 17 | ReturnValues.cc 18 | ) 19 | 20 | add_custom_target( 21 | run_examples 22 | COMMAND $ 23 | COMMAND $ 24 | COMMAND $ 25 | USES_TERMINAL 26 | ) 27 | 28 | add_dependencies( 29 | run_examples 30 | button 31 | interface 32 | return_values 33 | ) 34 | -------------------------------------------------------------------------------- /cmake/failtest.cmake: -------------------------------------------------------------------------------- 1 | # Creates "failtest_NAME" test from SOURCE file which will yield test success if cmake fails to 2 | # compile the source code. 3 | function(add_failtest name source) 4 | add_executable( 5 | _failtest_${name} 6 | ${source} 7 | ) 8 | 9 | set_target_properties( 10 | _failtest_${name} 11 | PROPERTIES EXCLUDE_FROM_ALL TRUE 12 | ) 13 | 14 | add_test( 15 | NAME failtest_${name} 16 | COMMAND 17 | ${CMAKE_COMMAND} --build . 18 | --target _failtest_${name} 19 | --config $ 20 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 21 | ) 22 | 23 | # Set that the test failing means success! 24 | set_tests_properties( 25 | failtest_${name} 26 | PROPERTIES WILL_FAIL TRUE 27 | ) 28 | endfunction() 29 | -------------------------------------------------------------------------------- /examples/Button.cc: -------------------------------------------------------------------------------- 1 | // Example that demonstrates a simplified button with specified action-on-click. 2 | 3 | #include "sigs.h" 4 | 5 | #include 6 | 7 | class Button { 8 | using ClickFn = void(); 9 | 10 | public: 11 | void click() 12 | { 13 | clickSignal(); 14 | } 15 | 16 | void setAction(std::function fn) 17 | { 18 | // Replace any previous handler. 19 | clickSignal.clear(); 20 | clickSignal.connect(fn); 21 | } 22 | 23 | private: 24 | sigs::Signal clickSignal; 25 | }; 26 | 27 | int main() 28 | { 29 | Button btn; 30 | btn.setAction([] { std::cout << "fn: clicked" << std::endl; }); 31 | btn.click(); 32 | 33 | btn.setAction([] { std::cout << "fn2: clicked" << std::endl; }); 34 | btn.click(); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /examples/Interface.cc: -------------------------------------------------------------------------------- 1 | // Example that demonstrates a simplified button with signal interface that doesn't expose anything 2 | // else than connect and disconnect methods. 3 | 4 | #include "sigs.h" 5 | 6 | #include 7 | 8 | class Button { 9 | public: 10 | void click() 11 | { 12 | clickSignal_(); 13 | } 14 | 15 | [[nodiscard]] auto clickSignal() 16 | { 17 | return clickSignal_.interface(); 18 | } 19 | 20 | private: 21 | sigs::Signal clickSignal_; 22 | }; 23 | 24 | int main() 25 | { 26 | Button btn; 27 | btn.clickSignal()->connect([] { std::cout << "direct fn" << std::endl; }); 28 | btn.clickSignal()->connect([] { std::cout << "direct fn 2" << std::endl; }); 29 | 30 | auto conn = btn.clickSignal()->connect([] { std::cout << "you won't see me" << std::endl; }); 31 | conn->disconnect(); 32 | 33 | btn.click(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /examples/ReturnValues.cc: -------------------------------------------------------------------------------- 1 | // Example of how to use return values of connected slots.. 2 | 3 | #include "sigs.h" 4 | 5 | #include 6 | 7 | class Calculator { 8 | public: 9 | void execute() 10 | { 11 | std::cout << "Calculating.." << std::endl; 12 | 13 | int sum = 0; 14 | executeSignal_([&sum](int retVal) { 15 | std::cout << "Incoming value: " << retVal << std::endl; 16 | sum += retVal; 17 | }); 18 | 19 | std::cout << "Sum of calculation: " << sum << std::endl; 20 | } 21 | 22 | [[nodiscard]] auto executeSignal() 23 | { 24 | return executeSignal_.interface(); 25 | } 26 | 27 | private: 28 | sigs::Signal executeSignal_; 29 | }; 30 | 31 | int main() 32 | { 33 | Calculator calc; 34 | auto sig = calc.executeSignal(); 35 | sig->connect([] { 36 | // Do something and return value.. 37 | return 42; 38 | }); 39 | sig->connect([] { return 2; }); 40 | calc.execute(); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | # On all pushes/PRs to master branche and every sunday at 4:42. 4 | on: 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | schedule: 10 | - cron: '42 4 * * 6' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | language: [ 'cpp', 'python' ] 25 | 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v2 29 | 30 | - name: Initialize CodeQL 31 | uses: github/codeql-action/init@v1 32 | with: 33 | languages: ${{ matrix.language }} 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v1 37 | 38 | - name: Perform CodeQL Analysis 39 | uses: github/codeql-action/analyze@v1 40 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories( 2 | ${CMAKE_SOURCE_DIR} 3 | ) 4 | 5 | # Include gtest as system headers so no warnings will be shown. 6 | include_directories( 7 | SYSTEM 8 | gtest/ 9 | gtest/include 10 | ) 11 | 12 | add_library( 13 | gtest 14 | gtest/src/gtest-all.cc 15 | ) 16 | 17 | # Ignore all warnings from gtest code. 18 | target_compile_options( 19 | gtest 20 | PRIVATE 21 | $<$:-w> 22 | $<$:-w> 23 | $<$:/W0> 24 | ) 25 | 26 | add_executable( 27 | ${testName} 28 | 29 | main.cc 30 | 31 | General.cc 32 | Interface.cc 33 | SignalBlocker.cc 34 | CustomTypes.cc 35 | ) 36 | 37 | add_test( 38 | NAME ${testName} 39 | COMMAND ${testName} 40 | ) 41 | 42 | target_link_libraries( 43 | ${testName} 44 | gtest 45 | ) 46 | 47 | if (LINUX) 48 | target_link_libraries( 49 | ${testName} 50 | -pthread 51 | ) 52 | endif() 53 | 54 | add_subdirectory(failtests) 55 | -------------------------------------------------------------------------------- /tests/CustomTypes.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gtest/gtest.h" 4 | 5 | #include "sigs.h" 6 | 7 | class Mutex { 8 | public: 9 | void lock() 10 | { 11 | locks++; 12 | } 13 | 14 | void unlock() 15 | { 16 | unlocks++; 17 | } 18 | 19 | int locks = 0, unlocks = 0; 20 | }; 21 | 22 | template 23 | class Lock { 24 | public: 25 | using mutex_type = Mutex; 26 | 27 | explicit Lock(Mutex &m_) : m(m_) 28 | { 29 | m.lock(); 30 | } 31 | 32 | ~Lock() 33 | { 34 | m.unlock(); 35 | EXPECT_EQ(m.locks, m.unlocks); 36 | EXPECT_GT(m.locks, 0); 37 | } 38 | 39 | Mutex &m; 40 | }; 41 | 42 | using LockMutex = Lock; 43 | 44 | template 45 | using CustomSignal = sigs::BasicSignal; 46 | 47 | TEST(CustomTypes, signal) 48 | { 49 | CustomSignal s; 50 | s.connect([] {}); 51 | s(); 52 | } 53 | 54 | TEST(CustomTypes, blocker) 55 | { 56 | CustomSignal s; 57 | s.connect([] {}); 58 | 59 | sigs::SignalBlocker sb(s); 60 | s(); 61 | } 62 | -------------------------------------------------------------------------------- /cmake/target.cmake: -------------------------------------------------------------------------------- 1 | set(BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/bin") 2 | set(LIB_DIR "${CMAKE_CURRENT_BINARY_DIR}/lib") 3 | 4 | if (WIN32) 5 | set(WIN_BIN_DIR "${BIN_DIR}/${CMAKE_BUILD_TYPE}") 6 | endif() 7 | 8 | set( 9 | TARGET_DIR 10 | ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ 11 | ) 12 | 13 | file( 14 | MAKE_DIRECTORY 15 | ${BIN_DIR} 16 | ${LIB_DIR} 17 | ) 18 | 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}) 20 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${BIN_DIR}) 21 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${BIN_DIR}) 22 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${BIN_DIR}) 23 | 24 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIB_DIR}) 25 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${LIB_DIR}) 26 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${LIB_DIR}) 27 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${LIB_DIR}) 28 | 29 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR}) 30 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE} ${LIB_DIR}) 31 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${LIB_DIR}) 32 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${LIB_DIR}) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2020 Morten Kristensen, me AT mortens DOT dev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/test-sanitizers.yml: -------------------------------------------------------------------------------- 1 | name: Clang Sanitizers 2 | 3 | # On all pushes to branches and pull requests in general. 4 | on: 5 | push: 6 | pull_request: 7 | 8 | env: 9 | BUILD_TYPE: Debug 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | sanitizer: [ADDRESS_SANITIZER, THREAD_SANITIZER, UNDEFINED_SANITIZER] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Configure cmake 22 | run: CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -D${{matrix.sanitizer}}=ON -DEVERY_WARNING=ON 23 | 24 | - name: Build 25 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --verbose 26 | 27 | - name: Test 28 | working-directory: ${{github.workspace}}/build 29 | run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure 30 | 31 | - name: Test sporadic failures 32 | working-directory: ${{github.workspace}}/build 33 | run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure --repeat until-fail:20 -R tests 34 | 35 | - name: Run examples 36 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --verbose --target run_examples 37 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/custom/gtest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Injection point for custom user configurations. See README for details 31 | // 32 | // ** Custom implementation starts here ** 33 | 34 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 35 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 36 | 37 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 38 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/custom/gtest-port.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Injection point for custom user configurations. See README for details 31 | // 32 | // ** Custom implementation starts here ** 33 | 34 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 35 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 36 | 37 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 38 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | Standard: c++20 4 | TabWidth: 2 5 | UseTab: Never 6 | AccessModifierOffset: -2 7 | AlignAfterOpenBracket: true 8 | AlignConsecutiveAssignments: false 9 | AlignEscapedNewlinesLeft: false 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllParametersOfDeclarationOnNextLine: false 13 | AllowShortBlocksOnASingleLine: false 14 | AllowShortCaseLabelsOnASingleLine: false 15 | AllowShortFunctionsOnASingleLine: false 16 | AllowShortIfStatementsOnASingleLine: true 17 | AllowShortLoopsOnASingleLine: false 18 | AlwaysBreakAfterDefinitionReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BreakBeforeBinaryOperators: None 24 | BreakBeforeBraces: Stroustrup 25 | BreakBeforeTernaryOperators: true 26 | BreakConstructorInitializersBeforeComma: false 27 | ColumnLimit: 100 28 | CommentPragmas: '^ IWYU pragma:' 29 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 30 | ConstructorInitializerIndentWidth: 2 31 | ContinuationIndentWidth: 2 32 | Cpp11BracedListStyle: true 33 | DerivePointerAlignment: false 34 | DisableFormat: false 35 | ExperimentalAutoDetectBinPacking: false 36 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 37 | IndentCaseLabels: false 38 | IndentWidth: 2 39 | IndentWrappedFunctionNames: false 40 | KeepEmptyLinesAtTheStartOfBlocks: true 41 | MacroBlockBegin: '' 42 | MacroBlockEnd: '' 43 | MaxEmptyLinesToKeep: 1 44 | NamespaceIndentation: None 45 | ObjCBlockIndentWidth: 2 46 | ObjCSpaceAfterProperty: false 47 | ObjCSpaceBeforeProtocolList: true 48 | PenaltyBreakBeforeFirstCallParameter: 19 49 | PenaltyBreakComment: 300 50 | PenaltyBreakFirstLessLess: 120 51 | PenaltyBreakString: 1000 52 | PenaltyExcessCharacter: 1000000 53 | PenaltyReturnTypeOnItsOwnLine: 60 54 | PointerAlignment: Right 55 | PointerBindsToType: false 56 | SpaceAfterCStyleCast: true 57 | SpaceBeforeAssignmentOperators: true 58 | SpaceBeforeParens: ControlStatements 59 | SpaceInEmptyParentheses: false 60 | SpacesBeforeTrailingComments: 1 61 | SpacesInAngles: false 62 | SpacesInContainerLiterals: true 63 | SpacesInCStyleCastParentheses: false 64 | SpacesInParentheses: false 65 | SpacesInSquareBrackets: false 66 | ... 67 | 68 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | # On all pushes to branches and pull requests in general. 4 | on: 5 | push: 6 | pull_request: 7 | 8 | env: 9 | BUILD_TYPE: Release 10 | 11 | jobs: 12 | test: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [windows-latest, macos-latest, ubuntu-latest] 17 | compiler: [default, gcc, clang] 18 | 19 | # Only run "default" on Windows and macOS, but both Clang and GCC on Linux. 20 | exclude: 21 | - os: windows-latest 22 | compiler: gcc 23 | - os: windows-latest 24 | compiler: clang 25 | - os: macos-latest 26 | compiler: gcc 27 | - os: macos-latest 28 | compiler: clang 29 | - os: ubuntu-latest 30 | compiler: default 31 | 32 | steps: 33 | - uses: actions/checkout@v2 34 | 35 | - name: Configure CMake (Linux – GCC) 36 | if: matrix.os == 'ubuntu-latest' && matrix.compiler == 'gcc' 37 | run: | 38 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ 39 | 40 | - name: Configure CMake (Linux – Clang) 41 | if: matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang' 42 | run: | 43 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ 44 | 45 | - name: Configure CMake (Windows / macOS – default) 46 | if: matrix.compiler == 'default' 47 | run: | 48 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} 49 | 50 | - name: Build 51 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --verbose 52 | 53 | - name: Test 54 | working-directory: ${{github.workspace}}/build 55 | run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure 56 | 57 | - name: Test sporadic failures 58 | working-directory: ${{github.workspace}}/build 59 | run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure --repeat until-fail:20 -R tests 60 | 61 | - name: Run examples 62 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --verbose --target run_examples 63 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/custom/gtest-printers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // This file provides an injection point for custom printers in a local 31 | // installation of gTest. 32 | // It will be included from gtest-printers.h and the overrides in this file 33 | // will be visible to everyone. 34 | // 35 | // Injection point for custom user configurations. See README for details 36 | // 37 | // ** Custom implementation starts here ** 38 | 39 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 40 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 41 | 42 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 43 | -------------------------------------------------------------------------------- /tests/Interface.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #include "sigs.h" 4 | 5 | TEST(Interface, instantiate) 6 | { 7 | sigs::Signal s; 8 | [[maybe_unused]] const auto interf = s.interface(); 9 | } 10 | 11 | inline void addOne(int &i) 12 | { 13 | i++; 14 | } 15 | 16 | TEST(Interface, function) 17 | { 18 | sigs::Signal s; 19 | s.interface()->connect(addOne); 20 | 21 | int i = 0; 22 | s(i); 23 | 24 | EXPECT_EQ(i, 1); 25 | } 26 | 27 | TEST(Interface, multipleFunctions) 28 | { 29 | sigs::Signal s; 30 | s.interface()->connect(addOne); 31 | s.interface()->connect(addOne); 32 | s.interface()->connect(addOne); 33 | 34 | int i = 0; 35 | s(i); 36 | 37 | EXPECT_EQ(i, 3); 38 | } 39 | 40 | TEST(Interface, functor) 41 | { 42 | class AddOneFunctor { 43 | public: 44 | void operator()(int &i) const 45 | { 46 | i++; 47 | } 48 | }; 49 | 50 | sigs::Signal s; 51 | s.interface()->connect(AddOneFunctor()); 52 | 53 | int i = 0; 54 | s(i); 55 | 56 | EXPECT_EQ(i, 1); 57 | } 58 | 59 | TEST(Interface, instanceMethod) 60 | { 61 | class Foo { 62 | public: 63 | void test(int &i) const 64 | { 65 | i++; 66 | } 67 | }; 68 | 69 | sigs::Signal s; 70 | 71 | Foo foo; 72 | s.interface()->connect(&foo, &Foo::test); 73 | 74 | int i = 0; 75 | s(i); 76 | 77 | EXPECT_EQ(i, 1); 78 | } 79 | 80 | TEST(Interface, lambda) 81 | { 82 | sigs::Signal s; 83 | s.interface()->connect([](auto &i) { i++; }); 84 | 85 | int i = 0; 86 | s(i); 87 | EXPECT_EQ(i, 1); 88 | } 89 | 90 | TEST(Interface, connectionDisconnectOnSignal) 91 | { 92 | sigs::Signal s; 93 | auto conn = s.connect([](int &i) { i++; }); 94 | 95 | int i = 0; 96 | s(i); 97 | EXPECT_EQ(i, 1); 98 | 99 | s.interface()->disconnect(conn); 100 | 101 | s(i); 102 | EXPECT_EQ(i, 1); 103 | } 104 | 105 | TEST(Interface, disconnectSignalFromSignal) 106 | { 107 | sigs::Signal s1; 108 | s1.connect([](int &i) { i++; }); 109 | 110 | decltype(s1) s2; 111 | s2.connect(s1); 112 | s2.interface()->disconnect(s1); 113 | 114 | int i = 0; 115 | s2(i); 116 | EXPECT_EQ(i, 0); 117 | } 118 | -------------------------------------------------------------------------------- /tests/gtest/src/gtest-all.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // 31 | // Google C++ Testing and Mocking Framework (Google Test) 32 | // 33 | // Sometimes it's desirable to build Google Test by compiling a single file. 34 | // This file serves this purpose. 35 | 36 | // This line ensures that gtest.h can be compiled on its own, even 37 | // when it's fused. 38 | #include "gtest/gtest.h" 39 | 40 | // The following lines pull in the real gtest *.cc files. 41 | #include "src/gtest-assertion-result.cc" 42 | #include "src/gtest-death-test.cc" 43 | #include "src/gtest-filepath.cc" 44 | #include "src/gtest-matchers.cc" 45 | #include "src/gtest-port.cc" 46 | #include "src/gtest-printers.cc" 47 | #include "src/gtest-test-part.cc" 48 | #include "src/gtest-typed-test.cc" 49 | #include "src/gtest.cc" 50 | -------------------------------------------------------------------------------- /tests/gtest/src/gtest_main.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | #include 31 | 32 | #include "gtest/gtest.h" 33 | 34 | #if defined(GTEST_OS_ESP8266) || defined(GTEST_OS_ESP32) || \ 35 | (defined(GTEST_OS_NRF52) && defined(ARDUINO)) 36 | // Arduino-like platforms: program entry points are setup/loop instead of main. 37 | 38 | #ifdef GTEST_OS_ESP8266 39 | extern "C" { 40 | #endif 41 | 42 | void setup() { testing::InitGoogleTest(); } 43 | 44 | void loop() { RUN_ALL_TESTS(); } 45 | 46 | #ifdef GTEST_OS_ESP8266 47 | } 48 | #endif 49 | 50 | #elif defined(GTEST_OS_QURT) 51 | // QuRT: program entry point is main, but argc/argv are unusable. 52 | 53 | GTEST_API_ int main() { 54 | printf("Running main() from %s\n", __FILE__); 55 | testing::InitGoogleTest(); 56 | return RUN_ALL_TESTS(); 57 | } 58 | #else 59 | // Normal platforms: program entry point is main, argc/argv are initialized. 60 | 61 | GTEST_API_ int main(int argc, char **argv) { 62 | printf("Running main() from %s\n", __FILE__); 63 | testing::InitGoogleTest(&argc, argv); 64 | return RUN_ALL_TESTS(); 65 | } 66 | #endif 67 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/gtest_prod.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Google C++ Testing and Mocking Framework definitions useful in production 31 | // code. 32 | 33 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ 34 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ 35 | 36 | // When you need to test the private or protected members of a class, 37 | // use the FRIEND_TEST macro to declare your tests as friends of the 38 | // class. For example: 39 | // 40 | // class MyClass { 41 | // private: 42 | // void PrivateMethod(); 43 | // FRIEND_TEST(MyClassTest, PrivateMethodWorks); 44 | // }; 45 | // 46 | // class MyClassTest : public testing::Test { 47 | // // ... 48 | // }; 49 | // 50 | // TEST_F(MyClassTest, PrivateMethodWorks) { 51 | // // Can call MyClass::PrivateMethod() here. 52 | // } 53 | // 54 | // Note: The test class must be in the same namespace as the class being tested. 55 | // For example, putting MyClassTest in an anonymous namespace will not work. 56 | 57 | #define FRIEND_TEST(test_case_name, test_name) \ 58 | friend class test_case_name##_##test_name##_Test 59 | 60 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ 61 | -------------------------------------------------------------------------------- /tests/gtest/src/gtest-assertion-result.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This file defines the AssertionResult type. 33 | 34 | #include "gtest/gtest-assertion-result.h" 35 | 36 | #include 37 | #include 38 | 39 | #include "gtest/gtest-message.h" 40 | 41 | namespace testing { 42 | 43 | // AssertionResult constructors. 44 | // Used in EXPECT_TRUE/FALSE(assertion_result). 45 | AssertionResult::AssertionResult(const AssertionResult& other) 46 | : success_(other.success_), 47 | message_(other.message_ != nullptr 48 | ? new ::std::string(*other.message_) 49 | : static_cast< ::std::string*>(nullptr)) {} 50 | 51 | // Swaps two AssertionResults. 52 | void AssertionResult::swap(AssertionResult& other) { 53 | using std::swap; 54 | swap(success_, other.success_); 55 | swap(message_, other.message_); 56 | } 57 | 58 | // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. 59 | AssertionResult AssertionResult::operator!() const { 60 | AssertionResult negation(!success_); 61 | if (message_ != nullptr) negation << *message_; 62 | return negation; 63 | } 64 | 65 | // Makes a successful assertion result. 66 | AssertionResult AssertionSuccess() { return AssertionResult(true); } 67 | 68 | // Makes a failed assertion result. 69 | AssertionResult AssertionFailure() { return AssertionResult(false); } 70 | 71 | // Makes a failed assertion result with the given failure message. 72 | // Deprecated; use AssertionFailure() << message. 73 | AssertionResult AssertionFailure(const Message& message) { 74 | return AssertionFailure() << message; 75 | } 76 | 77 | } // namespace testing 78 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Not using "cpp" because the default tools are so old! 2 | language: generic 3 | 4 | matrix: 5 | include: 6 | # works on Precise and Trusty 7 | - os: linux 8 | sudo: required 9 | addons: 10 | apt: 11 | sources: 12 | - ubuntu-toolchain-r-test 13 | packages: 14 | - g++-7 15 | env: 16 | - CC=gcc-7 17 | - CXX=g++-7 18 | 19 | # works on Precise and Trusty 20 | - os: linux 21 | sudo: required 22 | addons: 23 | apt: 24 | sources: 25 | - ubuntu-toolchain-r-test 26 | packages: 27 | - g++-8 28 | env: 29 | - CC=gcc-8 30 | - CXX=g++-8 31 | 32 | - os: linux 33 | sudo: required 34 | addons: 35 | apt: 36 | sources: 37 | - ubuntu-toolchain-r-test 38 | packages: 39 | - g++-9 40 | env: 41 | - CC=gcc-9 42 | - CXX=g++-9 43 | 44 | # works on Trusty 45 | - os: linux 46 | sudo: required 47 | addons: 48 | apt: 49 | sources: 50 | - ubuntu-toolchain-r-test 51 | - llvm-toolchain-trusty-7 52 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-7 main' 53 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 54 | packages: 55 | - g++-7 # Only to get the latest libstd++ 56 | - clang-7 57 | env: 58 | - CC=clang-7 59 | - CXX=clang++-7 60 | 61 | # works on Trusty 62 | - os: linux 63 | sudo: required 64 | addons: 65 | apt: 66 | sources: 67 | - ubuntu-toolchain-r-test 68 | - llvm-toolchain-trusty-8 69 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-8 main' 70 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 71 | packages: 72 | - g++-8 # Only to get the latest libstd++ 73 | - clang-8 74 | env: 75 | - CC=clang-8 76 | - CXX=clang++-8 77 | 78 | - os: linux 79 | sudo: required 80 | addons: 81 | apt: 82 | sources: 83 | - ubuntu-toolchain-r-test 84 | - llvm-toolchain-xenial-9 85 | - sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' 86 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 87 | packages: 88 | - g++-9 # Only to get the latest libstd++ 89 | - clang-9 90 | env: 91 | - CC=clang-9 92 | - CXX=clang++-9 93 | 94 | - os: linux 95 | sudo: required 96 | addons: 97 | apt: 98 | sources: 99 | - ubuntu-toolchain-r-test 100 | - llvm-toolchain-xenial-10 101 | - sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main' 102 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 103 | packages: 104 | - g++-9 # Only to get the latest libstd++. Xenial doesn't have GCC 10 right now.. 105 | - clang-10 106 | env: 107 | - CC=clang-10 108 | - CXX=clang++-10 109 | 110 | before_install: 111 | - echo $LANG 112 | - echo $LC_ALL 113 | - echo $CC 114 | - echo $CXX 115 | 116 | before_script: 117 | - cmake --system-information info.txt && cat info.txt 118 | - mkdir build 119 | - cd build 120 | - cmake .. 121 | 122 | script: 123 | - VERBOSE=1 make -j2 && ctest --verbose 124 | -------------------------------------------------------------------------------- /tests/gtest/src/gtest-matchers.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2007, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This file implements just enough of the matcher interface to allow 33 | // EXPECT_DEATH and friends to accept a matcher argument. 34 | 35 | #include "gtest/gtest-matchers.h" 36 | 37 | #include 38 | 39 | #include "gtest/internal/gtest-internal.h" 40 | #include "gtest/internal/gtest-port.h" 41 | 42 | namespace testing { 43 | 44 | // Constructs a matcher that matches a const std::string& whose value is 45 | // equal to s. 46 | Matcher::Matcher(const std::string& s) { *this = Eq(s); } 47 | 48 | // Constructs a matcher that matches a const std::string& whose value is 49 | // equal to s. 50 | Matcher::Matcher(const char* s) { 51 | *this = Eq(std::string(s)); 52 | } 53 | 54 | // Constructs a matcher that matches a std::string whose value is equal to 55 | // s. 56 | Matcher::Matcher(const std::string& s) { *this = Eq(s); } 57 | 58 | // Constructs a matcher that matches a std::string whose value is equal to 59 | // s. 60 | Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } 61 | 62 | #if GTEST_INTERNAL_HAS_STRING_VIEW 63 | // Constructs a matcher that matches a const StringView& whose value is 64 | // equal to s. 65 | Matcher::Matcher(const std::string& s) { 66 | *this = Eq(s); 67 | } 68 | 69 | // Constructs a matcher that matches a const StringView& whose value is 70 | // equal to s. 71 | Matcher::Matcher(const char* s) { 72 | *this = Eq(std::string(s)); 73 | } 74 | 75 | // Constructs a matcher that matches a const StringView& whose value is 76 | // equal to s. 77 | Matcher::Matcher(internal::StringView s) { 78 | *this = Eq(std::string(s)); 79 | } 80 | 81 | // Constructs a matcher that matches a StringView whose value is equal to 82 | // s. 83 | Matcher::Matcher(const std::string& s) { *this = Eq(s); } 84 | 85 | // Constructs a matcher that matches a StringView whose value is equal to 86 | // s. 87 | Matcher::Matcher(const char* s) { 88 | *this = Eq(std::string(s)); 89 | } 90 | 91 | // Constructs a matcher that matches a StringView whose value is equal to 92 | // s. 93 | Matcher::Matcher(internal::StringView s) { 94 | *this = Eq(std::string(s)); 95 | } 96 | #endif // GTEST_INTERNAL_HAS_STRING_VIEW 97 | 98 | } // namespace testing 99 | -------------------------------------------------------------------------------- /tests/SignalBlocker.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gtest/gtest.h" 4 | 5 | #include "sigs.h" 6 | 7 | TEST(SignalBlocker, instantiate) 8 | { 9 | using SignalType = sigs::Signal; 10 | SignalType s; 11 | sigs::SignalBlocker sb1(s); 12 | sigs::SignalBlocker sb2(s); 13 | sigs::SignalBlocker sb3(&s); 14 | sigs::SignalBlocker sb4(&s); 15 | } 16 | 17 | TEST(SignalBlocker, block) 18 | { 19 | sigs::Signal s; 20 | ASSERT_FALSE(s.blocked()); 21 | 22 | sigs::SignalBlocker sb(s); 23 | ASSERT_TRUE(s.blocked()); 24 | } 25 | 26 | TEST(SignalBlocker, unblock) 27 | { 28 | sigs::Signal s; 29 | ASSERT_FALSE(s.blocked()); 30 | 31 | sigs::SignalBlocker sb(s); 32 | ASSERT_TRUE(s.blocked()); 33 | 34 | sb.unblock(); 35 | ASSERT_FALSE(s.blocked()); 36 | } 37 | 38 | TEST(SignalBlocker, reblock) 39 | { 40 | sigs::Signal s; 41 | ASSERT_FALSE(s.blocked()); 42 | 43 | sigs::SignalBlocker sb(s); 44 | ASSERT_TRUE(s.blocked()); 45 | 46 | sb.unblock(); 47 | ASSERT_FALSE(s.blocked()); 48 | 49 | sb.reblock(); 50 | ASSERT_TRUE(s.blocked()); 51 | } 52 | 53 | TEST(SignalBlocker, scopedBlock) 54 | { 55 | sigs::Signal s; 56 | ASSERT_FALSE(s.blocked()); 57 | 58 | { 59 | sigs::SignalBlocker sb(s); 60 | ASSERT_TRUE(s.blocked()); 61 | } 62 | 63 | ASSERT_FALSE(s.blocked()); 64 | } 65 | 66 | TEST(SignalBlocker, scopedBlockPointer) 67 | { 68 | sigs::Signal s; 69 | ASSERT_FALSE(s.blocked()); 70 | 71 | { 72 | sigs::SignalBlocker sb(&s); 73 | ASSERT_TRUE(s.blocked()); 74 | } 75 | 76 | ASSERT_FALSE(s.blocked()); 77 | } 78 | 79 | /// Unblocking before scope ends must still result in being unblocked after scope ends. 80 | TEST(SignalBlocker, scopedUnblock) 81 | { 82 | sigs::Signal s; 83 | ASSERT_FALSE(s.blocked()); 84 | 85 | { 86 | sigs::SignalBlocker sb(s); 87 | ASSERT_TRUE(s.blocked()); 88 | 89 | sb.unblock(); 90 | } 91 | 92 | ASSERT_FALSE(s.blocked()); 93 | } 94 | 95 | /// Unblocking and reblocking before scope ends must still result in being unblocked after scope 96 | /// ends. 97 | TEST(SignalBlocker, scopedUnblockReblock) 98 | { 99 | sigs::Signal s; 100 | ASSERT_FALSE(s.blocked()); 101 | 102 | { 103 | sigs::SignalBlocker sb(s); 104 | ASSERT_TRUE(s.blocked()); 105 | 106 | sb.unblock(); 107 | sb.reblock(); 108 | } 109 | 110 | ASSERT_FALSE(s.blocked()); 111 | } 112 | 113 | TEST(SignalBlocker, scopedBlockPrevious) 114 | { 115 | sigs::Signal s; 116 | ASSERT_FALSE(s.blocked()); 117 | 118 | { 119 | sigs::SignalBlocker sb(s); 120 | ASSERT_TRUE(s.blocked()); 121 | 122 | { 123 | // Already blocked. 124 | sigs::SignalBlocker sb2(s); 125 | ASSERT_TRUE(s.blocked()); 126 | } 127 | 128 | // Must still be blocked at this point due to `sb`. 129 | ASSERT_TRUE(s.blocked()); 130 | } 131 | 132 | ASSERT_FALSE(s.blocked()); 133 | } 134 | 135 | TEST(SignalBlocker, moveConstructible) 136 | { 137 | sigs::Signal s; 138 | 139 | sigs::SignalBlocker sb(s); 140 | ASSERT_TRUE(s.blocked()); 141 | 142 | sigs::SignalBlocker sb2(std::move(sb)); 143 | ASSERT_TRUE(s.blocked()); 144 | } 145 | 146 | TEST(SignalBlocker, moveAssignable) 147 | { 148 | sigs::Signal s, s2; 149 | 150 | sigs::SignalBlocker sb(s); 151 | ASSERT_TRUE(s.blocked()); 152 | 153 | sigs::SignalBlocker sb2(s2); 154 | ASSERT_TRUE(s2.blocked()); 155 | 156 | sb2 = std::move(sb); 157 | ASSERT_TRUE(s.blocked()); 158 | 159 | // `s2` is unblocked when `sb` was moved to `sb2` since they block different signals. 160 | ASSERT_FALSE(s2.blocked()); 161 | } 162 | 163 | TEST(SignalBlocker, moveAssignableSameSignal) 164 | { 165 | sigs::Signal s; 166 | 167 | sigs::SignalBlocker sb(s); 168 | ASSERT_TRUE(s.blocked()); 169 | 170 | sigs::SignalBlocker sb2(s); 171 | ASSERT_TRUE(s.blocked()); 172 | 173 | sb2 = std::move(sb); 174 | 175 | // Stays blocked because `sb` and `sb2` were blocking the same signal. 176 | ASSERT_TRUE(s.blocked()); 177 | } 178 | -------------------------------------------------------------------------------- /tests/gtest/src/gtest-typed-test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. 2 | // All Rights Reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | #include "gtest/gtest-typed-test.h" 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "gtest/gtest.h" 37 | 38 | namespace testing { 39 | namespace internal { 40 | 41 | // Skips to the first non-space char in str. Returns an empty string if str 42 | // contains only whitespace characters. 43 | static const char* SkipSpaces(const char* str) { 44 | while (IsSpace(*str)) str++; 45 | return str; 46 | } 47 | 48 | static std::vector SplitIntoTestNames(const char* src) { 49 | std::vector name_vec; 50 | src = SkipSpaces(src); 51 | for (; src != nullptr; src = SkipComma(src)) { 52 | name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); 53 | } 54 | return name_vec; 55 | } 56 | 57 | // Verifies that registered_tests match the test names in 58 | // registered_tests_; returns registered_tests if successful, or 59 | // aborts the program otherwise. 60 | const char* TypedTestSuitePState::VerifyRegisteredTestNames( 61 | const char* test_suite_name, const char* file, int line, 62 | const char* registered_tests) { 63 | RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line)); 64 | 65 | typedef RegisteredTestsMap::const_iterator RegisteredTestIter; 66 | registered_ = true; 67 | 68 | std::vector name_vec = SplitIntoTestNames(registered_tests); 69 | 70 | Message errors; 71 | 72 | std::set tests; 73 | for (std::vector::const_iterator name_it = name_vec.begin(); 74 | name_it != name_vec.end(); ++name_it) { 75 | const std::string& name = *name_it; 76 | if (tests.count(name) != 0) { 77 | errors << "Test " << name << " is listed more than once.\n"; 78 | continue; 79 | } 80 | 81 | if (registered_tests_.count(name) != 0) { 82 | tests.insert(name); 83 | } else { 84 | errors << "No test named " << name 85 | << " can be found in this test suite.\n"; 86 | } 87 | } 88 | 89 | for (RegisteredTestIter it = registered_tests_.begin(); 90 | it != registered_tests_.end(); ++it) { 91 | if (tests.count(it->first) == 0) { 92 | errors << "You forgot to list test " << it->first << ".\n"; 93 | } 94 | } 95 | 96 | const std::string& errors_str = errors.GetString(); 97 | if (!errors_str.empty()) { 98 | fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), 99 | errors_str.c_str()); 100 | fflush(stderr); 101 | posix::Abort(); 102 | } 103 | 104 | return registered_tests; 105 | } 106 | 107 | } // namespace internal 108 | } // namespace testing 109 | -------------------------------------------------------------------------------- /tests/gtest/src/gtest-test-part.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // 31 | // The Google C++ Testing and Mocking Framework (Google Test) 32 | 33 | #include "gtest/gtest-test-part.h" 34 | 35 | #include 36 | #include 37 | 38 | #include "gtest/internal/gtest-port.h" 39 | #include "src/gtest-internal-inl.h" 40 | 41 | namespace testing { 42 | 43 | // Gets the summary of the failure message by omitting the stack trace 44 | // in it. 45 | std::string TestPartResult::ExtractSummary(const char* message) { 46 | const char* const stack_trace = strstr(message, internal::kStackTraceMarker); 47 | return stack_trace == nullptr ? message : std::string(message, stack_trace); 48 | } 49 | 50 | // Prints a TestPartResult object. 51 | std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { 52 | return os << internal::FormatFileLocation(result.file_name(), 53 | result.line_number()) 54 | << " " 55 | << (result.type() == TestPartResult::kSuccess ? "Success" 56 | : result.type() == TestPartResult::kSkip ? "Skipped" 57 | : result.type() == TestPartResult::kFatalFailure 58 | ? "Fatal failure" 59 | : "Non-fatal failure") 60 | << ":\n" 61 | << result.message() << std::endl; 62 | } 63 | 64 | // Appends a TestPartResult to the array. 65 | void TestPartResultArray::Append(const TestPartResult& result) { 66 | array_.push_back(result); 67 | } 68 | 69 | // Returns the TestPartResult at the given index (0-based). 70 | const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { 71 | if (index < 0 || index >= size()) { 72 | printf("\nInvalid index (%d) into TestPartResultArray.\n", index); 73 | internal::posix::Abort(); 74 | } 75 | 76 | return array_[static_cast(index)]; 77 | } 78 | 79 | // Returns the number of TestPartResult objects in the array. 80 | int TestPartResultArray::size() const { 81 | return static_cast(array_.size()); 82 | } 83 | 84 | namespace internal { 85 | 86 | HasNewFatalFailureHelper::HasNewFatalFailureHelper() 87 | : has_new_fatal_failure_(false), 88 | original_reporter_( 89 | GetUnitTestImpl()->GetTestPartResultReporterForCurrentThread()) { 90 | GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); 91 | } 92 | 93 | HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { 94 | GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( 95 | original_reporter_); 96 | } 97 | 98 | void HasNewFatalFailureHelper::ReportTestPartResult( 99 | const TestPartResult& result) { 100 | if (result.fatally_failed()) has_new_fatal_failure_ = true; 101 | original_reporter_->ReportTestPartResult(result); 102 | } 103 | 104 | } // namespace internal 105 | 106 | } // namespace testing 107 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/gtest-port-arch.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This header file defines the GTEST_OS_* macro. 33 | // It is separate from gtest-port.h so that custom/gtest-port.h can include it. 34 | 35 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 36 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 37 | 38 | // Determines the platform on which Google Test is compiled. 39 | #ifdef __CYGWIN__ 40 | #define GTEST_OS_CYGWIN 1 41 | #elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) 42 | #define GTEST_OS_WINDOWS_MINGW 1 43 | #define GTEST_OS_WINDOWS 1 44 | #elif defined _WIN32 45 | #define GTEST_OS_WINDOWS 1 46 | #ifdef _WIN32_WCE 47 | #define GTEST_OS_WINDOWS_MOBILE 1 48 | #elif defined(WINAPI_FAMILY) 49 | #include 50 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 51 | #define GTEST_OS_WINDOWS_DESKTOP 1 52 | #elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) 53 | #define GTEST_OS_WINDOWS_PHONE 1 54 | #elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) 55 | #define GTEST_OS_WINDOWS_RT 1 56 | #elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) 57 | #define GTEST_OS_WINDOWS_PHONE 1 58 | #define GTEST_OS_WINDOWS_TV_TITLE 1 59 | #elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_GAMES) 60 | #define GTEST_OS_WINDOWS_GAMES 1 61 | #else 62 | // WINAPI_FAMILY defined but no known partition matched. 63 | // Default to desktop. 64 | #define GTEST_OS_WINDOWS_DESKTOP 1 65 | #endif 66 | #else 67 | #define GTEST_OS_WINDOWS_DESKTOP 1 68 | #endif // _WIN32_WCE 69 | #elif defined __OS2__ 70 | #define GTEST_OS_OS2 1 71 | #elif defined __APPLE__ 72 | #define GTEST_OS_MAC 1 73 | #include 74 | #if TARGET_OS_IPHONE 75 | #define GTEST_OS_IOS 1 76 | #endif 77 | #elif defined __DragonFly__ 78 | #define GTEST_OS_DRAGONFLY 1 79 | #elif defined __FreeBSD__ 80 | #define GTEST_OS_FREEBSD 1 81 | #elif defined __Fuchsia__ 82 | #define GTEST_OS_FUCHSIA 1 83 | #elif defined(__GNU__) 84 | #define GTEST_OS_GNU_HURD 1 85 | #elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) 86 | #define GTEST_OS_GNU_KFREEBSD 1 87 | #elif defined __linux__ 88 | #define GTEST_OS_LINUX 1 89 | #if defined __ANDROID__ 90 | #define GTEST_OS_LINUX_ANDROID 1 91 | #endif 92 | #elif defined __MVS__ 93 | #define GTEST_OS_ZOS 1 94 | #elif defined(__sun) && defined(__SVR4) 95 | #define GTEST_OS_SOLARIS 1 96 | #elif defined(_AIX) 97 | #define GTEST_OS_AIX 1 98 | #elif defined(__hpux) 99 | #define GTEST_OS_HPUX 1 100 | #elif defined __native_client__ 101 | #define GTEST_OS_NACL 1 102 | #elif defined __NetBSD__ 103 | #define GTEST_OS_NETBSD 1 104 | #elif defined __OpenBSD__ 105 | #define GTEST_OS_OPENBSD 1 106 | #elif defined __QNX__ 107 | #define GTEST_OS_QNX 1 108 | #elif defined(__HAIKU__) 109 | #define GTEST_OS_HAIKU 1 110 | #elif defined ESP8266 111 | #define GTEST_OS_ESP8266 1 112 | #elif defined ESP32 113 | #define GTEST_OS_ESP32 1 114 | #elif defined(__XTENSA__) 115 | #define GTEST_OS_XTENSA 1 116 | #elif defined(__hexagon__) 117 | #define GTEST_OS_QURT 1 118 | #elif defined(CPU_QN9090) || defined(CPU_QN9090HN) 119 | #define GTEST_OS_NXP_QN9090 1 120 | #elif defined(NRF52) 121 | #define GTEST_OS_NRF52 1 122 | #endif // __CYGWIN__ 123 | 124 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 125 | -------------------------------------------------------------------------------- /cmake/compilation.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 20) 2 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 3 | 4 | set(COMMON_COMPILER_WARNINGS "-Wno-unused-parameter -Wempty-body -Woverloaded-virtual -Wtautological-compare -Wshadow -Wmissing-noreturn -Wdouble-promotion") 5 | set(CLANG_WARNINGS "-Wnull-arithmetic -Woverriding-method-mismatch -Wcovered-switch-default -Wzero-as-null-pointer-constant -Wweak-vtables -Wunused-private-field -Wno-covered-switch-default -Wmismatched-tags") 6 | set(GCC_WARNINGS "-Wuseless-cast") 7 | set(GCC10_WARNINGS "-Wmismatched-tags -Wredundant-tags") 8 | 9 | # Warnings turned into errors. 10 | set(COMMON_COMPILER_ERRORS "-Werror=return-type -Werror=delete-incomplete -Werror=delete-non-virtual-dtor -Werror=float-equal -Werror=reorder -Werror=uninitialized -Werror=unreachable-code -Werror=switch") 11 | set(CLANG_ERRORS "-Werror=inconsistent-missing-override -Werror=inconsistent-missing-destructor-override -Werror=division-by-zero -Werror=return-stack-address -Werror=pessimizing-move -Werror=infinite-recursion -Werror=nonportable-include-path") 12 | set(GCC_ERRORS "") 13 | set(GCC9_ERRORS "-Werror=pessimizing-move") 14 | 15 | # Some release optimization flags for GCC/Clang/MSVC. 16 | if (NOT MSVC) 17 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -pedantic -pedantic-errors ${COMMON_COMPILER_WARNINGS} ${COMMON_COMPILER_ERRORS}") 18 | set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") 19 | set(CMAKE_CXX_FLAGS_MINSIZEREL "-O3 -DNDEBUG") 20 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") 21 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") 22 | else() 23 | # /EHsc = enables unwind semantics when exception handler is used. 24 | # Ignore certain warnings: 25 | # C4514: 'function' : unreferenced inline function has been removed 26 | # C4820: bytes' bytes padding added after construct 'member_name' 27 | # C4710: 'function' : function not inlined 28 | # C4711: function 'function' selected for inline expansion 29 | # C4668: 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 30 | set(CMAKE_CXX_FLAGS "/Wall /EHsc /wd4514 /wd4820 /wd4710 /wd4711 /wd4668") 31 | endif() 32 | 33 | # Show color in diagnostics messages from Clang. 34 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics") 36 | endif() 37 | 38 | if (NOT MSVC) 39 | # Clang/GCC 40 | set(REL_OPTS "-O3 -pipe -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -ffast-math -funroll-loops") 41 | 42 | # GCC only 43 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 44 | set(REL_OPTS "${REL_OPTS} -fno-implement-inlines") 45 | 46 | # Clang only 47 | elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 48 | set(REL_OPTS "${REL_OPTS}") 49 | 50 | if (EVERY_WARNING) 51 | # But ignore some warnings. 52 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat -Wno-padded -Wno-shadow-field-in-constructor -Wno-c++98-compat-pedantic") 53 | # These happen in gtest which we don't care about: 54 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-global-constructors -Wno-used-but-marked-unused") 55 | endif() 56 | endif() 57 | 58 | set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_OPTS}") 59 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${REL_OPTS}") 60 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_OPTS}") 61 | endif() 62 | 63 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 64 | set(target_version "12.0") 65 | if (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER ${target_version} OR 66 | CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL ${target_version})) 67 | message(FATAL_ERROR "Requires GCC >= ${target_version}.") 68 | endif() 69 | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR 70 | CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0) 71 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC9_ERRORS}") 72 | endif() 73 | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0 OR 74 | CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 10.0) 75 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC10_WARNINGS}") 76 | endif() 77 | elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 78 | # Xcode 15 was based on Clang 15 which has full C++20 support (previously the Xcode version was 79 | # ahead of the Clang version). 80 | if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "AppleClang") 81 | set(target_version "15.0") 82 | else() 83 | set(target_version "15") 84 | endif() 85 | 86 | if (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL ${target_version} OR 87 | CMAKE_CXX_COMPILER_VERSION VERSION_GREATER ${target_version})) 88 | message(FATAL_ERROR "Requires ${CMAKE_CXX_COMPILER_ID} >= ${target_version}") 89 | elseif (APPLE) 90 | # Use libstdc++ on Linux but libc++ on macOS. 91 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 92 | endif() 93 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_WARNINGS} ${CLANG_ERRORS}") 94 | elseif (MSVC AND (${MSVC_VERSION} GREATER_EQUAL 1929)) 95 | # Requires at least VS2019 (v1929). 96 | # C++20 support is implicitly enabled. 97 | else() 98 | message(FATAL_ERROR "Your compiler does not support C++20 - aborting!") 99 | endif() 100 | 101 | # Detect if ccache is installed and use if it is the case. 102 | if (USE_CCACHE) 103 | find_program(CCACHE ccache) 104 | if (CCACHE) 105 | # Specify to launch ccache for compilation and linking globally. 106 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) 107 | set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) 108 | endif() 109 | endif() 110 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/gtest-test-part.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // IWYU pragma: private, include "gtest/gtest.h" 31 | // IWYU pragma: friend gtest/.* 32 | // IWYU pragma: friend gmock/.* 33 | 34 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ 35 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "gtest/internal/gtest-internal.h" 43 | #include "gtest/internal/gtest-string.h" 44 | 45 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 46 | /* class A needs to have dll-interface to be used by clients of class B */) 47 | 48 | namespace testing { 49 | 50 | // A copyable object representing the result of a test part (i.e. an 51 | // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). 52 | // 53 | // Don't inherit from TestPartResult as its destructor is not virtual. 54 | class GTEST_API_ TestPartResult { 55 | public: 56 | // The possible outcomes of a test part (i.e. an assertion or an 57 | // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). 58 | enum Type { 59 | kSuccess, // Succeeded. 60 | kNonFatalFailure, // Failed but the test can continue. 61 | kFatalFailure, // Failed and the test should be terminated. 62 | kSkip // Skipped. 63 | }; 64 | 65 | // C'tor. TestPartResult does NOT have a default constructor. 66 | // Always use this constructor (with parameters) to create a 67 | // TestPartResult object. 68 | TestPartResult(Type a_type, const char* a_file_name, int a_line_number, 69 | const char* a_message) 70 | : type_(a_type), 71 | file_name_(a_file_name == nullptr ? "" : a_file_name), 72 | line_number_(a_line_number), 73 | summary_(ExtractSummary(a_message)), 74 | message_(a_message) {} 75 | 76 | // Gets the outcome of the test part. 77 | Type type() const { return type_; } 78 | 79 | // Gets the name of the source file where the test part took place, or 80 | // NULL if it's unknown. 81 | const char* file_name() const { 82 | return file_name_.empty() ? nullptr : file_name_.c_str(); 83 | } 84 | 85 | // Gets the line in the source file where the test part took place, 86 | // or -1 if it's unknown. 87 | int line_number() const { return line_number_; } 88 | 89 | // Gets the summary of the failure message. 90 | const char* summary() const { return summary_.c_str(); } 91 | 92 | // Gets the message associated with the test part. 93 | const char* message() const { return message_.c_str(); } 94 | 95 | // Returns true if and only if the test part was skipped. 96 | bool skipped() const { return type_ == kSkip; } 97 | 98 | // Returns true if and only if the test part passed. 99 | bool passed() const { return type_ == kSuccess; } 100 | 101 | // Returns true if and only if the test part non-fatally failed. 102 | bool nonfatally_failed() const { return type_ == kNonFatalFailure; } 103 | 104 | // Returns true if and only if the test part fatally failed. 105 | bool fatally_failed() const { return type_ == kFatalFailure; } 106 | 107 | // Returns true if and only if the test part failed. 108 | bool failed() const { return fatally_failed() || nonfatally_failed(); } 109 | 110 | private: 111 | Type type_; 112 | 113 | // Gets the summary of the failure message by omitting the stack 114 | // trace in it. 115 | static std::string ExtractSummary(const char* message); 116 | 117 | // The name of the source file where the test part took place, or 118 | // "" if the source file is unknown. 119 | std::string file_name_; 120 | // The line in the source file where the test part took place, or -1 121 | // if the line number is unknown. 122 | int line_number_; 123 | std::string summary_; // The test failure summary. 124 | std::string message_; // The test failure message. 125 | }; 126 | 127 | // Prints a TestPartResult object. 128 | std::ostream& operator<<(std::ostream& os, const TestPartResult& result); 129 | 130 | // An array of TestPartResult objects. 131 | // 132 | // Don't inherit from TestPartResultArray as its destructor is not 133 | // virtual. 134 | class GTEST_API_ TestPartResultArray { 135 | public: 136 | TestPartResultArray() = default; 137 | 138 | // Appends the given TestPartResult to the array. 139 | void Append(const TestPartResult& result); 140 | 141 | // Returns the TestPartResult at the given index (0-based). 142 | const TestPartResult& GetTestPartResult(int index) const; 143 | 144 | // Returns the number of TestPartResult objects in the array. 145 | int size() const; 146 | 147 | private: 148 | std::vector array_; 149 | 150 | TestPartResultArray(const TestPartResultArray&) = delete; 151 | TestPartResultArray& operator=(const TestPartResultArray&) = delete; 152 | }; 153 | 154 | // This interface knows how to report a test part result. 155 | class GTEST_API_ TestPartResultReporterInterface { 156 | public: 157 | virtual ~TestPartResultReporterInterface() = default; 158 | 159 | virtual void ReportTestPartResult(const TestPartResult& result) = 0; 160 | }; 161 | 162 | namespace internal { 163 | 164 | // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a 165 | // statement generates new fatal failures. To do so it registers itself as the 166 | // current test part result reporter. Besides checking if fatal failures were 167 | // reported, it only delegates the reporting to the former result reporter. 168 | // The original result reporter is restored in the destructor. 169 | // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. 170 | class GTEST_API_ HasNewFatalFailureHelper 171 | : public TestPartResultReporterInterface { 172 | public: 173 | HasNewFatalFailureHelper(); 174 | ~HasNewFatalFailureHelper() override; 175 | void ReportTestPartResult(const TestPartResult& result) override; 176 | bool has_new_fatal_failure() const { return has_new_fatal_failure_; } 177 | 178 | private: 179 | bool has_new_fatal_failure_; 180 | TestPartResultReporterInterface* original_reporter_; 181 | 182 | HasNewFatalFailureHelper(const HasNewFatalFailureHelper&) = delete; 183 | HasNewFatalFailureHelper& operator=(const HasNewFatalFailureHelper&) = delete; 184 | }; 185 | 186 | } // namespace internal 187 | 188 | } // namespace testing 189 | 190 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 191 | 192 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ 193 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/gtest-string.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This header file declares the String class and functions used internally by 33 | // Google Test. They are subject to change without notice. They should not used 34 | // by code external to Google Test. 35 | // 36 | // This header file is #included by gtest-internal.h. 37 | // It should not be #included by other files. 38 | 39 | // IWYU pragma: private, include "gtest/gtest.h" 40 | // IWYU pragma: friend gtest/.* 41 | // IWYU pragma: friend gmock/.* 42 | 43 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ 44 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ 45 | 46 | #ifdef __BORLANDC__ 47 | // string.h is not guaranteed to provide strcpy on C++ Builder. 48 | #include 49 | #endif 50 | 51 | #include 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | #include "gtest/internal/gtest-port.h" 58 | 59 | namespace testing { 60 | namespace internal { 61 | 62 | // String - an abstract class holding static string utilities. 63 | class GTEST_API_ String { 64 | public: 65 | // Static utility methods 66 | 67 | // Clones a 0-terminated C string, allocating memory using new. The 68 | // caller is responsible for deleting the return value using 69 | // delete[]. Returns the cloned string, or NULL if the input is 70 | // NULL. 71 | // 72 | // This is different from strdup() in string.h, which allocates 73 | // memory using malloc(). 74 | static const char* CloneCString(const char* c_str); 75 | 76 | #ifdef GTEST_OS_WINDOWS_MOBILE 77 | // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be 78 | // able to pass strings to Win32 APIs on CE we need to convert them 79 | // to 'Unicode', UTF-16. 80 | 81 | // Creates a UTF-16 wide string from the given ANSI string, allocating 82 | // memory using new. The caller is responsible for deleting the return 83 | // value using delete[]. Returns the wide string, or NULL if the 84 | // input is NULL. 85 | // 86 | // The wide string is created using the ANSI codepage (CP_ACP) to 87 | // match the behaviour of the ANSI versions of Win32 calls and the 88 | // C runtime. 89 | static LPCWSTR AnsiToUtf16(const char* c_str); 90 | 91 | // Creates an ANSI string from the given wide string, allocating 92 | // memory using new. The caller is responsible for deleting the return 93 | // value using delete[]. Returns the ANSI string, or NULL if the 94 | // input is NULL. 95 | // 96 | // The returned string is created using the ANSI codepage (CP_ACP) to 97 | // match the behaviour of the ANSI versions of Win32 calls and the 98 | // C runtime. 99 | static const char* Utf16ToAnsi(LPCWSTR utf16_str); 100 | #endif 101 | 102 | // Compares two C strings. Returns true if and only if they have the same 103 | // content. 104 | // 105 | // Unlike strcmp(), this function can handle NULL argument(s). A 106 | // NULL C string is considered different to any non-NULL C string, 107 | // including the empty string. 108 | static bool CStringEquals(const char* lhs, const char* rhs); 109 | 110 | // Converts a wide C string to a String using the UTF-8 encoding. 111 | // NULL will be converted to "(null)". If an error occurred during 112 | // the conversion, "(failed to convert from wide string)" is 113 | // returned. 114 | static std::string ShowWideCString(const wchar_t* wide_c_str); 115 | 116 | // Compares two wide C strings. Returns true if and only if they have the 117 | // same content. 118 | // 119 | // Unlike wcscmp(), this function can handle NULL argument(s). A 120 | // NULL C string is considered different to any non-NULL C string, 121 | // including the empty string. 122 | static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); 123 | 124 | // Compares two C strings, ignoring case. Returns true if and only if 125 | // they have the same content. 126 | // 127 | // Unlike strcasecmp(), this function can handle NULL argument(s). 128 | // A NULL C string is considered different to any non-NULL C string, 129 | // including the empty string. 130 | static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); 131 | 132 | // Compares two wide C strings, ignoring case. Returns true if and only if 133 | // they have the same content. 134 | // 135 | // Unlike wcscasecmp(), this function can handle NULL argument(s). 136 | // A NULL C string is considered different to any non-NULL wide C string, 137 | // including the empty string. 138 | // NB: The implementations on different platforms slightly differ. 139 | // On windows, this method uses _wcsicmp which compares according to LC_CTYPE 140 | // environment variable. On GNU platform this method uses wcscasecmp 141 | // which compares according to LC_CTYPE category of the current locale. 142 | // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the 143 | // current locale. 144 | static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, 145 | const wchar_t* rhs); 146 | 147 | // Returns true if and only if the given string ends with the given suffix, 148 | // ignoring case. Any string is considered to end with an empty suffix. 149 | static bool EndsWithCaseInsensitive(const std::string& str, 150 | const std::string& suffix); 151 | 152 | // Formats an int value as "%02d". 153 | static std::string FormatIntWidth2(int value); // "%02d" for width == 2 154 | 155 | // Formats an int value to given width with leading zeros. 156 | static std::string FormatIntWidthN(int value, int width); 157 | 158 | // Formats an int value as "%X". 159 | static std::string FormatHexInt(int value); 160 | 161 | // Formats an int value as "%X". 162 | static std::string FormatHexUInt32(uint32_t value); 163 | 164 | // Formats a byte as "%02X". 165 | static std::string FormatByte(unsigned char value); 166 | 167 | private: 168 | String(); // Not meant to be instantiated. 169 | }; // class String 170 | 171 | // Gets the content of the stringstream's buffer as an std::string. Each '\0' 172 | // character in the buffer is replaced with "\\0". 173 | GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); 174 | 175 | } // namespace internal 176 | } // namespace testing 177 | 178 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ 179 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(sigs) 3 | 4 | set(CMAKE_COLOR_MAKEFILE ON) 5 | set(CMAKE_VERBOSE_MAKEFILE OFF) 6 | set(CMAKE_INCLUDE_CURRENT_DIR TRUE) 7 | set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) 8 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 9 | 10 | include(policies NO_POLICY_SCOPE) 11 | 12 | option(CODE_COVERAGE "Instrument for code coverage (clang only!)" OFF) 13 | option(ADDRESS_SANITIZER "Use memory error detector (clang only and implies debug mode!)" OFF) 14 | option(THREAD_SANITIZER "Use thread data race detector (clang only and implies debug mode!)" OFF) 15 | option(UNDEFINED_SANITIZER "Use undefined behavior detector (clang only and implies debug mode!)" OFF) 16 | option(EVERY_WARNING "Use -Weverything (clang only)" OFF) 17 | 18 | option(STATIC_ANALYZER "Do static analysis (gcc/clang only and implies debug mode!)" OFF) 19 | 20 | option(USE_CCACHE "Use ccache (if found) to speed up compile and link" OFF) 21 | 22 | if (NOT CMAKE_BUILD_TYPE) 23 | set(CMAKE_BUILD_TYPE Release) 24 | endif() 25 | 26 | # Output compile_commands.json (Ninja generator only!) 27 | set(CMAKE_EXPORT_COMPILE_COMMANDS YES) 28 | 29 | include(platform) 30 | include(target) 31 | 32 | include(ProcessorCount) 33 | ProcessorCount(CPU_COUNT) 34 | if (${CPU_COUNT} EQUAL 0) 35 | message("Could not determine processor count! Defaulting to 1.") 36 | set(CPU_COUNT 1) 37 | endif() 38 | 39 | if (CODE_COVERAGE) 40 | find_program(found_llvm_profdata llvm-profdata) 41 | find_program(found_llvm_cov llvm-cov) 42 | 43 | if (NOT found_llvm_profdata) 44 | message(WARNING "llvm-profdata not found! Is required for code coverage, disabling.") 45 | set(CODE_COVERAGE OFF) 46 | endif() 47 | 48 | if (NOT found_llvm_cov) 49 | message(WARNING "llvm-cov not found! Is required for code coverage, disabling.") 50 | set(CODE_COVERAGE OFF) 51 | endif() 52 | 53 | if (CODE_COVERAGE) 54 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping") 55 | endif() 56 | endif() 57 | 58 | if (ADDRESS_SANITIZER) 59 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls") 60 | set(CMAKE_BUILD_TYPE Debug) 61 | endif() 62 | if (THREAD_SANITIZER) 63 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") 64 | set(CMAKE_BUILD_TYPE Debug) 65 | endif() 66 | if (UNDEFINED_SANITIZER) 67 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") 68 | set(CMAKE_BUILD_TYPE Debug) 69 | endif() 70 | 71 | if (STATIC_ANALYZER) 72 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 73 | find_program(found_scan_build scan-build) 74 | if (NOT found_scan_build) 75 | message(WARNING "scan-build not found! Is required for static analysis, disabling.") 76 | set(STATIC_ANALYZER OFF) 77 | else() 78 | set(CMAKE_BUILD_TYPE Debug) 79 | endif() 80 | elseif ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 81 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fanalyzer") 82 | set(CMAKE_BUILD_TYPE Debug) 83 | endif() 84 | endif() 85 | 86 | # Names 87 | set(testName tests) 88 | 89 | include(CTest) 90 | enable_testing() 91 | add_subdirectory(tests) 92 | 93 | add_subdirectory(examples) 94 | 95 | # Requires llvm/clang v4+! 96 | # Setup: cmake -G -DCODE_COVERAGE=ON ../../ 97 | if (CODE_COVERAGE) 98 | add_custom_target( 99 | codecov 100 | 101 | rm -fr report.dir \; LLVM_PROFILE_FILE=tests.profraw $ >/dev/null && llvm-profdata merge -sparse tests.profraw -o tests.profdata && llvm-cov show $ -instr-profile=tests.profdata -format html -o report.dir -Xdemangler c++filt -Xdemangler -n -show-line-counts-or-regions && llvm-cov report $ -instr-profile=tests.profdata -Xdemangler c++filt -Xdemangler -n -use-color && echo '============================\\nReport at: report.dir/index.html\\n============================' 102 | 103 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 104 | COMMENT "Generating test code coverage report" 105 | DEPENDS ${testName} 106 | USES_TERMINAL 107 | ) 108 | endif() 109 | 110 | # Setup: scan-build cmake -G -DSTATIC_ANALYZER=ON ../../ 111 | if (STATIC_ANALYZER AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 112 | add_custom_target( 113 | sa 114 | 115 | scan-build -v -V -k cmake --build . 116 | 117 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 118 | COMMENT "Doing static analysis" 119 | USES_TERMINAL 120 | ) 121 | endif() 122 | 123 | # cppcheck can be cloned and compiled: git clone git@github.com:danmar/cppcheck.git 124 | # Remember to compile using CFGDIR=absolute-path-to-cfg-folder and HAVE_RULES=yes! 125 | find_program(found_cppcheck cppcheck) 126 | if (found_cppcheck) 127 | add_custom_target( 128 | cppcheck 129 | 130 | # unusedFunction can't be used with -j for some reason. 131 | cppcheck --enable=all -j ${CPU_COUNT} --std=c++20 --language=c++ --inconclusive 132 | --project=${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json --xml 2> cppcheck.xml && 133 | python3 ${CMAKE_SOURCE_DIR}/scripts/cppcheck-htmlreport.py --file=cppcheck.xml --report-dir=cppcheck 134 | 135 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 136 | COMMENT "Running cppcheck" 137 | USES_TERMINAL 138 | ) 139 | endif() 140 | 141 | find_program(found_clang_tidy clang-tidy) 142 | if (found_clang_tidy) 143 | add_custom_target( 144 | clang-tidy 145 | 146 | clang-tidy -p ${CMAKE_CURRENT_BINARY_DIR} sigs.h 147 | 148 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 149 | COMMENT "Checking with clang-tidy" 150 | USES_TERMINAL 151 | ) 152 | 153 | add_custom_target( 154 | clang-tidy-fix 155 | 156 | clang-tidy -p ${CMAKE_CURRENT_BINARY_DIR} --fix sigs.h 157 | 158 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 159 | COMMENT "Fixing with clang-tidy" 160 | USES_TERMINAL 161 | ) 162 | endif() 163 | 164 | message(STATUS "--------------------------------------------------") 165 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 166 | 167 | if (APPLE) 168 | message(STATUS "macOS deployent SDK: ${CMAKE_OSX_DEPLOYMENT_TARGET}") 169 | endif() 170 | 171 | message(STATUS "Compiler: ${CMAKE_CXX_COMPILER} (${CMAKE_CXX_COMPILER_ID})") 172 | 173 | if (USE_CCACHE) 174 | message(STATUS "CCache: ${CCACHE} (using to speed up compile + link)") 175 | else() 176 | message(STATUS "CCache: OFF") 177 | endif() 178 | 179 | message(STATUS "Detected processor count: ${CPU_COUNT}") 180 | 181 | if (found_cppcheck) 182 | message(STATUS "cppcheck target: enabled") 183 | else() 184 | message(STATUS "cppcheck target: disabled (cppcheck not found)") 185 | endif() 186 | 187 | if (found_clang_tidy) 188 | message(STATUS "clang-tidy targets: clang-tidy, clang-tidy-fix") 189 | else() 190 | message(STATUS "clang-tidy targets: disabled (clang-tidy not found)") 191 | endif() 192 | 193 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") 194 | if (STATIC_ANALYZER) 195 | message(STATUS "Static analyzer: ${STATIC_ANALYZER} (-fanalyzer)") 196 | else() 197 | message(STATUS "Static analyzer: ${STATIC_ANALYZER}") 198 | endif() 199 | endif() 200 | 201 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 202 | if (CODE_COVERAGE) 203 | message(STATUS "Code coverage: ${CODE_COVERAGE} (target: codecov)") 204 | else() 205 | message(STATUS "Code coverage: ${CODE_COVERAGE}") 206 | endif() 207 | 208 | if (STATIC_ANALYZER) 209 | message(STATUS "Static analyzer: ${STATIC_ANALYZER} (target: sa)") 210 | else() 211 | message(STATUS "Static analyzer: ${STATIC_ANALYZER}") 212 | endif() 213 | 214 | message(STATUS "Sanitizers:") 215 | message(STATUS " Address: ${ADDRESS_SANITIZER}") 216 | message(STATUS " Thread: ${THREAD_SANITIZER}") 217 | message(STATUS " Undefined: ${UNDEFINED_SANITIZER}") 218 | if ((ADDRESS_SANITIZER AND THREAD_SANITIZER) OR (ADDRESS_SANITIZER AND UNDEFINED_SANITIZER) OR 219 | (THREAD_SANITIZER AND UNDEFINED_SANITIZER)) 220 | message(FATAL_ERROR "Sanitizers cannot be mixed! Only use one at a time.") 221 | endif() 222 | 223 | if (EVERY_WARNING) 224 | message(STATUS "-Weverything: ON") 225 | else() 226 | message(STATUS "-Weverything: OFF") 227 | endif() 228 | endif() 229 | 230 | message(STATUS "--------------------------------------------------") 231 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/gtest-type-util.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. 2 | // All Rights Reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Type utilities needed for implementing typed and type-parameterized 31 | // tests. 32 | 33 | // IWYU pragma: private, include "gtest/gtest.h" 34 | // IWYU pragma: friend gtest/.* 35 | // IWYU pragma: friend gmock/.* 36 | 37 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ 38 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include "gtest/internal/gtest-port.h" 45 | 46 | // #ifdef __GNUC__ is too general here. It is possible to use gcc without using 47 | // libstdc++ (which is where cxxabi.h comes from). 48 | #if GTEST_HAS_CXXABI_H_ 49 | #include 50 | #elif defined(__HP_aCC) 51 | #include 52 | #endif // GTEST_HASH_CXXABI_H_ 53 | 54 | namespace testing { 55 | namespace internal { 56 | 57 | // Canonicalizes a given name with respect to the Standard C++ Library. 58 | // This handles removing the inline namespace within `std` that is 59 | // used by various standard libraries (e.g., `std::__1`). Names outside 60 | // of namespace std are returned unmodified. 61 | inline std::string CanonicalizeForStdLibVersioning(std::string s) { 62 | static const char prefix[] = "std::__"; 63 | if (s.compare(0, strlen(prefix), prefix) == 0) { 64 | std::string::size_type end = s.find("::", strlen(prefix)); 65 | if (end != s.npos) { 66 | // Erase everything between the initial `std` and the second `::`. 67 | s.erase(strlen("std"), end - strlen("std")); 68 | } 69 | } 70 | 71 | // Strip redundant spaces in typename to match MSVC 72 | // For example, std::pair -> std::pair 73 | static const char to_search[] = ", "; 74 | const char replace_char = ','; 75 | size_t pos = 0; 76 | while (true) { 77 | // Get the next occurrence from the current position 78 | pos = s.find(to_search, pos); 79 | if (pos == std::string::npos) { 80 | break; 81 | } 82 | // Replace this occurrence of substring 83 | s.replace(pos, strlen(to_search), 1, replace_char); 84 | ++pos; 85 | } 86 | return s; 87 | } 88 | 89 | #if GTEST_HAS_RTTI 90 | // GetTypeName(const std::type_info&) returns a human-readable name of type T. 91 | inline std::string GetTypeName(const std::type_info& type) { 92 | const char* const name = type.name(); 93 | #if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) 94 | int status = 0; 95 | // gcc's implementation of typeid(T).name() mangles the type name, 96 | // so we have to demangle it. 97 | #if GTEST_HAS_CXXABI_H_ 98 | using abi::__cxa_demangle; 99 | #endif // GTEST_HAS_CXXABI_H_ 100 | char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); 101 | const std::string name_str(status == 0 ? readable_name : name); 102 | free(readable_name); 103 | return CanonicalizeForStdLibVersioning(name_str); 104 | #elif defined(_MSC_VER) 105 | // Strip struct and class due to differences between 106 | // MSVC and other compilers. std::pair is printed as 107 | // "struct std::pair" when using MSVC vs "std::pair" with 108 | // other compilers. 109 | std::string s = name; 110 | // Only strip the leading "struct " and "class ", so uses rfind == 0 to 111 | // ensure that 112 | if (s.rfind("struct ", 0) == 0) { 113 | s = s.substr(strlen("struct ")); 114 | } else if (s.rfind("class ", 0) == 0) { 115 | s = s.substr(strlen("class ")); 116 | } 117 | return s; 118 | #else 119 | return name; 120 | #endif // GTEST_HAS_CXXABI_H_ || __HP_aCC 121 | } 122 | #endif // GTEST_HAS_RTTI 123 | 124 | // GetTypeName() returns a human-readable name of type T if and only if 125 | // RTTI is enabled, otherwise it returns a dummy type name. 126 | // NB: This function is also used in Google Mock, so don't move it inside of 127 | // the typed-test-only section below. 128 | template 129 | std::string GetTypeName() { 130 | #if GTEST_HAS_RTTI 131 | return GetTypeName(typeid(T)); 132 | #else 133 | return ""; 134 | #endif // GTEST_HAS_RTTI 135 | } 136 | 137 | // A unique type indicating an empty node 138 | struct None {}; 139 | 140 | #define GTEST_TEMPLATE_ \ 141 | template \ 142 | class 143 | 144 | // The template "selector" struct TemplateSel is used to 145 | // represent Tmpl, which must be a class template with one type 146 | // parameter, as a type. TemplateSel::Bind::type is defined 147 | // as the type Tmpl. This allows us to actually instantiate the 148 | // template "selected" by TemplateSel. 149 | // 150 | // This trick is necessary for simulating typedef for class templates, 151 | // which C++ doesn't support directly. 152 | template 153 | struct TemplateSel { 154 | template 155 | struct Bind { 156 | typedef Tmpl type; 157 | }; 158 | }; 159 | 160 | #define GTEST_BIND_(TmplSel, T) TmplSel::template Bind::type 161 | 162 | template 163 | struct Templates { 164 | using Head = TemplateSel; 165 | using Tail = Templates; 166 | }; 167 | 168 | template 169 | struct Templates { 170 | using Head = TemplateSel; 171 | using Tail = None; 172 | }; 173 | 174 | // Tuple-like type lists 175 | template 176 | struct Types { 177 | using Head = Head_; 178 | using Tail = Types; 179 | }; 180 | 181 | template 182 | struct Types { 183 | using Head = Head_; 184 | using Tail = None; 185 | }; 186 | 187 | // Helper metafunctions to tell apart a single type from types 188 | // generated by ::testing::Types 189 | template 190 | struct ProxyTypeList { 191 | using type = Types; 192 | }; 193 | 194 | template 195 | struct is_proxy_type_list : std::false_type {}; 196 | 197 | template 198 | struct is_proxy_type_list> : std::true_type {}; 199 | 200 | // Generator which conditionally creates type lists. 201 | // It recognizes if a requested type list should be created 202 | // and prevents creating a new type list nested within another one. 203 | template 204 | struct GenerateTypeList { 205 | private: 206 | using proxy = typename std::conditional::value, T, 207 | ProxyTypeList>::type; 208 | 209 | public: 210 | using type = typename proxy::type; 211 | }; 212 | 213 | } // namespace internal 214 | 215 | template 216 | using Types = internal::ProxyTypeList; 217 | 218 | } // namespace testing 219 | 220 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Test](https://github.com/netromdk/sigs/workflows/Test/badge.svg?branch=master)](https://github.com/netromdk/sigs/actions) 2 | [![Clang Sanitizers](https://github.com/netromdk/sigs/workflows/Clang%20Sanitizers/badge.svg?branch=master)](https://github.com/netromdk/sigs/actions) 3 | [![CodeQL](https://github.com/netromdk/sigs/workflows/CodeQL/badge.svg?branch=master)](https://github.com/netromdk/sigs/security/code-scanning) 4 | 5 | # sigs 6 | Simple thread-safe signal/slot C++20 library, which is templated and include-only. No linking required. Just include the header file "*sigs.h*" (C++17 version in "*sigs17.h*"). 7 | 8 | In all its simplicity, the class `sigs::Signal` implements a signal that can be triggered when some event occurs. To receive the signal slots can be connected to it. A slot can be any callable type: lambda, functor, function, or member function. Slots can be disconnected when not needed anymore. 9 | 10 | A signal is triggered by invoking its `operator()()` with an optional amount of arguments to be forwarded to each of the connected slots' invocations. But they must conform with the parameter types of `sigs::Signal::SlotType`, which reflects the first template argument given when instantiating a `sigs::Signal`. 11 | 12 | Table of contents 13 | ================= 14 | 15 | * [Examples](#examples) 16 | * [Ambiguous types](#ambiguous-types) 17 | * [Return values](#return-values) 18 | * [Signal interface](#signal-interface) 19 | * [Blocking signals and slots](#blocking-signals-and-slots) 20 | * [Customizing lock and mutex types](#customizing-lock-and-mutex-types) 21 | 22 | Examples 23 | ======== 24 | The most simple use case is having a `void()` invoked: 25 | 26 | ```c++ 27 | sigs::Signal s; 28 | s.connect([]{ std::cout << "Hello, signals. I'm an invoked slot.\n"; }); 29 | s(); // Trigger it, which will call the function. 30 | ``` 31 | 32 | As mentioned above you can pass arbitrary arguments to the slots but the types will be enforced at compile-time. 33 | 34 | ```c++ 35 | sigs::Signal s; 36 | s.connect([](int n, const std::string &str) { 37 | std::cout << "I received " << n << " and " << str << std::endl; 38 | }); 39 | 40 | // Prints "I received 42 and I like lambdas!". 41 | s(42, "I like lambdas!"); 42 | 43 | // Error! "no known conversion from 'char const[5]' to 'int' for 1st argument". 44 | s("hmm?", "I like lambdas!"); 45 | ``` 46 | 47 | When connecting a slot the result is a `sigs::Connection`, and the connection can be disconnected by calling `sigs::Connection::disconnect()` or `sigs::Signal::disconnect(sigs::Connection)`. 48 | 49 | ```c++ 50 | sigs::Signal s; 51 | s.connect([]{ std::cout << "Hi"; }); 52 | auto conn = s.connect([]{ std::cout << " there!\n"; }); 53 | 54 | // Prints "Hi there!". 55 | s(); 56 | 57 | // Disconnect second slot. 58 | conn->disconnect(); 59 | 60 | // Or by using the signal: s.disconnect(conn); 61 | 62 | // Prints "Hi". 63 | s(); 64 | ``` 65 | 66 | Note that all slots can be disconnected by giving no arguments to `sigs::Signal::disconnect()`, or by calling `sigs::Signal::clear()`. 67 | 68 | Slots can be any callable type: lambda, functor, or function. Even member functions. 69 | 70 | ```c++ 71 | void func() { 72 | std::cout << "Called function\n"; 73 | } 74 | 75 | class Functor { 76 | public: 77 | void operator()() { 78 | std::cout << "Called functor\n"; 79 | } 80 | }; 81 | 82 | class Foo { 83 | public: 84 | void test() { 85 | std::cout << "Called member fuction\n"; 86 | } 87 | }; 88 | 89 | sigs::Signal s; 90 | s.connect(func); 91 | s.connect([]{ std::cout << "Called lambda\n"; }); 92 | s.connect(Functor()); 93 | 94 | Foo foo; 95 | s.connect(&foo, &Foo::test); 96 | 97 | s(); 98 | 99 | /* Prints: 100 | Called function 101 | Called lambda 102 | Called functor 103 | Called member funtion 104 | */ 105 | ``` 106 | 107 | Another useful feature is the ability to connect signals to signals. If a first signal is connected to a second signal, and the second signal is triggered, then all of the slots of the first signal are triggered as well - and with the same arguments. 108 | 109 | ```c++ 110 | sigs::Signal s1; 111 | s1.connect([]{ std::cout << "Hello 1 from s1\n"; }); 112 | s1.connect([]{ std::cout << "Hello 2 from s1\n"; }); 113 | 114 | decltype(s1) s2; 115 | s2.connect(s1); 116 | 117 | s2(); 118 | 119 | /* Prints: 120 | Hello 1 from s1 121 | Hello 2 from s1 122 | */ 123 | ``` 124 | 125 | A signal can be disconnected by using `sigs::Signal::disconnect(sigs::Signal&)`, or the regular `sigs::Connection::disconnect()`. 126 | 127 | Ambiguous types 128 | =============== 129 | Sometimes there are several overloads for a given function and then it's not enough to just specify `&Class::functionName` because the compiler does not know which overload to choose. 130 | 131 | Consider the following code: 132 | 133 | ```c++ 134 | class Ambiguous { 135 | public: 136 | void foo(int i, int j) { std::cout << "Ambiguous::foo(int, int)\n"; } 137 | 138 | void foo(int i, float j) { std::cout << "Ambiguous::foo(int, float)\n"; } 139 | }; 140 | 141 | sigs::Signal s; 142 | 143 | Ambiguous amb; 144 | s.connect(&amb, &Ambiguous::foo); // <-- Will fail! 145 | ``` 146 | 147 | Instead we must use the `sigs::Use<>::overloadOf()` construct: 148 | 149 | ```c++ 150 | s.connect(&amb, sigs::Use::overloadOf(&Ambiguous::foo)); 151 | s(42, 48); 152 | 153 | /* Prints: 154 | Ambiguous::foo(int, int) 155 | */ 156 | ``` 157 | 158 | Without changing the signal we can also connect the second overload `foo(int, float)`: 159 | 160 | ```c++ 161 | // This one only works because int can be coerced into float. 162 | s.connect(&amb, sigs::Use::overloadOf(&Ambiguous::foo)); 163 | s(12, 34); 164 | 165 | /* Prints: 166 | Ambiguous::foo(int, int) 167 | Ambiguous::foo(int, float) 168 | */ 169 | ``` 170 | 171 | Return values 172 | ============= 173 | If slots have return values they can be gathered by triggering the signal with a function. But the argument type must be the same as the return type! 174 | 175 | The following example adds together the integers from each connected slot: 176 | ```c++ 177 | sigs::Signal s; 178 | s.connect([] { return 1; }); 179 | s.connect([] { return 2; }); 180 | s.connect([] { return 3; }); 181 | 182 | int sum = 0; 183 | s([&sum](int retVal) { sum += retVal; }); 184 | // sum is now = 1 + 2 + 3 = 6 185 | ``` 186 | 187 | Signal interface 188 | ================ 189 | When a signal is used in an abstraction one most often doesn't want it exposed directly as a public member since it destroys encapsulation. `sigs::Signal::interface()` can be used instead to only expose connect and disconnect methods of the signal - it is a `std::unique_ptr` wrapper instance. 190 | 191 | The example shows a button abstraction where actions can easily be added or removed while preserving the encapsulation of the signal: 192 | ```c++ 193 | class Button { 194 | public: 195 | void click() 196 | { 197 | clickSignal_(); 198 | } 199 | 200 | [[nodiscard]] auto clickSignal() 201 | { 202 | return clickSignal_.interface(); 203 | } 204 | 205 | private: 206 | sigs::Signal clickSignal_; 207 | }; 208 | 209 | int main() 210 | { 211 | Button btn; 212 | btn.clickSignal()->connect([] { std::cout << "direct fn" << std::endl; }); 213 | btn.clickSignal()->connect([] { std::cout << "direct fn 2" << std::endl; }); 214 | 215 | auto conn = btn.clickSignal()->connect([] { std::cout << "you won't see me" << std::endl; }); 216 | conn->disconnect(); 217 | 218 | btn.click(); 219 | return 0; 220 | } 221 | ``` 222 | 223 | Blocking signals and slots 224 | ========================== 225 | Sometimes it is necessary to block a signal, and any recursive signals, from triggering. That is achieved through `sigs::Signal::setBlocked(bool)` and `sigs::Signal::blocked()`: 226 | ```c++ 227 | sigs::Signal s; 228 | s.connect([] { /* .. */ }); 229 | s.connect([] { /* .. */ }); 230 | s.setBlocked(true); 231 | 232 | // No slots will be triggered since the signal is blocked. 233 | s(); 234 | ``` 235 | 236 | To make things simpler, the `sigs::SignalBlocker` class utilizes the RAII idiom to block/unblock via its own scoped lifetime: 237 | ```c++ 238 | sigs::Signal s; 239 | s.connect([] { /* .. */ }); 240 | s.connect([] { /* .. */ }); 241 | 242 | { 243 | sigs::SignalBlocker blocker(s); 244 | 245 | // No slots will be triggered since the signal is blocked. 246 | s(); 247 | } 248 | 249 | // All connected slots are triggered since the signal is no longer blocked. 250 | s(); 251 | ``` 252 | 253 | Customizing lock and mutex types 254 | ================================ 255 | 256 | The default signal type `sigs::Signal` is actually short for `sigs::BasicSignal` (with `sigs::BasicLock = std::lock_guard`). Thus the lock type is `std::lock_guard` and the mutex type is `std::mutex`. 257 | 258 | Custom lock and mutex types can be supplied by defining a new type, for instance: 259 | ```c++ 260 | template 261 | using MySignal = sigs::BasicSignal; 262 | ``` 263 | 264 | The required lock and mutex interfaces are as follows: 265 | ```c++ 266 | class Mutex { 267 | public: 268 | void lock(); 269 | void unlock(); 270 | }; 271 | 272 | template 273 | class Lock { 274 | public: 275 | using mutex_type = Mutex; 276 | 277 | explicit Lock(Mutex &); 278 | }; 279 | ``` 280 | 281 | The lock type is supposed to lock/unlock following the RAII idiom. 282 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/gtest-assertion-result.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This file implements the AssertionResult type. 33 | 34 | // IWYU pragma: private, include "gtest/gtest.h" 35 | // IWYU pragma: friend gtest/.* 36 | // IWYU pragma: friend gmock/.* 37 | 38 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_ 39 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "gtest/gtest-message.h" 47 | #include "gtest/internal/gtest-port.h" 48 | 49 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 50 | /* class A needs to have dll-interface to be used by clients of class B */) 51 | 52 | namespace testing { 53 | 54 | // A class for indicating whether an assertion was successful. When 55 | // the assertion wasn't successful, the AssertionResult object 56 | // remembers a non-empty message that describes how it failed. 57 | // 58 | // To create an instance of this class, use one of the factory functions 59 | // (AssertionSuccess() and AssertionFailure()). 60 | // 61 | // This class is useful for two purposes: 62 | // 1. Defining predicate functions to be used with Boolean test assertions 63 | // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts 64 | // 2. Defining predicate-format functions to be 65 | // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). 66 | // 67 | // For example, if you define IsEven predicate: 68 | // 69 | // testing::AssertionResult IsEven(int n) { 70 | // if ((n % 2) == 0) 71 | // return testing::AssertionSuccess(); 72 | // else 73 | // return testing::AssertionFailure() << n << " is odd"; 74 | // } 75 | // 76 | // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) 77 | // will print the message 78 | // 79 | // Value of: IsEven(Fib(5)) 80 | // Actual: false (5 is odd) 81 | // Expected: true 82 | // 83 | // instead of a more opaque 84 | // 85 | // Value of: IsEven(Fib(5)) 86 | // Actual: false 87 | // Expected: true 88 | // 89 | // in case IsEven is a simple Boolean predicate. 90 | // 91 | // If you expect your predicate to be reused and want to support informative 92 | // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up 93 | // about half as often as positive ones in our tests), supply messages for 94 | // both success and failure cases: 95 | // 96 | // testing::AssertionResult IsEven(int n) { 97 | // if ((n % 2) == 0) 98 | // return testing::AssertionSuccess() << n << " is even"; 99 | // else 100 | // return testing::AssertionFailure() << n << " is odd"; 101 | // } 102 | // 103 | // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print 104 | // 105 | // Value of: IsEven(Fib(6)) 106 | // Actual: true (8 is even) 107 | // Expected: false 108 | // 109 | // NB: Predicates that support negative Boolean assertions have reduced 110 | // performance in positive ones so be careful not to use them in tests 111 | // that have lots (tens of thousands) of positive Boolean assertions. 112 | // 113 | // To use this class with EXPECT_PRED_FORMAT assertions such as: 114 | // 115 | // // Verifies that Foo() returns an even number. 116 | // EXPECT_PRED_FORMAT1(IsEven, Foo()); 117 | // 118 | // you need to define: 119 | // 120 | // testing::AssertionResult IsEven(const char* expr, int n) { 121 | // if ((n % 2) == 0) 122 | // return testing::AssertionSuccess(); 123 | // else 124 | // return testing::AssertionFailure() 125 | // << "Expected: " << expr << " is even\n Actual: it's " << n; 126 | // } 127 | // 128 | // If Foo() returns 5, you will see the following message: 129 | // 130 | // Expected: Foo() is even 131 | // Actual: it's 5 132 | // 133 | 134 | // Returned AssertionResult objects may not be ignored. 135 | // Note: Disabled for SWIG as it doesn't parse attributes correctly. 136 | #if !defined(SWIG) 137 | class [[nodiscard]] AssertionResult; 138 | #endif // !SWIG 139 | 140 | class GTEST_API_ AssertionResult { 141 | public: 142 | // Copy constructor. 143 | // Used in EXPECT_TRUE/FALSE(assertion_result). 144 | AssertionResult(const AssertionResult& other); 145 | 146 | // C4800 is a level 3 warning in Visual Studio 2015 and earlier. 147 | // This warning is not emitted in Visual Studio 2017. 148 | // This warning is off by default starting in Visual Studio 2019 but can be 149 | // enabled with command-line options. 150 | #if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) 151 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) 152 | #endif 153 | 154 | // Used in the EXPECT_TRUE/FALSE(bool_expression). 155 | // 156 | // T must be contextually convertible to bool. 157 | // 158 | // The second parameter prevents this overload from being considered if 159 | // the argument is implicitly convertible to AssertionResult. In that case 160 | // we want AssertionResult's copy constructor to be used. 161 | template 162 | explicit AssertionResult( 163 | const T& success, 164 | typename std::enable_if< 165 | !std::is_convertible::value>::type* 166 | /*enabler*/ 167 | = nullptr) 168 | : success_(success) {} 169 | 170 | #if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) 171 | GTEST_DISABLE_MSC_WARNINGS_POP_() 172 | #endif 173 | 174 | // Assignment operator. 175 | AssertionResult& operator=(AssertionResult other) { 176 | swap(other); 177 | return *this; 178 | } 179 | 180 | // Returns true if and only if the assertion succeeded. 181 | operator bool() const { return success_; } // NOLINT 182 | 183 | // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. 184 | AssertionResult operator!() const; 185 | 186 | // Returns the text streamed into this AssertionResult. Test assertions 187 | // use it when they fail (i.e., the predicate's outcome doesn't match the 188 | // assertion's expectation). When nothing has been streamed into the 189 | // object, returns an empty string. 190 | const char* message() const { 191 | return message_ != nullptr ? message_->c_str() : ""; 192 | } 193 | // Deprecated; please use message() instead. 194 | const char* failure_message() const { return message(); } 195 | 196 | // Streams a custom failure message into this object. 197 | template 198 | AssertionResult& operator<<(const T& value) { 199 | AppendMessage(Message() << value); 200 | return *this; 201 | } 202 | 203 | // Allows streaming basic output manipulators such as endl or flush into 204 | // this object. 205 | AssertionResult& operator<<( 206 | ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { 207 | AppendMessage(Message() << basic_manipulator); 208 | return *this; 209 | } 210 | 211 | private: 212 | // Appends the contents of message to message_. 213 | void AppendMessage(const Message& a_message) { 214 | if (message_ == nullptr) message_ = ::std::make_unique<::std::string>(); 215 | message_->append(a_message.GetString().c_str()); 216 | } 217 | 218 | // Swap the contents of this AssertionResult with other. 219 | void swap(AssertionResult& other); 220 | 221 | // Stores result of the assertion predicate. 222 | bool success_; 223 | // Stores the message describing the condition in case the expectation 224 | // construct is not satisfied with the predicate's outcome. 225 | // Referenced via a pointer to avoid taking too much stack frame space 226 | // with test assertions. 227 | std::unique_ptr< ::std::string> message_; 228 | }; 229 | 230 | // Makes a successful assertion result. 231 | GTEST_API_ AssertionResult AssertionSuccess(); 232 | 233 | // Makes a failed assertion result. 234 | GTEST_API_ AssertionResult AssertionFailure(); 235 | 236 | // Makes a failed assertion result with the given failure message. 237 | // Deprecated; use AssertionFailure() << msg. 238 | GTEST_API_ AssertionResult AssertionFailure(const Message& msg); 239 | 240 | } // namespace testing 241 | 242 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 243 | 244 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_ 245 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/gtest-message.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This header file defines the Message class. 33 | // 34 | // IMPORTANT NOTE: Due to limitation of the C++ language, we have to 35 | // leave some internal implementation details in this header file. 36 | // They are clearly marked by comments like this: 37 | // 38 | // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. 39 | // 40 | // Such code is NOT meant to be used by a user directly, and is subject 41 | // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user 42 | // program! 43 | 44 | // IWYU pragma: private, include "gtest/gtest.h" 45 | // IWYU pragma: friend gtest/.* 46 | // IWYU pragma: friend gmock/.* 47 | 48 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ 49 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include "gtest/internal/gtest-port.h" 58 | 59 | #ifdef GTEST_HAS_ABSL 60 | #include 61 | 62 | #include "absl/strings/has_absl_stringify.h" 63 | #include "absl/strings/str_cat.h" 64 | #endif // GTEST_HAS_ABSL 65 | 66 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 67 | /* class A needs to have dll-interface to be used by clients of class B */) 68 | 69 | // Ensures that there is at least one operator<< in the global namespace. 70 | // See Message& operator<<(...) below for why. 71 | void operator<<(const testing::internal::Secret&, int); 72 | 73 | namespace testing { 74 | 75 | // The Message class works like an ostream repeater. 76 | // 77 | // Typical usage: 78 | // 79 | // 1. You stream a bunch of values to a Message object. 80 | // It will remember the text in a stringstream. 81 | // 2. Then you stream the Message object to an ostream. 82 | // This causes the text in the Message to be streamed 83 | // to the ostream. 84 | // 85 | // For example; 86 | // 87 | // testing::Message foo; 88 | // foo << 1 << " != " << 2; 89 | // std::cout << foo; 90 | // 91 | // will print "1 != 2". 92 | // 93 | // Message is not intended to be inherited from. In particular, its 94 | // destructor is not virtual. 95 | // 96 | // Note that stringstream behaves differently in gcc and in MSVC. You 97 | // can stream a NULL char pointer to it in the former, but not in the 98 | // latter (it causes an access violation if you do). The Message 99 | // class hides this difference by treating a NULL char pointer as 100 | // "(null)". 101 | class GTEST_API_ Message { 102 | private: 103 | // The type of basic IO manipulators (endl, ends, and flush) for 104 | // narrow streams. 105 | typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); 106 | 107 | public: 108 | // Constructs an empty Message. 109 | Message(); 110 | 111 | // Copy constructor. 112 | Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT 113 | *ss_ << msg.GetString(); 114 | } 115 | 116 | // Constructs a Message from a C-string. 117 | explicit Message(const char* str) : ss_(new ::std::stringstream) { 118 | *ss_ << str; 119 | } 120 | 121 | // Streams a non-pointer value to this object. If building a version of 122 | // GoogleTest with ABSL, this overload is only enabled if the value does not 123 | // have an AbslStringify definition. 124 | template < 125 | typename T 126 | #ifdef GTEST_HAS_ABSL 127 | , 128 | typename std::enable_if::value, // NOLINT 129 | int>::type = 0 130 | #endif // GTEST_HAS_ABSL 131 | > 132 | inline Message& operator<<(const T& val) { 133 | // Some libraries overload << for STL containers. These 134 | // overloads are defined in the global namespace instead of ::std. 135 | // 136 | // C++'s symbol lookup rule (i.e. Koenig lookup) says that these 137 | // overloads are visible in either the std namespace or the global 138 | // namespace, but not other namespaces, including the testing 139 | // namespace which Google Test's Message class is in. 140 | // 141 | // To allow STL containers (and other types that has a << operator 142 | // defined in the global namespace) to be used in Google Test 143 | // assertions, testing::Message must access the custom << operator 144 | // from the global namespace. With this using declaration, 145 | // overloads of << defined in the global namespace and those 146 | // visible via Koenig lookup are both exposed in this function. 147 | using ::operator<<; 148 | *ss_ << val; 149 | return *this; 150 | } 151 | 152 | #ifdef GTEST_HAS_ABSL 153 | // Streams a non-pointer value with an AbslStringify definition to this 154 | // object. 155 | template ::value, // NOLINT 157 | int>::type = 0> 158 | inline Message& operator<<(const T& val) { 159 | // ::operator<< is needed here for a similar reason as with the non-Abseil 160 | // version above 161 | using ::operator<<; 162 | *ss_ << absl::StrCat(val); 163 | return *this; 164 | } 165 | #endif // GTEST_HAS_ABSL 166 | 167 | // Streams a pointer value to this object. 168 | // 169 | // This function is an overload of the previous one. When you 170 | // stream a pointer to a Message, this definition will be used as it 171 | // is more specialized. (The C++ Standard, section 172 | // [temp.func.order].) If you stream a non-pointer, then the 173 | // previous definition will be used. 174 | // 175 | // The reason for this overload is that streaming a NULL pointer to 176 | // ostream is undefined behavior. Depending on the compiler, you 177 | // may get "0", "(nil)", "(null)", or an access violation. To 178 | // ensure consistent result across compilers, we always treat NULL 179 | // as "(null)". 180 | template 181 | inline Message& operator<<(T* const& pointer) { // NOLINT 182 | if (pointer == nullptr) { 183 | *ss_ << "(null)"; 184 | } else { 185 | *ss_ << pointer; 186 | } 187 | return *this; 188 | } 189 | 190 | // Since the basic IO manipulators are overloaded for both narrow 191 | // and wide streams, we have to provide this specialized definition 192 | // of operator <<, even though its body is the same as the 193 | // templatized version above. Without this definition, streaming 194 | // endl or other basic IO manipulators to Message will confuse the 195 | // compiler. 196 | Message& operator<<(BasicNarrowIoManip val) { 197 | *ss_ << val; 198 | return *this; 199 | } 200 | 201 | // Instead of 1/0, we want to see true/false for bool values. 202 | Message& operator<<(bool b) { return *this << (b ? "true" : "false"); } 203 | 204 | // These two overloads allow streaming a wide C string to a Message 205 | // using the UTF-8 encoding. 206 | Message& operator<<(const wchar_t* wide_c_str); 207 | Message& operator<<(wchar_t* wide_c_str); 208 | 209 | #if GTEST_HAS_STD_WSTRING 210 | // Converts the given wide string to a narrow string using the UTF-8 211 | // encoding, and streams the result to this Message object. 212 | Message& operator<<(const ::std::wstring& wstr); 213 | #endif // GTEST_HAS_STD_WSTRING 214 | 215 | // Gets the text streamed to this object so far as an std::string. 216 | // Each '\0' character in the buffer is replaced with "\\0". 217 | // 218 | // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. 219 | std::string GetString() const; 220 | 221 | private: 222 | // We'll hold the text streamed to this object here. 223 | const std::unique_ptr< ::std::stringstream> ss_; 224 | 225 | // We declare (but don't implement) this to prevent the compiler 226 | // from implementing the assignment operator. 227 | void operator=(const Message&); 228 | }; 229 | 230 | // Streams a Message to an ostream. 231 | inline std::ostream& operator<<(std::ostream& os, const Message& sb) { 232 | return os << sb.GetString(); 233 | } 234 | 235 | namespace internal { 236 | 237 | // Converts a streamable value to an std::string. A NULL pointer is 238 | // converted to "(null)". When the input value is a ::string, 239 | // ::std::string, ::wstring, or ::std::wstring object, each NUL 240 | // character in it is replaced with "\\0". 241 | template 242 | std::string StreamableToString(const T& streamable) { 243 | return (Message() << streamable).GetString(); 244 | } 245 | 246 | } // namespace internal 247 | } // namespace testing 248 | 249 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 250 | 251 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ 252 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/gtest-filepath.h: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Google Test filepath utilities 31 | // 32 | // This header file declares classes and functions used internally by 33 | // Google Test. They are subject to change without notice. 34 | // 35 | // This file is #included in gtest/internal/gtest-internal.h. 36 | // Do not include this header file separately! 37 | 38 | // IWYU pragma: private, include "gtest/gtest.h" 39 | // IWYU pragma: friend gtest/.* 40 | // IWYU pragma: friend gmock/.* 41 | 42 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ 43 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ 44 | 45 | #include 46 | #include 47 | 48 | #include "gtest/internal/gtest-port.h" 49 | #include "gtest/internal/gtest-string.h" 50 | 51 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 52 | /* class A needs to have dll-interface to be used by clients of class B */) 53 | 54 | #if GTEST_HAS_FILE_SYSTEM 55 | 56 | namespace testing { 57 | namespace internal { 58 | 59 | // FilePath - a class for file and directory pathname manipulation which 60 | // handles platform-specific conventions (like the pathname separator). 61 | // Used for helper functions for naming files in a directory for xml output. 62 | // Except for Set methods, all methods are const or static, which provides an 63 | // "immutable value object" -- useful for peace of mind. 64 | // A FilePath with a value ending in a path separator ("like/this/") represents 65 | // a directory, otherwise it is assumed to represent a file. In either case, 66 | // it may or may not represent an actual file or directory in the file system. 67 | // Names are NOT checked for syntax correctness -- no checking for illegal 68 | // characters, malformed paths, etc. 69 | 70 | class GTEST_API_ FilePath { 71 | public: 72 | FilePath() : pathname_("") {} 73 | FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) {} 74 | FilePath(FilePath&& rhs) noexcept : pathname_(std::move(rhs.pathname_)) {} 75 | 76 | explicit FilePath(std::string pathname) : pathname_(std::move(pathname)) { 77 | Normalize(); 78 | } 79 | 80 | FilePath& operator=(const FilePath& rhs) { 81 | Set(rhs); 82 | return *this; 83 | } 84 | FilePath& operator=(FilePath&& rhs) noexcept { 85 | pathname_ = std::move(rhs.pathname_); 86 | return *this; 87 | } 88 | 89 | void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } 90 | 91 | const std::string& string() const { return pathname_; } 92 | const char* c_str() const { return pathname_.c_str(); } 93 | 94 | // Returns the current working directory, or "" if unsuccessful. 95 | static FilePath GetCurrentDir(); 96 | 97 | // Given directory = "dir", base_name = "test", number = 0, 98 | // extension = "xml", returns "dir/test.xml". If number is greater 99 | // than zero (e.g., 12), returns "dir/test_12.xml". 100 | // On Windows platform, uses \ as the separator rather than /. 101 | static FilePath MakeFileName(const FilePath& directory, 102 | const FilePath& base_name, int number, 103 | const char* extension); 104 | 105 | // Given directory = "dir", relative_path = "test.xml", 106 | // returns "dir/test.xml". 107 | // On Windows, uses \ as the separator rather than /. 108 | static FilePath ConcatPaths(const FilePath& directory, 109 | const FilePath& relative_path); 110 | 111 | // Returns a pathname for a file that does not currently exist. The pathname 112 | // will be directory/base_name.extension or 113 | // directory/base_name_.extension if directory/base_name.extension 114 | // already exists. The number will be incremented until a pathname is found 115 | // that does not already exist. 116 | // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. 117 | // There could be a race condition if two or more processes are calling this 118 | // function at the same time -- they could both pick the same filename. 119 | static FilePath GenerateUniqueFileName(const FilePath& directory, 120 | const FilePath& base_name, 121 | const char* extension); 122 | 123 | // Returns true if and only if the path is "". 124 | bool IsEmpty() const { return pathname_.empty(); } 125 | 126 | // If input name has a trailing separator character, removes it and returns 127 | // the name, otherwise return the name string unmodified. 128 | // On Windows platform, uses \ as the separator, other platforms use /. 129 | FilePath RemoveTrailingPathSeparator() const; 130 | 131 | // Returns a copy of the FilePath with the directory part removed. 132 | // Example: FilePath("path/to/file").RemoveDirectoryName() returns 133 | // FilePath("file"). If there is no directory part ("just_a_file"), it returns 134 | // the FilePath unmodified. If there is no file part ("just_a_dir/") it 135 | // returns an empty FilePath (""). 136 | // On Windows platform, '\' is the path separator, otherwise it is '/'. 137 | FilePath RemoveDirectoryName() const; 138 | 139 | // RemoveFileName returns the directory path with the filename removed. 140 | // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". 141 | // If the FilePath is "a_file" or "/a_file", RemoveFileName returns 142 | // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does 143 | // not have a file, like "just/a/dir/", it returns the FilePath unmodified. 144 | // On Windows platform, '\' is the path separator, otherwise it is '/'. 145 | FilePath RemoveFileName() const; 146 | 147 | // Returns a copy of the FilePath with the case-insensitive extension removed. 148 | // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns 149 | // FilePath("dir/file"). If a case-insensitive extension is not 150 | // found, returns a copy of the original FilePath. 151 | FilePath RemoveExtension(const char* extension) const; 152 | 153 | // Creates directories so that path exists. Returns true if successful or if 154 | // the directories already exist; returns false if unable to create 155 | // directories for any reason. Will also return false if the FilePath does 156 | // not represent a directory (that is, it doesn't end with a path separator). 157 | bool CreateDirectoriesRecursively() const; 158 | 159 | // Create the directory so that path exists. Returns true if successful or 160 | // if the directory already exists; returns false if unable to create the 161 | // directory for any reason, including if the parent directory does not 162 | // exist. Not named "CreateDirectory" because that's a macro on Windows. 163 | bool CreateFolder() const; 164 | 165 | // Returns true if FilePath describes something in the file-system, 166 | // either a file, directory, or whatever, and that something exists. 167 | bool FileOrDirectoryExists() const; 168 | 169 | // Returns true if pathname describes a directory in the file-system 170 | // that exists. 171 | bool DirectoryExists() const; 172 | 173 | // Returns true if FilePath ends with a path separator, which indicates that 174 | // it is intended to represent a directory. Returns false otherwise. 175 | // This does NOT check that a directory (or file) actually exists. 176 | bool IsDirectory() const; 177 | 178 | // Returns true if pathname describes a root directory. (Windows has one 179 | // root directory per disk drive.) 180 | bool IsRootDirectory() const; 181 | 182 | // Returns true if pathname describes an absolute path. 183 | bool IsAbsolutePath() const; 184 | 185 | private: 186 | // Replaces multiple consecutive separators with a single separator. 187 | // For example, "bar///foo" becomes "bar/foo". Does not eliminate other 188 | // redundancies that might be in a pathname involving "." or "..". 189 | // 190 | // A pathname with multiple consecutive separators may occur either through 191 | // user error or as a result of some scripts or APIs that generate a pathname 192 | // with a trailing separator. On other platforms the same API or script 193 | // may NOT generate a pathname with a trailing "/". Then elsewhere that 194 | // pathname may have another "/" and pathname components added to it, 195 | // without checking for the separator already being there. 196 | // The script language and operating system may allow paths like "foo//bar" 197 | // but some of the functions in FilePath will not handle that correctly. In 198 | // particular, RemoveTrailingPathSeparator() only removes one separator, and 199 | // it is called in CreateDirectoriesRecursively() assuming that it will change 200 | // a pathname from directory syntax (trailing separator) to filename syntax. 201 | // 202 | // On Windows this method also replaces the alternate path separator '/' with 203 | // the primary path separator '\\', so that for example "bar\\/\\foo" becomes 204 | // "bar\\foo". 205 | 206 | void Normalize(); 207 | 208 | // Returns a pointer to the last occurrence of a valid path separator in 209 | // the FilePath. On Windows, for example, both '/' and '\' are valid path 210 | // separators. Returns NULL if no path separator was found. 211 | const char* FindLastPathSeparator() const; 212 | 213 | // Returns the length of the path root, including the directory separator at 214 | // the end of the prefix. Returns zero by definition if the path is relative. 215 | // Examples: 216 | // - [Windows] "..\Sibling" => 0 217 | // - [Windows] "\Windows" => 1 218 | // - [Windows] "C:/Windows\Notepad.exe" => 3 219 | // - [Windows] "\\Host\Share\C$/Windows" => 13 220 | // - [UNIX] "/bin" => 1 221 | size_t CalculateRootLength() const; 222 | 223 | std::string pathname_; 224 | }; // class FilePath 225 | 226 | } // namespace internal 227 | } // namespace testing 228 | 229 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 230 | 231 | #endif // GTEST_HAS_FILE_SYSTEM 232 | 233 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ 234 | -------------------------------------------------------------------------------- /tests/General.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "gtest/gtest.h" 7 | 8 | #include "sigs.h" 9 | 10 | using namespace std::chrono_literals; 11 | 12 | TEST(General, instantiate) 13 | { 14 | sigs::Signal s; 15 | sigs::Signal s2; 16 | sigs::Signal s3; 17 | } 18 | 19 | inline void addOne(int &i) 20 | { 21 | i++; 22 | } 23 | 24 | TEST(General, function) 25 | { 26 | sigs::Signal s; 27 | s.connect(addOne); 28 | 29 | int i = 0; 30 | s(i); 31 | 32 | EXPECT_EQ(i, 1); 33 | } 34 | 35 | TEST(General, multipleFunctions) 36 | { 37 | sigs::Signal s; 38 | s.connect(addOne); 39 | s.connect(addOne); 40 | s.connect(addOne); 41 | 42 | int i = 0; 43 | s(i); 44 | 45 | EXPECT_EQ(i, 3); 46 | } 47 | 48 | TEST(General, functor) 49 | { 50 | class AddOneFunctor { 51 | public: 52 | void operator()(int &i) const 53 | { 54 | i++; 55 | } 56 | }; 57 | 58 | sigs::Signal s; 59 | s.connect(AddOneFunctor()); 60 | 61 | int i = 0; 62 | s(i); 63 | 64 | EXPECT_EQ(i, 1); 65 | } 66 | 67 | TEST(General, instanceMethod) 68 | { 69 | class Foo { 70 | public: 71 | void test(int &i) const 72 | { 73 | i++; 74 | } 75 | }; 76 | 77 | sigs::Signal s; 78 | 79 | Foo foo; 80 | s.connect(&foo, &Foo::test); 81 | 82 | int i = 0; 83 | s(i); 84 | 85 | EXPECT_EQ(i, 1); 86 | } 87 | 88 | TEST(General, lambda) 89 | { 90 | sigs::Signal s; 91 | s.connect([](int &i) { i++; }); 92 | 93 | int i = 0; 94 | s(i); 95 | EXPECT_EQ(i, 1); 96 | } 97 | 98 | TEST(General, connectionDisconnectDirectly) 99 | { 100 | sigs::Signal s; 101 | auto conn = s.connect([](int &i) { i++; }); 102 | 103 | int i = 0; 104 | s(i); 105 | EXPECT_EQ(i, 1); 106 | 107 | conn->disconnect(); 108 | 109 | s(i); 110 | EXPECT_EQ(i, 1); 111 | } 112 | 113 | TEST(General, connectionDisconnectOnSignal) 114 | { 115 | sigs::Signal s; 116 | auto conn = s.connect([](int &i) { i++; }); 117 | 118 | int i = 0; 119 | s(i); 120 | EXPECT_EQ(i, 1); 121 | 122 | s.disconnect(conn); 123 | 124 | s(i); 125 | EXPECT_EQ(i, 1); 126 | } 127 | 128 | TEST(General, specificConnectionDisconnectOnSignal) 129 | { 130 | sigs::Signal s; 131 | s.connect([](int &i) { i += 2; }); 132 | auto conn = s.connect([](int &i) { i += 4; }); 133 | s.connect([](int &i) { i += 8; }); 134 | 135 | int i = 0; 136 | s(i); 137 | EXPECT_EQ(i, 2 + 4 + 8); 138 | 139 | // Disconnect middle connection only. 140 | s.disconnect(conn); 141 | 142 | s(i); 143 | EXPECT_EQ(i, (2 + 4 + 8) + (2 + 8)); 144 | } 145 | 146 | TEST(General, connectSignalToSignal) 147 | { 148 | sigs::Signal s1; 149 | s1.connect([](int &i) { i++; }); 150 | 151 | decltype(s1) s2; 152 | s2.connect(s1); 153 | 154 | int i = 0; 155 | s2(i); 156 | EXPECT_EQ(i, 1); 157 | } 158 | 159 | TEST(General, disconnectSignalFromSignal) 160 | { 161 | sigs::Signal s1; 162 | s1.connect([](int &i) { i++; }); 163 | 164 | decltype(s1) s2; 165 | s2.connect(s1); 166 | s2.disconnect(s1); 167 | 168 | int i = 0; 169 | s2(i); 170 | EXPECT_EQ(i, 0); 171 | } 172 | 173 | // Check for debug assertion. 174 | #ifndef NDEBUG 175 | TEST(General, disconnectSignalFromSelf) 176 | { 177 | sigs::Signal s; 178 | EXPECT_DEATH(s.disconnect(s), "Disconnecting from self has no effect."); 179 | } 180 | #endif 181 | 182 | TEST(General, ambiguousMembers) 183 | { 184 | class Ambiguous { 185 | public: 186 | void foo(int i) 187 | { 188 | value += i; 189 | } 190 | 191 | void foo(float j) 192 | { 193 | value += static_cast(j); 194 | } 195 | 196 | int value = 0; 197 | }; 198 | 199 | sigs::Signal s; 200 | 201 | Ambiguous amb; 202 | auto conn = s.connect(&amb, sigs::Use::overloadOf(&Ambiguous::foo)); 203 | s(42); 204 | EXPECT_EQ(amb.value, 42); 205 | conn->disconnect(); 206 | 207 | // This one only works because int can be coerced into float. 208 | s.connect(&amb, sigs::Use::overloadOf(&Ambiguous::foo)); 209 | s(1); 210 | EXPECT_EQ(amb.value, 43); 211 | } 212 | 213 | TEST(General, returnValues) 214 | { 215 | sigs::Signal s; 216 | s.connect([] { return 1; }); 217 | s.connect([] { return 2; }); 218 | s.connect([] { return 3; }); 219 | 220 | int sum = 0; 221 | s([&sum](int retVal) { sum += retVal; }); 222 | 223 | EXPECT_EQ(sum, 1 + 2 + 3); 224 | } 225 | 226 | TEST(General, returnValuesWithSignals) 227 | { 228 | sigs::Signal s, s2, s3; 229 | s3.connect([] { return 1; }); 230 | s2.connect([] { return 2; }); 231 | s2.connect([] { return 3; }); 232 | s.connect(s2); 233 | s.connect(s3); 234 | s.connect([] { return 4; }); 235 | 236 | int sum = 0; 237 | s([&sum](int retVal) { sum += retVal; }); 238 | 239 | EXPECT_EQ(sum, 1 + 2 + 3 + 4); 240 | } 241 | 242 | TEST(General, returnValuesBlocked) 243 | { 244 | sigs::Signal s; 245 | s.connect([] { return 1; }); 246 | s.setBlocked(true); 247 | 248 | int sum = 0; 249 | s([&sum](int retVal) { sum += retVal; }); 250 | 251 | EXPECT_EQ(sum, 0); 252 | } 253 | 254 | TEST(General, sameSlotManyConnections) 255 | { 256 | int calls = 0; 257 | const auto slot = [&calls] { calls++; }; 258 | 259 | sigs::Signal s; 260 | s.connect(slot); 261 | s(); 262 | EXPECT_EQ(calls, 1); 263 | 264 | s.connect(slot); 265 | s(); 266 | EXPECT_EQ(calls, 3); 267 | 268 | // This yielded 4 calls when eraseEntries() didn't clear correctly. 269 | s.clear(); 270 | s(); 271 | EXPECT_EQ(calls, 3); 272 | } 273 | 274 | TEST(General, clearEquivalentToAllDisconnects) 275 | { 276 | int calls = 0; 277 | const auto slot = [&calls] { calls++; }; 278 | 279 | sigs::Signal s; 280 | 281 | { 282 | calls = 0; 283 | auto conn1 = s.connect(slot); 284 | auto conn2 = s.connect(slot); 285 | s(); 286 | EXPECT_EQ(calls, 2); 287 | 288 | s.clear(); 289 | s(); 290 | EXPECT_EQ(calls, 2); 291 | } 292 | 293 | { 294 | calls = 0; 295 | auto conn1 = s.connect(slot); 296 | auto conn2 = s.connect(slot); 297 | s(); 298 | EXPECT_EQ(calls, 2); 299 | 300 | s.disconnect(conn1); 301 | s.disconnect(conn2); 302 | s(); 303 | EXPECT_EQ(calls, 2); 304 | } 305 | } 306 | 307 | TEST(General, size) 308 | { 309 | sigs::Signal s; 310 | ASSERT_EQ(s.size(), 0); 311 | 312 | s.connect([] {}); 313 | s.connect([] {}); 314 | ASSERT_EQ(s.size(), 2); 315 | 316 | s.clear(); 317 | ASSERT_EQ(s.size(), 0); 318 | } 319 | 320 | TEST(General, empty) 321 | { 322 | sigs::Signal s; 323 | ASSERT_TRUE(s.empty()); 324 | 325 | s.connect([] {}); 326 | ASSERT_FALSE(s.empty()); 327 | 328 | s.clear(); 329 | ASSERT_TRUE(s.empty()); 330 | } 331 | 332 | TEST(General, disconnectWithNoSlotClearsAll) 333 | { 334 | sigs::Signal s; 335 | s.connect([] {}); 336 | s.connect([] {}); 337 | s.disconnect(); 338 | ASSERT_TRUE(s.empty()); 339 | } 340 | 341 | TEST(General, blocked) 342 | { 343 | sigs::Signal s; 344 | ASSERT_FALSE(s.blocked()); 345 | s.setBlocked(true); 346 | ASSERT_TRUE(s.blocked()); 347 | } 348 | 349 | TEST(General, blockedPreviousValue) 350 | { 351 | sigs::Signal s; 352 | ASSERT_FALSE(s.setBlocked(true)); 353 | ASSERT_TRUE(s.setBlocked(true)); 354 | } 355 | 356 | TEST(General, blockedSlots) 357 | { 358 | int calls = 0; 359 | const auto slot = [&calls] { calls++; }; 360 | 361 | sigs::Signal s; 362 | s.connect(slot); 363 | 364 | s(); 365 | ASSERT_EQ(calls, 1); 366 | 367 | s.setBlocked(true); 368 | ASSERT_TRUE(s.blocked()); 369 | 370 | s(); 371 | ASSERT_EQ(calls, 1); 372 | 373 | s.setBlocked(false); 374 | ASSERT_FALSE(s.blocked()); 375 | 376 | s(); 377 | ASSERT_EQ(calls, 2); 378 | } 379 | 380 | TEST(General, blockedSignals) 381 | { 382 | int calls = 0; 383 | const auto slot = [&calls] { calls++; }; 384 | 385 | sigs::Signal s, s2; 386 | s2.connect(slot); 387 | s.connect(s2); 388 | 389 | s(); 390 | ASSERT_EQ(calls, 1); 391 | 392 | // Block outer signal. 393 | s.setBlocked(true); 394 | ASSERT_TRUE(s.blocked()); 395 | ASSERT_FALSE(s2.blocked()); 396 | 397 | s(); 398 | ASSERT_EQ(calls, 1); 399 | 400 | s.setBlocked(false); 401 | ASSERT_FALSE(s.blocked()); 402 | 403 | s(); 404 | ASSERT_EQ(calls, 2); 405 | 406 | // Block inner signal. 407 | s2.setBlocked(true); 408 | ASSERT_TRUE(s2.blocked()); 409 | ASSERT_FALSE(s.blocked()); 410 | 411 | s(); 412 | ASSERT_EQ(calls, 2); 413 | } 414 | 415 | TEST(General, copyConstructible) 416 | { 417 | sigs::Signal s; 418 | s.connect([] {}); 419 | s.connect([] {}); 420 | s.setBlocked(true); 421 | 422 | decltype(s) s2(s); 423 | ASSERT_EQ(s2.size(), 2); 424 | ASSERT_TRUE(s2.blocked()); 425 | } 426 | 427 | TEST(General, copyAssignable) 428 | { 429 | sigs::Signal s; 430 | s.connect([] {}); 431 | s.connect([] {}); 432 | s.setBlocked(true); 433 | 434 | decltype(s) s2; 435 | s2 = s; 436 | ASSERT_EQ(s2.size(), 2); 437 | ASSERT_TRUE(s2.blocked()); 438 | } 439 | 440 | TEST(General, dontMoveRvalues) 441 | { 442 | sigs::Signal s; 443 | 444 | std::string res; 445 | auto func = [&res](std::string str) { res += str; }; 446 | s.connect(func); 447 | s.connect(func); 448 | s.connect(func); 449 | 450 | s("test"); 451 | ASSERT_EQ("testtesttest", res); 452 | } 453 | 454 | TEST(General, dontMoveRvaluesReturnValue) 455 | { 456 | sigs::Signal s; 457 | 458 | std::string res; 459 | auto func = [&res](std::string str) -> int { 460 | res += str; 461 | return 1; 462 | }; 463 | s.connect(func); 464 | s.connect(func); 465 | s.connect(func); 466 | 467 | int sum = 0; 468 | s([&sum](int retVal) { sum += retVal; }, "test"); 469 | 470 | ASSERT_EQ("testtesttest", res); 471 | ASSERT_EQ(3, sum); 472 | } 473 | 474 | TEST(General, dontMoveRvaluesSubSignal) 475 | { 476 | std::string res; 477 | auto func = [&res](std::string str) { res += str; }; 478 | 479 | sigs::Signal s; 480 | s.connect(func); 481 | 482 | decltype(s) s2; 483 | s2.connect(func); 484 | s2.connect(s); 485 | s2.connect(func); 486 | 487 | s2("test"); 488 | ASSERT_EQ("testtesttest", res); 489 | } 490 | 491 | TEST(General, threadedInvocation) 492 | { 493 | int sum = 0; 494 | auto func = [&sum] { sum++; }; 495 | 496 | sigs::Signal s; 497 | s.connect(func); 498 | s.connect(func); 499 | 500 | int n = 3; 501 | std::thread t([&s, n] { 502 | for (int i = 0; i < n; ++i) { 503 | s(); 504 | } 505 | }); 506 | t.join(); 507 | 508 | ASSERT_EQ(n * 2, sum); 509 | } 510 | 511 | TEST(General, threadedDontMoveRvalues) 512 | { 513 | unsigned int sum = 0; 514 | std::string res; 515 | auto func = [&](std::string str) { 516 | sum++; 517 | res += str; 518 | }; 519 | 520 | sigs::Signal s; 521 | s.connect(func); 522 | s.connect(func); 523 | 524 | int n = 3; 525 | std::thread t([&s, n] { 526 | for (int i = 0; i < n; ++i) { 527 | s("x"); 528 | } 529 | }); 530 | t.join(); 531 | 532 | ASSERT_EQ(n * 2, sum); 533 | ASSERT_EQ(std::string(sum, 'x'), res); 534 | } 535 | 536 | TEST(General, valueReferences) 537 | { 538 | sigs::Signal s; 539 | 540 | int res = 0, iterations = 3; 541 | for (int j = 0; j < iterations; ++j) { 542 | s.connect([](int &i) { i++; }); 543 | } 544 | 545 | s(res); 546 | ASSERT_EQ(iterations, res); 547 | } 548 | 549 | // If locks aren't used inside the Signal, the synchronicity could be off and the value differs. 550 | TEST(General, threadedLocking) 551 | { 552 | sigs::Signal s; 553 | s.connect([](int &i) { i++; }); 554 | 555 | int n = 0; 556 | 557 | auto func = [&] { 558 | std::this_thread::sleep_for(25ms); 559 | s(n); 560 | }; 561 | 562 | std::thread t1(func); 563 | std::thread t2(func); 564 | std::thread t3(func); 565 | t1.join(); 566 | t2.join(); 567 | t3.join(); 568 | 569 | ASSERT_EQ(3, n); 570 | } 571 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/gtest-spi.h: -------------------------------------------------------------------------------- 1 | // Copyright 2007, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Utilities for testing Google Test itself and code that uses Google Test 31 | // (e.g. frameworks built on top of Google Test). 32 | 33 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ 34 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ 35 | 36 | #include 37 | 38 | #include "gtest/gtest.h" 39 | 40 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 41 | /* class A needs to have dll-interface to be used by clients of class B */) 42 | 43 | namespace testing { 44 | 45 | // This helper class can be used to mock out Google Test failure reporting 46 | // so that we can test Google Test or code that builds on Google Test. 47 | // 48 | // An object of this class appends a TestPartResult object to the 49 | // TestPartResultArray object given in the constructor whenever a Google Test 50 | // failure is reported. It can either intercept only failures that are 51 | // generated in the same thread that created this object or it can intercept 52 | // all generated failures. The scope of this mock object can be controlled with 53 | // the second argument to the two arguments constructor. 54 | class GTEST_API_ ScopedFakeTestPartResultReporter 55 | : public TestPartResultReporterInterface { 56 | public: 57 | // The two possible mocking modes of this object. 58 | enum InterceptMode { 59 | INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. 60 | INTERCEPT_ALL_THREADS // Intercepts all failures. 61 | }; 62 | 63 | // The c'tor sets this object as the test part result reporter used 64 | // by Google Test. The 'result' parameter specifies where to report the 65 | // results. This reporter will only catch failures generated in the current 66 | // thread. DEPRECATED 67 | explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); 68 | 69 | // Same as above, but you can choose the interception scope of this object. 70 | ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, 71 | TestPartResultArray* result); 72 | 73 | // The d'tor restores the previous test part result reporter. 74 | ~ScopedFakeTestPartResultReporter() override; 75 | 76 | // Appends the TestPartResult object to the TestPartResultArray 77 | // received in the constructor. 78 | // 79 | // This method is from the TestPartResultReporterInterface 80 | // interface. 81 | void ReportTestPartResult(const TestPartResult& result) override; 82 | 83 | private: 84 | void Init(); 85 | 86 | const InterceptMode intercept_mode_; 87 | TestPartResultReporterInterface* old_reporter_; 88 | TestPartResultArray* const result_; 89 | 90 | ScopedFakeTestPartResultReporter(const ScopedFakeTestPartResultReporter&) = 91 | delete; 92 | ScopedFakeTestPartResultReporter& operator=( 93 | const ScopedFakeTestPartResultReporter&) = delete; 94 | }; 95 | 96 | namespace internal { 97 | 98 | // A helper class for implementing EXPECT_FATAL_FAILURE() and 99 | // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given 100 | // TestPartResultArray contains exactly one failure that has the given 101 | // type and contains the given substring. If that's not the case, a 102 | // non-fatal failure will be generated. 103 | class GTEST_API_ SingleFailureChecker { 104 | public: 105 | // The constructor remembers the arguments. 106 | SingleFailureChecker(const TestPartResultArray* results, 107 | TestPartResult::Type type, const std::string& substr); 108 | ~SingleFailureChecker(); 109 | 110 | private: 111 | const TestPartResultArray* const results_; 112 | const TestPartResult::Type type_; 113 | const std::string substr_; 114 | 115 | SingleFailureChecker(const SingleFailureChecker&) = delete; 116 | SingleFailureChecker& operator=(const SingleFailureChecker&) = delete; 117 | }; 118 | 119 | } // namespace internal 120 | 121 | } // namespace testing 122 | 123 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 124 | 125 | // A set of macros for testing Google Test assertions or code that's expected 126 | // to generate Google Test fatal failures (e.g. a failure from an ASSERT_EQ, but 127 | // not a non-fatal failure, as from EXPECT_EQ). It verifies that the given 128 | // statement will cause exactly one fatal Google Test failure with 'substr' 129 | // being part of the failure message. 130 | // 131 | // There are two different versions of this macro. EXPECT_FATAL_FAILURE only 132 | // affects and considers failures generated in the current thread and 133 | // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. 134 | // 135 | // The verification of the assertion is done correctly even when the statement 136 | // throws an exception or aborts the current function. 137 | // 138 | // Known restrictions: 139 | // - 'statement' cannot reference local non-static variables or 140 | // non-static members of the current object. 141 | // - 'statement' cannot return a value. 142 | // - You cannot stream a failure message to this macro. 143 | // 144 | // Note that even though the implementations of the following two 145 | // macros are much alike, we cannot refactor them to use a common 146 | // helper macro, due to some peculiarity in how the preprocessor 147 | // works. The AcceptsMacroThatExpandsToUnprotectedComma test in 148 | // gtest_unittest.cc will fail to compile if we do that. 149 | #define EXPECT_FATAL_FAILURE(statement, substr) \ 150 | do { \ 151 | class GTestExpectFatalFailureHelper { \ 152 | public: \ 153 | static void Execute() { statement; } \ 154 | }; \ 155 | ::testing::TestPartResultArray gtest_failures; \ 156 | ::testing::internal::SingleFailureChecker gtest_checker( \ 157 | >est_failures, ::testing::TestPartResult::kFatalFailure, (substr)); \ 158 | { \ 159 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ 160 | ::testing::ScopedFakeTestPartResultReporter:: \ 161 | INTERCEPT_ONLY_CURRENT_THREAD, \ 162 | >est_failures); \ 163 | GTestExpectFatalFailureHelper::Execute(); \ 164 | } \ 165 | } while (::testing::internal::AlwaysFalse()) 166 | 167 | #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ 168 | do { \ 169 | class GTestExpectFatalFailureHelper { \ 170 | public: \ 171 | static void Execute() { statement; } \ 172 | }; \ 173 | ::testing::TestPartResultArray gtest_failures; \ 174 | ::testing::internal::SingleFailureChecker gtest_checker( \ 175 | >est_failures, ::testing::TestPartResult::kFatalFailure, (substr)); \ 176 | { \ 177 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ 178 | ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ 179 | >est_failures); \ 180 | GTestExpectFatalFailureHelper::Execute(); \ 181 | } \ 182 | } while (::testing::internal::AlwaysFalse()) 183 | 184 | // A macro for testing Google Test assertions or code that's expected to 185 | // generate Google Test non-fatal failures (e.g. a failure from an EXPECT_EQ, 186 | // but not from an ASSERT_EQ). It asserts that the given statement will cause 187 | // exactly one non-fatal Google Test failure with 'substr' being part of the 188 | // failure message. 189 | // 190 | // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only 191 | // affects and considers failures generated in the current thread and 192 | // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. 193 | // 194 | // 'statement' is allowed to reference local variables and members of 195 | // the current object. 196 | // 197 | // The verification of the assertion is done correctly even when the statement 198 | // throws an exception or aborts the current function. 199 | // 200 | // Known restrictions: 201 | // - You cannot stream a failure message to this macro. 202 | // 203 | // Note that even though the implementations of the following two 204 | // macros are much alike, we cannot refactor them to use a common 205 | // helper macro, due to some peculiarity in how the preprocessor 206 | // works. If we do that, the code won't compile when the user gives 207 | // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that 208 | // expands to code containing an unprotected comma. The 209 | // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc 210 | // catches that. 211 | // 212 | // For the same reason, we have to write 213 | // if (::testing::internal::AlwaysTrue()) { statement; } 214 | // instead of 215 | // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) 216 | // to avoid an MSVC warning on unreachable code. 217 | #define EXPECT_NONFATAL_FAILURE(statement, substr) \ 218 | do { \ 219 | ::testing::TestPartResultArray gtest_failures; \ 220 | ::testing::internal::SingleFailureChecker gtest_checker( \ 221 | >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ 222 | (substr)); \ 223 | { \ 224 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ 225 | ::testing::ScopedFakeTestPartResultReporter:: \ 226 | INTERCEPT_ONLY_CURRENT_THREAD, \ 227 | >est_failures); \ 228 | if (::testing::internal::AlwaysTrue()) { \ 229 | statement; \ 230 | } \ 231 | } \ 232 | } while (::testing::internal::AlwaysFalse()) 233 | 234 | #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ 235 | do { \ 236 | ::testing::TestPartResultArray gtest_failures; \ 237 | ::testing::internal::SingleFailureChecker gtest_checker( \ 238 | >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ 239 | (substr)); \ 240 | { \ 241 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ 242 | ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ 243 | >est_failures); \ 244 | if (::testing::internal::AlwaysTrue()) { \ 245 | statement; \ 246 | } \ 247 | } \ 248 | } while (::testing::internal::AlwaysFalse()) 249 | 250 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ 251 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/gtest_pred_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Implements a family of generic predicate assertion macros. 31 | 32 | // IWYU pragma: private, include "gtest/gtest.h" 33 | // IWYU pragma: friend gtest/.* 34 | // IWYU pragma: friend gmock/.* 35 | 36 | #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ 37 | #define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ 38 | 39 | #include "gtest/gtest-assertion-result.h" 40 | #include "gtest/internal/gtest-internal.h" 41 | #include "gtest/internal/gtest-port.h" 42 | 43 | namespace testing { 44 | 45 | // This header implements a family of generic predicate assertion 46 | // macros: 47 | // 48 | // ASSERT_PRED_FORMAT1(pred_format, v1) 49 | // ASSERT_PRED_FORMAT2(pred_format, v1, v2) 50 | // ... 51 | // 52 | // where pred_format is a function or functor that takes n (in the 53 | // case of ASSERT_PRED_FORMATn) values and their source expression 54 | // text, and returns a testing::AssertionResult. See the definition 55 | // of ASSERT_EQ in gtest.h for an example. 56 | // 57 | // If you don't care about formatting, you can use the more 58 | // restrictive version: 59 | // 60 | // ASSERT_PRED1(pred, v1) 61 | // ASSERT_PRED2(pred, v1, v2) 62 | // ... 63 | // 64 | // where pred is an n-ary function or functor that returns bool, 65 | // and the values v1, v2, ..., must support the << operator for 66 | // streaming to std::ostream. 67 | // 68 | // We also define the EXPECT_* variations. 69 | // 70 | // For now we only support predicates whose arity is at most 5. 71 | // Please email googletestframework@googlegroups.com if you need 72 | // support for higher arities. 73 | 74 | // GTEST_ASSERT_ is the basic statement to which all of the assertions 75 | // in this file reduce. Don't use this in your code. 76 | 77 | #define GTEST_ASSERT_(expression, on_failure) \ 78 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ 79 | if (const ::testing::AssertionResult gtest_ar = (expression)) \ 80 | ; \ 81 | else \ 82 | on_failure(gtest_ar.failure_message()) 83 | 84 | // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use 85 | // this in your code. 86 | template 87 | AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, 88 | Pred pred, const T1& v1) { 89 | if (pred(v1)) return AssertionSuccess(); 90 | 91 | return AssertionFailure() 92 | << pred_text << "(" << e1 << ") evaluates to false, where" 93 | << "\n" 94 | << e1 << " evaluates to " << ::testing::PrintToString(v1); 95 | } 96 | 97 | // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. 98 | // Don't use this in your code. 99 | #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure) \ 100 | GTEST_ASSERT_(pred_format(#v1, v1), on_failure) 101 | 102 | // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use 103 | // this in your code. 104 | #define GTEST_PRED1_(pred, v1, on_failure) \ 105 | GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, #v1, pred, v1), on_failure) 106 | 107 | // Unary predicate assertion macros. 108 | #define EXPECT_PRED_FORMAT1(pred_format, v1) \ 109 | GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) 110 | #define EXPECT_PRED1(pred, v1) GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) 111 | #define ASSERT_PRED_FORMAT1(pred_format, v1) \ 112 | GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) 113 | #define ASSERT_PRED1(pred, v1) GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) 114 | 115 | // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use 116 | // this in your code. 117 | template 118 | AssertionResult AssertPred2Helper(const char* pred_text, const char* e1, 119 | const char* e2, Pred pred, const T1& v1, 120 | const T2& v2) { 121 | if (pred(v1, v2)) return AssertionSuccess(); 122 | 123 | return AssertionFailure() 124 | << pred_text << "(" << e1 << ", " << e2 125 | << ") evaluates to false, where" 126 | << "\n" 127 | << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" 128 | << e2 << " evaluates to " << ::testing::PrintToString(v2); 129 | } 130 | 131 | // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. 132 | // Don't use this in your code. 133 | #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure) \ 134 | GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure) 135 | 136 | // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use 137 | // this in your code. 138 | #define GTEST_PRED2_(pred, v1, v2, on_failure) \ 139 | GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, #v1, #v2, pred, v1, v2), \ 140 | on_failure) 141 | 142 | // Binary predicate assertion macros. 143 | #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ 144 | GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) 145 | #define EXPECT_PRED2(pred, v1, v2) \ 146 | GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) 147 | #define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ 148 | GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) 149 | #define ASSERT_PRED2(pred, v1, v2) \ 150 | GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) 151 | 152 | // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use 153 | // this in your code. 154 | template 155 | AssertionResult AssertPred3Helper(const char* pred_text, const char* e1, 156 | const char* e2, const char* e3, Pred pred, 157 | const T1& v1, const T2& v2, const T3& v3) { 158 | if (pred(v1, v2, v3)) return AssertionSuccess(); 159 | 160 | return AssertionFailure() 161 | << pred_text << "(" << e1 << ", " << e2 << ", " << e3 162 | << ") evaluates to false, where" 163 | << "\n" 164 | << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" 165 | << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" 166 | << e3 << " evaluates to " << ::testing::PrintToString(v3); 167 | } 168 | 169 | // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. 170 | // Don't use this in your code. 171 | #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure) \ 172 | GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), on_failure) 173 | 174 | // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use 175 | // this in your code. 176 | #define GTEST_PRED3_(pred, v1, v2, v3, on_failure) \ 177 | GTEST_ASSERT_( \ 178 | ::testing::AssertPred3Helper(#pred, #v1, #v2, #v3, pred, v1, v2, v3), \ 179 | on_failure) 180 | 181 | // Ternary predicate assertion macros. 182 | #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ 183 | GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) 184 | #define EXPECT_PRED3(pred, v1, v2, v3) \ 185 | GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) 186 | #define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ 187 | GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) 188 | #define ASSERT_PRED3(pred, v1, v2, v3) \ 189 | GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) 190 | 191 | // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use 192 | // this in your code. 193 | template 194 | AssertionResult AssertPred4Helper(const char* pred_text, const char* e1, 195 | const char* e2, const char* e3, 196 | const char* e4, Pred pred, const T1& v1, 197 | const T2& v2, const T3& v3, const T4& v4) { 198 | if (pred(v1, v2, v3, v4)) return AssertionSuccess(); 199 | 200 | return AssertionFailure() 201 | << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 202 | << ") evaluates to false, where" 203 | << "\n" 204 | << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" 205 | << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" 206 | << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" 207 | << e4 << " evaluates to " << ::testing::PrintToString(v4); 208 | } 209 | 210 | // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. 211 | // Don't use this in your code. 212 | #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure) \ 213 | GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), on_failure) 214 | 215 | // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use 216 | // this in your code. 217 | #define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure) \ 218 | GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, #v1, #v2, #v3, #v4, pred, \ 219 | v1, v2, v3, v4), \ 220 | on_failure) 221 | 222 | // 4-ary predicate assertion macros. 223 | #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ 224 | GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) 225 | #define EXPECT_PRED4(pred, v1, v2, v3, v4) \ 226 | GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) 227 | #define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ 228 | GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) 229 | #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ 230 | GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) 231 | 232 | // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use 233 | // this in your code. 234 | template 236 | AssertionResult AssertPred5Helper(const char* pred_text, const char* e1, 237 | const char* e2, const char* e3, 238 | const char* e4, const char* e5, Pred pred, 239 | const T1& v1, const T2& v2, const T3& v3, 240 | const T4& v4, const T5& v5) { 241 | if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); 242 | 243 | return AssertionFailure() 244 | << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 245 | << ", " << e5 << ") evaluates to false, where" 246 | << "\n" 247 | << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" 248 | << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" 249 | << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" 250 | << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" 251 | << e5 << " evaluates to " << ::testing::PrintToString(v5); 252 | } 253 | 254 | // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. 255 | // Don't use this in your code. 256 | #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure) \ 257 | GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ 258 | on_failure) 259 | 260 | // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use 261 | // this in your code. 262 | #define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure) \ 263 | GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, #v1, #v2, #v3, #v4, #v5, \ 264 | pred, v1, v2, v3, v4, v5), \ 265 | on_failure) 266 | 267 | // 5-ary predicate assertion macros. 268 | #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ 269 | GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) 270 | #define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ 271 | GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) 272 | #define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ 273 | GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) 274 | #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ 275 | GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) 276 | 277 | } // namespace testing 278 | 279 | #endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ 280 | -------------------------------------------------------------------------------- /sigs17.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | sigs 3 | 4 | Simple thread-safe signal/slot C++17 include-only library. 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2015-2020 Morten Kristensen, me AT mortens DOT dev 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 11 | associated documentation files (the "Software"), to deal in the Software without restriction, 12 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 13 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all copies or substantial 17 | portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 20 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 22 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | ***************************************************************************************************/ 25 | 26 | #ifndef SIGS_SIGNAL_SLOT_H 27 | #define SIGS_SIGNAL_SLOT_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // The following is used for making variadic type lists for binding member functions and their 43 | // parameters. 44 | namespace sigs { 45 | 46 | template 47 | class Seq { 48 | }; 49 | 50 | template 51 | class MakeSeq : public MakeSeq { 52 | }; 53 | 54 | template 55 | class MakeSeq<0, Ns...> : public Seq { 56 | }; 57 | 58 | template 59 | class Placeholder { 60 | }; 61 | 62 | } // namespace sigs 63 | 64 | // std::bind uses std::is_placeholder to detect placeholders for unbounded arguments, so it must be 65 | // overridden to accept the custom sigs::Placeholder type. 66 | namespace std { 67 | 68 | template 69 | class is_placeholder> : public integral_constant { 70 | }; 71 | 72 | } // namespace std 73 | 74 | namespace sigs { 75 | 76 | /// When a member function has muliple overloads and you need to use just one of them. 77 | /** Example: 78 | signal.connect(&instance, sigs::Use::overloadOf(&TheClass::func)); 79 | */ 80 | template 81 | struct Use final { 82 | template 83 | [[nodiscard]] static inline auto overloadOf(Ret (Cls::*MembFunc)(Args...)) noexcept 84 | { 85 | return MembFunc; 86 | } 87 | }; 88 | 89 | class ConnectionBase final { 90 | template 91 | friend class BasicSignal; 92 | 93 | public: 94 | void disconnect() 95 | { 96 | if (deleter) deleter(); 97 | } 98 | 99 | private: 100 | std::function deleter; 101 | }; 102 | 103 | using Connection = std::shared_ptr; 104 | 105 | namespace detail { 106 | 107 | /// VoidableFunction is used internally to generate a function type depending on whether the return 108 | /// type of the signal is non-void. 109 | template 110 | class VoidableFunction final { 111 | public: 112 | using func = std::function; 113 | }; 114 | 115 | /// Specialization for void return types. 116 | template <> 117 | class VoidableFunction final { 118 | public: 119 | using func = std::function; 120 | }; 121 | 122 | } // namespace detail 123 | 124 | template 125 | class BasicSignal; 126 | 127 | template 128 | class SignalBlocker { 129 | static_assert(std::is_base_of_v, Sig>, 130 | "Sig must extend sigs::BasicSignal"); 131 | 132 | public: 133 | explicit SignalBlocker(Sig *sig) noexcept : sig_(sig) 134 | { 135 | reblock(); 136 | } 137 | 138 | explicit SignalBlocker(Sig &sig) noexcept : sig_(&sig) 139 | { 140 | reblock(); 141 | } 142 | 143 | virtual ~SignalBlocker() noexcept 144 | { 145 | unblock(); 146 | } 147 | 148 | SignalBlocker(const SignalBlocker &rhs) = delete; 149 | SignalBlocker &operator=(const SignalBlocker &rhs) = delete; 150 | 151 | SignalBlocker(SignalBlocker &&rhs) noexcept 152 | { 153 | moveAssign(std::move(rhs)); 154 | } 155 | 156 | /// Unblocks `this` if signals of `this` and `rhs` aren't the same. 157 | SignalBlocker &operator=(SignalBlocker &&rhs) noexcept 158 | { 159 | if (sig_ != rhs.sig_) { 160 | unblock(); 161 | } 162 | 163 | moveAssign(std::move(rhs)); 164 | return *this; 165 | } 166 | 167 | void reblock() noexcept 168 | { 169 | if (sig_) { 170 | previous = sig_->setBlocked(true); 171 | } 172 | } 173 | 174 | void unblock() noexcept 175 | { 176 | if (sig_) { 177 | sig_->setBlocked(previous); 178 | } 179 | } 180 | 181 | private: 182 | void moveAssign(SignalBlocker &&rhs) 183 | { 184 | sig_ = rhs.sig_; 185 | previous = rhs.previous; 186 | 187 | // `rhs` won't do any action on destruction. 188 | rhs.sig_ = nullptr; 189 | } 190 | 191 | Sig *sig_ = nullptr; 192 | bool previous = false; 193 | }; 194 | 195 | /// Suppress CTAD warning. 196 | template 197 | SignalBlocker(Sig) -> SignalBlocker; 198 | 199 | template 200 | class BasicSignal { 201 | public: 202 | using RetArgs = Ret(Args...); 203 | using SignalType = BasicSignal; 204 | using LockType = Lock; 205 | using ReturnType = Ret; 206 | 207 | private: 208 | using Slot = std::function; 209 | using Mutex = typename Lock::mutex_type; 210 | 211 | class Entry final { 212 | public: 213 | Entry(const Slot &slot, Connection conn) noexcept 214 | : slot_(slot), conn_(std::move(conn)), signal_(nullptr) 215 | { 216 | } 217 | 218 | Entry(Slot &&slot, Connection conn) noexcept 219 | : slot_(std::move(slot)), conn_(std::move(conn)), signal_(nullptr) 220 | { 221 | } 222 | 223 | Entry(BasicSignal *signal, Connection conn) noexcept : conn_(std::move(conn)), signal_(signal) 224 | { 225 | } 226 | 227 | const Slot &slot() const noexcept 228 | { 229 | return slot_; 230 | } 231 | 232 | BasicSignal *signal() const noexcept 233 | { 234 | return signal_; 235 | } 236 | 237 | [[nodiscard]] Connection conn() const noexcept 238 | { 239 | return conn_; 240 | } 241 | 242 | private: 243 | Slot slot_; 244 | Connection conn_; 245 | BasicSignal *signal_; 246 | }; 247 | 248 | using Cont = std::vector; 249 | 250 | public: 251 | using SlotType = Slot; 252 | 253 | /// Interface that only exposes connect and disconnect methods. 254 | class Interface final { 255 | public: 256 | explicit Interface(SignalType *sig) noexcept : sig_(sig) 257 | { 258 | } 259 | 260 | inline Connection connect(const Slot &slot) noexcept 261 | { 262 | return sig_->connect(slot); 263 | } 264 | 265 | inline Connection connect(Slot &&slot) noexcept 266 | { 267 | return sig_->connect(slot); 268 | } 269 | 270 | template 271 | inline Connection connect(Instance *instance, MembFunc Instance::*mf) noexcept 272 | { 273 | return sig_->connect(instance, mf); 274 | } 275 | 276 | inline Connection connect(BasicSignal &signal) noexcept 277 | { 278 | return sig_->connect(signal); 279 | } 280 | 281 | inline void disconnect(std::optional conn) noexcept 282 | { 283 | sig_->disconnect(conn); 284 | } 285 | 286 | inline void disconnect(BasicSignal &signal) noexcept 287 | { 288 | sig_->disconnect(signal); 289 | } 290 | 291 | private: 292 | SignalType *sig_ = nullptr; 293 | }; 294 | 295 | BasicSignal() noexcept = default; 296 | 297 | virtual ~BasicSignal() noexcept 298 | { 299 | Lock lock(entriesMutex); 300 | for (auto &entry : entries) { 301 | if (auto conn = entry.conn(); conn) { 302 | conn->deleter = nullptr; 303 | } 304 | } 305 | } 306 | 307 | BasicSignal(const BasicSignal &rhs) noexcept : BasicSignal() 308 | { 309 | Lock lock1(entriesMutex); 310 | Lock lock2(rhs.entriesMutex); 311 | entries = rhs.entries; 312 | 313 | // `atomic_bool` can't be copied, so copy value. 314 | blocked_ = rhs.blocked_.load(); 315 | } 316 | 317 | BasicSignal &operator=(const BasicSignal &rhs) noexcept 318 | { 319 | Lock lock1(entriesMutex); 320 | Lock lock2(rhs.entriesMutex); 321 | entries = rhs.entries; 322 | blocked_ = rhs.blocked_.load(); 323 | return *this; 324 | } 325 | 326 | BasicSignal(BasicSignal &&rhs) noexcept = default; 327 | BasicSignal &operator=(BasicSignal &&rhs) noexcept = default; 328 | 329 | std::size_t size() const noexcept 330 | { 331 | Lock lock(entriesMutex); 332 | return entries.size(); 333 | } 334 | 335 | bool empty() const noexcept 336 | { 337 | return 0 == size(); 338 | } 339 | 340 | Connection connect(const Slot &slot) noexcept 341 | { 342 | Lock lock(entriesMutex); 343 | auto conn = makeConnection(); 344 | entries.emplace_back(Entry(slot, conn)); 345 | return conn; 346 | } 347 | 348 | Connection connect(Slot &&slot) noexcept 349 | { 350 | Lock lock(entriesMutex); 351 | auto conn = makeConnection(); 352 | entries.emplace_back(Entry(std::move(slot), conn)); 353 | return conn; 354 | } 355 | 356 | template 357 | Connection connect(Instance *instance, MembFunc Instance::*mf) noexcept 358 | { 359 | Lock lock(entriesMutex); 360 | auto slot = bindMf(instance, mf); 361 | auto conn = makeConnection(); 362 | entries.emplace_back(Entry(slot, conn)); 363 | return conn; 364 | } 365 | 366 | /// Connecting a signal will trigger all of its slots when this signal is triggered. 367 | Connection connect(BasicSignal &signal) noexcept 368 | { 369 | Lock lock(entriesMutex); 370 | auto conn = makeConnection(); 371 | entries.emplace_back(Entry(&signal, conn)); 372 | return conn; 373 | } 374 | 375 | void clear() noexcept 376 | { 377 | Lock lock(entriesMutex); 378 | eraseEntries(); 379 | } 380 | 381 | /// Disconnects \p conn from signal. 382 | /** If no value is given, all slots are disconnected. */ 383 | void disconnect(const std::optional &conn = std::nullopt) noexcept 384 | { 385 | if (!conn) { 386 | clear(); 387 | return; 388 | } 389 | 390 | Lock lock(entriesMutex); 391 | eraseEntries([conn](auto it) { return it->conn() == conn; }); 392 | } 393 | 394 | void disconnect(BasicSignal &signal) noexcept 395 | { 396 | assert(&signal != this && "Disconnecting from self has no effect."); 397 | 398 | Lock lock(entriesMutex); 399 | eraseEntries([sig = &signal](auto it) { return it->signal() == sig; }); 400 | } 401 | 402 | void operator()(Args &&...args) noexcept 403 | { 404 | if (blocked()) return; 405 | 406 | Lock lock(entriesMutex); 407 | for (auto &entry : entries) { 408 | if (auto *sig = entry.signal(); sig) { 409 | (*sig)(std::forward(args)...); 410 | } 411 | else { 412 | entry.slot()(std::forward(args)...); 413 | } 414 | } 415 | } 416 | 417 | template ::func> 418 | void operator()(const RetFunc &retFunc, Args &&...args) noexcept 419 | { 420 | static_assert(!std::is_void_v, "Must have non-void return type!"); 421 | 422 | if (blocked()) return; 423 | 424 | Lock lock(entriesMutex); 425 | for (auto &entry : entries) { 426 | if (auto *sig = entry.signal(); sig) { 427 | (*sig)(retFunc, std::forward(args)...); 428 | } 429 | else { 430 | retFunc(entry.slot()(std::forward(args)...)); 431 | } 432 | } 433 | } 434 | 435 | [[nodiscard]] inline std::unique_ptr interface() noexcept 436 | { 437 | return std::make_unique(this); 438 | } 439 | 440 | /// Returns the previous blocked state. 441 | bool setBlocked(bool blocked) 442 | { 443 | const auto previous = blocked_.load(); 444 | blocked_ = blocked; 445 | return previous; 446 | } 447 | 448 | bool blocked() const 449 | { 450 | return blocked_; 451 | } 452 | 453 | private: 454 | [[nodiscard]] inline Connection makeConnection() noexcept 455 | { 456 | auto conn = std::make_shared(); 457 | conn->deleter = [this, conn] { this->disconnect(conn); }; 458 | return conn; 459 | } 460 | 461 | /// Expects entries container to be locked beforehand. 462 | [[nodiscard]] typename Cont::iterator eraseEntry(typename Cont::iterator it) noexcept 463 | { 464 | auto conn = it->conn(); 465 | if (conn) { 466 | conn->deleter = nullptr; 467 | } 468 | return entries.erase(it); 469 | } 470 | 471 | void eraseEntries(std::function pred = [](auto /*unused*/) { 472 | return true; 473 | }) noexcept 474 | { 475 | for (auto it = entries.begin(); it != entries.end();) { 476 | if (pred(it)) { 477 | it = eraseEntry(it); 478 | } 479 | else { 480 | ++it; 481 | } 482 | } 483 | } 484 | 485 | template 486 | [[nodiscard]] inline Slot bindMf(Instance *instance, MembFunc Instance::*mf, 487 | Seq /*unused*/) noexcept 488 | { 489 | return std::bind(mf, instance, Placeholder()...); 490 | } 491 | 492 | template 493 | [[nodiscard]] inline Slot bindMf(Instance *instance, MembFunc Instance::*mf) noexcept 494 | { 495 | return bindMf(instance, mf, MakeSeq()); 496 | } 497 | 498 | Cont entries; 499 | mutable Mutex entriesMutex; 500 | std::atomic_bool blocked_ = false; 501 | }; 502 | 503 | using BasicLock = std::lock_guard; 504 | 505 | /// Default signal types. 506 | //@{ 507 | 508 | template 509 | using Signal = BasicSignal; 510 | 511 | //@} 512 | 513 | } // namespace sigs 514 | 515 | #endif // SIGS_SIGNAL_SLOT_H 516 | -------------------------------------------------------------------------------- /tests/gtest/include/gtest/internal/gtest-death-test-internal.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The Google C++ Testing and Mocking Framework (Google Test) 31 | // 32 | // This header file defines internal utilities needed for implementing 33 | // death tests. They are subject to change without notice. 34 | 35 | // IWYU pragma: private, include "gtest/gtest.h" 36 | // IWYU pragma: friend gtest/.* 37 | // IWYU pragma: friend gmock/.* 38 | 39 | #ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ 40 | #define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include "gtest/gtest-matchers.h" 48 | #include "gtest/internal/gtest-internal.h" 49 | #include "gtest/internal/gtest-port.h" 50 | 51 | GTEST_DECLARE_string_(internal_run_death_test); 52 | 53 | namespace testing { 54 | namespace internal { 55 | 56 | // Name of the flag (needed for parsing Google Test flag). 57 | const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; 58 | 59 | // A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads 60 | // and interpreted as a regex (rather than an Eq matcher) for legacy 61 | // compatibility. 62 | inline Matcher MakeDeathTestMatcher( 63 | ::testing::internal::RE regex) { 64 | return ContainsRegex(regex.pattern()); 65 | } 66 | inline Matcher MakeDeathTestMatcher(const char* regex) { 67 | return ContainsRegex(regex); 68 | } 69 | inline Matcher MakeDeathTestMatcher( 70 | const ::std::string& regex) { 71 | return ContainsRegex(regex); 72 | } 73 | 74 | // If a Matcher is passed to EXPECT_DEATH (etc.), it's 75 | // used directly. 76 | inline Matcher MakeDeathTestMatcher( 77 | Matcher matcher) { 78 | return matcher; 79 | } 80 | 81 | #ifdef GTEST_HAS_DEATH_TEST 82 | 83 | GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 84 | /* class A needs to have dll-interface to be used by clients of class B */) 85 | 86 | // DeathTest is a class that hides much of the complexity of the 87 | // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method 88 | // returns a concrete class that depends on the prevailing death test 89 | // style, as defined by the --gtest_death_test_style and/or 90 | // --gtest_internal_run_death_test flags. 91 | 92 | // In describing the results of death tests, these terms are used with 93 | // the corresponding definitions: 94 | // 95 | // exit status: The integer exit information in the format specified 96 | // by wait(2) 97 | // exit code: The integer code passed to exit(3), _Exit(2), or 98 | // returned from main() 99 | class GTEST_API_ DeathTest { 100 | public: 101 | // Create returns false if there was an error determining the 102 | // appropriate action to take for the current death test; for example, 103 | // if the gtest_death_test_style flag is set to an invalid value. 104 | // The LastMessage method will return a more detailed message in that 105 | // case. Otherwise, the DeathTest pointer pointed to by the "test" 106 | // argument is set. If the death test should be skipped, the pointer 107 | // is set to NULL; otherwise, it is set to the address of a new concrete 108 | // DeathTest object that controls the execution of the current test. 109 | static bool Create(const char* statement, Matcher matcher, 110 | const char* file, int line, DeathTest** test); 111 | DeathTest(); 112 | virtual ~DeathTest() = default; 113 | 114 | // A helper class that aborts a death test when it's deleted. 115 | class ReturnSentinel { 116 | public: 117 | explicit ReturnSentinel(DeathTest* test) : test_(test) {} 118 | ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } 119 | 120 | private: 121 | DeathTest* const test_; 122 | ReturnSentinel(const ReturnSentinel&) = delete; 123 | ReturnSentinel& operator=(const ReturnSentinel&) = delete; 124 | }; 125 | 126 | // An enumeration of possible roles that may be taken when a death 127 | // test is encountered. EXECUTE means that the death test logic should 128 | // be executed immediately. OVERSEE means that the program should prepare 129 | // the appropriate environment for a child process to execute the death 130 | // test, then wait for it to complete. 131 | enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; 132 | 133 | // An enumeration of the three reasons that a test might be aborted. 134 | enum AbortReason { 135 | TEST_ENCOUNTERED_RETURN_STATEMENT, 136 | TEST_THREW_EXCEPTION, 137 | TEST_DID_NOT_DIE 138 | }; 139 | 140 | // Assumes one of the above roles. 141 | virtual TestRole AssumeRole() = 0; 142 | 143 | // Waits for the death test to finish and returns its status. 144 | virtual int Wait() = 0; 145 | 146 | // Returns true if the death test passed; that is, the test process 147 | // exited during the test, its exit status matches a user-supplied 148 | // predicate, and its stderr output matches a user-supplied regular 149 | // expression. 150 | // The user-supplied predicate may be a macro expression rather 151 | // than a function pointer or functor, or else Wait and Passed could 152 | // be combined. 153 | virtual bool Passed(bool exit_status_ok) = 0; 154 | 155 | // Signals that the death test did not die as expected. 156 | virtual void Abort(AbortReason reason) = 0; 157 | 158 | // Returns a human-readable outcome message regarding the outcome of 159 | // the last death test. 160 | static const char* LastMessage(); 161 | 162 | static void set_last_death_test_message(const std::string& message); 163 | 164 | private: 165 | // A string containing a description of the outcome of the last death test. 166 | static std::string last_death_test_message_; 167 | 168 | DeathTest(const DeathTest&) = delete; 169 | DeathTest& operator=(const DeathTest&) = delete; 170 | }; 171 | 172 | GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 173 | 174 | // Factory interface for death tests. May be mocked out for testing. 175 | class DeathTestFactory { 176 | public: 177 | virtual ~DeathTestFactory() = default; 178 | virtual bool Create(const char* statement, 179 | Matcher matcher, const char* file, 180 | int line, DeathTest** test) = 0; 181 | }; 182 | 183 | // A concrete DeathTestFactory implementation for normal use. 184 | class DefaultDeathTestFactory : public DeathTestFactory { 185 | public: 186 | bool Create(const char* statement, Matcher matcher, 187 | const char* file, int line, DeathTest** test) override; 188 | }; 189 | 190 | // Returns true if exit_status describes a process that was terminated 191 | // by a signal, or exited normally with a nonzero exit code. 192 | GTEST_API_ bool ExitedUnsuccessfully(int exit_status); 193 | 194 | // Traps C++ exceptions escaping statement and reports them as test 195 | // failures. Note that trapping SEH exceptions is not implemented here. 196 | #if GTEST_HAS_EXCEPTIONS 197 | #define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ 198 | try { \ 199 | GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ 200 | } catch (const ::std::exception& gtest_exception) { \ 201 | fprintf( \ 202 | stderr, \ 203 | "\n%s: Caught std::exception-derived exception escaping the " \ 204 | "death test statement. Exception message: %s\n", \ 205 | ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ 206 | gtest_exception.what()); \ 207 | fflush(stderr); \ 208 | death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ 209 | } catch (...) { \ 210 | death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ 211 | } 212 | 213 | #else 214 | #define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ 215 | GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) 216 | 217 | #endif 218 | 219 | // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, 220 | // ASSERT_EXIT*, and EXPECT_EXIT*. 221 | #define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ 222 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ 223 | if (::testing::internal::AlwaysTrue()) { \ 224 | ::testing::internal::DeathTest* gtest_dt; \ 225 | if (!::testing::internal::DeathTest::Create( \ 226 | #statement, \ 227 | ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ 228 | __FILE__, __LINE__, >est_dt)) { \ 229 | goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ 230 | } \ 231 | if (gtest_dt != nullptr) { \ 232 | std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ 233 | switch (gtest_dt->AssumeRole()) { \ 234 | case ::testing::internal::DeathTest::OVERSEE_TEST: \ 235 | if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ 236 | goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ 237 | } \ 238 | break; \ 239 | case ::testing::internal::DeathTest::EXECUTE_TEST: { \ 240 | const ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ 241 | gtest_dt); \ 242 | GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ 243 | gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ 244 | break; \ 245 | } \ 246 | } \ 247 | } \ 248 | } else \ 249 | GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ 250 | : fail(::testing::internal::DeathTest::LastMessage()) 251 | // The symbol "fail" here expands to something into which a message 252 | // can be streamed. 253 | 254 | // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in 255 | // NDEBUG mode. In this case we need the statements to be executed and the macro 256 | // must accept a streamed message even though the message is never printed. 257 | // The regex object is not evaluated, but it is used to prevent "unused" 258 | // warnings and to avoid an expression that doesn't compile in debug mode. 259 | #define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ 260 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ 261 | if (::testing::internal::AlwaysTrue()) { \ 262 | GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ 263 | } else if (!::testing::internal::AlwaysTrue()) { \ 264 | ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ 265 | } else \ 266 | ::testing::Message() 267 | 268 | // A class representing the parsed contents of the 269 | // --gtest_internal_run_death_test flag, as it existed when 270 | // RUN_ALL_TESTS was called. 271 | class InternalRunDeathTestFlag { 272 | public: 273 | InternalRunDeathTestFlag(const std::string& a_file, int a_line, int an_index, 274 | int a_write_fd) 275 | : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} 276 | 277 | ~InternalRunDeathTestFlag() { 278 | if (write_fd_ >= 0) posix::Close(write_fd_); 279 | } 280 | 281 | const std::string& file() const { return file_; } 282 | int line() const { return line_; } 283 | int index() const { return index_; } 284 | int write_fd() const { return write_fd_; } 285 | 286 | private: 287 | std::string file_; 288 | int line_; 289 | int index_; 290 | int write_fd_; 291 | 292 | InternalRunDeathTestFlag(const InternalRunDeathTestFlag&) = delete; 293 | InternalRunDeathTestFlag& operator=(const InternalRunDeathTestFlag&) = delete; 294 | }; 295 | 296 | // Returns a newly created InternalRunDeathTestFlag object with fields 297 | // initialized from the GTEST_FLAG(internal_run_death_test) flag if 298 | // the flag is specified; otherwise returns NULL. 299 | InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); 300 | 301 | #endif // GTEST_HAS_DEATH_TEST 302 | 303 | } // namespace internal 304 | } // namespace testing 305 | 306 | #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ 307 | -------------------------------------------------------------------------------- /sigs.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | sigs 3 | 4 | Simple thread-safe signal/slot C++20 include-only library. 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2015-2020 Morten Kristensen, me AT mortens DOT dev 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 11 | associated documentation files (the "Software"), to deal in the Software without restriction, 12 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 13 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all copies or substantial 17 | portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 20 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 22 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | ***************************************************************************************************/ 25 | 26 | #ifndef SIGS_SIGNAL_SLOT_H 27 | #define SIGS_SIGNAL_SLOT_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | // The following is used for making variadic type lists for binding member functions and their 41 | // parameters. 42 | namespace sigs { 43 | 44 | template 45 | class Seq {}; 46 | 47 | template 48 | class MakeSeq : public MakeSeq {}; 49 | 50 | template 51 | class MakeSeq<0, Ns...> : public Seq {}; 52 | 53 | template 54 | class Placeholder {}; 55 | 56 | } // namespace sigs 57 | 58 | // std::bind uses std::is_placeholder to detect placeholders for unbounded arguments, so it must be 59 | // overridden to accept the custom sigs::Placeholder type. 60 | namespace std { 61 | 62 | template 63 | class is_placeholder> : public integral_constant {}; 64 | 65 | } // namespace std 66 | 67 | namespace sigs { 68 | 69 | /// When a member function has muliple overloads and you need to use just one of them. 70 | /** Example: 71 | signal.connect(&instance, sigs::Use::overloadOf(&TheClass::func)); 72 | */ 73 | template 74 | struct Use final { 75 | constexpr Use(const Use &) = delete; 76 | constexpr Use(Use &&) = delete; 77 | 78 | constexpr Use &operator=(const Use &) = delete; 79 | constexpr Use &operator=(Use &&) = delete; 80 | 81 | template 82 | [[nodiscard]] static constexpr auto overloadOf(Ret (Cls::*MembFunc)(Args...)) noexcept 83 | { 84 | return MembFunc; 85 | } 86 | }; 87 | 88 | class ConnectionBase final { 89 | template 90 | friend class BasicSignal; 91 | 92 | public: 93 | ConnectionBase() noexcept = default; 94 | ~ConnectionBase() noexcept = default; 95 | 96 | ConnectionBase(const ConnectionBase &) noexcept = default; 97 | ConnectionBase(ConnectionBase &&) noexcept = default; 98 | 99 | ConnectionBase &operator=(const ConnectionBase &) noexcept = default; 100 | ConnectionBase &operator=(ConnectionBase &&) noexcept = default; 101 | 102 | void disconnect() 103 | { 104 | if (deleter) deleter(); 105 | } 106 | 107 | private: 108 | std::function deleter; 109 | }; 110 | 111 | using Connection = std::shared_ptr; 112 | 113 | namespace detail { 114 | 115 | /// VoidableFunction is used internally to generate a function type depending on whether the return 116 | /// type of the signal is non-void. 117 | template 118 | class VoidableFunction final { 119 | public: 120 | using func = std::function; 121 | }; 122 | 123 | /// Specialization for void return types. 124 | template <> 125 | class VoidableFunction final { 126 | public: 127 | using func = std::function; 128 | }; 129 | 130 | } // namespace detail 131 | 132 | template 133 | class BasicSignal; 134 | 135 | template 136 | class SignalBlocker { 137 | static_assert(std::is_base_of_v, Sig>, 138 | "Sig must extend sigs::BasicSignal"); 139 | 140 | public: 141 | explicit constexpr SignalBlocker(Sig *sig) noexcept : sig_(sig) 142 | { 143 | reblock(); 144 | } 145 | 146 | explicit constexpr SignalBlocker(Sig &sig) noexcept : sig_(&sig) 147 | { 148 | reblock(); 149 | } 150 | 151 | virtual constexpr ~SignalBlocker() noexcept 152 | { 153 | unblock(); 154 | } 155 | 156 | constexpr SignalBlocker(const SignalBlocker &rhs) = delete; 157 | constexpr SignalBlocker &operator=(const SignalBlocker &rhs) = delete; 158 | 159 | constexpr SignalBlocker(SignalBlocker &&rhs) noexcept 160 | { 161 | moveAssign(std::move(rhs)); 162 | } 163 | 164 | /// Unblocks `this` if signals of `this` and `rhs` aren't the same. 165 | constexpr SignalBlocker &operator=(SignalBlocker &&rhs) noexcept 166 | { 167 | if (sig_ != rhs.sig_) { 168 | unblock(); 169 | } 170 | 171 | moveAssign(std::move(rhs)); 172 | return *this; 173 | } 174 | 175 | constexpr void reblock() noexcept 176 | { 177 | if (sig_) { 178 | previous = sig_->setBlocked(true); 179 | } 180 | } 181 | 182 | constexpr void unblock() noexcept 183 | { 184 | if (sig_) { 185 | sig_->setBlocked(previous); 186 | } 187 | } 188 | 189 | private: 190 | constexpr void moveAssign(SignalBlocker &&rhs) 191 | { 192 | sig_ = rhs.sig_; 193 | previous = rhs.previous; 194 | 195 | // `rhs` won't do any action on destruction. 196 | rhs.sig_ = nullptr; 197 | } 198 | 199 | Sig *sig_ = nullptr; 200 | bool previous = false; 201 | }; 202 | 203 | /// Suppress CTAD warning. 204 | template 205 | SignalBlocker(Sig) -> SignalBlocker; 206 | 207 | template 208 | class BasicSignal { 209 | public: 210 | using RetArgs = Ret(Args...); 211 | using SignalType = BasicSignal; 212 | using LockType = Lock; 213 | using ReturnType = Ret; 214 | 215 | private: 216 | using Slot = std::function; 217 | using Mutex = typename Lock::mutex_type; 218 | 219 | class Entry final { 220 | public: 221 | Entry(const Slot &slot, Connection conn) noexcept 222 | : slot_(slot), conn_(std::move(conn)), signal_(nullptr) 223 | { 224 | } 225 | 226 | Entry(Slot &&slot, Connection conn) noexcept 227 | : slot_(std::move(slot)), conn_(std::move(conn)), signal_(nullptr) 228 | { 229 | } 230 | 231 | Entry(BasicSignal *signal, Connection conn) noexcept : conn_(std::move(conn)), signal_(signal) 232 | { 233 | } 234 | 235 | constexpr const Slot &slot() const noexcept 236 | { 237 | return slot_; 238 | } 239 | 240 | constexpr BasicSignal *signal() const noexcept 241 | { 242 | return signal_; 243 | } 244 | 245 | [[nodiscard]] Connection conn() const noexcept 246 | { 247 | return conn_; 248 | } 249 | 250 | private: 251 | Slot slot_; 252 | Connection conn_; 253 | BasicSignal *signal_; 254 | }; 255 | 256 | using Cont = std::vector; 257 | 258 | public: 259 | using SlotType = Slot; 260 | 261 | /// Interface that only exposes connect and disconnect methods. 262 | class Interface final { 263 | public: 264 | explicit constexpr Interface(SignalType *sig) noexcept : sig_(sig) 265 | { 266 | } 267 | 268 | constexpr ~Interface() noexcept = default; 269 | 270 | constexpr Interface(const Interface &) = delete; 271 | constexpr Interface(Interface &&) = delete; 272 | 273 | constexpr Interface &operator=(const Interface &) = delete; 274 | constexpr Interface &operator=(Interface &&) = delete; 275 | 276 | Connection connect(const Slot &slot) noexcept 277 | { 278 | return sig_->connect(slot); 279 | } 280 | 281 | Connection connect(Slot &&slot) noexcept 282 | { 283 | return sig_->connect(std::move(slot)); 284 | } 285 | 286 | template 287 | Connection connect(Instance *instance, MembFunc Instance::*mf) noexcept 288 | { 289 | return sig_->connect(instance, mf); 290 | } 291 | 292 | Connection connect(BasicSignal &signal) noexcept 293 | { 294 | return sig_->connect(signal); 295 | } 296 | 297 | void disconnect(std::optional conn) noexcept 298 | { 299 | sig_->disconnect(conn); 300 | } 301 | 302 | constexpr void disconnect(BasicSignal &signal) noexcept 303 | { 304 | sig_->disconnect(signal); 305 | } 306 | 307 | private: 308 | SignalType *sig_ = nullptr; 309 | }; 310 | 311 | constexpr BasicSignal() noexcept = default; 312 | 313 | constexpr virtual ~BasicSignal() noexcept 314 | { 315 | Lock lock(entriesMutex); 316 | for (auto &entry : entries) { 317 | if (auto conn = entry.conn(); conn) { 318 | conn->deleter = nullptr; 319 | } 320 | } 321 | } 322 | 323 | constexpr BasicSignal(const BasicSignal &rhs) noexcept : BasicSignal() 324 | { 325 | Lock lock1(entriesMutex); 326 | Lock lock2(rhs.entriesMutex); 327 | entries = rhs.entries; 328 | 329 | // `atomic_bool` can't be copied, so copy value. 330 | blocked_ = rhs.blocked_.load(); 331 | } 332 | 333 | constexpr BasicSignal &operator=(const BasicSignal &rhs) noexcept 334 | { 335 | Lock lock1(entriesMutex); 336 | Lock lock2(rhs.entriesMutex); 337 | entries = rhs.entries; 338 | blocked_ = rhs.blocked_.load(); 339 | return *this; 340 | } 341 | 342 | constexpr BasicSignal(BasicSignal &&rhs) noexcept = default; 343 | constexpr BasicSignal &operator=(BasicSignal &&rhs) noexcept = default; 344 | 345 | constexpr std::size_t size() const noexcept 346 | { 347 | Lock lock(entriesMutex); 348 | return std::size(entries); 349 | } 350 | 351 | constexpr bool empty() const noexcept 352 | { 353 | return 0 == size(); 354 | } 355 | 356 | Connection connect(const Slot &slot) noexcept 357 | { 358 | Lock lock(entriesMutex); 359 | auto conn = makeConnection(); 360 | entries.emplace_back(Entry(slot, conn)); 361 | return conn; 362 | } 363 | 364 | Connection connect(Slot &&slot) noexcept 365 | { 366 | Lock lock(entriesMutex); 367 | auto conn = makeConnection(); 368 | entries.emplace_back(Entry(std::move(slot), conn)); 369 | return conn; 370 | } 371 | 372 | template 373 | Connection connect(Instance *instance, MembFunc Instance::*mf) noexcept 374 | { 375 | Lock lock(entriesMutex); 376 | auto slot = bindMf(instance, mf); 377 | auto conn = makeConnection(); 378 | entries.emplace_back(Entry(slot, conn)); 379 | return conn; 380 | } 381 | 382 | /// Connecting a signal will trigger all of its slots when this signal is triggered. 383 | Connection connect(BasicSignal &signal) noexcept 384 | { 385 | Lock lock(entriesMutex); 386 | auto conn = makeConnection(); 387 | entries.emplace_back(Entry(&signal, conn)); 388 | return conn; 389 | } 390 | 391 | constexpr void clear() noexcept 392 | { 393 | Lock lock(entriesMutex); 394 | eraseEntries(); 395 | } 396 | 397 | /// Disconnects \p conn from signal. 398 | /** If no value is given, all slots are disconnected. */ 399 | constexpr void disconnect(const std::optional &conn = std::nullopt) noexcept 400 | { 401 | if (!conn) { 402 | clear(); 403 | return; 404 | } 405 | 406 | Lock lock(entriesMutex); 407 | eraseEntries([conn](auto it) { return it->conn() == conn; }); 408 | } 409 | 410 | constexpr void disconnect(BasicSignal &signal) noexcept 411 | { 412 | assert(&signal != this && "Disconnecting from self has no effect."); 413 | 414 | Lock lock(entriesMutex); 415 | eraseEntries([sig = &signal](auto it) { return it->signal() == sig; }); 416 | } 417 | 418 | constexpr void operator()(Args &&...args) noexcept 419 | { 420 | if (blocked()) return; 421 | 422 | Lock lock(entriesMutex); 423 | for (auto &entry : entries) { 424 | if (auto *sig = entry.signal(); sig) { 425 | (*sig)(std::forward(args)...); 426 | } 427 | else { 428 | entry.slot()(std::forward(args)...); 429 | } 430 | } 431 | } 432 | 433 | template ::func> 434 | constexpr void operator()(const RetFunc &retFunc, Args &&...args) noexcept 435 | { 436 | static_assert(!std::is_void_v, "Must have non-void return type!"); 437 | 438 | if (blocked()) return; 439 | 440 | Lock lock(entriesMutex); 441 | for (auto &entry : entries) { 442 | if (auto *sig = entry.signal(); sig) { 443 | (*sig)(retFunc, std::forward(args)...); 444 | } 445 | else { 446 | retFunc(entry.slot()(std::forward(args)...)); 447 | } 448 | } 449 | } 450 | 451 | [[nodiscard]] constexpr std::unique_ptr interface() noexcept 452 | { 453 | return std::make_unique(this); 454 | } 455 | 456 | /// Returns the previous blocked state. 457 | constexpr bool setBlocked(bool blocked) 458 | { 459 | const auto previous = blocked_.load(); 460 | blocked_ = blocked; 461 | return previous; 462 | } 463 | 464 | constexpr bool blocked() const 465 | { 466 | return blocked_; 467 | } 468 | 469 | private: 470 | [[nodiscard]] Connection makeConnection() noexcept 471 | { 472 | auto conn = std::make_shared(); 473 | conn->deleter = [this, conn] { this->disconnect(conn); }; 474 | return conn; 475 | } 476 | 477 | /// Expects entries container to be locked beforehand. 478 | [[nodiscard]] constexpr typename Cont::iterator eraseEntry(typename Cont::iterator it) noexcept 479 | { 480 | auto conn = it->conn(); 481 | if (conn) { 482 | conn->deleter = nullptr; 483 | } 484 | return entries.erase(it); 485 | } 486 | 487 | constexpr void eraseEntries(std::function pred = 488 | [](auto /*unused*/) { return true; }) noexcept 489 | { 490 | for (auto it = entries.begin(); it != entries.end();) { 491 | if (pred(it)) { 492 | it = eraseEntry(it); 493 | } 494 | else { 495 | ++it; 496 | } 497 | } 498 | } 499 | 500 | template 501 | [[nodiscard]] constexpr Slot bindMf(Instance *instance, MembFunc Instance::*mf, 502 | Seq /*unused*/) noexcept 503 | { 504 | return std::bind(mf, instance, Placeholder()...); 505 | } 506 | 507 | template 508 | [[nodiscard]] constexpr Slot bindMf(Instance *instance, MembFunc Instance::*mf) noexcept 509 | { 510 | return bindMf(instance, mf, MakeSeq()); 511 | } 512 | 513 | Cont entries; 514 | mutable Mutex entriesMutex; 515 | std::atomic_bool blocked_ = false; 516 | }; 517 | 518 | using BasicLock = std::scoped_lock; 519 | 520 | /// Default signal types. 521 | //@{ 522 | 523 | template 524 | using Signal = BasicSignal; 525 | 526 | //@} 527 | 528 | } // namespace sigs 529 | 530 | #endif // SIGS_SIGNAL_SLOT_H 531 | --------------------------------------------------------------------------------