From 5f020288762fc8dba08050773befece941b76cf1 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 16:28:17 +0300 Subject: [PATCH 01/80] Added Common++ unit test project based on Gtest. --- Tests/CMakeLists.txt | 1 + Tests/Common++Test/CMakeLists.txt | 44 ++++++++++ Tests/Common++Test/Tests/IPAddressTests.cpp | 90 +++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 Tests/Common++Test/CMakeLists.txt create mode 100644 Tests/Common++Test/Tests/IPAddressTests.cpp diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index b36ff25a4d..0bfb577b9c 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,4 +1,5 @@ if(PCAPPP_BUILD_TESTS) + add_subdirectory(Common++Test) add_subdirectory(Packet++Test) add_subdirectory(Pcap++Test) add_subdirectory(PcppTestFramework) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt new file mode 100644 index 0000000000..8eb6f385a5 --- /dev/null +++ b/Tests/Common++Test/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.14) + +include(FetchContent) + +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.11.0 +) + +if(WIN32) + # Prevent overriding the parent project's compiler/linker settings. + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +endif() + +FetchContent_MakeAvailable(googletest) + + +add_executable( + Common++Test + Tests/IPAddressTests.cpp) + +target_link_libraries( + Common++Test + PRIVATE Common++ + gtest + gtest_main +) + +if(MSVC) + # This executable requires getopt.h not available on VStudio + target_link_libraries(Common++Test PRIVATE Getopt-for-Visual-Studio) +endif() + +set_property(TARGET Common++Test PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Bin") +set_property(TARGET Common++Test PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/Bin") +set_property(TARGET Common++Test PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/Bin") + +enable_testing() + +add_test( + NAME Common++Test + COMMAND $ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp new file mode 100644 index 0000000000..69171b14c2 --- /dev/null +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -0,0 +1,90 @@ +#include +#include + +#include "IpAddress.h" + +namespace pcpp +{ + TEST(IPv4AddressTest, IPv4AddressStatics) + { + IPv4Address const& ipZero = IPv4Address::Zero; + EXPECT_EQ(ipZero.toInt(), 0); + EXPECT_EQ(ipZero.toString(), "0.0.0.0"); + + IPv4Address const& ipMulticastLower = IPv4Address::MulticastRangeLowerBound; + EXPECT_EQ(ipMulticastLower.toInt(), 0x000000E0); + EXPECT_EQ(ipMulticastLower.toString(), "224.0.0.0"); + + IPv4Address const& ipMulticastUpper = IPv4Address::MulticastRangeUpperBound; + EXPECT_EQ(ipMulticastUpper.toInt(), 0xFFFFFFEF); + EXPECT_EQ(ipMulticastUpper.toString(), "239.255.255.255"); + + EXPECT_TRUE(IPv4Address::isValidIPv4Address("222.146.254.245")); + EXPECT_FALSE(IPv4Address::isValidIPv4Address("222.146.300.245")); + EXPECT_FALSE(IPv4Address::isValidIPv4Address("bogus string")); + } + + TEST(IPv4AddressTest, IPv4AddressBasics) + { + IPv4Address ipDefault; + EXPECT_EQ(ipDefault.toInt(), 0); + EXPECT_EQ(ipDefault.toString(), "0.0.0.0"); + EXPECT_EQ(ipDefault, pcpp::IPv4Address::Zero); + + IPv4Address ipString("0.0.0.1"); + EXPECT_EQ(ipString.toInt(), 0x01000000); + EXPECT_EQ(ipString.toString(), "0.0.0.1"); + EXPECT_THROW(IPv4Address("0.0.0.644"), std::invalid_argument) << "IPv4Address does not throw for out of bounds IP string."; + EXPECT_THROW(IPv4Address("bogusString"), std::invalid_argument) << "IPv4Address does not throw for non-IP string."; + + IPv4Address ipUint32(0x085201A0); + EXPECT_EQ(ipUint32.toInt(), 0x085201A0); + EXPECT_EQ(ipUint32.toString(), "160.1.82.8"); + + std::array ipArrayBuffer = {192, 100, 1, 1}; + IPv4Address ipUint8Raw(ipArrayBuffer.data()); + EXPECT_EQ(ipUint8Raw.toInt(), 0x010164C0); + EXPECT_EQ(ipUint8Raw.toString(), "192.100.1.1"); + EXPECT_EQ(ipUint8Raw.toByteArray(), ipArrayBuffer); + EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), ipUint8Raw.toBytes(), 4)); + + IPv4Address ipUint8Array(ipArrayBuffer); + EXPECT_EQ(ipUint8Array.toInt(), 0x010164C0); + EXPECT_EQ(ipUint8Array.toString(), "192.100.1.1"); + EXPECT_EQ(ipUint8Array.toByteArray(), ipArrayBuffer); + EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), ipUint8Array.toBytes(), 4)); + + EXPECT_EQ(ipUint8Raw, ipUint8Array) << "Comparison operator '==' does not compare equal values."; + EXPECT_NE(ipUint8Raw, ipDefault) << "Comparison operator '!=' does not compare unequal values."; + }; + + TEST(IPv4AddressTest, Multicast) + { + FAIL() << "Not Implemented"; + } + + TEST(IPv6AddressTest, IPv6AddressTest) + { + FAIL() << "Not Implemented"; + }; + + TEST(IPAddressTest, IPAddressTest) + { + FAIL() << "Not Implemented"; + } + + TEST(IPv4NetworkTest, IPv4NetworkTest) + { + FAIL() << "Not Implemented"; + } + + TEST(IPv6NetworkTest, IPv6NetworkTest) + { + FAIL() << "Not Implemented"; + } + + TEST(IPNetworkTest, IPNetworkTest) + { + FAIL() << "Not Implemented"; + } +} // namespace pcpp \ No newline at end of file From 0687ddd76aa9612b75b18291ca848f0a132e136a Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 16:37:19 +0300 Subject: [PATCH 02/80] Fixed includes. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 69171b14c2..76bdf2f2e9 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "IpAddress.h" @@ -22,7 +23,7 @@ namespace pcpp EXPECT_TRUE(IPv4Address::isValidIPv4Address("222.146.254.245")); EXPECT_FALSE(IPv4Address::isValidIPv4Address("222.146.300.245")); EXPECT_FALSE(IPv4Address::isValidIPv4Address("bogus string")); - } + }; TEST(IPv4AddressTest, IPv4AddressBasics) { @@ -61,7 +62,7 @@ namespace pcpp TEST(IPv4AddressTest, Multicast) { FAIL() << "Not Implemented"; - } + }; TEST(IPv6AddressTest, IPv6AddressTest) { @@ -71,20 +72,20 @@ namespace pcpp TEST(IPAddressTest, IPAddressTest) { FAIL() << "Not Implemented"; - } + }; TEST(IPv4NetworkTest, IPv4NetworkTest) { FAIL() << "Not Implemented"; - } + }; TEST(IPv6NetworkTest, IPv6NetworkTest) { FAIL() << "Not Implemented"; - } + }; TEST(IPNetworkTest, IPNetworkTest) { FAIL() << "Not Implemented"; - } + }; } // namespace pcpp \ No newline at end of file From a004e3c19c7db8f7ffb808a739b931304eb6f2ce Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 17:11:00 +0300 Subject: [PATCH 03/80] Changed gtest version to 1.12 which is the last to support Cpp11. --- Tests/Common++Test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 8eb6f385a5..218f1eaede 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -5,7 +5,7 @@ include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.11.0 + GIT_TAG release-1.12.0 ) if(WIN32) From 94a3b0ef9dce775d7c01f24f1e7efa7cbf61fac4 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 17:15:27 +0300 Subject: [PATCH 04/80] Added Gmock in addition to Gtest. --- Tests/Common++Test/CMakeLists.txt | 3 +- Tests/Common++Test/Tests/IPAddressTests.cpp | 43 +++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 218f1eaede..3ab3e30728 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -24,7 +24,8 @@ target_link_libraries( Common++Test PRIVATE Common++ gtest - gtest_main + gmock + gmock_main ) if(MSVC) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 76bdf2f2e9..4318460795 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "IpAddress.h" @@ -55,17 +56,53 @@ namespace pcpp EXPECT_EQ(ipUint8Array.toByteArray(), ipArrayBuffer); EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), ipUint8Array.toBytes(), 4)); - EXPECT_EQ(ipUint8Raw, ipUint8Array) << "Comparison operator '==' does not compare equal values."; - EXPECT_NE(ipUint8Raw, ipDefault) << "Comparison operator '!=' does not compare unequal values."; + EXPECT_TRUE(ipUint8Raw == ipUint8Array) << "Comparison operator '==' does not compare equal values correctly."; + EXPECT_FALSE(ipUint8Raw == ipDefault) << "Comparison operator '==' does not compare unequal values correctly."; + EXPECT_FALSE(ipUint8Raw != ipUint8Array) << "Comparison operator '!=' does not compare equal values correctly."; + EXPECT_TRUE(ipUint8Raw != ipDefault) << "Comparison operator '!=' does not compare unequal values correctly."; + + EXPECT_TRUE(ipDefault < ipString) << "Comparison operator '<' does not compare less than values correctly."; + EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; }; TEST(IPv4AddressTest, Multicast) + { + IPv4Address underMulticastBound(0x000000D1); + EXPECT_FALSE(underMulticastBound.isMulticast()); + + IPv4Address atLowerMulticastBound(0x000000E0); + EXPECT_TRUE(atLowerMulticastBound.isMulticast()); + + IPv4Address inMulticastRange(0x000000EF); + EXPECT_TRUE(inMulticastRange.isMulticast()); + + IPv4Address atUpperMulticastBound(0xFFFFFFEF); + EXPECT_TRUE(atUpperMulticastBound.isMulticast()); + + IPv4Address overMulticastBound(0x000000F0); + EXPECT_FALSE(overMulticastBound.isMulticast()); + }; + + TEST(IPv4AddressTest, MatchNetwork) { FAIL() << "Not Implemented"; }; - TEST(IPv6AddressTest, IPv6AddressTest) + TEST(IPv6AddressTest, IPv6Statics) + { + IPv6Address const& ipZero = IPv6Address::Zero; + EXPECT_EQ(ipZero.toString(), "::"); + EXPECT_THAT(ipZero.toByteArray(), ::testing::Each(0)); + + IPv6Address const& ipMulticastLower = IPv6Address::MulticastRangeLowerBound; + EXPECT_EQ(ipMulticastLower.toString(), "ff00::"); + EXPECT_THAT(ipMulticastLower.toByteArray(), ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00)); + }; + + TEST(IPv6AddressTest, IPv6AddressBasics) { + IPv6Address ipDefault; + FAIL() << "Not Implemented"; }; From be20d78157772f230c2c567c6f47cc15c71bd72b Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 17:26:13 +0300 Subject: [PATCH 05/80] Added IPv6 tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 34 ++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 4318460795..a297ec1053 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -88,7 +88,7 @@ namespace pcpp FAIL() << "Not Implemented"; }; - TEST(IPv6AddressTest, IPv6Statics) + TEST(IPv6AddressTest, IPv6AddressStatics) { IPv6Address const& ipZero = IPv6Address::Zero; EXPECT_EQ(ipZero.toString(), "::"); @@ -96,14 +96,40 @@ namespace pcpp IPv6Address const& ipMulticastLower = IPv6Address::MulticastRangeLowerBound; EXPECT_EQ(ipMulticastLower.toString(), "ff00::"); - EXPECT_THAT(ipMulticastLower.toByteArray(), ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00)); + EXPECT_THAT(ipMulticastLower.toByteArray(), + ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); }; TEST(IPv6AddressTest, IPv6AddressBasics) { IPv6Address ipDefault; - - FAIL() << "Not Implemented"; + EXPECT_EQ(ipDefault.toString(), "::"); + EXPECT_THAT(ipDefault.toByteArray(), ::testing::Each(0)); + + IPv6Address ipString("2001:0db8:85a3:0000:0000:8a4e:0370:7334"); + EXPECT_EQ(ipString.toString(), "2001:db8:85a3::8a4e:370:7334"); + EXPECT_THAT(ipString.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x4E, 0x03, 0x70, 0x73, 0x34)); + + EXPECT_THROW(IPv6Address("2001:0db8:85a3:0000:0000:8a4e:0370:7334:extra"), std::invalid_argument) << "IPv6Address does not throw for out of bounds IP string."; + EXPECT_THROW(IPv6Address("bogusString"), std::invalid_argument) << "IPv6Address does not throw for non-IP string."; + + std::array ipArrayBuffer = {0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34}; + + IPv6Address ipUint8Raw(ipArrayBuffer.data()); + EXPECT_EQ(ipUint8Raw.toString(), "2001:db8:85a3::8a2e:370:7334"); + EXPECT_THAT(ipUint8Raw.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); + + IPv6Address ipUint8Array(ipArrayBuffer); + EXPECT_EQ(ipUint8Array.toString(), "2001:db8:85a3::8a2e:370:7334"); + EXPECT_THAT(ipUint8Array.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); + + EXPECT_TRUE(ipUint8Raw == ipUint8Array) << "Comparison operator '==' does not compare equal values correctly."; + EXPECT_FALSE(ipUint8Raw == ipDefault) << "Comparison operator '==' does not compare unequal values correctly."; + EXPECT_FALSE(ipUint8Raw != ipUint8Array) << "Comparison operator '!=' does not compare equal values correctly."; + EXPECT_TRUE(ipUint8Raw != ipDefault) << "Comparison operator '!=' does not compare unequal values correctly."; + + EXPECT_TRUE(ipDefault < ipString) << "Comparison operator '<' does not compare less than values correctly."; + EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; }; TEST(IPAddressTest, IPAddressTest) From 3395ac76814e7381484697fed551984e88ac3e92 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 17:51:13 +0300 Subject: [PATCH 06/80] Added IPAddress tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 109 +++++++++++++++++--- 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index a297ec1053..3bf78f3c78 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -36,14 +36,16 @@ namespace pcpp IPv4Address ipString("0.0.0.1"); EXPECT_EQ(ipString.toInt(), 0x01000000); EXPECT_EQ(ipString.toString(), "0.0.0.1"); - EXPECT_THROW(IPv4Address("0.0.0.644"), std::invalid_argument) << "IPv4Address does not throw for out of bounds IP string."; - EXPECT_THROW(IPv4Address("bogusString"), std::invalid_argument) << "IPv4Address does not throw for non-IP string."; + EXPECT_THROW(IPv4Address("0.0.0.644"), std::invalid_argument) + << "IPv4Address does not throw for out of bounds IP string."; + EXPECT_THROW(IPv4Address("bogusString"), std::invalid_argument) + << "IPv4Address does not throw for non-IP string."; IPv4Address ipUint32(0x085201A0); EXPECT_EQ(ipUint32.toInt(), 0x085201A0); EXPECT_EQ(ipUint32.toString(), "160.1.82.8"); - std::array ipArrayBuffer = {192, 100, 1, 1}; + std::array ipArrayBuffer = { 192, 100, 1, 1 }; IPv4Address ipUint8Raw(ipArrayBuffer.data()); EXPECT_EQ(ipUint8Raw.toInt(), 0x010164C0); EXPECT_EQ(ipUint8Raw.toString(), "192.100.1.1"); @@ -75,10 +77,10 @@ namespace pcpp IPv4Address inMulticastRange(0x000000EF); EXPECT_TRUE(inMulticastRange.isMulticast()); - + IPv4Address atUpperMulticastBound(0xFFFFFFEF); EXPECT_TRUE(atUpperMulticastBound.isMulticast()); - + IPv4Address overMulticastBound(0x000000F0); EXPECT_FALSE(overMulticastBound.isMulticast()); }; @@ -97,7 +99,8 @@ namespace pcpp IPv6Address const& ipMulticastLower = IPv6Address::MulticastRangeLowerBound; EXPECT_EQ(ipMulticastLower.toString(), "ff00::"); EXPECT_THAT(ipMulticastLower.toByteArray(), - ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); + ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00)); }; TEST(IPv6AddressTest, IPv6AddressBasics) @@ -108,20 +111,28 @@ namespace pcpp IPv6Address ipString("2001:0db8:85a3:0000:0000:8a4e:0370:7334"); EXPECT_EQ(ipString.toString(), "2001:db8:85a3::8a4e:370:7334"); - EXPECT_THAT(ipString.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x4E, 0x03, 0x70, 0x73, 0x34)); + EXPECT_THAT(ipString.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, + 0x00, 0x8A, 0x4E, 0x03, 0x70, 0x73, 0x34)); - EXPECT_THROW(IPv6Address("2001:0db8:85a3:0000:0000:8a4e:0370:7334:extra"), std::invalid_argument) << "IPv6Address does not throw for out of bounds IP string."; - EXPECT_THROW(IPv6Address("bogusString"), std::invalid_argument) << "IPv6Address does not throw for non-IP string."; + EXPECT_THROW(IPv6Address("2001:0db8:85a3:0000:0000:8a4e:0370:7334:extra"), std::invalid_argument) + << "IPv6Address does not throw for out of bounds IP string."; + EXPECT_THROW(IPv6Address("2001::ab01::c"), std::invalid_argument) + << "IPv6Address does not throw for multiple double colon in IP string."; + EXPECT_THROW(IPv6Address("bogusString"), std::invalid_argument) + << "IPv6Address does not throw for non-IP string."; - std::array ipArrayBuffer = {0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34}; + std::array ipArrayBuffer = { 0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, + 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34 }; IPv6Address ipUint8Raw(ipArrayBuffer.data()); EXPECT_EQ(ipUint8Raw.toString(), "2001:db8:85a3::8a2e:370:7334"); - EXPECT_THAT(ipUint8Raw.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); + EXPECT_THAT(ipUint8Raw.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, + 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); IPv6Address ipUint8Array(ipArrayBuffer); EXPECT_EQ(ipUint8Array.toString(), "2001:db8:85a3::8a2e:370:7334"); - EXPECT_THAT(ipUint8Array.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); + EXPECT_THAT(ipUint8Array.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, + 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); EXPECT_TRUE(ipUint8Raw == ipUint8Array) << "Comparison operator '==' does not compare equal values correctly."; EXPECT_FALSE(ipUint8Raw == ipDefault) << "Comparison operator '==' does not compare unequal values correctly."; @@ -130,9 +141,81 @@ namespace pcpp EXPECT_TRUE(ipDefault < ipString) << "Comparison operator '<' does not compare less than values correctly."; EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; + + std::array outBuffer = {}; + ipUint8Array.copyTo(outBuffer.data()); + EXPECT_EQ(ipUint8Array.toByteArray(), outBuffer); + + uint8_t* heapOutBuffer = nullptr; + std::size_t heapOutBufferSize = 0; + ipUint8Array.copyTo(&heapOutBuffer, heapOutBufferSize); + + ASSERT_NE(heapOutBuffer, nullptr); + EXPECT_EQ(heapOutBufferSize, 16); + EXPECT_THAT(heapOutBuffer, ::testing::ElementsAreArray(ipUint8Array.toByteArray())); + delete[] heapOutBuffer; + }; + + TEST(IPv6AddressTest, Multicast) + { + IPv6Address underMulticastBound("fef0::"); + EXPECT_FALSE(underMulticastBound.isMulticast()); + + IPv6Address atLowerMulticastBound("ff00::"); + EXPECT_TRUE(atLowerMulticastBound.isMulticast()); + + IPv6Address inMulticastRange("ff00::ef"); + EXPECT_TRUE(inMulticastRange.isMulticast()); + }; + + TEST(IPv6AddressTest, MatchNetwork) + { + FAIL() << "Not Implemented"; + }; + + TEST(IPAddressTest, IPAddressBasics) + { + IPAddress ipDefault; + EXPECT_EQ(ipDefault.getType(), IPAddress::AddressType::IPv4AddressType); + EXPECT_EQ(ipDefault.getIPv4(), IPv4Address::Zero); + EXPECT_TRUE(ipDefault.isZero()); + EXPECT_EQ(ipDefault.toString(), "0.0.0.0"); + + IPAddress ip4String("192.168.0.1"); + EXPECT_EQ(ip4String.getType(), IPAddress::AddressType::IPv4AddressType); + EXPECT_EQ(ip4String.getIPv4(), IPv4Address("192.168.0.1")); + EXPECT_FALSE(ip4String.isZero()); + EXPECT_EQ(ip4String.toString(), "192.168.0.1"); + + IPAddress ip6ZeroString("::"); + EXPECT_EQ(ip6ZeroString.getType(), IPAddress::AddressType::IPv6AddressType); + EXPECT_EQ(ip6ZeroString.getIPv6(), IPv6Address::Zero); + EXPECT_TRUE(ip6ZeroString.isZero()); + EXPECT_EQ(ip6ZeroString.toString(), "::"); + + IPAddress ip6String("2001:db8:85a3::8a2e:370:7334"); + EXPECT_EQ(ip6String.getType(), IPAddress::AddressType::IPv6AddressType); + EXPECT_EQ(ip6String.getIPv6(), IPv6Address("2001:db8:85a3::8a2e:370:7334")); + EXPECT_FALSE(ip6String.isZero()); + EXPECT_EQ(ip6String.toString(), "2001:db8:85a3::8a2e:370:7334"); + + EXPECT_THROW(IPAddress("192.168.300.1"), std::invalid_argument); + EXPECT_THROW(IPAddress("2001:db8:85a3::8a2e:370:7334:extra"), std::invalid_argument) + << "IPAddress does not throw for out of bounds IP string."; + EXPECT_THROW(IPv6Address("2001::ab01::c"), std::invalid_argument) + << "IPAddress does not throw for multiple double colon in IP string."; + EXPECT_THROW(IPAddress("bogusString"), std::invalid_argument) << "IPAddress does not throw for non-IP string."; + + EXPECT_TRUE(ipDefault == IPv4Address::Zero) << "Comparison operator '==' does not compare equal values correctly."; + EXPECT_FALSE(ipDefault != IPv4Address::Zero) << "Comparison operator '!=' does not compare equal values correctly."; + + EXPECT_FALSE(ipDefault == ip6ZeroString) << "Comparison operator '==' between IPv4 and IPv6 should always return false"; + EXPECT_TRUE(ipDefault != ip6ZeroString) << "Comparison operator '!=' between IPv4 and IPv6 should always return true"; + + // Todo: less than operator }; - TEST(IPAddressTest, IPAddressTest) + TEST(IPAddressTest, Multicast) { FAIL() << "Not Implemented"; }; From 55fdf10bf7218b0010b65249f0f7d2c91ff8a8aa Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 17:51:47 +0300 Subject: [PATCH 07/80] Lint --- Tests/Common++Test/Tests/IPAddressTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 3bf78f3c78..734514aa2c 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -234,4 +234,4 @@ namespace pcpp { FAIL() << "Not Implemented"; }; -} // namespace pcpp \ No newline at end of file +} // namespace pcpp From f447d9c98519601fed6e1719c44cccb85673894f Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 18:01:10 +0300 Subject: [PATCH 08/80] Fixed matcher error. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 734514aa2c..ce14b3ec1f 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -152,7 +152,7 @@ namespace pcpp ASSERT_NE(heapOutBuffer, nullptr); EXPECT_EQ(heapOutBufferSize, 16); - EXPECT_THAT(heapOutBuffer, ::testing::ElementsAreArray(ipUint8Array.toByteArray())); + EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), heapOutBuffer, 16)); delete[] heapOutBuffer; }; From 5b37a1f1a5c4219f7ad373cef6e026627bd8c874 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 18:34:02 +0300 Subject: [PATCH 09/80] Added _ipv4 and _ipv6 string literals. --- Common++/header/IpAddress.h | 13 +++++++++++++ Tests/Common++Test/Tests/IPAddressTests.cpp | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Common++/header/IpAddress.h b/Common++/header/IpAddress.h index 243dae0ef9..45f5b657ce 100644 --- a/Common++/header/IpAddress.h +++ b/Common++/header/IpAddress.h @@ -1082,6 +1082,19 @@ namespace pcpp std::unique_ptr m_IPv4Network; std::unique_ptr m_IPv6Network; }; + + namespace literals + { + inline IPv4Address operator""_ipv4(const char* addrString, std::size_t size) + { + return IPv4Address(std::string(addrString, size)); + } + + inline IPv6Address operator""_ipv6(const char* addrString, std::size_t size) + { + return IPv6Address(std::string(addrString, size)); + } + } } // namespace pcpp inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Address& ipv4Address) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index ce14b3ec1f..c5552e91d1 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -67,6 +67,14 @@ namespace pcpp EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; }; + TEST(IPv4AddressTest, Literals) + { + using namespace pcpp::literals; + + IPv4Address ipString = "192.168.1.5"_ipv4; + EXPECT_EQ(ipString.toInt(), 0x0501A8C0); + } + TEST(IPv4AddressTest, Multicast) { IPv4Address underMulticastBound(0x000000D1); @@ -156,6 +164,15 @@ namespace pcpp delete[] heapOutBuffer; }; + TEST(IPv6AddressTest, Literals) + { + using namespace pcpp::literals; + + IPv6Address ipString = "2001:0db8:85a3:0000:0000:8a4e:0370:7334"_ipv6; + EXPECT_THAT(ipString.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, + 0x00, 0x8A, 0x4E, 0x03, 0x70, 0x73, 0x34)); + } + TEST(IPv6AddressTest, Multicast) { IPv6Address underMulticastBound("fef0::"); From 12e4599fe48cdb0b5da038ca3f3b9a485d7c59d5 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 18:43:23 +0300 Subject: [PATCH 10/80] Added IPv4 Network unit tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 47 ++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index c5552e91d1..bb561e9a1a 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -237,7 +237,52 @@ namespace pcpp FAIL() << "Not Implemented"; }; - TEST(IPv4NetworkTest, IPv4NetworkTest) + TEST(IPv4NetworkTest, IPv4NetworkBasics) + { + using namespace pcpp::literals; + + IPv4Network netSingle("192.168.1.1"_ipv4); + EXPECT_EQ(netSingle.getPrefixLen(), 32u); + EXPECT_EQ(netSingle.getNetmask(), "255.255.255.255"); + EXPECT_EQ(netSingle.getNetworkPrefix(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingle.getLowestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingle.getHighestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingle.getTotalAddressCount(), 1); + + IPv4Network netPrefix("192.168.1.1"_ipv4, 24u); + EXPECT_EQ(netPrefix.getPrefixLen(), 24u); + EXPECT_EQ(netPrefix.getNetmask(), "255.255.255.0"); + EXPECT_EQ(netPrefix.getNetworkPrefix(), "192.168.1.0"_ipv4); + EXPECT_EQ(netPrefix.getLowestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netPrefix.getHighestAddress(), "192.168.1.254"_ipv4); + EXPECT_EQ(netPrefix.getTotalAddressCount(), 256); + + IPv4Network netNetmask("192.168.1.1"_ipv4, "255.255.0.0"); + EXPECT_EQ(netNetmask.getPrefixLen(), 16u); + EXPECT_EQ(netNetmask.getNetmask(), "255.255.0.0"); + EXPECT_EQ(netNetmask.getNetworkPrefix(), "192.168.0.0"_ipv4); + EXPECT_EQ(netNetmask.getLowestAddress(), "192.168.0.1"_ipv4); + EXPECT_EQ(netNetmask.getHighestAddress(), "192.168.255.254"_ipv4); + EXPECT_EQ(netNetmask.getTotalAddressCount(), 256 * 256); + + IPv4Network netStringWithPrefix("192.168.1.1/8"); + EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 8u); + EXPECT_EQ(netStringWithPrefix.getNetmask(), "255.0.0.0"); + EXPECT_EQ(netStringWithPrefix.getNetworkPrefix(), "192.0.0.0"_ipv4); + EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "192.0.0.1"_ipv4); + EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "192.255.255.254"_ipv4); + EXPECT_EQ(netStringWithPrefix.getTotalAddressCount(), 256 * 256 * 256); + + IPv4Network netStringWithMask("192.168.1.1/255.0.0.0"); + EXPECT_EQ(netStringWithMask.getPrefixLen(), 8u); + EXPECT_EQ(netStringWithMask.getNetmask(), "255.0.0.0"); + EXPECT_EQ(netStringWithMask.getNetworkPrefix(), "192.0.0.0"_ipv4); + EXPECT_EQ(netStringWithMask.getLowestAddress(), "192.0.0.1"_ipv4); + EXPECT_EQ(netStringWithMask.getHighestAddress(), "192.255.255.254"_ipv4); + EXPECT_EQ(netStringWithMask.getTotalAddressCount(), 256 * 256 * 256); + }; + + TEST(IPv4NetworkTest, IPv4NetworkIncludes) { FAIL() << "Not Implemented"; }; From 0f20bb969c936bf3263dbafee754a5a96768cd6e Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 19:17:52 +0300 Subject: [PATCH 11/80] Added IPv6 Network unit tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 54 ++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index bb561e9a1a..2a7d68eaf5 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -287,12 +287,62 @@ namespace pcpp FAIL() << "Not Implemented"; }; - TEST(IPv6NetworkTest, IPv6NetworkTest) + TEST(IPv6NetworkTest, IPv6NetworkBasics) + { + using namespace pcpp::literals; + + IPv6Network netSingle("2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingle.getPrefixLen(), 128u); + EXPECT_EQ(netSingle.getNetmask(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + EXPECT_EQ(netSingle.getNetworkPrefix(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingle.getLowestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingle.getHighestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingle.getTotalAddressCount(), 1); + + IPv6Network netPrefix("2001:db8:85a3::8a2e:370:7334"_ipv6, 96u); + EXPECT_EQ(netPrefix.getPrefixLen(), 96u); + EXPECT_EQ(netPrefix.getNetmask(), "ffff:ffff:ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netPrefix.getNetworkPrefix(), "2001:db8:85a3::8a2e:0:0"_ipv6); + EXPECT_EQ(netPrefix.getLowestAddress(), "2001:db8:85a3::8a2e:0:1"_ipv6); + EXPECT_EQ(netPrefix.getHighestAddress(), "2001:db8:85a3::8a2e:ffff:ffff"_ipv6); + EXPECT_EQ(netPrefix.getTotalAddressCount(), 4294967296ul); + + IPv6Network netNetmask("2001:db8:85a3::8a2e:370:7334"_ipv6, "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netNetmask.getPrefixLen(), 64u); + EXPECT_EQ(netNetmask.getNetmask(), "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netNetmask.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); + EXPECT_EQ(netNetmask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); + EXPECT_EQ(netNetmask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); + EXPECT_THROW(netNetmask.getTotalAddressCount(), std::out_of_range); + + IPv6Network netStringWithPrefix("2001:db8:85a3::8a2e:370:7334/64"); + EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 64u); + EXPECT_EQ(netStringWithPrefix.getNetmask(), "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netStringWithPrefix.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); + EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "2001:db8:85a3::1"_ipv6); + EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); + EXPECT_THROW(netStringWithPrefix.getTotalAddressCount(), std::out_of_range); + + IPv6Network netStringWithMask("2001:db8:85a3::8a2e:370:7334/ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netStringWithMask.getPrefixLen(), 64u); + EXPECT_EQ(netStringWithMask.getNetmask(), "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netStringWithMask.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); + EXPECT_EQ(netStringWithMask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); + EXPECT_EQ(netStringWithMask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); + EXPECT_THROW(netStringWithMask.getTotalAddressCount(), std::out_of_range); + }; + + TEST(IPv6NetworkTest, IPv6NetworkIncludes) + { + FAIL() << "Not Implemented"; + }; + + TEST(IPNetworkTest, IPNetworkBasics) { FAIL() << "Not Implemented"; }; - TEST(IPNetworkTest, IPNetworkTest) + TEST(IPNetworkTest, IPNetworkIncludes) { FAIL() << "Not Implemented"; }; From a2718d8fce5b066630bded4fe2250089ba1a83f7 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 21 Jul 2024 19:34:25 +0300 Subject: [PATCH 12/80] Added IPNetwork unit tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 34 ++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 2a7d68eaf5..1b20d1d0db 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -248,6 +248,7 @@ namespace pcpp EXPECT_EQ(netSingle.getLowestAddress(), "192.168.1.1"_ipv4); EXPECT_EQ(netSingle.getHighestAddress(), "192.168.1.1"_ipv4); EXPECT_EQ(netSingle.getTotalAddressCount(), 1); + EXPECT_EQ(netSingle.toString(), "192.168.1.1/32"); IPv4Network netPrefix("192.168.1.1"_ipv4, 24u); EXPECT_EQ(netPrefix.getPrefixLen(), 24u); @@ -256,6 +257,7 @@ namespace pcpp EXPECT_EQ(netPrefix.getLowestAddress(), "192.168.1.1"_ipv4); EXPECT_EQ(netPrefix.getHighestAddress(), "192.168.1.254"_ipv4); EXPECT_EQ(netPrefix.getTotalAddressCount(), 256); + EXPECT_EQ(netPrefix.toString(), "192.168.1.0/24"); IPv4Network netNetmask("192.168.1.1"_ipv4, "255.255.0.0"); EXPECT_EQ(netNetmask.getPrefixLen(), 16u); @@ -264,6 +266,7 @@ namespace pcpp EXPECT_EQ(netNetmask.getLowestAddress(), "192.168.0.1"_ipv4); EXPECT_EQ(netNetmask.getHighestAddress(), "192.168.255.254"_ipv4); EXPECT_EQ(netNetmask.getTotalAddressCount(), 256 * 256); + EXPECT_EQ(netNetmask.toString(), "192.168.0.0/16"); IPv4Network netStringWithPrefix("192.168.1.1/8"); EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 8u); @@ -272,6 +275,7 @@ namespace pcpp EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "192.0.0.1"_ipv4); EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "192.255.255.254"_ipv4); EXPECT_EQ(netStringWithPrefix.getTotalAddressCount(), 256 * 256 * 256); + EXPECT_EQ(netStringWithPrefix.toString(), "192.0.0.0/8"); IPv4Network netStringWithMask("192.168.1.1/255.0.0.0"); EXPECT_EQ(netStringWithMask.getPrefixLen(), 8u); @@ -280,6 +284,7 @@ namespace pcpp EXPECT_EQ(netStringWithMask.getLowestAddress(), "192.0.0.1"_ipv4); EXPECT_EQ(netStringWithMask.getHighestAddress(), "192.255.255.254"_ipv4); EXPECT_EQ(netStringWithMask.getTotalAddressCount(), 256 * 256 * 256); + EXPECT_EQ(netStringWithMask.toString(), "192.0.0.0/8"); }; TEST(IPv4NetworkTest, IPv4NetworkIncludes) @@ -298,6 +303,7 @@ namespace pcpp EXPECT_EQ(netSingle.getLowestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); EXPECT_EQ(netSingle.getHighestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); EXPECT_EQ(netSingle.getTotalAddressCount(), 1); + EXPECT_EQ(netSingle.toString(), "2001:db8:85a3::8a2e:370:7334/128"); IPv6Network netPrefix("2001:db8:85a3::8a2e:370:7334"_ipv6, 96u); EXPECT_EQ(netPrefix.getPrefixLen(), 96u); @@ -306,6 +312,7 @@ namespace pcpp EXPECT_EQ(netPrefix.getLowestAddress(), "2001:db8:85a3::8a2e:0:1"_ipv6); EXPECT_EQ(netPrefix.getHighestAddress(), "2001:db8:85a3::8a2e:ffff:ffff"_ipv6); EXPECT_EQ(netPrefix.getTotalAddressCount(), 4294967296ul); + EXPECT_EQ(netPrefix.toString(), "2001:db8:85a3::8a2e:0:0/96"); IPv6Network netNetmask("2001:db8:85a3::8a2e:370:7334"_ipv6, "ffff:ffff:ffff:ffff::"); EXPECT_EQ(netNetmask.getPrefixLen(), 64u); @@ -314,6 +321,7 @@ namespace pcpp EXPECT_EQ(netNetmask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); EXPECT_EQ(netNetmask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); EXPECT_THROW(netNetmask.getTotalAddressCount(), std::out_of_range); + EXPECT_EQ(netNetmask.toString(), "2001:db8:85a3::/64"); IPv6Network netStringWithPrefix("2001:db8:85a3::8a2e:370:7334/64"); EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 64u); @@ -322,6 +330,7 @@ namespace pcpp EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "2001:db8:85a3::1"_ipv6); EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); EXPECT_THROW(netStringWithPrefix.getTotalAddressCount(), std::out_of_range); + EXPECT_EQ(netStringWithPrefix.toString(), "2001:db8:85a3::/64"); IPv6Network netStringWithMask("2001:db8:85a3::8a2e:370:7334/ffff:ffff:ffff:ffff::"); EXPECT_EQ(netStringWithMask.getPrefixLen(), 64u); @@ -330,6 +339,7 @@ namespace pcpp EXPECT_EQ(netStringWithMask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); EXPECT_EQ(netStringWithMask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); EXPECT_THROW(netStringWithMask.getTotalAddressCount(), std::out_of_range); + EXPECT_EQ(netStringWithMask.toString(), "2001:db8:85a3::/64"); }; TEST(IPv6NetworkTest, IPv6NetworkIncludes) @@ -339,7 +349,29 @@ namespace pcpp TEST(IPNetworkTest, IPNetworkBasics) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + IPNetwork netSingleV4("192.168.1.1"_ipv4); + EXPECT_TRUE(netSingleV4.isIPv4Network()); + EXPECT_FALSE(netSingleV4.isIPv6Network()); + EXPECT_EQ(netSingleV4.getPrefixLen(), 32u); + EXPECT_EQ(netSingleV4.getNetmask(), "255.255.255.255"); + EXPECT_EQ(netSingleV4.getNetworkPrefix(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingleV4.getLowestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingleV4.getHighestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingleV4.getTotalAddressCount(), 1); + EXPECT_EQ(netSingleV4.toString(), "192.168.1.1/32"); + + IPNetwork netSingleV6("2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_FALSE(netSingleV6.isIPv4Network()); + EXPECT_TRUE(netSingleV6.isIPv6Network()); + EXPECT_EQ(netSingleV6.getPrefixLen(), 128u); + EXPECT_EQ(netSingleV6.getNetmask(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + EXPECT_EQ(netSingleV6.getNetworkPrefix(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingleV6.getLowestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingleV6.getHighestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingleV6.getTotalAddressCount(), 1); + EXPECT_EQ(netSingleV6.toString(), "2001:db8:85a3::8a2e:370:7334/128"); }; TEST(IPNetworkTest, IPNetworkIncludes) From e29190aa43ddbf2d6908bc9ee1f4bd9ccd6abfba Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 17:13:45 +0300 Subject: [PATCH 13/80] Added more unit tests. - Added IPAddress multicast unit tests. - Added IPNetwork includes unit tests. - Formatting --- Tests/Common++Test/Tests/IPAddressTests.cpp | 118 ++++++++++++++++++-- 1 file changed, 109 insertions(+), 9 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 1b20d1d0db..67b096223b 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -223,18 +223,54 @@ namespace pcpp << "IPAddress does not throw for multiple double colon in IP string."; EXPECT_THROW(IPAddress("bogusString"), std::invalid_argument) << "IPAddress does not throw for non-IP string."; - EXPECT_TRUE(ipDefault == IPv4Address::Zero) << "Comparison operator '==' does not compare equal values correctly."; - EXPECT_FALSE(ipDefault != IPv4Address::Zero) << "Comparison operator '!=' does not compare equal values correctly."; + EXPECT_TRUE(ipDefault == IPv4Address::Zero) + << "Comparison operator '==' does not compare equal values correctly."; + EXPECT_FALSE(ipDefault != IPv4Address::Zero) + << "Comparison operator '!=' does not compare equal values correctly."; - EXPECT_FALSE(ipDefault == ip6ZeroString) << "Comparison operator '==' between IPv4 and IPv6 should always return false"; - EXPECT_TRUE(ipDefault != ip6ZeroString) << "Comparison operator '!=' between IPv4 and IPv6 should always return true"; + EXPECT_FALSE(ipDefault == ip6ZeroString) + << "Comparison operator '==' between IPv4 and IPv6 should always return false"; + EXPECT_TRUE(ipDefault != ip6ZeroString) + << "Comparison operator '!=' between IPv4 and IPv6 should always return true"; // Todo: less than operator }; TEST(IPAddressTest, Multicast) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + { + SCOPED_TRACE("IPv4"); + + IPAddress underMulticastBound("223.0.0.0"_ipv4); + EXPECT_FALSE(underMulticastBound.isMulticast()); + + IPAddress atLowerMulticastBound("224.0.0.0"_ipv4); + EXPECT_TRUE(atLowerMulticastBound.isMulticast()); + + IPAddress inMulticastRange("230.9.4.1"_ipv4); + EXPECT_TRUE(inMulticastRange.isMulticast()); + + IPAddress atUpperMulticastBound("239.255.255.255"_ipv4); + EXPECT_TRUE(atUpperMulticastBound.isMulticast()); + + IPAddress overMulticastBound("240.0.0.0"_ipv4); + EXPECT_FALSE(overMulticastBound.isMulticast()); + } + + { + SCOPED_TRACE("IPv6"); + + IPAddress underMulticastBound("fef0::"_ipv6); + EXPECT_FALSE(underMulticastBound.isMulticast()); + + IPAddress atLowerMulticastBound("ff00::"_ipv6); + EXPECT_TRUE(atLowerMulticastBound.isMulticast()); + + IPAddress inMulticastRange("ff00::ef"_ipv6); + EXPECT_TRUE(inMulticastRange.isMulticast()); + } }; TEST(IPv4NetworkTest, IPv4NetworkBasics) @@ -249,7 +285,7 @@ namespace pcpp EXPECT_EQ(netSingle.getHighestAddress(), "192.168.1.1"_ipv4); EXPECT_EQ(netSingle.getTotalAddressCount(), 1); EXPECT_EQ(netSingle.toString(), "192.168.1.1/32"); - + IPv4Network netPrefix("192.168.1.1"_ipv4, 24u); EXPECT_EQ(netPrefix.getPrefixLen(), 24u); EXPECT_EQ(netPrefix.getNetmask(), "255.255.255.0"); @@ -289,7 +325,19 @@ namespace pcpp TEST(IPv4NetworkTest, IPv4NetworkIncludes) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + IPv4Network netBase("192.168.0.0/16"); + + EXPECT_TRUE(netBase.includes("192.168.1.0"_ipv4)); + EXPECT_TRUE(netBase.includes("192.168.1.1"_ipv4)); + EXPECT_TRUE(netBase.includes("192.168.2.1"_ipv4)); + EXPECT_FALSE(netBase.includes("192.169.2.1"_ipv4)); + + EXPECT_TRUE(netBase.includes(IPv4Network("192.168.1.0/24"))); + EXPECT_TRUE(netBase.includes(IPv4Network("192.168.2.0/24"))); + EXPECT_TRUE(netBase.includes(IPv4Network("192.168.0.0/16"))); + EXPECT_FALSE(netBase.includes(IPv4Network("192.0.0.0/8"))); }; TEST(IPv6NetworkTest, IPv6NetworkBasics) @@ -344,7 +392,17 @@ namespace pcpp TEST(IPv6NetworkTest, IPv6NetworkIncludes) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + IPv6Network netBase("2001:db8:85a3:34ac::/64"); + + EXPECT_TRUE(netBase.includes("2001:db8:85a3:34ac::1"_ipv6)); + EXPECT_TRUE(netBase.includes("2001:db8:85a3:34ac:c::2"_ipv6)); + EXPECT_FALSE(netBase.includes("2001:db8:85a3:34ab::1"_ipv6)); + + EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/64"))); + EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/72"))); + EXPECT_FALSE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/56"))); }; TEST(IPNetworkTest, IPNetworkBasics) @@ -376,6 +434,48 @@ namespace pcpp TEST(IPNetworkTest, IPNetworkIncludes) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + IPNetwork netBaseV4("192.168.0.0/16"); + EXPECT_TRUE(netBaseV4.includes("192.168.1.0"_ipv4)); + EXPECT_TRUE(netBaseV4.includes("192.168.1.1"_ipv4)); + EXPECT_TRUE(netBaseV4.includes("192.168.2.1"_ipv4)); + EXPECT_FALSE(netBaseV4.includes("192.169.2.1"_ipv4)); + EXPECT_FALSE(netBaseV4.includes("2001:db8:85a3:34ac::"_ipv6)); + EXPECT_FALSE(netBaseV4.includes("::C0A9:0201"_ipv6)) << "IPNetwork in V4 mode should not match V6 equivalents."; + + EXPECT_TRUE(netBaseV4.includes(IPNetwork("192.168.1.0/24"))); + EXPECT_TRUE(netBaseV4.includes(IPNetwork("192.168.2.0/24"))); + EXPECT_TRUE(netBaseV4.includes(IPNetwork("192.168.0.0/16"))); + EXPECT_FALSE(netBaseV4.includes(IPNetwork("192.0.0.0/8"))); + EXPECT_FALSE(netBaseV4.includes(IPNetwork("2001:db8:85a3:34ac::/64"))); + EXPECT_FALSE(netBaseV4.includes(IPNetwork("::c0a9:0000/112"))) + << "IPNetwork in V4 mode should not match V6 equivalents."; + EXPECT_FALSE(netBaseV4.includes(IPNetwork("::c0a9:0201/116"))) + << "IPNetwork in V4 mode should not match V6 equivalents."; + + IPNetwork netBaseV6("2001:db8:85a3:34ac::/64"); + EXPECT_TRUE(netBaseV6.includes("2001:db8:85a3:34ac::1"_ipv6)); + EXPECT_TRUE(netBaseV6.includes("2001:db8:85a3:34ac:c::2"_ipv6)); + EXPECT_FALSE(netBaseV6.includes("2001:db8:85a3:34ab::1"_ipv6)); + + EXPECT_TRUE(netBaseV6.includes(IPNetwork("2001:db8:85a3:34ac::/64"))); + EXPECT_TRUE(netBaseV6.includes(IPNetwork("2001:db8:85a3:34ac::/72"))); + EXPECT_FALSE(netBaseV6.includes(IPNetwork("2001:db8:85a3:34ac::/56"))); + + IPNetwork netBaseV6_V4compat("::c0a8:0000/112"); + EXPECT_FALSE(netBaseV6_V4compat.includes("192.168.1.0"_ipv4)) + << "IPNetwork in V6 mode should not match V4 equivalent ranges."; + EXPECT_FALSE(netBaseV6_V4compat.includes("192.168.2.1"_ipv4)) + << "IPNetwork in V6 mode should not match V4 equivalent ranges."; + EXPECT_FALSE(netBaseV6_V4compat.includes("192.169.2.1"_ipv4)) + << "IPNetwork in V6 mode should not match V4 equivalent ranges."; + + EXPECT_FALSE(netBaseV6_V4compat.includes(IPNetwork("192.169.1.1/15"))) + << "IPNetwork in V6 mode should not match V4 equivalent ranges."; + EXPECT_FALSE(netBaseV6_V4compat.includes(IPNetwork("192.169.1.1/16"))) + << "IPNetwork in V6 mode should not match V4 equivalent ranges."; + EXPECT_FALSE(netBaseV6_V4compat.includes(IPNetwork("192.169.1.1/17"))) + << "IPNetwork in V6 mode should not match V4 equivalent ranges."; }; } // namespace pcpp From 0f3f927cf7d9fa695fac5357451406ce9ddc3c36 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 17:27:06 +0300 Subject: [PATCH 14/80] Added IP(v4/v6)Address match network tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 44 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 67b096223b..109f52c0c9 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -95,7 +95,25 @@ namespace pcpp TEST(IPv4AddressTest, MatchNetwork) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + IPv4Address ipBase = "192.168.1.1"_ipv4; + + EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/16")); + EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/24")); + EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/32")); + + EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/16"))); + EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/24"))); + EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/32"))); + + EXPECT_FALSE(ipBase.matchNetwork("192.168.1.2/32")); + EXPECT_FALSE(ipBase.matchNetwork("192.168.2.1/24")); + EXPECT_FALSE(ipBase.matchNetwork("192.169.1.1/16")); + + EXPECT_FALSE(ipBase.matchNetwork(IPv4Network("192.168.1.2/32"))); + EXPECT_FALSE(ipBase.matchNetwork(IPv4Network("192.168.2.1/24"))); + EXPECT_FALSE(ipBase.matchNetwork(IPv4Network("192.169.1.1/16"))); }; TEST(IPv6AddressTest, IPv6AddressStatics) @@ -187,7 +205,29 @@ namespace pcpp TEST(IPv6AddressTest, MatchNetwork) { - FAIL() << "Not Implemented"; + using namespace pcpp::literals; + + IPv6Address ipBase = "2001:db8:85a3::8a2e:370:7334"_ipv6; + + EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::8a2e:370:7334/128")); + EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::8a2e:0:0/96")); + EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::/64")); + EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::/32")); + + EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2e:370:7334/128"))); + EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2e:0:0/96"))); + EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::/64"))); + EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::/32"))); + + EXPECT_FALSE(ipBase.matchNetwork("2001:db8:85a3::8a2e:370:7344/128")); + EXPECT_FALSE(ipBase.matchNetwork("2001:db8:85a3::8a2f:0:0/96")); + EXPECT_FALSE(ipBase.matchNetwork("2001:db8:85b3::/64")); + EXPECT_FALSE(ipBase.matchNetwork("2002:db8:85a3::/32")); + + EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2e:370:7344/128"))); + EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2f:0:0/96"))); + EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2001:db8:85b3::/64"))); + EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2002:db8:85a3::/32"))); }; TEST(IPAddressTest, IPAddressBasics) From c8d04dedf21d880836092e107761f183ae1ddd7c Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 17:29:13 +0300 Subject: [PATCH 15/80] Lint --- Tests/Common++Test/Tests/IPAddressTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 109f52c0c9..9c118cd814 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -102,7 +102,7 @@ namespace pcpp EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/16")); EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/24")); EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/32")); - + EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/16"))); EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/24"))); EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/32"))); From a67ebe72cf554e26d1be4cc444a146eab2ad0bcf Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 18:02:00 +0300 Subject: [PATCH 16/80] Added MacAddress constructor from std::array. --- Common++/header/MacAddress.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Common++/header/MacAddress.h b/Common++/header/MacAddress.h index 29333aa02d..5a972c45e9 100644 --- a/Common++/header/MacAddress.h +++ b/Common++/header/MacAddress.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -41,6 +42,15 @@ namespace pcpp memcpy(m_Address, addr, sizeof(m_Address)); } + /** + * A constructor that creates an instance of the class out of a std::array. + * @param[in] addr The std::array containing 6 bytes representing the MAC address. + */ + explicit MacAddress(std::array const& addr) + { + std::copy(addr.begin(), addr.end(), std::begin(m_Address)); + } + /** * A constructor that creates an instance of the class out of a std::string. * If the string doesn't represent a valid MAC address, the constructor throws an exception. From a93a202d15897612332a1f8db17c58698a1c0e6f Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 18:02:10 +0300 Subject: [PATCH 17/80] Added MacAddress unit tests. --- Tests/Common++Test/Tests/MacAddressTests.cpp | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Tests/Common++Test/Tests/MacAddressTests.cpp diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp new file mode 100644 index 0000000000..9c4f8e2d12 --- /dev/null +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include "MacAddress.h" + +namespace pcpp +{ + TEST(MacAddressTest, MacAddressStatics) + { + EXPECT_EQ(MacAddress::Zero.toString(), "00:00:00:00:00:00"); + }; + + TEST(MacAddressTest, MacAddressBasics) + { + MacAddress macAddr1; + EXPECT_EQ(macAddr1.toString(), "00:00:00:00:00:00"); + + std::array addr = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; + MacAddress macAddr2(addr.data()); + EXPECT_EQ(macAddr2.toString(), "00:11:22:33:44:55"); + + MacAddress macAddr3(addr); + EXPECT_EQ(macAddr3.toString(), "00:11:22:33:44:55"); + + MacAddress macAddr4("00:11:22:33:44:55"); + EXPECT_EQ(macAddr4.toString(), "00:11:22:33:44:55"); + EXPECT_THROW(MacAddress("00:11:22:33:44"), std::invalid_argument); + EXPECT_THROW(MacAddress("00:11:22:33:44:55:66"), std::invalid_argument); + EXPECT_THROW(MacAddress("bogus string"), std::invalid_argument); + + MacAddress macAddr5(std::string("00:11:22:33:44:55")); + EXPECT_EQ(macAddr5.toString(), "00:11:22:33:44:55"); + + MacAddress macAddr6(0x00, 0x11, 0x22, 0x33, 0x44, 0x55); + EXPECT_EQ(macAddr6.toString(), "00:11:22:33:44:55"); + + MacAddress macAddr7{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; + EXPECT_EQ(macAddr7.toString(), "00:11:22:33:44:55"); + EXPECT_THROW(MacAddress({ 0x00, 0x11, 0x22, 0x33, 0x44 }), std::invalid_argument); + EXPECT_THROW(MacAddress({ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }), std::invalid_argument); + + MacAddress macAddr8 = "00:11:22:33:44:55"; + EXPECT_EQ(macAddr8.toString(), "00:11:22:33:44:55"); + + MacAddress macAddr9 = std::string("00:11:22:33:44:55"); + EXPECT_EQ(macAddr9.toString(), "00:11:22:33:44:55"); + + MacAddress macAddr10 = MacAddress("00:11:22:33:44:55"); + EXPECT_EQ(macAddr10.toString(), "00:11:22:33:44:55"); + + EXPECT_FALSE(macAddr1 == macAddr2) << "Comparison operator '==' does not compare unequal values correctly."; + EXPECT_TRUE(macAddr2 == macAddr3) << "Comparison operator '==' does not compare equal values correctly."; + + EXPECT_TRUE(macAddr1 != macAddr2) << "Comparison operator '!=' does not compare unequal values correctly."; + EXPECT_FALSE(macAddr2 != macAddr3) << "Comparison operator '!=' does not compare equal values correctly."; + }; +} // namespace pcpp From 66d1937a8b03b0a66b104d11aff62b966b9c797b Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 18:05:05 +0300 Subject: [PATCH 18/80] Added MacAddress tests for output to stream. --- Tests/Common++Test/Tests/MacAddressTests.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp index 9c4f8e2d12..8872afae62 100644 --- a/Tests/Common++Test/Tests/MacAddressTests.cpp +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -56,4 +57,12 @@ namespace pcpp EXPECT_TRUE(macAddr1 != macAddr2) << "Comparison operator '!=' does not compare unequal values correctly."; EXPECT_FALSE(macAddr2 != macAddr3) << "Comparison operator '!=' does not compare equal values correctly."; }; + + TEST(MacAddressTest, ToStream) + { + MacAddress macAddr("00:11:22:33:44:55"); + std::stringstream stream; + stream << macAddr; + EXPECT_EQ(stream.str(), "00:11:22:33:44:55"); + }; } // namespace pcpp From aa92f72f4b251fdc0a24cfab359593eb70fae379 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 19:06:03 +0300 Subject: [PATCH 19/80] Added unit tests for PointerVector and test fixture with built-in memleak detection. --- Tests/Common++Test/CMakeLists.txt | 5 +- .../Common++Test/Tests/PointerVectorTests.cpp | 118 ++++++++++++++++++ .../Utils/MemoryLeakDetectorFixture.hpp | 28 +++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 Tests/Common++Test/Tests/PointerVectorTests.cpp create mode 100644 Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 3ab3e30728..dac0532651 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -18,11 +18,14 @@ FetchContent_MakeAvailable(googletest) add_executable( Common++Test - Tests/IPAddressTests.cpp) + Tests/IPAddressTests.cpp + Tests/MacAddressTests.cpp + Tests/PointerVectorTests.cpp ) target_link_libraries( Common++Test PRIVATE Common++ + memplumber gtest gmock gmock_main diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp new file mode 100644 index 0000000000..30d93f6784 --- /dev/null +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include + +#include "..\Utils\MemoryLeakDetectorFixture.hpp" + +#include "PointerVector.h" + +namespace pcpp +{ + class PointerVectorTest : public MemoryLeakDetectorTest + { + }; + + TEST_F(PointerVectorTest, PointerVectorBasics) + { + PointerVector pVector; + PointerVector const& cpVector = pVector; + EXPECT_EQ(pVector.size(), 0); + + pVector.pushBack(new int(1)); + EXPECT_EQ(pVector.size(), 1); + + EXPECT_THROW(pVector.pushBack(nullptr), std::invalid_argument); + EXPECT_THROW(pVector.pushBack(std::unique_ptr()), std::invalid_argument); + + int* atIdx0 = pVector.at(0); + ASSERT_NE(atIdx0, nullptr); + EXPECT_EQ(*atIdx0, 1); + + int const* cAtIdx0 = cpVector.at(0); + ASSERT_NE(atIdx0, nullptr); + EXPECT_EQ(*atIdx0, 1); + + pVector.pushBack(std::unique_ptr(new int(2))); + EXPECT_EQ(pVector.size(), 2); + + { + int* atFront = pVector.front(); + ASSERT_NE(atFront, nullptr); + EXPECT_EQ(*atFront, 1); + + int const* cAtFront = cpVector.front(); + ASSERT_NE(cAtFront, nullptr); + EXPECT_EQ(*cAtFront, 1); + + int* atBack = pVector.back(); + ASSERT_NE(atBack, nullptr); + EXPECT_EQ(*atBack, 2); + + int const* cAtBack = cpVector.back(); + ASSERT_NE(cAtBack, nullptr); + EXPECT_EQ(*cAtBack, 2); + } + + { + auto itBegin = pVector.begin(); + auto itEnd = pVector.end(); + + EXPECT_EQ(std::distance(itBegin, itEnd), 2); + EXPECT_EQ(**itBegin, 1); + EXPECT_EQ(**std::next(itBegin), 2); + } + + { + std::unique_ptr p = pVector.getAndDetach(1); + EXPECT_EQ(*p, 2); + EXPECT_EQ(pVector.size(), 1); + } + + PointerVector pVectorCopy = pVector; + EXPECT_EQ(pVectorCopy.size(), pVector.size()); + EXPECT_NE(pVectorCopy.at(0), pVector.at(0)); + EXPECT_EQ(*pVectorCopy.at(0), *pVector.at(0)); + + { + PointerVector pVectorMove = std::move(pVector); + EXPECT_EQ(pVector.size(), 0); + EXPECT_EQ(pVectorMove.size(), 1); + EXPECT_EQ(*pVectorMove.at(0), 1); + + pVector = std::move(pVectorMove); + ASSERT_EQ(pVector.size(), 1); + } + + pVectorCopy.clear(); + EXPECT_EQ(pVectorCopy.size(), 0); + EXPECT_EQ(pVector.size(), 1); + + pVector.pushBack(new int(3)); + EXPECT_EQ(pVector.size(), 2); + + { + int* removed = pVector.getAndRemoveFromVector(pVector.begin()); + EXPECT_EQ(*removed, 1); + EXPECT_EQ(pVector.size(), 1); + EXPECT_EQ(*pVector.front(), 3); + delete removed; + } + + pVector.erase(pVector.begin()); + EXPECT_EQ(pVector.size(), 0); + + pVector.pushBack(new int(4)); + pVector.pushBack(new int(5)); + EXPECT_EQ(pVector.size(), 2); + + { + std::unique_ptr p = pVector.getAndDetach(pVector.begin()); + ASSERT_NE(p, nullptr); + EXPECT_EQ(*p, 4); + EXPECT_EQ(pVector.size(), 1); + } + } +} // namespace pcpp \ No newline at end of file diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp new file mode 100644 index 0000000000..bdca0fa150 --- /dev/null +++ b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp @@ -0,0 +1,28 @@ +#include +#include + +namespace pcpp +{ + class MemoryLeakDetectorTest : public ::testing::Test + { + protected: + void SetUp() override + { + MemPlumber::start(); + } + + void TearDown() override + { + std::size_t memLeakCount = 0; + std::uint64_t memLeakSize = 0; + MemPlumber::memLeakCheck(memLeakCount, memLeakSize); + MemPlumber::stopAndFreeAllMemory(); + + if (memLeakCount > 0 || memLeakSize > 0) + { + FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize << " [bytes] leaked"; + } + } + }; + +} // namespace pcpp \ No newline at end of file From d191cdbb8d7ea0f04ee16e5e4877db4808df26e0 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 22 Jul 2024 19:06:57 +0300 Subject: [PATCH 20/80] Lint --- Tests/Common++Test/Tests/PointerVectorTests.cpp | 2 +- Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index 30d93f6784..086ac2f84b 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -115,4 +115,4 @@ namespace pcpp EXPECT_EQ(pVector.size(), 1); } } -} // namespace pcpp \ No newline at end of file +} // namespace pcpp diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp index bdca0fa150..9955d475dc 100644 --- a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp +++ b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp @@ -24,5 +24,5 @@ namespace pcpp } } }; - -} // namespace pcpp \ No newline at end of file + +} // namespace pcpp From bd8ecd9336a7a79d12f862504501f7c33f874c88 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 24 Jul 2024 10:40:09 +0300 Subject: [PATCH 21/80] Included 'googletest' configuration for cppcheck. --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cdbd8c581d..acf1e363aa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: args: ["--style=file"] # Use the .clang-format file for configuration files: ^Common\+\+/.*\.(cpp|h)$ - id: cppcheck - args: ["--std=c++11", "--language=c++", "--suppressions-list=cppcheckSuppressions.txt", "--inline-suppr", "--force"] + args: ["--std=c++11", "--language=c++", "--suppressions-list=cppcheckSuppressions.txt", "--inline-suppr", "--force", "--library=googletest"] - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: From 70708fdbd59f0ea397772749e5b4613deb9631bc Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 24 Jul 2024 10:42:00 +0300 Subject: [PATCH 22/80] Fixed include of MemoryLeakDetectorFixture... hopefully the correct way. --- Tests/Common++Test/CMakeLists.txt | 5 +++++ Tests/Common++Test/Tests/PointerVectorTests.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index dac0532651..a018622c93 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -31,6 +31,11 @@ target_link_libraries( gmock_main ) +target_include_directories(Common++Test PRIVATE + $ +) + + if(MSVC) # This executable requires getopt.h not available on VStudio target_link_libraries(Common++Test PRIVATE Getopt-for-Visual-Studio) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index 086ac2f84b..53f9df298e 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -5,7 +5,7 @@ #include #include -#include "..\Utils\MemoryLeakDetectorFixture.hpp" +#include "MemoryLeakDetectorFixture.hpp" #include "PointerVector.h" From d45b54da7ff8ba5275f3258929166093d4d5cff2 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 24 Jul 2024 11:28:49 +0300 Subject: [PATCH 23/80] Fixed wrong variable assert. --- Tests/Common++Test/Tests/PointerVectorTests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index 53f9df298e..c242f2d343 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -32,8 +32,8 @@ namespace pcpp EXPECT_EQ(*atIdx0, 1); int const* cAtIdx0 = cpVector.at(0); - ASSERT_NE(atIdx0, nullptr); - EXPECT_EQ(*atIdx0, 1); + ASSERT_NE(cAtIdx0, nullptr); + EXPECT_EQ(*cAtIdx0, 1); pVector.pushBack(std::unique_ptr(new int(2))); EXPECT_EQ(pVector.size(), 2); From a9cd1b8ee0ba0478089c571621d0578bd1167814 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 24 Jul 2024 14:21:21 +0300 Subject: [PATCH 24/80] Added unit test for functions in the general utilities header. --- Tests/Common++Test/CMakeLists.txt | 1 + .../Common++Test/Tests/GeneralUtilsTests.cpp | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Tests/Common++Test/Tests/GeneralUtilsTests.cpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index a018622c93..3ef00592eb 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -18,6 +18,7 @@ FetchContent_MakeAvailable(googletest) add_executable( Common++Test + Tests/GeneralUtilsTests.cpp Tests/IPAddressTests.cpp Tests/MacAddressTests.cpp Tests/PointerVectorTests.cpp ) diff --git a/Tests/Common++Test/Tests/GeneralUtilsTests.cpp b/Tests/Common++Test/Tests/GeneralUtilsTests.cpp new file mode 100644 index 0000000000..096f7bdb94 --- /dev/null +++ b/Tests/Common++Test/Tests/GeneralUtilsTests.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +#include "GeneralUtils.h" + +namespace pcpp +{ + TEST(GeneralUtilsTests, byteArrayToHexString) + { + std::array byteArr = {0xaa, 0x2b, 0x10}; + EXPECT_EQ(byteArrayToHexString(byteArr.data(), byteArr.size()), "aa2b10"); + }; + + TEST(GeneralUtilsTests, hexStringToByteArray) + { + std::array resultByteArr = {0}; + EXPECT_EQ(hexStringToByteArray("aa2b10", resultByteArr.data(), resultByteArr.size()), 3); + EXPECT_EQ(resultByteArr, (std::array{0xaa, 0x2b, 0x10})); + }; + + TEST(GeneralUtilsTests, cross_platform_memmem) + { + const char haystack[] = "Hello, World!"; + const char needle[] = "World"; + EXPECT_EQ(cross_platform_memmem(haystack, sizeof(haystack), needle, sizeof(needle) - 1 /* ignore the null terminator */), haystack + 7); + }; + + TEST(GeneralUtilsTests, align) + { + EXPECT_EQ(align<4>(3), 4); + EXPECT_EQ(align<4>(4), 4); + EXPECT_EQ(align<4>(5), 8); + }; +} // namespace pcpp From 4803471fb16a7d83f04aa157d0468203b6691731 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 24 Jul 2024 14:41:46 +0300 Subject: [PATCH 25/80] Added unit tests for LRUList. --- Tests/Common++Test/CMakeLists.txt | 4 +- Tests/Common++Test/Tests/LRUListTests.cpp | 73 +++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 Tests/Common++Test/Tests/LRUListTests.cpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 3ef00592eb..5db009953b 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -21,7 +21,9 @@ add_executable( Tests/GeneralUtilsTests.cpp Tests/IPAddressTests.cpp Tests/MacAddressTests.cpp - Tests/PointerVectorTests.cpp ) + Tests/PointerVectorTests.cpp + Tests/LRUListTests.cpp +) target_link_libraries( Common++Test diff --git a/Tests/Common++Test/Tests/LRUListTests.cpp b/Tests/Common++Test/Tests/LRUListTests.cpp new file mode 100644 index 0000000000..c3a8b18ded --- /dev/null +++ b/Tests/Common++Test/Tests/LRUListTests.cpp @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "LRUList.h" + +namespace pcpp +{ + TEST(LRUListTest, PutAndErase) + { + int deletedValue = 0; + LRUList lruCache(4); + EXPECT_EQ(lruCache.getMaxSize(), 4); + EXPECT_EQ(lruCache.getSize(), 0); + ASSERT_EQ(deletedValue, 0); + + lruCache.put(1, &deletedValue); + EXPECT_EQ(lruCache.getSize(), 1); + EXPECT_EQ(deletedValue, 0); + + lruCache.put(1, &deletedValue); + EXPECT_EQ(lruCache.getSize(), 1); + EXPECT_EQ(deletedValue, 0); + + lruCache.put(2, &deletedValue); + EXPECT_EQ(deletedValue, 0); + lruCache.put(3, &deletedValue); + EXPECT_EQ(deletedValue, 0); + lruCache.put(4, &deletedValue); + EXPECT_EQ(lruCache.getMaxSize(), 4); + EXPECT_EQ(lruCache.getSize(), 4); + EXPECT_EQ(deletedValue, 0); + + lruCache.put(5, &deletedValue); + EXPECT_EQ(lruCache.getMaxSize(), 4); + EXPECT_EQ(lruCache.getSize(), 4); + EXPECT_EQ(deletedValue, 1); + + deletedValue = 0; + ASSERT_EQ(deletedValue, 0); + lruCache.eraseElement(3); + EXPECT_EQ(lruCache.getSize(), 3); + + lruCache.put(6, &deletedValue); + EXPECT_EQ(deletedValue, 0); + EXPECT_EQ(lruCache.getSize(), 4); + + lruCache.eraseElement(7); + EXPECT_EQ(lruCache.getSize(), 4); + }; + + TEST(LRUListTest, RecentlyUsedElementAccessors) + { + LRUList lruCache(4); + ASSERT_EQ(lruCache.getMaxSize(), 4); + + lruCache.put(1); + lruCache.put(2); + lruCache.put(3); + lruCache.put(4); + + EXPECT_EQ(lruCache.getMRUElement(), 4); + EXPECT_EQ(lruCache.getLRUElement(), 1); + + lruCache.put(5); + EXPECT_EQ(lruCache.getMRUElement(), 5); + EXPECT_EQ(lruCache.getLRUElement(), 2); + + lruCache.put(3); + EXPECT_EQ(lruCache.getMRUElement(), 3); + EXPECT_EQ(lruCache.getLRUElement(), 2); + }; +} // namespace pcpp From 9e77c18662a63d6d38b44f0bd741a0252da71412 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 24 Jul 2024 14:45:20 +0300 Subject: [PATCH 26/80] Lint --- Tests/Common++Test/Tests/LRUListTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/LRUListTests.cpp b/Tests/Common++Test/Tests/LRUListTests.cpp index c3a8b18ded..62795474e9 100644 --- a/Tests/Common++Test/Tests/LRUListTests.cpp +++ b/Tests/Common++Test/Tests/LRUListTests.cpp @@ -17,7 +17,7 @@ namespace pcpp lruCache.put(1, &deletedValue); EXPECT_EQ(lruCache.getSize(), 1); EXPECT_EQ(deletedValue, 0); - + lruCache.put(1, &deletedValue); EXPECT_EQ(lruCache.getSize(), 1); EXPECT_EQ(deletedValue, 0); From d503bcdec1a382ff902f9d0ef7afde5a66b5a24c Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Tue, 30 Jul 2024 17:53:16 +0300 Subject: [PATCH 27/80] Added cast to ptr type because direct nullptr is deleted function. --- Tests/Common++Test/Tests/PointerVectorTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index c242f2d343..b6c89a5f19 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -24,7 +24,7 @@ namespace pcpp pVector.pushBack(new int(1)); EXPECT_EQ(pVector.size(), 1); - EXPECT_THROW(pVector.pushBack(nullptr), std::invalid_argument); + EXPECT_THROW(pVector.pushBack(static_cast(nullptr)), std::invalid_argument); EXPECT_THROW(pVector.pushBack(std::unique_ptr()), std::invalid_argument); int* atIdx0 = pVector.at(0); From f1baa83265d910d4bd259ce25ee8e862fe4051b6 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 15 Aug 2024 13:54:52 +0300 Subject: [PATCH 28/80] Lint --- Common++/header/IpAddress.h | 2 +- Tests/Common++Test/Tests/GeneralUtilsTests.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Common++/header/IpAddress.h b/Common++/header/IpAddress.h index 45f5b657ce..c4686f712a 100644 --- a/Common++/header/IpAddress.h +++ b/Common++/header/IpAddress.h @@ -1094,7 +1094,7 @@ namespace pcpp { return IPv6Address(std::string(addrString, size)); } - } + } // namespace literals } // namespace pcpp inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Address& ipv4Address) diff --git a/Tests/Common++Test/Tests/GeneralUtilsTests.cpp b/Tests/Common++Test/Tests/GeneralUtilsTests.cpp index 096f7bdb94..b56c49dc45 100644 --- a/Tests/Common++Test/Tests/GeneralUtilsTests.cpp +++ b/Tests/Common++Test/Tests/GeneralUtilsTests.cpp @@ -9,22 +9,24 @@ namespace pcpp { TEST(GeneralUtilsTests, byteArrayToHexString) { - std::array byteArr = {0xaa, 0x2b, 0x10}; + std::array byteArr = { 0xaa, 0x2b, 0x10 }; EXPECT_EQ(byteArrayToHexString(byteArr.data(), byteArr.size()), "aa2b10"); }; TEST(GeneralUtilsTests, hexStringToByteArray) { - std::array resultByteArr = {0}; + std::array resultByteArr = { 0 }; EXPECT_EQ(hexStringToByteArray("aa2b10", resultByteArr.data(), resultByteArr.size()), 3); - EXPECT_EQ(resultByteArr, (std::array{0xaa, 0x2b, 0x10})); + EXPECT_EQ(resultByteArr, (std::array{ 0xaa, 0x2b, 0x10 })); }; TEST(GeneralUtilsTests, cross_platform_memmem) { const char haystack[] = "Hello, World!"; const char needle[] = "World"; - EXPECT_EQ(cross_platform_memmem(haystack, sizeof(haystack), needle, sizeof(needle) - 1 /* ignore the null terminator */), haystack + 7); + EXPECT_EQ(cross_platform_memmem(haystack, sizeof(haystack), needle, + sizeof(needle) - 1 /* ignore the null terminator */), + haystack + 7); }; TEST(GeneralUtilsTests, align) @@ -33,4 +35,4 @@ namespace pcpp EXPECT_EQ(align<4>(4), 4); EXPECT_EQ(align<4>(5), 8); }; -} // namespace pcpp +} // namespace pcpp From 6b501302bdfc2292a233b7c424fcbb3a29003aaa Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 15 Aug 2024 14:00:13 +0300 Subject: [PATCH 29/80] Fixed issue with temporary. --- Tests/Common++Test/Tests/PointerVectorTests.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index b6c89a5f19..edba7d4b16 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -94,7 +94,10 @@ namespace pcpp EXPECT_EQ(pVector.size(), 2); { - int* removed = pVector.getAndRemoveFromVector(pVector.begin()); + // Can't pass pVector.begin() directly to getAndRemoveFromVector because temporaries can't be passed as + // non-const reference. + auto it = pVector.begin(); + int* removed = pVector.getAndRemoveFromVector(it); EXPECT_EQ(*removed, 1); EXPECT_EQ(pVector.size(), 1); EXPECT_EQ(*pVector.front(), 3); From 012df844cb2a4ec4445584e957a666b1318b0154 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 7 Sep 2024 14:45:12 +0300 Subject: [PATCH 30/80] Lint - hopefully. --- Tests/Common++Test/CMakeLists.txt | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 5db009953b..9c1eb6973f 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -3,14 +3,16 @@ cmake_minimum_required(VERSION 3.14) include(FetchContent) FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.0 + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.0 ) if(WIN32) # Prevent overriding the parent project's compiler/linker settings. - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + set(gtest_force_shared_crt + ON + CACHE BOOL "" FORCE) endif() FetchContent_MakeAvailable(googletest) @@ -20,10 +22,9 @@ add_executable( Common++Test Tests/GeneralUtilsTests.cpp Tests/IPAddressTests.cpp - Tests/MacAddressTests.cpp - Tests/PointerVectorTests.cpp Tests/LRUListTests.cpp -) + Tests/MacAddressTests.cpp + Tests/PointerVectorTests.cpp) target_link_libraries( Common++Test @@ -31,12 +32,9 @@ target_link_libraries( memplumber gtest gmock - gmock_main -) + gmock_main) -target_include_directories(Common++Test PRIVATE - $ -) +target_include_directories(Common++Test PRIVATE $) if(MSVC) From e875c0b2ee0c4e72ab7dba674b1d5379ff265035 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 8 Sep 2024 10:08:39 +0300 Subject: [PATCH 31/80] Pulled operator << overloads into the 'pcpp' namespace to leverage ADL as it does not consider functions in the global namespace. - Pulled operator<< for IpAddress into the `pcpp` namespace. - Pulled operator<< for IpV4Address into the `pcpp` namespace. - Pulled operator<< for IpV6Address into the `pcpp` namespace. - Pulled operator<< for IpNetwork into the `pcpp` namespace. - Pulled operator<< for IpV4Network into the `pcpp` namespace. - Pulled operator<< for IpV6Network into the `pcpp` namespace. - Pulled operator<< for MacAddress into the `pcpp` namespace. --- Common++/header/IpAddress.h | 62 ++++++++++----------- Common++/header/MacAddress.h | 12 ++-- Tests/Common++Test/Tests/IPAddressTests.cpp | 61 ++++++++++++++++++++ 3 files changed, 98 insertions(+), 37 deletions(-) diff --git a/Common++/header/IpAddress.h b/Common++/header/IpAddress.h index c4686f712a..53f13461c1 100644 --- a/Common++/header/IpAddress.h +++ b/Common++/header/IpAddress.h @@ -1095,40 +1095,40 @@ namespace pcpp return IPv6Address(std::string(addrString, size)); } } // namespace literals -} // namespace pcpp -inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Address& ipv4Address) -{ - os << ipv4Address.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Address& ipv4Address) + { + os << ipv4Address.toString(); + return os; + } -inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv6Address& ipv6Address) -{ - os << ipv6Address.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv6Address& ipv6Address) + { + os << ipv6Address.toString(); + return os; + } -inline std::ostream& operator<<(std::ostream& os, const pcpp::IPAddress& ipAddress) -{ - os << ipAddress.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::IPAddress& ipAddress) + { + os << ipAddress.toString(); + return os; + } -inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Network& network) -{ - os << network.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Network& network) + { + os << network.toString(); + return os; + } -inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv6Network& network) -{ - os << network.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv6Network& network) + { + os << network.toString(); + return os; + } -inline std::ostream& operator<<(std::ostream& os, const pcpp::IPNetwork& network) -{ - os << network.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::IPNetwork& network) + { + os << network.toString(); + return os; + } +} // namespace pcpp diff --git a/Common++/header/MacAddress.h b/Common++/header/MacAddress.h index 5a972c45e9..e452da1468 100644 --- a/Common++/header/MacAddress.h +++ b/Common++/header/MacAddress.h @@ -183,10 +183,10 @@ namespace pcpp private: uint8_t m_Address[6] = { 0 }; }; -} // namespace pcpp -inline std::ostream& operator<<(std::ostream& os, const pcpp::MacAddress& macAddress) -{ - os << macAddress.toString(); - return os; -} + inline std::ostream& operator<<(std::ostream& os, const pcpp::MacAddress& macAddress) + { + os << macAddress.toString(); + return os; + } +} // namespace pcpp diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 9c118cd814..7d96fca738 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -67,6 +68,14 @@ namespace pcpp EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; }; + TEST(IPv4AddressTest, OutputStreamOperator) + { + IPAddress ip("192.100.1.1"); + std::stringstream ss; + ss << ip; + EXPECT_EQ(ss.str(), "192.100.1.1"); + } + TEST(IPv4AddressTest, Literals) { using namespace pcpp::literals; @@ -182,6 +191,14 @@ namespace pcpp delete[] heapOutBuffer; }; + TEST(IPv6AddressTest, OutputStreamOperator) + { + IPv6Address ip("2001:db8:85a3::8a2e:370:7334"); + std::stringstream ss; + ss << ip; + EXPECT_EQ(ss.str(), "2001:db8:85a3::8a2e:370:7334"); + } + TEST(IPv6AddressTest, Literals) { using namespace pcpp::literals; @@ -276,6 +293,19 @@ namespace pcpp // Todo: less than operator }; + TEST(IPAddressTest, OutputStreamOperrator) + { + IPAddress ip4("192.168.0.1"); + std::stringstream ss; + ss << ip4; + EXPECT_EQ(ss.str(), "192.168.0.1"); + + IPAddress ip6("2001:db8:85a3::8a2e:370:7334"); + ss.str(""); + ss << ip6; + EXPECT_EQ(ss.str(), "2001:db8:85a3::8a2e:370:7334"); + } + TEST(IPAddressTest, Multicast) { using namespace pcpp::literals; @@ -380,6 +410,14 @@ namespace pcpp EXPECT_FALSE(netBase.includes(IPv4Network("192.0.0.0/8"))); }; + TEST(IPv4NetworkTest, OutputStreamOperator) + { + IPv4Network net("192.168.1.1/32"); + std::stringstream ss; + ss << net; + EXPECT_EQ(ss.str(), "192.168.1.1/32"); + } + TEST(IPv6NetworkTest, IPv6NetworkBasics) { using namespace pcpp::literals; @@ -445,6 +483,16 @@ namespace pcpp EXPECT_FALSE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/56"))); }; + TEST(IPv6NetworkTest, OutputStreamOperator) + { + using namespace pcpp::literals; + + IPv6Network net("2001:db8:85a3:34ac::/64"); + std::stringstream ss; + ss << net; + EXPECT_EQ(ss.str(), "2001:db8:85a3:34ac::/64"); + } + TEST(IPNetworkTest, IPNetworkBasics) { using namespace pcpp::literals; @@ -518,4 +566,17 @@ namespace pcpp EXPECT_FALSE(netBaseV6_V4compat.includes(IPNetwork("192.169.1.1/17"))) << "IPNetwork in V6 mode should not match V4 equivalent ranges."; }; + + TEST(IPNetworkTest, OutputStreamOperator) + { + IPv4Network netV4("192.168.1.1/32"); + std::stringstream ss; + ss << netV4; + EXPECT_EQ(ss.str(), "192.168.1.1/32"); + + ss.str(""); + IPNetwork netV6("2001:db8:85a3:34ac::/64"); + ss << netV6; + EXPECT_EQ(ss.str(), "2001:db8:85a3:34ac::/64"); + } } // namespace pcpp From 3a97325db364a175862b56dd00db2dc66f44b333 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 8 Sep 2024 10:11:15 +0300 Subject: [PATCH 32/80] Renamed MacAddress ToStream test to be consistent with IPAddress tests of the same nature. --- Tests/Common++Test/Tests/MacAddressTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp index 8872afae62..f2c01e605d 100644 --- a/Tests/Common++Test/Tests/MacAddressTests.cpp +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -58,7 +58,7 @@ namespace pcpp EXPECT_FALSE(macAddr2 != macAddr3) << "Comparison operator '!=' does not compare equal values correctly."; }; - TEST(MacAddressTest, ToStream) + TEST(MacAddressTest, OutputStreamOperator) { MacAddress macAddr("00:11:22:33:44:55"); std::stringstream stream; From 01b5cc1a18435df8bf92d7edd488663bc19eebcd Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 8 Sep 2024 10:20:01 +0300 Subject: [PATCH 33/80] CMakeLists lint... --- Tests/Common++Test/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 9c1eb6973f..f7effa771c 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -5,8 +5,7 @@ include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.0 -) + GIT_TAG release-1.12.0) if(WIN32) # Prevent overriding the parent project's compiler/linker settings. @@ -17,7 +16,6 @@ endif() FetchContent_MakeAvailable(googletest) - add_executable( Common++Test Tests/GeneralUtilsTests.cpp @@ -36,7 +34,6 @@ target_link_libraries( target_include_directories(Common++Test PRIVATE $) - if(MSVC) # This executable requires getopt.h not available on VStudio target_link_libraries(Common++Test PRIVATE Getopt-for-Visual-Studio) From db34edb37200fd41a282ca7b308a2d353a5813b4 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 22 Jan 2025 20:45:45 +0200 Subject: [PATCH 34/80] Split common unit tests into smaller tests. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 739 +++++++++++------- Tests/Common++Test/Tests/LRUListTests.cpp | 121 +-- Tests/Common++Test/Tests/MacAddressTests.cpp | 129 ++- .../Common++Test/Tests/PointerVectorTests.cpp | 229 ++++-- 4 files changed, 761 insertions(+), 457 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 7d96fca738..c1d10f8637 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -8,83 +8,47 @@ namespace pcpp { - TEST(IPv4AddressTest, IPv4AddressStatics) + TEST(IPv4AddressTest, DefaultConstructor) { - IPv4Address const& ipZero = IPv4Address::Zero; - EXPECT_EQ(ipZero.toInt(), 0); - EXPECT_EQ(ipZero.toString(), "0.0.0.0"); - - IPv4Address const& ipMulticastLower = IPv4Address::MulticastRangeLowerBound; - EXPECT_EQ(ipMulticastLower.toInt(), 0x000000E0); - EXPECT_EQ(ipMulticastLower.toString(), "224.0.0.0"); - - IPv4Address const& ipMulticastUpper = IPv4Address::MulticastRangeUpperBound; - EXPECT_EQ(ipMulticastUpper.toInt(), 0xFFFFFFEF); - EXPECT_EQ(ipMulticastUpper.toString(), "239.255.255.255"); + IPv4Address addr1; + EXPECT_EQ(addr1.toString(), "0.0.0.0"); + } - EXPECT_TRUE(IPv4Address::isValidIPv4Address("222.146.254.245")); - EXPECT_FALSE(IPv4Address::isValidIPv4Address("222.146.300.245")); - EXPECT_FALSE(IPv4Address::isValidIPv4Address("bogus string")); - }; + TEST(IPv4AddressTest, ConstructorWithInteger) + { + IPv4Address addr2(0x0100A8C0); // 192.168.0.1 + EXPECT_EQ(addr2.toString(), "192.168.0.1"); + } - TEST(IPv4AddressTest, IPv4AddressBasics) - { - IPv4Address ipDefault; - EXPECT_EQ(ipDefault.toInt(), 0); - EXPECT_EQ(ipDefault.toString(), "0.0.0.0"); - EXPECT_EQ(ipDefault, pcpp::IPv4Address::Zero); - - IPv4Address ipString("0.0.0.1"); - EXPECT_EQ(ipString.toInt(), 0x01000000); - EXPECT_EQ(ipString.toString(), "0.0.0.1"); - EXPECT_THROW(IPv4Address("0.0.0.644"), std::invalid_argument) - << "IPv4Address does not throw for out of bounds IP string."; - EXPECT_THROW(IPv4Address("bogusString"), std::invalid_argument) - << "IPv4Address does not throw for non-IP string."; - - IPv4Address ipUint32(0x085201A0); - EXPECT_EQ(ipUint32.toInt(), 0x085201A0); - EXPECT_EQ(ipUint32.toString(), "160.1.82.8"); - - std::array ipArrayBuffer = { 192, 100, 1, 1 }; - IPv4Address ipUint8Raw(ipArrayBuffer.data()); - EXPECT_EQ(ipUint8Raw.toInt(), 0x010164C0); - EXPECT_EQ(ipUint8Raw.toString(), "192.100.1.1"); - EXPECT_EQ(ipUint8Raw.toByteArray(), ipArrayBuffer); - EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), ipUint8Raw.toBytes(), 4)); - - IPv4Address ipUint8Array(ipArrayBuffer); - EXPECT_EQ(ipUint8Array.toInt(), 0x010164C0); - EXPECT_EQ(ipUint8Array.toString(), "192.100.1.1"); - EXPECT_EQ(ipUint8Array.toByteArray(), ipArrayBuffer); - EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), ipUint8Array.toBytes(), 4)); - - EXPECT_TRUE(ipUint8Raw == ipUint8Array) << "Comparison operator '==' does not compare equal values correctly."; - EXPECT_FALSE(ipUint8Raw == ipDefault) << "Comparison operator '==' does not compare unequal values correctly."; - EXPECT_FALSE(ipUint8Raw != ipUint8Array) << "Comparison operator '!=' does not compare equal values correctly."; - EXPECT_TRUE(ipUint8Raw != ipDefault) << "Comparison operator '!=' does not compare unequal values correctly."; - - EXPECT_TRUE(ipDefault < ipString) << "Comparison operator '<' does not compare less than values correctly."; - EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; - }; + TEST(IPv4AddressTest, ConstructorWithByteArray) + { + uint8_t bytes[4] = { 192, 168, 0, 1 }; + IPv4Address addr3(bytes); + EXPECT_EQ(addr3.toString(), "192.168.0.1"); + } - TEST(IPv4AddressTest, OutputStreamOperator) + TEST(IPv4AddressTest, ConstructorWithStdArray) { - IPAddress ip("192.100.1.1"); - std::stringstream ss; - ss << ip; - EXPECT_EQ(ss.str(), "192.100.1.1"); + std::array byteArray = { 192, 168, 0, 1 }; + IPv4Address addr4(byteArray); + EXPECT_EQ(addr4.toString(), "192.168.0.1"); } - TEST(IPv4AddressTest, Literals) + TEST(IPv4AddressTest, ConstructorWithString) { - using namespace pcpp::literals; + IPv4Address addr5("192.168.0.1"); + EXPECT_EQ(addr5.toString(), "192.168.0.1"); + } - IPv4Address ipString = "192.168.1.5"_ipv4; - EXPECT_EQ(ipString.toInt(), 0x0501A8C0); + TEST(IPv4AddressTest, ToBytesMethod) + { + std::array bytes = { 192, 168, 0, 1 }; + IPv4Address addr5("192.168.0.1"); + const uint8_t* addrBytes = addr5.toBytes(); + EXPECT_EQ(memcmp(addrBytes, bytes.data(), 4), 0); } - TEST(IPv4AddressTest, Multicast) + TEST(IPv4AddressTest, IsMulticastMethod) { IPv4Address underMulticastBound(0x000000D1); EXPECT_FALSE(underMulticastBound.isMulticast()); @@ -100,54 +64,102 @@ namespace pcpp IPv4Address overMulticastBound(0x000000F0); EXPECT_FALSE(overMulticastBound.isMulticast()); - }; + } - TEST(IPv4AddressTest, MatchNetwork) + TEST(IPv4AddressTest, EqualityOperator) { - using namespace pcpp::literals; + IPv4Address addr5("192.168.0.1"); + IPv4Address addr6("192.168.0.1"); + EXPECT_TRUE(addr5 == addr6); + IPv4Address addr7("192.168.0.2"); + EXPECT_FALSE(addr5 == addr7); + } + + TEST(IPv4AddressTest, LessThanOperator) + { + IPv4Address addr5("192.168.0.1"); + IPv4Address addr7("192.168.0.2"); + EXPECT_TRUE(addr5 < addr7); + EXPECT_FALSE(addr7 < addr5); + } - IPv4Address ipBase = "192.168.1.1"_ipv4; + TEST(IPv4AddressTest, MatchNetworkMethodWithIPv4Network) + { + IPv4Address addr5("192.168.0.1"); + IPv4Network network("192.168.0.0/24"); + EXPECT_TRUE(addr5.matchNetwork(network)); + + IPv4Network network2("192.168.1.0/24"); + EXPECT_FALSE(addr5.matchNetwork(network2)); + + IPv4Network network3("192.168.1.0/16"); + EXPECT_TRUE(addr5.matchNetwork(network3)); + } - EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/16")); - EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/24")); - EXPECT_TRUE(ipBase.matchNetwork("192.168.1.1/32")); + TEST(IPv4AddressTest, MatchNetworkMethodWithString) + { + IPv4Address addr5("192.168.0.1"); + EXPECT_TRUE(addr5.matchNetwork("192.168.0.0/24")); + EXPECT_FALSE(addr5.matchNetwork("192.168.1.0/24")); + EXPECT_TRUE(addr5.matchNetwork("192.168.1.0/16")); + } - EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/16"))); - EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/24"))); - EXPECT_TRUE(ipBase.matchNetwork(IPv4Network("192.168.1.1/32"))); + TEST(IPv4AddressTest, IsValidIPv4AddressStaticMethod) + { + EXPECT_TRUE(IPv4Address::isValidIPv4Address("192.168.0.1")); + EXPECT_FALSE(IPv4Address::isValidIPv4Address("999.999.999.999")); + EXPECT_FALSE(IPv4Address::isValidIPv4Address("bogus string")); + } - EXPECT_FALSE(ipBase.matchNetwork("192.168.1.2/32")); - EXPECT_FALSE(ipBase.matchNetwork("192.168.2.1/24")); - EXPECT_FALSE(ipBase.matchNetwork("192.169.1.1/16")); + TEST(IPv4AddressTest, OutputStreamOperator) + { + IPAddress ip("192.100.1.1"); + std::stringstream ss; + ss << ip; + EXPECT_EQ(ss.str(), "192.100.1.1"); + } - EXPECT_FALSE(ipBase.matchNetwork(IPv4Network("192.168.1.2/32"))); - EXPECT_FALSE(ipBase.matchNetwork(IPv4Network("192.168.2.1/24"))); - EXPECT_FALSE(ipBase.matchNetwork(IPv4Network("192.169.1.1/16"))); + TEST(IPv4AddressTest, ConstantHelpers) + { + EXPECT_EQ(IPv4Address::Zero.toString(), "0.0.0.0"); + EXPECT_EQ(IPv4Address::MulticastRangeLowerBound.toString(), "224.0.0.0"); + EXPECT_EQ(IPv4Address::MulticastRangeUpperBound.toString(), "239.255.255.255"); }; - TEST(IPv6AddressTest, IPv6AddressStatics) + TEST(IPv4AddressTest, Literals) { - IPv6Address const& ipZero = IPv6Address::Zero; - EXPECT_EQ(ipZero.toString(), "::"); - EXPECT_THAT(ipZero.toByteArray(), ::testing::Each(0)); + using namespace pcpp::literals; - IPv6Address const& ipMulticastLower = IPv6Address::MulticastRangeLowerBound; - EXPECT_EQ(ipMulticastLower.toString(), "ff00::"); - EXPECT_THAT(ipMulticastLower.toByteArray(), - ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00)); - }; + IPv4Address ipString = "192.168.1.5"_ipv4; + EXPECT_EQ(ipString.toInt(), 0x0501A8C0); + } - TEST(IPv6AddressTest, IPv6AddressBasics) + TEST(IPv6AddressTest, DefaultConstructor) { - IPv6Address ipDefault; - EXPECT_EQ(ipDefault.toString(), "::"); - EXPECT_THAT(ipDefault.toByteArray(), ::testing::Each(0)); + IPv6Address addr1; + EXPECT_EQ(addr1.toString(), "::"); + } - IPv6Address ipString("2001:0db8:85a3:0000:0000:8a4e:0370:7334"); - EXPECT_EQ(ipString.toString(), "2001:db8:85a3::8a4e:370:7334"); - EXPECT_THAT(ipString.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, - 0x00, 0x8A, 0x4E, 0x03, 0x70, 0x73, 0x34)); + TEST(IPv6AddressTest, ConstructorWithByteArray) + { + uint8_t bytes[16] = { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; + IPv6Address addr2(bytes); + EXPECT_EQ(addr2.toString(), "2001:db8:85a3::8a2e:370:7334"); + } + + TEST(IPv6AddressTest, ConstructorWithStdArray) + { + std::array byteArray = { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; + IPv6Address addr3(byteArray); + EXPECT_EQ(addr3.toString(), "2001:db8:85a3::8a2e:370:7334"); + } + + TEST(IPv6AddressTest, ConstructorWithString) + { + IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); + EXPECT_EQ(addr4.toString(), "2001:db8:85a3::8a2e:370:7334"); EXPECT_THROW(IPv6Address("2001:0db8:85a3:0000:0000:8a4e:0370:7334:extra"), std::invalid_argument) << "IPv6Address does not throw for out of bounds IP string."; @@ -155,40 +167,70 @@ namespace pcpp << "IPv6Address does not throw for multiple double colon in IP string."; EXPECT_THROW(IPv6Address("bogusString"), std::invalid_argument) << "IPv6Address does not throw for non-IP string."; + } + + TEST(IPv6AddressTest, ToBytesMethod) + { + std::array bytes = { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; + IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); + const uint8_t* addrBytes = addr4.toBytes(); + EXPECT_EQ(memcmp(addrBytes, bytes.data(), 16), 0); + } - std::array ipArrayBuffer = { 0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, - 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34 }; + TEST(IPv6AddressTest, IsMulticastMethod) + { + IPv6Address underMulticastBound("fef0::"); + EXPECT_FALSE(underMulticastBound.isMulticast()); + + IPv6Address atLowerMulticastBound("ff00::"); + EXPECT_TRUE(atLowerMulticastBound.isMulticast()); - IPv6Address ipUint8Raw(ipArrayBuffer.data()); - EXPECT_EQ(ipUint8Raw.toString(), "2001:db8:85a3::8a2e:370:7334"); - EXPECT_THAT(ipUint8Raw.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, - 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); + IPv6Address inMulticastRange("ff00::ef"); + EXPECT_TRUE(inMulticastRange.isMulticast()); + } - IPv6Address ipUint8Array(ipArrayBuffer); - EXPECT_EQ(ipUint8Array.toString(), "2001:db8:85a3::8a2e:370:7334"); - EXPECT_THAT(ipUint8Array.toByteArray(), ::testing::ElementsAre(0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, - 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x34)); + TEST(IPv6AddressTest, EqualityOperator) + { + IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); + IPv6Address addr5("2001:db8:85a3::8a2e:370:7334"); + EXPECT_TRUE(addr4 == addr5); + IPv6Address addr6("2001:db8:85a3::8a2e:370:7335"); + EXPECT_FALSE(addr4 == addr6); + } - EXPECT_TRUE(ipUint8Raw == ipUint8Array) << "Comparison operator '==' does not compare equal values correctly."; - EXPECT_FALSE(ipUint8Raw == ipDefault) << "Comparison operator '==' does not compare unequal values correctly."; - EXPECT_FALSE(ipUint8Raw != ipUint8Array) << "Comparison operator '!=' does not compare equal values correctly."; - EXPECT_TRUE(ipUint8Raw != ipDefault) << "Comparison operator '!=' does not compare unequal values correctly."; + TEST(IPv6AddressTest, LessThanOperator) + { + IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); + IPv6Address addr6("2001:db8:85a3::8a2e:370:7335"); + EXPECT_TRUE(addr4 < addr6); + EXPECT_FALSE(addr6 < addr4); + } - EXPECT_TRUE(ipDefault < ipString) << "Comparison operator '<' does not compare less than values correctly."; - EXPECT_FALSE(ipString < ipDefault) << "Comparison operator '<' does not compare less than values correctly."; + TEST(IPv6AddressTest, MatchNetworkMethodWithIPv6Network) + { + IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); + IPv6Network network("2001:db8::/32"); + EXPECT_TRUE(addr4.matchNetwork(network)); + + IPv6Network network2("2001:db9::/32"); + EXPECT_FALSE(addr4.matchNetwork(network2)); + } - std::array outBuffer = {}; - ipUint8Array.copyTo(outBuffer.data()); - EXPECT_EQ(ipUint8Array.toByteArray(), outBuffer); + TEST(IPv6AddressTest, MatchNetworkMethodWithString) + { + IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); + EXPECT_TRUE(addr4.matchNetwork("2001:db8::/32")); + EXPECT_FALSE(addr4.matchNetwork("2001:db9::/32")); + } - uint8_t* heapOutBuffer = nullptr; - std::size_t heapOutBufferSize = 0; - ipUint8Array.copyTo(&heapOutBuffer, heapOutBufferSize); + TEST(IPv6AddressTest, ConstantHelpers) + { + EXPECT_THAT(IPv6Address::Zero.toByteArray(), ::testing::Each(0)); - ASSERT_NE(heapOutBuffer, nullptr); - EXPECT_EQ(heapOutBufferSize, 16); - EXPECT_TRUE(0 == std::memcmp(ipArrayBuffer.data(), heapOutBuffer, 16)); - delete[] heapOutBuffer; + EXPECT_THAT(IPv6Address::MulticastRangeLowerBound.toByteArray(), + ::testing::ElementsAre(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00)); }; TEST(IPv6AddressTest, OutputStreamOperator) @@ -208,105 +250,90 @@ namespace pcpp 0x00, 0x8A, 0x4E, 0x03, 0x70, 0x73, 0x34)); } - TEST(IPv6AddressTest, Multicast) + TEST(IPAddressTest, DefaultConstructor) { - IPv6Address underMulticastBound("fef0::"); - EXPECT_FALSE(underMulticastBound.isMulticast()); - - IPv6Address atLowerMulticastBound("ff00::"); - EXPECT_TRUE(atLowerMulticastBound.isMulticast()); - - IPv6Address inMulticastRange("ff00::ef"); - EXPECT_TRUE(inMulticastRange.isMulticast()); - }; + IPAddress ipDefault; + EXPECT_EQ(ipDefault.getType(), IPAddress::AddressType::IPv4AddressType); + EXPECT_EQ(ipDefault.getIPv4(), IPv4Address::Zero); + } - TEST(IPv6AddressTest, MatchNetwork) + TEST(IPAddressTest, ConstructorWithIPv4Address) { - using namespace pcpp::literals; - - IPv6Address ipBase = "2001:db8:85a3::8a2e:370:7334"_ipv6; - - EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::8a2e:370:7334/128")); - EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::8a2e:0:0/96")); - EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::/64")); - EXPECT_TRUE(ipBase.matchNetwork("2001:db8:85a3::/32")); - - EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2e:370:7334/128"))); - EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2e:0:0/96"))); - EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::/64"))); - EXPECT_TRUE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::/32"))); - - EXPECT_FALSE(ipBase.matchNetwork("2001:db8:85a3::8a2e:370:7344/128")); - EXPECT_FALSE(ipBase.matchNetwork("2001:db8:85a3::8a2f:0:0/96")); - EXPECT_FALSE(ipBase.matchNetwork("2001:db8:85b3::/64")); - EXPECT_FALSE(ipBase.matchNetwork("2002:db8:85a3::/32")); - - EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2e:370:7344/128"))); - EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2001:db8:85a3::8a2f:0:0/96"))); - EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2001:db8:85b3::/64"))); - EXPECT_FALSE(ipBase.matchNetwork(IPv6Network("2002:db8:85a3::/32"))); - }; + IPv4Address ipv4Addr("192.168.0.1"); + IPAddress addr1(ipv4Addr); + EXPECT_EQ(addr1.getType(), IPAddress::AddressType::IPv4AddressType); + EXPECT_EQ(addr1.getIPv4(), ipv4Addr); + } - TEST(IPAddressTest, IPAddressBasics) + TEST(IPAddressTest, ConstructorWithIPv6Address) { - IPAddress ipDefault; - EXPECT_EQ(ipDefault.getType(), IPAddress::AddressType::IPv4AddressType); - EXPECT_EQ(ipDefault.getIPv4(), IPv4Address::Zero); - EXPECT_TRUE(ipDefault.isZero()); - EXPECT_EQ(ipDefault.toString(), "0.0.0.0"); + IPv6Address ipv6Addr("2001:db8:85a3::8a2e:370:7334"); + IPAddress addr2(ipv6Addr); + EXPECT_EQ(addr2.getType(), IPAddress::AddressType::IPv6AddressType); + EXPECT_EQ(addr2.getIPv6(), ipv6Addr); + } - IPAddress ip4String("192.168.0.1"); - EXPECT_EQ(ip4String.getType(), IPAddress::AddressType::IPv4AddressType); - EXPECT_EQ(ip4String.getIPv4(), IPv4Address("192.168.0.1")); - EXPECT_FALSE(ip4String.isZero()); - EXPECT_EQ(ip4String.toString(), "192.168.0.1"); + TEST(IPAddressTest, ConstructorWithString) + { + IPAddress ipv4String("192.168.0.1"); + EXPECT_EQ(ipv4String.getType(), IPAddress::AddressType::IPv4AddressType); + EXPECT_EQ(ipv4String.getIPv4(), IPv4Address("192.168.0.1")); - IPAddress ip6ZeroString("::"); - EXPECT_EQ(ip6ZeroString.getType(), IPAddress::AddressType::IPv6AddressType); - EXPECT_EQ(ip6ZeroString.getIPv6(), IPv6Address::Zero); - EXPECT_TRUE(ip6ZeroString.isZero()); - EXPECT_EQ(ip6ZeroString.toString(), "::"); + EXPECT_THROW(IPAddress("192.168.300.1"), std::invalid_argument); IPAddress ip6String("2001:db8:85a3::8a2e:370:7334"); EXPECT_EQ(ip6String.getType(), IPAddress::AddressType::IPv6AddressType); EXPECT_EQ(ip6String.getIPv6(), IPv6Address("2001:db8:85a3::8a2e:370:7334")); - EXPECT_FALSE(ip6String.isZero()); - EXPECT_EQ(ip6String.toString(), "2001:db8:85a3::8a2e:370:7334"); - EXPECT_THROW(IPAddress("192.168.300.1"), std::invalid_argument); - EXPECT_THROW(IPAddress("2001:db8:85a3::8a2e:370:7334:extra"), std::invalid_argument) - << "IPAddress does not throw for out of bounds IP string."; - EXPECT_THROW(IPv6Address("2001::ab01::c"), std::invalid_argument) - << "IPAddress does not throw for multiple double colon in IP string."; - EXPECT_THROW(IPAddress("bogusString"), std::invalid_argument) << "IPAddress does not throw for non-IP string."; + EXPECT_THROW(IPAddress("2001:db8:85a3::8a2e:370:7334:extra"), std::invalid_argument); + EXPECT_THROW(IPv6Address("2001::ab01::c"), std::invalid_argument); + EXPECT_THROW(IPAddress("bogusString"), std::invalid_argument); + } - EXPECT_TRUE(ipDefault == IPv4Address::Zero) - << "Comparison operator '==' does not compare equal values correctly."; - EXPECT_FALSE(ipDefault != IPv4Address::Zero) - << "Comparison operator '!=' does not compare equal values correctly."; + TEST(IPAddressTest, AssignmentOperatorWithIPv4Address) + { + IPv4Address ipv4Addr("192.168.0.1"); + IPAddress ipAddr; + ASSERT_EQ(ipAddr.getType(), IPAddress::AddressType::IPv4AddressType); + ASSERT_EQ(ipAddr.getIPv4(), IPv4Address::Zero); - EXPECT_FALSE(ipDefault == ip6ZeroString) - << "Comparison operator '==' between IPv4 and IPv6 should always return false"; - EXPECT_TRUE(ipDefault != ip6ZeroString) - << "Comparison operator '!=' between IPv4 and IPv6 should always return true"; + ipAddr = ipv4Addr; - // Todo: less than operator - }; + EXPECT_EQ(ipAddr.getType(), IPAddress::AddressType::IPv4AddressType); + EXPECT_EQ(ipAddr.getIPv4(), ipv4Addr); + } - TEST(IPAddressTest, OutputStreamOperrator) + TEST(IPAddressTest, AssignmentOperatorWithIPv6Address) + { + IPv6Address ipv6Addr("2001:db8:85a3::8a2e:370:7334"); + IPAddress ipAddr; + ASSERT_EQ(ipAddr.getType(), IPAddress::AddressType::IPv4AddressType); + ASSERT_EQ(ipAddr.getIPv4(), IPv4Address::Zero); + + ipAddr = ipv6Addr; + EXPECT_EQ(ipAddr.getType(), IPAddress::AddressType::IPv6AddressType); + EXPECT_EQ(ipAddr.getIPv6(), ipv6Addr); + } + + TEST(IPAddressTest, IsIPv4Method) { IPAddress ip4("192.168.0.1"); - std::stringstream ss; - ss << ip4; - EXPECT_EQ(ss.str(), "192.168.0.1"); + EXPECT_TRUE(ip4.isIPv4()); IPAddress ip6("2001:db8:85a3::8a2e:370:7334"); - ss.str(""); - ss << ip6; - EXPECT_EQ(ss.str(), "2001:db8:85a3::8a2e:370:7334"); + EXPECT_FALSE(ip6.isIPv4()); + } + + TEST(IPAddressTest, IsIPv6Method) + { + IPAddress ip4("192.168.0.1"); + EXPECT_FALSE(ip4.isIPv6()); + + IPAddress ip6("2001:db8:85a3::8a2e:370:7334"); + EXPECT_TRUE(ip6.isIPv6()); } - TEST(IPAddressTest, Multicast) + TEST(IPAddressTest, IsMulticastMethod) { using namespace pcpp::literals; @@ -343,7 +370,20 @@ namespace pcpp } }; - TEST(IPv4NetworkTest, IPv4NetworkBasics) + TEST(IPAddressTest, OutputStreamOperrator) + { + IPAddress ip4("192.168.0.1"); + std::stringstream ss; + ss << ip4; + EXPECT_EQ(ss.str(), "192.168.0.1"); + + IPAddress ip6("2001:db8:85a3::8a2e:370:7334"); + ss.str(""); + ss << ip6; + EXPECT_EQ(ss.str(), "2001:db8:85a3::8a2e:370:7334"); + } + + TEST(IPv4NetworkTest, ConstructorWithSingleAddress) { using namespace pcpp::literals; @@ -355,7 +395,12 @@ namespace pcpp EXPECT_EQ(netSingle.getHighestAddress(), "192.168.1.1"_ipv4); EXPECT_EQ(netSingle.getTotalAddressCount(), 1); EXPECT_EQ(netSingle.toString(), "192.168.1.1/32"); + } + TEST(IPv4NetworkTest, ConstructorWithAddressAndPrefix) + { + using namespace pcpp::literals; + IPv4Network netPrefix("192.168.1.1"_ipv4, 24u); EXPECT_EQ(netPrefix.getPrefixLen(), 24u); EXPECT_EQ(netPrefix.getNetmask(), "255.255.255.0"); @@ -364,6 +409,11 @@ namespace pcpp EXPECT_EQ(netPrefix.getHighestAddress(), "192.168.1.254"_ipv4); EXPECT_EQ(netPrefix.getTotalAddressCount(), 256); EXPECT_EQ(netPrefix.toString(), "192.168.1.0/24"); + } + + TEST(IPv4NetworkTest, ConstructorWithAddressAndNetmask) + { + using namespace pcpp::literals; IPv4Network netNetmask("192.168.1.1"_ipv4, "255.255.0.0"); EXPECT_EQ(netNetmask.getPrefixLen(), 16u); @@ -373,41 +423,62 @@ namespace pcpp EXPECT_EQ(netNetmask.getHighestAddress(), "192.168.255.254"_ipv4); EXPECT_EQ(netNetmask.getTotalAddressCount(), 256 * 256); EXPECT_EQ(netNetmask.toString(), "192.168.0.0/16"); + } - IPv4Network netStringWithPrefix("192.168.1.1/8"); - EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 8u); - EXPECT_EQ(netStringWithPrefix.getNetmask(), "255.0.0.0"); - EXPECT_EQ(netStringWithPrefix.getNetworkPrefix(), "192.0.0.0"_ipv4); - EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "192.0.0.1"_ipv4); - EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "192.255.255.254"_ipv4); - EXPECT_EQ(netStringWithPrefix.getTotalAddressCount(), 256 * 256 * 256); - EXPECT_EQ(netStringWithPrefix.toString(), "192.0.0.0/8"); - - IPv4Network netStringWithMask("192.168.1.1/255.0.0.0"); - EXPECT_EQ(netStringWithMask.getPrefixLen(), 8u); - EXPECT_EQ(netStringWithMask.getNetmask(), "255.0.0.0"); - EXPECT_EQ(netStringWithMask.getNetworkPrefix(), "192.0.0.0"_ipv4); - EXPECT_EQ(netStringWithMask.getLowestAddress(), "192.0.0.1"_ipv4); - EXPECT_EQ(netStringWithMask.getHighestAddress(), "192.255.255.254"_ipv4); - EXPECT_EQ(netStringWithMask.getTotalAddressCount(), 256 * 256 * 256); - EXPECT_EQ(netStringWithMask.toString(), "192.0.0.0/8"); - }; + TEST(IPv4NetworkTest, ConstructorWithString) + { + using namespace pcpp::literals; + + { + SCOPED_TRACE("Valid c'tor: IPv4 address + prefix len"); + + IPv4Network netStringWithPrefix("192.168.1.1/8"); + EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 8u); + EXPECT_EQ(netStringWithPrefix.getNetmask(), "255.0.0.0"); + EXPECT_EQ(netStringWithPrefix.getNetworkPrefix(), "192.0.0.0"_ipv4); + EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "192.0.0.1"_ipv4); + EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "192.255.255.254"_ipv4); + EXPECT_EQ(netStringWithPrefix.getTotalAddressCount(), 256 * 256 * 256); + EXPECT_EQ(netStringWithPrefix.toString(), "192.0.0.0/8"); + } - TEST(IPv4NetworkTest, IPv4NetworkIncludes) + { + SCOPED_TRACE("Valid c'tor: IPv4 address + netmask"); + + IPv4Network netStringWithMask("192.168.1.1/255.0.0.0"); + EXPECT_EQ(netStringWithMask.getPrefixLen(), 8u); + EXPECT_EQ(netStringWithMask.getNetmask(), "255.0.0.0"); + EXPECT_EQ(netStringWithMask.getNetworkPrefix(), "192.0.0.0"_ipv4); + EXPECT_EQ(netStringWithMask.getLowestAddress(), "192.0.0.1"_ipv4); + EXPECT_EQ(netStringWithMask.getHighestAddress(), "192.255.255.254"_ipv4); + EXPECT_EQ(netStringWithMask.getTotalAddressCount(), 256 * 256 * 256); + EXPECT_EQ(netStringWithMask.toString(), "192.0.0.0/8"); + } + } + + TEST(IPv4NetworkTest, IncludesMethod) { using namespace pcpp::literals; IPv4Network netBase("192.168.0.0/16"); - EXPECT_TRUE(netBase.includes("192.168.1.0"_ipv4)); - EXPECT_TRUE(netBase.includes("192.168.1.1"_ipv4)); - EXPECT_TRUE(netBase.includes("192.168.2.1"_ipv4)); - EXPECT_FALSE(netBase.includes("192.169.2.1"_ipv4)); + { + SCOPED_TRACE("With single address"); + + EXPECT_TRUE(netBase.includes("192.168.1.0"_ipv4)); + EXPECT_TRUE(netBase.includes("192.168.1.1"_ipv4)); + EXPECT_TRUE(netBase.includes("192.168.2.1"_ipv4)); + EXPECT_FALSE(netBase.includes("192.169.2.1"_ipv4)); + } + + { + SCOPED_TRACE("With network"); - EXPECT_TRUE(netBase.includes(IPv4Network("192.168.1.0/24"))); - EXPECT_TRUE(netBase.includes(IPv4Network("192.168.2.0/24"))); - EXPECT_TRUE(netBase.includes(IPv4Network("192.168.0.0/16"))); - EXPECT_FALSE(netBase.includes(IPv4Network("192.0.0.0/8"))); + EXPECT_TRUE(netBase.includes(IPv4Network("192.168.1.0/24"))); + EXPECT_TRUE(netBase.includes(IPv4Network("192.168.2.0/24"))); + EXPECT_TRUE(netBase.includes(IPv4Network("192.168.0.0/16"))); + EXPECT_FALSE(netBase.includes(IPv4Network("192.0.0.0/8"))); + } }; TEST(IPv4NetworkTest, OutputStreamOperator) @@ -418,7 +489,7 @@ namespace pcpp EXPECT_EQ(ss.str(), "192.168.1.1/32"); } - TEST(IPv6NetworkTest, IPv6NetworkBasics) + TEST(IPv6NetworkTest, ConstructorWithSingleAddress) { using namespace pcpp::literals; @@ -430,6 +501,11 @@ namespace pcpp EXPECT_EQ(netSingle.getHighestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); EXPECT_EQ(netSingle.getTotalAddressCount(), 1); EXPECT_EQ(netSingle.toString(), "2001:db8:85a3::8a2e:370:7334/128"); + } + + TEST(IPv6NetworkTest, ConstructorWithAddressAndPrefix) + { + using namespace pcpp::literals; IPv6Network netPrefix("2001:db8:85a3::8a2e:370:7334"_ipv6, 96u); EXPECT_EQ(netPrefix.getPrefixLen(), 96u); @@ -439,6 +515,11 @@ namespace pcpp EXPECT_EQ(netPrefix.getHighestAddress(), "2001:db8:85a3::8a2e:ffff:ffff"_ipv6); EXPECT_EQ(netPrefix.getTotalAddressCount(), 4294967296ul); EXPECT_EQ(netPrefix.toString(), "2001:db8:85a3::8a2e:0:0/96"); + } + + TEST(IPv6NetworkTest, ConstructorWithAddressAndNetmask) + { + using namespace pcpp::literals; IPv6Network netNetmask("2001:db8:85a3::8a2e:370:7334"_ipv6, "ffff:ffff:ffff:ffff::"); EXPECT_EQ(netNetmask.getPrefixLen(), 64u); @@ -448,39 +529,59 @@ namespace pcpp EXPECT_EQ(netNetmask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); EXPECT_THROW(netNetmask.getTotalAddressCount(), std::out_of_range); EXPECT_EQ(netNetmask.toString(), "2001:db8:85a3::/64"); + } - IPv6Network netStringWithPrefix("2001:db8:85a3::8a2e:370:7334/64"); - EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 64u); - EXPECT_EQ(netStringWithPrefix.getNetmask(), "ffff:ffff:ffff:ffff::"); - EXPECT_EQ(netStringWithPrefix.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); - EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "2001:db8:85a3::1"_ipv6); - EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); - EXPECT_THROW(netStringWithPrefix.getTotalAddressCount(), std::out_of_range); - EXPECT_EQ(netStringWithPrefix.toString(), "2001:db8:85a3::/64"); - - IPv6Network netStringWithMask("2001:db8:85a3::8a2e:370:7334/ffff:ffff:ffff:ffff::"); - EXPECT_EQ(netStringWithMask.getPrefixLen(), 64u); - EXPECT_EQ(netStringWithMask.getNetmask(), "ffff:ffff:ffff:ffff::"); - EXPECT_EQ(netStringWithMask.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); - EXPECT_EQ(netStringWithMask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); - EXPECT_EQ(netStringWithMask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); - EXPECT_THROW(netStringWithMask.getTotalAddressCount(), std::out_of_range); - EXPECT_EQ(netStringWithMask.toString(), "2001:db8:85a3::/64"); - }; + TEST(IPv6NetworkTest, ConstructorWithString) + { + using namespace pcpp::literals; - TEST(IPv6NetworkTest, IPv6NetworkIncludes) + { + SCOPED_TRACE("Valid c'tor: IPv6 address + prefix len"); + + IPv6Network netStringWithPrefix("2001:db8:85a3::8a2e:370:7334/64"); + EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 64u); + EXPECT_EQ(netStringWithPrefix.getNetmask(), "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netStringWithPrefix.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); + EXPECT_EQ(netStringWithPrefix.getLowestAddress(), "2001:db8:85a3::1"_ipv6); + EXPECT_EQ(netStringWithPrefix.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); + EXPECT_THROW(netStringWithPrefix.getTotalAddressCount(), std::out_of_range); + EXPECT_EQ(netStringWithPrefix.toString(), "2001:db8:85a3::/64"); + } + + { + SCOPED_TRACE("Valid c'tor: IPv6 address + netmask"); + + IPv6Network netStringWithMask("2001:db8:85a3::8a2e:370:7334/ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netStringWithMask.getPrefixLen(), 64u); + EXPECT_EQ(netStringWithMask.getNetmask(), "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netStringWithMask.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); + EXPECT_EQ(netStringWithMask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); + EXPECT_EQ(netStringWithMask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); + EXPECT_THROW(netStringWithMask.getTotalAddressCount(), std::out_of_range); + EXPECT_EQ(netStringWithMask.toString(), "2001:db8:85a3::/64"); + } + } + TEST(IPv6NetworkTest, IncludesMethod) { using namespace pcpp::literals; IPv6Network netBase("2001:db8:85a3:34ac::/64"); - EXPECT_TRUE(netBase.includes("2001:db8:85a3:34ac::1"_ipv6)); - EXPECT_TRUE(netBase.includes("2001:db8:85a3:34ac:c::2"_ipv6)); - EXPECT_FALSE(netBase.includes("2001:db8:85a3:34ab::1"_ipv6)); + { + SCOPED_TRACE("With single address"); + + EXPECT_TRUE(netBase.includes("2001:db8:85a3:34ac::1"_ipv6)); + EXPECT_TRUE(netBase.includes("2001:db8:85a3:34ac:c::2"_ipv6)); + EXPECT_FALSE(netBase.includes("2001:db8:85a3:34ab::1"_ipv6)); + } - EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/64"))); - EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/72"))); - EXPECT_FALSE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/56"))); + { + SCOPED_TRACE("With network"); + + EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/64"))); + EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/72"))); + EXPECT_FALSE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/56"))); + } }; TEST(IPv6NetworkTest, OutputStreamOperator) @@ -493,34 +594,103 @@ namespace pcpp EXPECT_EQ(ss.str(), "2001:db8:85a3:34ac::/64"); } - TEST(IPNetworkTest, IPNetworkBasics) + TEST(IPNetworkTest, ConstructorWithSingleAddress) { using namespace pcpp::literals; - IPNetwork netSingleV4("192.168.1.1"_ipv4); - EXPECT_TRUE(netSingleV4.isIPv4Network()); - EXPECT_FALSE(netSingleV4.isIPv6Network()); - EXPECT_EQ(netSingleV4.getPrefixLen(), 32u); - EXPECT_EQ(netSingleV4.getNetmask(), "255.255.255.255"); - EXPECT_EQ(netSingleV4.getNetworkPrefix(), "192.168.1.1"_ipv4); - EXPECT_EQ(netSingleV4.getLowestAddress(), "192.168.1.1"_ipv4); - EXPECT_EQ(netSingleV4.getHighestAddress(), "192.168.1.1"_ipv4); - EXPECT_EQ(netSingleV4.getTotalAddressCount(), 1); - EXPECT_EQ(netSingleV4.toString(), "192.168.1.1/32"); - - IPNetwork netSingleV6("2001:db8:85a3::8a2e:370:7334"_ipv6); - EXPECT_FALSE(netSingleV6.isIPv4Network()); - EXPECT_TRUE(netSingleV6.isIPv6Network()); - EXPECT_EQ(netSingleV6.getPrefixLen(), 128u); - EXPECT_EQ(netSingleV6.getNetmask(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - EXPECT_EQ(netSingleV6.getNetworkPrefix(), "2001:db8:85a3::8a2e:370:7334"_ipv6); - EXPECT_EQ(netSingleV6.getLowestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); - EXPECT_EQ(netSingleV6.getHighestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); - EXPECT_EQ(netSingleV6.getTotalAddressCount(), 1); - EXPECT_EQ(netSingleV6.toString(), "2001:db8:85a3::8a2e:370:7334/128"); - }; + { + SCOPED_TRACE("IPv4 address"); + + IPNetwork netSingleV4("192.168.1.1"_ipv4); + EXPECT_TRUE(netSingleV4.isIPv4Network()); + EXPECT_FALSE(netSingleV4.isIPv6Network()); + EXPECT_EQ(netSingleV4.getPrefixLen(), 32u); + EXPECT_EQ(netSingleV4.getNetmask(), "255.255.255.255"); + EXPECT_EQ(netSingleV4.getNetworkPrefix(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingleV4.getLowestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingleV4.getHighestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netSingleV4.getTotalAddressCount(), 1); + EXPECT_EQ(netSingleV4.toString(), "192.168.1.1/32"); + } + { + SCOPED_TRACE("IPv6 address"); + + IPNetwork netSingleV6("2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_FALSE(netSingleV6.isIPv4Network()); + EXPECT_TRUE(netSingleV6.isIPv6Network()); + EXPECT_EQ(netSingleV6.getPrefixLen(), 128u); + EXPECT_EQ(netSingleV6.getNetmask(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + EXPECT_EQ(netSingleV6.getNetworkPrefix(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingleV6.getLowestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingleV6.getHighestAddress(), "2001:db8:85a3::8a2e:370:7334"_ipv6); + EXPECT_EQ(netSingleV6.getTotalAddressCount(), 1); + EXPECT_EQ(netSingleV6.toString(), "2001:db8:85a3::8a2e:370:7334/128"); + } + } + + TEST(IPNetworkTest, ConstructorWithAddressAndPrefix) + { + using namespace pcpp::literals; + + { + SCOPED_TRACE("IPv4 address"); + + IPNetwork netPrefix("192.168.1.1"_ipv4, 24u); + EXPECT_EQ(netPrefix.getPrefixLen(), 24u); + EXPECT_EQ(netPrefix.getNetmask(), "255.255.255.0"); + EXPECT_EQ(netPrefix.getNetworkPrefix(), "192.168.1.0"_ipv4); + EXPECT_EQ(netPrefix.getLowestAddress(), "192.168.1.1"_ipv4); + EXPECT_EQ(netPrefix.getHighestAddress(), "192.168.1.254"_ipv4); + EXPECT_EQ(netPrefix.getTotalAddressCount(), 256); + EXPECT_EQ(netPrefix.toString(), "192.168.1.0/24"); + } + + { + SCOPED_TRACE("IPv6 address"); + + IPNetwork netPrefix("2001:db8:85a3::8a2e:370:7334"_ipv6, 96u); + EXPECT_EQ(netPrefix.getPrefixLen(), 96u); + EXPECT_EQ(netPrefix.getNetmask(), "ffff:ffff:ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netPrefix.getNetworkPrefix(), "2001:db8:85a3::8a2e:0:0"_ipv6); + EXPECT_EQ(netPrefix.getLowestAddress(), "2001:db8:85a3::8a2e:0:1"_ipv6); + EXPECT_EQ(netPrefix.getHighestAddress(), "2001:db8:85a3::8a2e:ffff:ffff"_ipv6); + EXPECT_EQ(netPrefix.getTotalAddressCount(), 4294967296ul); + EXPECT_EQ(netPrefix.toString(), "2001:db8:85a3::8a2e:0:0/96"); + } + } + + TEST(IPNetworkTest, ConstructorWithAddressAndNetmask) + { + using namespace pcpp::literals; + + { + SCOPED_TRACE("IPv4 address"); + + IPNetwork netNetmask("192.168.1.1"_ipv4, "255.255.0.0"); + EXPECT_EQ(netNetmask.getPrefixLen(), 16u); + EXPECT_EQ(netNetmask.getNetmask(), "255.255.0.0"); + EXPECT_EQ(netNetmask.getNetworkPrefix(), "192.168.0.0"_ipv4); + EXPECT_EQ(netNetmask.getLowestAddress(), "192.168.0.1"_ipv4); + EXPECT_EQ(netNetmask.getHighestAddress(), "192.168.255.254"_ipv4); + EXPECT_EQ(netNetmask.getTotalAddressCount(), 256 * 256); + EXPECT_EQ(netNetmask.toString(), "192.168.0.0/16"); + } + + { + SCOPED_TRACE("IPv6 address"); + + IPNetwork netNetmask("2001:db8:85a3::8a2e:370:7334"_ipv6, "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netNetmask.getPrefixLen(), 64u); + EXPECT_EQ(netNetmask.getNetmask(), "ffff:ffff:ffff:ffff::"); + EXPECT_EQ(netNetmask.getNetworkPrefix(), "2001:db8:85a3::"_ipv6); + EXPECT_EQ(netNetmask.getLowestAddress(), "2001:db8:85a3::1"_ipv6); + EXPECT_EQ(netNetmask.getHighestAddress(), "2001:db8:85a3::ffff:ffff:ffff:ffff"_ipv6); + EXPECT_THROW(netNetmask.getTotalAddressCount(), std::out_of_range); + EXPECT_EQ(netNetmask.toString(), "2001:db8:85a3::/64"); + } + } - TEST(IPNetworkTest, IPNetworkIncludes) + TEST(IPNetworkTest, IncludesMethodWithIPv4) { using namespace pcpp::literals; @@ -541,6 +711,11 @@ namespace pcpp << "IPNetwork in V4 mode should not match V6 equivalents."; EXPECT_FALSE(netBaseV4.includes(IPNetwork("::c0a9:0201/116"))) << "IPNetwork in V4 mode should not match V6 equivalents."; + } + + TEST(IPNetworkTest, IncludesMethodWithIPv6) + { + using namespace pcpp::literals; IPNetwork netBaseV6("2001:db8:85a3:34ac::/64"); EXPECT_TRUE(netBaseV6.includes("2001:db8:85a3:34ac::1"_ipv6)); @@ -565,7 +740,7 @@ namespace pcpp << "IPNetwork in V6 mode should not match V4 equivalent ranges."; EXPECT_FALSE(netBaseV6_V4compat.includes(IPNetwork("192.169.1.1/17"))) << "IPNetwork in V6 mode should not match V4 equivalent ranges."; - }; + } TEST(IPNetworkTest, OutputStreamOperator) { diff --git a/Tests/Common++Test/Tests/LRUListTests.cpp b/Tests/Common++Test/Tests/LRUListTests.cpp index 62795474e9..86483b59ba 100644 --- a/Tests/Common++Test/Tests/LRUListTests.cpp +++ b/Tests/Common++Test/Tests/LRUListTests.cpp @@ -6,68 +6,83 @@ namespace pcpp { - TEST(LRUListTest, PutAndErase) + TEST(LRUListTest, PutTest) { - int deletedValue = 0; - LRUList lruCache(4); - EXPECT_EQ(lruCache.getMaxSize(), 4); - EXPECT_EQ(lruCache.getSize(), 0); - ASSERT_EQ(deletedValue, 0); - - lruCache.put(1, &deletedValue); - EXPECT_EQ(lruCache.getSize(), 1); - EXPECT_EQ(deletedValue, 0); - - lruCache.put(1, &deletedValue); - EXPECT_EQ(lruCache.getSize(), 1); - EXPECT_EQ(deletedValue, 0); - - lruCache.put(2, &deletedValue); - EXPECT_EQ(deletedValue, 0); - lruCache.put(3, &deletedValue); - EXPECT_EQ(deletedValue, 0); - lruCache.put(4, &deletedValue); - EXPECT_EQ(lruCache.getMaxSize(), 4); - EXPECT_EQ(lruCache.getSize(), 4); - EXPECT_EQ(deletedValue, 0); - - lruCache.put(5, &deletedValue); - EXPECT_EQ(lruCache.getMaxSize(), 4); - EXPECT_EQ(lruCache.getSize(), 4); + LRUList lruList(3); + int deletedValue; + + // Test inserting elements + EXPECT_EQ(lruList.put(1), 0); + EXPECT_EQ(lruList.put(2), 0); + EXPECT_EQ(lruList.put(3), 0); + EXPECT_EQ(lruList.getSize(), 3); + + // Test inserting an element that exceeds the max size + EXPECT_EQ(lruList.put(4, &deletedValue), 1); EXPECT_EQ(deletedValue, 1); + EXPECT_EQ(lruList.getSize(), 3); + + // Test inserting an existing element + EXPECT_EQ(lruList.put(2), 0); + EXPECT_EQ(lruList.getSize(), 3); + } + + TEST(LRUListTest, GetTest) + { + LRUList lruList(2); + + lruList.put("first"); + lruList.put("second"); + + // Test getting the most recently used element + EXPECT_EQ(lruList.getMRUElement(), "second"); - deletedValue = 0; - ASSERT_EQ(deletedValue, 0); - lruCache.eraseElement(3); - EXPECT_EQ(lruCache.getSize(), 3); + // Test getting the least recently used element + EXPECT_EQ(lruList.getLRUElement(), "first"); - lruCache.put(6, &deletedValue); - EXPECT_EQ(deletedValue, 0); - EXPECT_EQ(lruCache.getSize(), 4); + lruList.put("third"); - lruCache.eraseElement(7); - EXPECT_EQ(lruCache.getSize(), 4); - }; + // Test getting the new most recently used element + EXPECT_EQ(lruList.getMRUElement(), "third"); - TEST(LRUListTest, RecentlyUsedElementAccessors) + // Test getting the new least recently used element + EXPECT_EQ(lruList.getLRUElement(), "second"); + } + + TEST(LRUListTest, EraseTest) { - LRUList lruCache(4); - ASSERT_EQ(lruCache.getMaxSize(), 4); + LRUList lruList(3); + + lruList.put(1); + lruList.put(2); + lruList.put(3); + + // Test erasing an element + lruList.eraseElement(2); + EXPECT_EQ(lruList.getSize(), 2); + + // Test erasing a non-existing element + lruList.eraseElement(4); + EXPECT_EQ(lruList.getSize(), 2); + } + + TEST(LRUListTest, SizeTest) + { + LRUList lruList(3); + + // Test initial size + EXPECT_EQ(lruList.getSize(), 0); - lruCache.put(1); - lruCache.put(2); - lruCache.put(3); - lruCache.put(4); + lruList.put(1); + lruList.put(2); - EXPECT_EQ(lruCache.getMRUElement(), 4); - EXPECT_EQ(lruCache.getLRUElement(), 1); + // Test size after inserting elements + EXPECT_EQ(lruList.getSize(), 2); - lruCache.put(5); - EXPECT_EQ(lruCache.getMRUElement(), 5); - EXPECT_EQ(lruCache.getLRUElement(), 2); + lruList.put(3); + lruList.put(4); - lruCache.put(3); - EXPECT_EQ(lruCache.getMRUElement(), 3); - EXPECT_EQ(lruCache.getLRUElement(), 2); - }; + // Test size after exceeding max size + EXPECT_EQ(lruList.getSize(), 3); + } } // namespace pcpp diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp index f2c01e605d..eab5e5b075 100644 --- a/Tests/Common++Test/Tests/MacAddressTests.cpp +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -8,61 +8,116 @@ namespace pcpp { - TEST(MacAddressTest, MacAddressStatics) + TEST(MacAddressTest, DefaultConstructor) { - EXPECT_EQ(MacAddress::Zero.toString(), "00:00:00:00:00:00"); - }; + pcpp::MacAddress mac; + std::array expected = { 0, 0, 0, 0, 0, 0 }; + EXPECT_EQ(std::memcmp(mac.getRawData(), expected.data(), 6), 0); + } - TEST(MacAddressTest, MacAddressBasics) + TEST(MacAddressTest, ByteArrayConstructor) { - MacAddress macAddr1; - EXPECT_EQ(macAddr1.toString(), "00:00:00:00:00:00"); + uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 }; + pcpp::MacAddress mac(addr); + EXPECT_EQ(std::memcmp(mac.getRawData(), addr, 6), 0); + } - std::array addr = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - MacAddress macAddr2(addr.data()); - EXPECT_EQ(macAddr2.toString(), "00:11:22:33:44:55"); + TEST(MacAddressTest, StdArrayConstructor) + { + std::array addr = { 1, 2, 3, 4, 5, 6 }; + pcpp::MacAddress mac(addr); + EXPECT_EQ(std::memcmp(mac.getRawData(), addr.data(), 6), 0); + } - MacAddress macAddr3(addr); - EXPECT_EQ(macAddr3.toString(), "00:11:22:33:44:55"); + TEST(MacAddressTest, StringConstructor) + { + std::string addr = "01:02:03:04:05:06"; + pcpp::MacAddress mac(addr); + std::array expected = { 1, 2, 3, 4, 5, 6 }; + EXPECT_EQ(std::memcmp(mac.getRawData(), expected.data(), 6), 0); - MacAddress macAddr4("00:11:22:33:44:55"); - EXPECT_EQ(macAddr4.toString(), "00:11:22:33:44:55"); - EXPECT_THROW(MacAddress("00:11:22:33:44"), std::invalid_argument); - EXPECT_THROW(MacAddress("00:11:22:33:44:55:66"), std::invalid_argument); - EXPECT_THROW(MacAddress("bogus string"), std::invalid_argument); + EXPECT_THROW(pcpp::MacAddress("01:02:03:04:05"), std::invalid_argument); + EXPECT_THROW(pcpp::MacAddress("01:02:03:04:05:06:07"), std::invalid_argument); + EXPECT_THROW(pcpp::MacAddress("bogus string"), std::invalid_argument); + } - MacAddress macAddr5(std::string("00:11:22:33:44:55")); - EXPECT_EQ(macAddr5.toString(), "00:11:22:33:44:55"); + TEST(MacAddressTest, OctetConstructor) + { + pcpp::MacAddress mac(1, 2, 3, 4, 5, 6); + std::array expected = { 1, 2, 3, 4, 5, 6 }; + EXPECT_EQ(std::memcmp(mac.getRawData(), expected.data(), 6), 0); + } - MacAddress macAddr6(0x00, 0x11, 0x22, 0x33, 0x44, 0x55); - EXPECT_EQ(macAddr6.toString(), "00:11:22:33:44:55"); + TEST(MacAddressTest, InitializerListConstructor) + { + pcpp::MacAddress mac({ 1, 2, 3, 4, 5, 6 }); + std::array expected = { 1, 2, 3, 4, 5, 6 }; + EXPECT_EQ(std::memcmp(mac.getRawData(), expected.data(), 6), 0); + } - MacAddress macAddr7{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - EXPECT_EQ(macAddr7.toString(), "00:11:22:33:44:55"); - EXPECT_THROW(MacAddress({ 0x00, 0x11, 0x22, 0x33, 0x44 }), std::invalid_argument); - EXPECT_THROW(MacAddress({ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }), std::invalid_argument); + TEST(MacAddressTest, EqualityOperator) + { + pcpp::MacAddress mac1(1, 2, 3, 4, 5, 6); + pcpp::MacAddress mac2(1, 2, 3, 4, 5, 6); + EXPECT_TRUE(mac1 == mac2); - MacAddress macAddr8 = "00:11:22:33:44:55"; - EXPECT_EQ(macAddr8.toString(), "00:11:22:33:44:55"); + pcpp::MacAddress mac3(1, 2, 3, 4, 5, 7); + EXPECT_FALSE(mac1 == mac3); + } - MacAddress macAddr9 = std::string("00:11:22:33:44:55"); - EXPECT_EQ(macAddr9.toString(), "00:11:22:33:44:55"); + TEST(MacAddressTest, InequalityOperator) + { + pcpp::MacAddress mac1(1, 2, 3, 4, 5, 6); + pcpp::MacAddress mac2(1, 2, 3, 4, 5, 7); + EXPECT_TRUE(mac1 != mac2); - MacAddress macAddr10 = MacAddress("00:11:22:33:44:55"); - EXPECT_EQ(macAddr10.toString(), "00:11:22:33:44:55"); + pcpp::MacAddress mac3(1, 2, 3, 4, 5, 6); + EXPECT_FALSE(mac1 != mac3); + } - EXPECT_FALSE(macAddr1 == macAddr2) << "Comparison operator '==' does not compare unequal values correctly."; - EXPECT_TRUE(macAddr2 == macAddr3) << "Comparison operator '==' does not compare equal values correctly."; + TEST(MacAddressTest, AssignmentOperator) + { + pcpp::MacAddress mac; + mac = { 1, 2, 3, 4, 5, 6 }; + std::array expected = { 1, 2, 3, 4, 5, 6 }; + EXPECT_EQ(std::memcmp(mac.getRawData(), expected.data(), 6), 0); + } - EXPECT_TRUE(macAddr1 != macAddr2) << "Comparison operator '!=' does not compare unequal values correctly."; - EXPECT_FALSE(macAddr2 != macAddr3) << "Comparison operator '!=' does not compare equal values correctly."; - }; + TEST(MacAddressTest, ToString) + { + pcpp::MacAddress mac(1, 2, 3, 4, 5, 6); + EXPECT_EQ(mac.toString(), "01:02:03:04:05:06"); + } + + TEST(MacAddressTest, CopyToAllocatedArray) + { + pcpp::MacAddress mac(1, 2, 3, 4, 5, 6); + uint8_t* arr = nullptr; + mac.copyTo(&arr); + std::array expected = { 1, 2, 3, 4, 5, 6 }; + EXPECT_EQ(std::memcmp(arr, expected.data(), 6), 0); + delete[] arr; + } + + TEST(MacAddressTest, CopyToPreAllocatedArray) + { + pcpp::MacAddress mac(1, 2, 3, 4, 5, 6); + std::array arr; + mac.copyTo(arr.data()); + std::array expected = { 1, 2, 3, 4, 5, 6 }; + EXPECT_EQ(arr, expected); + } TEST(MacAddressTest, OutputStreamOperator) { - MacAddress macAddr("00:11:22:33:44:55"); + MacAddress macAddr(1, 2, 3, 4, 5, 6); std::stringstream stream; stream << macAddr; - EXPECT_EQ(stream.str(), "00:11:22:33:44:55"); + EXPECT_EQ(stream.str(), "01:02:03:04:05:06"); + }; + + TEST(MacAddressTest, ConstantHelpers) + { + EXPECT_EQ(MacAddress::Zero, MacAddress(0, 0, 0, 0, 0, 0)); }; } // namespace pcpp diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index edba7d4b16..9299fef2af 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include @@ -11,111 +11,170 @@ namespace pcpp { - class PointerVectorTest : public MemoryLeakDetectorTest + class TestObject { + public: + TestObject(int value) : m_Value(value) + {} + int getValue() const + { + return m_Value; + } + std::unique_ptr clone() const + { + return std::make_unique(*this); + } + + private: + int m_Value; }; - TEST_F(PointerVectorTest, PointerVectorBasics) + class PointerVectorTest : public MemoryLeakDetectorTest { - PointerVector pVector; - PointerVector const& cpVector = pVector; - EXPECT_EQ(pVector.size(), 0); - - pVector.pushBack(new int(1)); - EXPECT_EQ(pVector.size(), 1); - - EXPECT_THROW(pVector.pushBack(static_cast(nullptr)), std::invalid_argument); - EXPECT_THROW(pVector.pushBack(std::unique_ptr()), std::invalid_argument); - - int* atIdx0 = pVector.at(0); - ASSERT_NE(atIdx0, nullptr); - EXPECT_EQ(*atIdx0, 1); + }; - int const* cAtIdx0 = cpVector.at(0); - ASSERT_NE(cAtIdx0, nullptr); - EXPECT_EQ(*cAtIdx0, 1); + TEST_F(PointerVectorTest, DefaultConstructor) + { + pcpp::PointerVector vec; + EXPECT_EQ(vec.size(), 0); + } - pVector.pushBack(std::unique_ptr(new int(2))); - EXPECT_EQ(pVector.size(), 2); + TEST_F(PointerVectorTest, CopyConstructor) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + + pcpp::PointerVector copyVec(vec); + EXPECT_EQ(copyVec.size(), 2); + EXPECT_EQ(copyVec.at(0)->getValue(), 1); + EXPECT_EQ(copyVec.at(1)->getValue(), 2); + } - { - int* atFront = pVector.front(); - ASSERT_NE(atFront, nullptr); - EXPECT_EQ(*atFront, 1); + TEST_F(PointerVectorTest, MoveConstructor) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + + pcpp::PointerVector movedVec(std::move(vec)); + EXPECT_EQ(movedVec.size(), 2); + EXPECT_EQ(movedVec.at(0)->getValue(), 1); + EXPECT_EQ(movedVec.at(1)->getValue(), 2); + EXPECT_EQ(vec.size(), 0); + } - int const* cAtFront = cpVector.front(); - ASSERT_NE(cAtFront, nullptr); - EXPECT_EQ(*cAtFront, 1); + TEST_F(PointerVectorTest, CopyAssignmentOperator) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + + pcpp::PointerVector copyVec; + copyVec = vec; + EXPECT_EQ(copyVec.size(), 2); + EXPECT_EQ(copyVec.at(0)->getValue(), 1); + EXPECT_EQ(copyVec.at(1)->getValue(), 2); + } - int* atBack = pVector.back(); - ASSERT_NE(atBack, nullptr); - EXPECT_EQ(*atBack, 2); + TEST_F(PointerVectorTest, MoveAssignmentOperator) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + + pcpp::PointerVector movedVec; + movedVec = std::move(vec); + EXPECT_EQ(movedVec.size(), 2); + EXPECT_EQ(movedVec.at(0)->getValue(), 1); + EXPECT_EQ(movedVec.at(1)->getValue(), 2); + EXPECT_EQ(vec.size(), 0); + } - int const* cAtBack = cpVector.back(); - ASSERT_NE(cAtBack, nullptr); - EXPECT_EQ(*cAtBack, 2); - } + TEST_F(PointerVectorTest, PushBack) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); - { - auto itBegin = pVector.begin(); - auto itEnd = pVector.end(); + EXPECT_EQ(vec.size(), 2); + EXPECT_EQ(vec.at(0)->getValue(), 1); + EXPECT_EQ(vec.at(1)->getValue(), 2); + } - EXPECT_EQ(std::distance(itBegin, itEnd), 2); - EXPECT_EQ(**itBegin, 1); - EXPECT_EQ(**std::next(itBegin), 2); - } + TEST_F(PointerVectorTest, PushBackUniquePtr) + { + pcpp::PointerVector vec; + vec.pushBack(std::unique_ptr(new TestObject(1))); + vec.pushBack(std::unique_ptr(new TestObject(2))); - { - std::unique_ptr p = pVector.getAndDetach(1); - EXPECT_EQ(*p, 2); - EXPECT_EQ(pVector.size(), 1); - } + EXPECT_EQ(vec.size(), 2); + EXPECT_EQ(vec.at(0)->getValue(), 1); + EXPECT_EQ(vec.at(1)->getValue(), 2); + } - PointerVector pVectorCopy = pVector; - EXPECT_EQ(pVectorCopy.size(), pVector.size()); - EXPECT_NE(pVectorCopy.at(0), pVector.at(0)); - EXPECT_EQ(*pVectorCopy.at(0), *pVector.at(0)); + TEST_F(PointerVectorTest, Clear) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + vec.clear(); - { - PointerVector pVectorMove = std::move(pVector); - EXPECT_EQ(pVector.size(), 0); - EXPECT_EQ(pVectorMove.size(), 1); - EXPECT_EQ(*pVectorMove.at(0), 1); + EXPECT_EQ(vec.size(), 0); + } - pVector = std::move(pVectorMove); - ASSERT_EQ(pVector.size(), 1); - } + TEST_F(PointerVectorTest, Erase) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + vec.pushBack(new TestObject(3)); + + auto it = vec.begin(); + ++it; + vec.erase(it); + + EXPECT_EQ(vec.size(), 2); + EXPECT_EQ(vec.at(0)->getValue(), 1); + EXPECT_EQ(vec.at(1)->getValue(), 3); + } - pVectorCopy.clear(); - EXPECT_EQ(pVectorCopy.size(), 0); - EXPECT_EQ(pVector.size(), 1); + TEST_F(PointerVectorTest, GetAndDetach) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); + + auto obj = vec.getAndDetach(0); + EXPECT_EQ(obj->getValue(), 1); + EXPECT_EQ(vec.size(), 1); + EXPECT_EQ(vec.at(0)->getValue(), 2); + } - pVector.pushBack(new int(3)); - EXPECT_EQ(pVector.size(), 2); + TEST_F(PointerVectorTest, At) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); - { - // Can't pass pVector.begin() directly to getAndRemoveFromVector because temporaries can't be passed as - // non-const reference. - auto it = pVector.begin(); - int* removed = pVector.getAndRemoveFromVector(it); - EXPECT_EQ(*removed, 1); - EXPECT_EQ(pVector.size(), 1); - EXPECT_EQ(*pVector.front(), 3); - delete removed; - } + EXPECT_EQ(vec.at(0)->getValue(), 1); + EXPECT_EQ(vec.at(1)->getValue(), 2); + } - pVector.erase(pVector.begin()); - EXPECT_EQ(pVector.size(), 0); + TEST_F(PointerVectorTest, FrontBack) + { + pcpp::PointerVector vec; + vec.pushBack(new TestObject(1)); + vec.pushBack(new TestObject(2)); - pVector.pushBack(new int(4)); - pVector.pushBack(new int(5)); - EXPECT_EQ(pVector.size(), 2); + EXPECT_EQ(vec.front()->getValue(), 1); + EXPECT_EQ(vec.back()->getValue(), 2); + } - { - std::unique_ptr p = pVector.getAndDetach(pVector.begin()); - ASSERT_NE(p, nullptr); - EXPECT_EQ(*p, 4); - EXPECT_EQ(pVector.size(), 1); - } + TEST_F(PointerVectorTest, PushBackNullptr) + { + pcpp::PointerVector vec; + TestObject* obj = nullptr; // Using nullptr directly in pushBack is a compile time error. + EXPECT_THROW(vec.pushBack(obj), std::invalid_argument); } } // namespace pcpp From 84d7d326b926d2960cc44e99723280784206a1c6 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 22 Jan 2025 20:46:07 +0200 Subject: [PATCH 35/80] Added const qualifier to MacAddress::Zero. --- Common++/header/MacAddress.h | 2 +- Common++/src/MacAddress.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common++/header/MacAddress.h b/Common++/header/MacAddress.h index 04f37c43e7..4202d38837 100644 --- a/Common++/header/MacAddress.h +++ b/Common++/header/MacAddress.h @@ -144,7 +144,7 @@ namespace pcpp } /// A static value representing a zero value of MAC address, meaning address of value "00:00:00:00:00:00" - static MacAddress Zero; + static const MacAddress Zero; private: uint8_t m_Address[6] = { 0 }; diff --git a/Common++/src/MacAddress.cpp b/Common++/src/MacAddress.cpp index 18886faaea..36739211be 100644 --- a/Common++/src/MacAddress.cpp +++ b/Common++/src/MacAddress.cpp @@ -3,7 +3,7 @@ namespace pcpp { - MacAddress MacAddress::Zero(0, 0, 0, 0, 0, 0); + const MacAddress MacAddress::Zero(0, 0, 0, 0, 0, 0); std::string MacAddress::toString() const { From e9f7930ea2bc923974a490f442eff01cae43c96a Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 22 Jan 2025 20:46:19 +0200 Subject: [PATCH 36/80] Lint --- Common++/header/IpAddress.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common++/header/IpAddress.h b/Common++/header/IpAddress.h index 6b903b008b..813d2a4e90 100644 --- a/Common++/header/IpAddress.h +++ b/Common++/header/IpAddress.h @@ -439,7 +439,7 @@ namespace pcpp {} /// A constructor that creates an instance of the class out of an address representing the network prefix - /// and a prefix length + /// and a prefix length /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument /// exception is thrown /// @param prefixLen A number between 0 and 32 representing the prefix length. From 1b02e456798caa38ab7aef04f6f9a9832502a67f Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 22 Jan 2025 22:10:53 +0200 Subject: [PATCH 37/80] Added basic single threaded logger unit tests. --- Tests/Common++Test/CMakeLists.txt | 1 + Tests/Common++Test/Tests/LoggerTests.cpp | 232 +++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 Tests/Common++Test/Tests/LoggerTests.cpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index f7effa771c..7b9cdc8ffb 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable( Common++Test Tests/GeneralUtilsTests.cpp Tests/IPAddressTests.cpp + Tests/LoggerTests.cpp Tests/LRUListTests.cpp Tests/MacAddressTests.cpp Tests/PointerVectorTests.cpp) diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp new file mode 100644 index 0000000000..a0d3bdf3a8 --- /dev/null +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "Logger.h" + + +namespace pcpp +{ + constexpr char getPathSeparator() + { +#ifdef _WIN32 + return '\\'; +#else + return '/'; +#endif // _WIN32 + } + + class LogCallbackMock + { + public: + MOCK_METHOD(void, call, + (pcpp::Logger::LogLevel logLevel, const std::string& logMessage, const std::string& fileName, + const std::string& method, const int line), + (const)); + + // Redirects the call to the mock method + void operator()(pcpp::Logger::LogLevel logLevel, const std::string& logMessage, const std::string& fileName, + const std::string& method, const int line) const + { + call(logLevel, logMessage, fileName, method, line); + } + }; + + class LoggerTest : public ::testing::Test + { + public: + LoggerTest() : m_Logger(Logger::getInstance()) + { + // Setup log callback trampoline + m_Logger.setLogPrinter(&LoggerTest::logPrinterTrampoline); + } + + ~LoggerTest() + { + // Reset log callback trampoline + m_Logger.enableLogs(); + m_Logger.setAllModulesToLogLevel(Logger::Info); + m_Logger.resetLogPrinter(); + } + + void SetUp() override + { + // Enable all logs and set them to Info level by default + m_Logger.enableLogs(); + m_Logger.setAllModulesToLogLevel(Logger::Info); + + // Setup log callback mock + m_LogCallbackMock = std::unique_ptr(new LogCallbackMock()); + } + + void TearDown() override + { + // Reset log callback mock + m_LogCallbackMock.reset(); + } + + protected: + +// Spoofing the log module for testing purposes +#pragma push_macro("LOG_MODULE") +#undef LOG_MODULE +#define LOG_MODULE ::pcpp::LogModule::PacketLogModuleArpLayer + + void invokeDebugLog(std::string const& msg) + { + PCPP_LOG_DEBUG(msg); + } + + void invokeErrorLog(std::string const& msg) + { + PCPP_LOG_ERROR(msg); + } + + static const LogModule SpoofedLogModule = LOG_MODULE; + +#pragma pop_macro("LOG_MODULE") + + static void logPrinterTrampoline(Logger::LogLevel logLevel, const std::string& logMessage, + const std::string& fileName, const std::string& method, const int line) + { + if (m_LogCallbackMock != nullptr) + { + // Dereference the pointer and call the mock with the parameters. + (*m_LogCallbackMock)(logLevel, logMessage, fileName, method, line); + } + else + { + throw std::runtime_error("Log Trampoline Error: Log callback not set"); + } + } + + static std::unique_ptr m_LogCallbackMock; + Logger& m_Logger; + }; + + std::unique_ptr LoggerTest::m_LogCallbackMock = nullptr; + + TEST_F(LoggerTest, LogLevelAsString) + { + EXPECT_EQ(Logger::logLevelAsString(Logger::Error), "ERROR"); + EXPECT_EQ(Logger::logLevelAsString(Logger::Info), "INFO"); + EXPECT_EQ(Logger::logLevelAsString(Logger::Debug), "DEBUG"); + } + + TEST_F(LoggerTest, GetSetLogLevel) + { + EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Info) << "Initial setup should have initialized all modules to Info"; + + m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); + EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Debug); + EXPECT_TRUE(m_Logger.isDebugEnabled(SpoofedLogModule)); + } + + TEST_F(LoggerTest, SetAllModulesMethod) + { + for (int module = 1; module < NumOfLogModules; module++) + { + ASSERT_EQ(m_Logger.getLogLevel(static_cast(module)), Logger::Info); + } + + m_Logger.setAllModulesToLogLevel(Logger::Debug); + + for (int module = 1; module < NumOfLogModules; module++) + { + EXPECT_EQ(m_Logger.getLogLevel(static_cast(module)), Logger::Debug); + } + } + + TEST_F(LoggerTest, LogError) + { + using testing::_; + + ASSERT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Info) + << "Initial setup should have initialized all modules to Info"; + + // Expect a call to the log callback mock + EXPECT_CALL(*m_LogCallbackMock, + call(Logger::Error, "Error Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) + .Times(1); + + invokeErrorLog("Error Log Message"); + } + + TEST_F(LoggerTest, LogDebug) + { + using testing::_; + + m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); + ASSERT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Debug); + + // Expect a call to the log callback mock + EXPECT_CALL(*m_LogCallbackMock, + call(Logger::Debug, "Debug Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) + .Times(1); + + invokeDebugLog("Debug Log Message"); + } + + TEST_F(LoggerTest, GlobalLogSuppression) + { + using testing::_; + + m_Logger.suppressLogs(); + EXPECT_FALSE(m_Logger.logsEnabled()); + + // Expect no calls to the log callback mock + EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Global Log Suppression Error", _ /* Filename */, + _ /* method */, _ /* line number */)) + .Times(0); + + invokeErrorLog("Global Log Suppression Error"); + + // Verifies that all expectations on the mock have been met and clears them. + ::testing::Mock::VerifyAndClearExpectations(m_LogCallbackMock.get()); + + m_Logger.enableLogs(); + EXPECT_TRUE(m_Logger.logsEnabled()); + + EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Global Log Suppression Error", _ /* Filename */, + _ /* method */, _ /* line number */)) + .Times(1); + + invokeErrorLog("Global Log Suppression Error"); + } + + TEST_F(LoggerTest, ModuleLevelLogSuppression) + { + using ::testing::_; + + m_Logger.setLogLevel(SpoofedLogModule, Logger::Error); + + EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Module Level Log Suppression Debug", _ /* Filename */, + _ /* method */, _ /* line number */)) + .Times(0); + EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Module Level Log Suppression Error", _ /* Filename */, + _ /* method */, _ /* line number */)) + .Times(1); + + invokeDebugLog("Module Level Log Suppression Debug"); + invokeErrorLog("Module Level Log Suppression Error"); + + // Verifies that all expectations on the mock have been met and clears them. + ::testing::Mock::VerifyAndClearExpectations(m_LogCallbackMock.get()); + + m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); + + EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Module Level Log Suppression Debug", _ /* Filename */, + _ /* method */, _ /* line number */)) + .Times(1); + EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Module Level Log Suppression Error", _ /* Filename */, + _ /* method */, _ /* line number */)) + .Times(1); + + invokeDebugLog("Module Level Log Suppression Debug"); + invokeErrorLog("Module Level Log Suppression Error"); + } +} // namespace pcpp \ No newline at end of file From b09fc3c050787ea35dc9159efa883818bf154a3e Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 23 Jan 2025 10:11:40 +0200 Subject: [PATCH 38/80] Simplified logger fixture setup and teardown. --- Tests/Common++Test/Tests/LoggerTests.cpp | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index a0d3bdf3a8..194782db09 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -38,23 +38,18 @@ namespace pcpp class LoggerTest : public ::testing::Test { + using Base = ::testing::Test; public: LoggerTest() : m_Logger(Logger::getInstance()) - { - // Setup log callback trampoline - m_Logger.setLogPrinter(&LoggerTest::logPrinterTrampoline); - } - - ~LoggerTest() - { - // Reset log callback trampoline - m_Logger.enableLogs(); - m_Logger.setAllModulesToLogLevel(Logger::Info); - m_Logger.resetLogPrinter(); - } + {} void SetUp() override { + Base::SetUp(); + + // Setup log callback trampoline + m_Logger.setLogPrinter(&LoggerTest::logPrinterTrampoline); + // Enable all logs and set them to Info level by default m_Logger.enableLogs(); m_Logger.setAllModulesToLogLevel(Logger::Info); @@ -65,8 +60,15 @@ namespace pcpp void TearDown() override { + // Reset log callback trampoline + m_Logger.enableLogs(); + m_Logger.setAllModulesToLogLevel(Logger::Info); + m_Logger.resetLogPrinter(); + // Reset log callback mock m_LogCallbackMock.reset(); + + Base::TearDown(); } protected: From 977abb42f6dd7b20a798dd0ad276c601e2541ac0 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 23 Jan 2025 10:16:00 +0200 Subject: [PATCH 39/80] Added explicit main file. --- Tests/Common++Test/CMakeLists.txt | 4 ++-- Tests/Common++Test/main.cpp | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 Tests/Common++Test/main.cpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 7b9cdc8ffb..7034b6cf1d 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -18,6 +18,7 @@ FetchContent_MakeAvailable(googletest) add_executable( Common++Test + main.cpp Tests/GeneralUtilsTests.cpp Tests/IPAddressTests.cpp Tests/LoggerTests.cpp @@ -30,8 +31,7 @@ target_link_libraries( PRIVATE Common++ memplumber gtest - gmock - gmock_main) + gmock) target_include_directories(Common++Test PRIVATE $) diff --git a/Tests/Common++Test/main.cpp b/Tests/Common++Test/main.cpp new file mode 100644 index 0000000000..73fb35f5ad --- /dev/null +++ b/Tests/Common++Test/main.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char* argv[]) +{ + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} From 67c6a22c6e8bc9340650fe909b3ce8ca3bd56343 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 23 Jan 2025 11:05:06 +0200 Subject: [PATCH 40/80] Added conditional skipping of memory leak checks for MSVC Release builds. --- .../Utils/MemoryLeakDetectorFixture.hpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp index 9955d475dc..f1a50e9995 100644 --- a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp +++ b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp @@ -1,14 +1,40 @@ #include #include +#include + namespace pcpp { class MemoryLeakDetectorTest : public ::testing::Test { + using Base = ::testing::Test; + + public: + static void SetUpTestSuite() + { +#ifdef NDEBUG + // TODO: Do we still need this? The issue seems to be closed? + skipMemLeakCheck = true; + std::call_once(m_MSVC_WarningPrinted, [] { + std::cout + << "Disabling memory leak check in MSVC Release builds due to caching logic in stream objects that looks like a memory leak:\n" + " https://github.com/cpputest/cpputest/issues/786#issuecomment-148921958" + << std::endl; + }); +#else + skipMemLeakCheck = false; +#endif + } + protected: void SetUp() override { - MemPlumber::start(); + Base::SetUp(); + + if (!skipMemLeakCheck) + { + MemPlumber::start(); + } } void TearDown() override @@ -22,7 +48,14 @@ namespace pcpp { FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize << " [bytes] leaked"; } + Base::TearDown(); } + + private: + static bool skipMemLeakCheck; + static std::once_flag m_MSVC_WarningPrinted; }; + bool MemoryLeakDetectorTest::skipMemLeakCheck = false; + std::once_flag MemoryLeakDetectorTest::m_MSVC_WarningPrinted; } // namespace pcpp From e5cf5fb0cb63e2ef1a5f7a6232eee3e89208efa9 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 23 Jan 2025 11:05:39 +0200 Subject: [PATCH 41/80] Added build information to the test executable. --- Tests/Common++Test/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Tests/Common++Test/main.cpp b/Tests/Common++Test/main.cpp index 73fb35f5ad..9197bc0933 100644 --- a/Tests/Common++Test/main.cpp +++ b/Tests/Common++Test/main.cpp @@ -1,8 +1,16 @@ +#include + #include #include +#include "PcapPlusPlusVersion.h" + int main(int argc, char* argv[]) { + std::cout << "PcapPlusPlus version: " << pcpp::getPcapPlusPlusVersionFull() << '\n' + << "Built: " << pcpp::getBuildDateTime() << '\n' + << "Built from: " << pcpp::getGitInfo() << std::endl; + ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } From 5076d2976e594ce41ceffb177021bb1ef3ebe0e1 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 23 Jan 2025 11:20:57 +0200 Subject: [PATCH 42/80] Added tests for CoreMask transformations. --- Tests/Common++Test/CMakeLists.txt | 3 +- Tests/Common++Test/Tests/SystemUtilsTests.cpp | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 Tests/Common++Test/Tests/SystemUtilsTests.cpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 7034b6cf1d..fa0df6fc00 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -24,7 +24,8 @@ add_executable( Tests/LoggerTests.cpp Tests/LRUListTests.cpp Tests/MacAddressTests.cpp - Tests/PointerVectorTests.cpp) + Tests/PointerVectorTests.cpp + Tests/SystemUtilsTests.cpp) target_link_libraries( Common++Test diff --git a/Tests/Common++Test/Tests/SystemUtilsTests.cpp b/Tests/Common++Test/Tests/SystemUtilsTests.cpp new file mode 100644 index 0000000000..0b7fb31b66 --- /dev/null +++ b/Tests/Common++Test/Tests/SystemUtilsTests.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include "SystemUtils.h" + +namespace pcpp +{ + + TEST(CoreMaskTest, CreateCoreMaskFromCoreIdsMethod) + { + const std::vector coreIds{ 0, 1, 2, 3 }; + CoreMask mask = createCoreMaskFromCoreIds(coreIds); + + EXPECT_EQ(mask, 0x0F); + }; + + TEST(CoreMaskTest, CreateCoreMaskFromCoreVectorMethod) + { + + const std::vector cores{ + SystemCores::Core0, + SystemCores::Core1, + SystemCores::Core2, + SystemCores::Core3, + }; + + CoreMask mask = createCoreMaskFromCoreVector(cores); + + EXPECT_EQ(mask, 0x0F); + }; + + TEST(CoreMaskTest, CreateCoreVectorFromCoreMaskMethod) + { + const CoreMask mask = 0x0F; + const std::vector expectedCores = { + SystemCores::Core0, + SystemCores::Core1, + SystemCores::Core2, + SystemCores::Core3, + }; + std::vector cores; + + createCoreVectorFromCoreMask(mask, cores); + + EXPECT_EQ(cores, expectedCores); + }; +} // namespace pcpp \ No newline at end of file From 3fa3dfd4c9f5cbff55aaa826885ffbb8f419b8e1 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 3 Apr 2025 18:16:38 +0300 Subject: [PATCH 43/80] Removed make_unique usage. --- Tests/Common++Test/Tests/PointerVectorTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index 9299fef2af..fb62a26daf 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -22,7 +22,7 @@ namespace pcpp } std::unique_ptr clone() const { - return std::make_unique(*this); + return std::unique_ptr(new TestObject(*this)); } private: From fc0ea181b76a0ed8807a4715293a9e420e21c90c Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 3 Apr 2025 18:17:19 +0300 Subject: [PATCH 44/80] Lint --- Common++/header/IpAddress.h | 2 +- Tests/Common++Test/Tests/IPAddressTests.cpp | 20 +++++++++---------- Tests/Common++Test/Tests/LoggerTests.cpp | 18 ++++++++--------- Tests/Common++Test/Tests/SystemUtilsTests.cpp | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Common++/header/IpAddress.h b/Common++/header/IpAddress.h index 9ebda47f2a..1bb88faf57 100644 --- a/Common++/header/IpAddress.h +++ b/Common++/header/IpAddress.h @@ -439,7 +439,7 @@ namespace pcpp {} /// A constructor that creates an instance of the class out of an address representing the network prefix - /// and a prefix length + /// and a prefix length /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument /// exception is thrown /// @param prefixLen A number between 0 and 32 representing the prefix length. diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index c1d10f8637..1653443c23 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -16,7 +16,7 @@ namespace pcpp TEST(IPv4AddressTest, ConstructorWithInteger) { - IPv4Address addr2(0x0100A8C0); // 192.168.0.1 + IPv4Address addr2(0x0100A8C0); // 192.168.0.1 EXPECT_EQ(addr2.toString(), "192.168.0.1"); } @@ -88,7 +88,7 @@ namespace pcpp IPv4Address addr5("192.168.0.1"); IPv4Network network("192.168.0.0/24"); EXPECT_TRUE(addr5.matchNetwork(network)); - + IPv4Network network2("192.168.1.0/24"); EXPECT_FALSE(addr5.matchNetwork(network2)); @@ -172,7 +172,7 @@ namespace pcpp TEST(IPv6AddressTest, ToBytesMethod) { std::array bytes = { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, - 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; + 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); const uint8_t* addrBytes = addr4.toBytes(); EXPECT_EQ(memcmp(addrBytes, bytes.data(), 16), 0); @@ -212,7 +212,7 @@ namespace pcpp IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); IPv6Network network("2001:db8::/32"); EXPECT_TRUE(addr4.matchNetwork(network)); - + IPv6Network network2("2001:db9::/32"); EXPECT_FALSE(addr4.matchNetwork(network2)); } @@ -309,7 +309,7 @@ namespace pcpp IPAddress ipAddr; ASSERT_EQ(ipAddr.getType(), IPAddress::AddressType::IPv4AddressType); ASSERT_EQ(ipAddr.getIPv4(), IPv4Address::Zero); - + ipAddr = ipv6Addr; EXPECT_EQ(ipAddr.getType(), IPAddress::AddressType::IPv6AddressType); EXPECT_EQ(ipAddr.getIPv6(), ipv6Addr); @@ -400,7 +400,7 @@ namespace pcpp TEST(IPv4NetworkTest, ConstructorWithAddressAndPrefix) { using namespace pcpp::literals; - + IPv4Network netPrefix("192.168.1.1"_ipv4, 24u); EXPECT_EQ(netPrefix.getPrefixLen(), 24u); EXPECT_EQ(netPrefix.getNetmask(), "255.255.255.0"); @@ -431,7 +431,7 @@ namespace pcpp { SCOPED_TRACE("Valid c'tor: IPv4 address + prefix len"); - + IPv4Network netStringWithPrefix("192.168.1.1/8"); EXPECT_EQ(netStringWithPrefix.getPrefixLen(), 8u); EXPECT_EQ(netStringWithPrefix.getNetmask(), "255.0.0.0"); @@ -470,7 +470,7 @@ namespace pcpp EXPECT_TRUE(netBase.includes("192.168.2.1"_ipv4)); EXPECT_FALSE(netBase.includes("192.169.2.1"_ipv4)); } - + { SCOPED_TRACE("With network"); @@ -577,7 +577,7 @@ namespace pcpp { SCOPED_TRACE("With network"); - + EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/64"))); EXPECT_TRUE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/72"))); EXPECT_FALSE(netBase.includes(IPv6Network("2001:db8:85a3:34ac::/56"))); @@ -658,7 +658,7 @@ namespace pcpp EXPECT_EQ(netPrefix.toString(), "2001:db8:85a3::8a2e:0:0/96"); } } - + TEST(IPNetworkTest, ConstructorWithAddressAndNetmask) { using namespace pcpp::literals; diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index 194782db09..64665ffc50 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -8,7 +8,6 @@ #include "Logger.h" - namespace pcpp { constexpr char getPathSeparator() @@ -39,6 +38,7 @@ namespace pcpp class LoggerTest : public ::testing::Test { using Base = ::testing::Test; + public: LoggerTest() : m_Logger(Logger::getInstance()) {} @@ -46,14 +46,14 @@ namespace pcpp void SetUp() override { Base::SetUp(); - + // Setup log callback trampoline m_Logger.setLogPrinter(&LoggerTest::logPrinterTrampoline); - + // Enable all logs and set them to Info level by default m_Logger.enableLogs(); m_Logger.setAllModulesToLogLevel(Logger::Info); - + // Setup log callback mock m_LogCallbackMock = std::unique_ptr(new LogCallbackMock()); } @@ -72,7 +72,6 @@ namespace pcpp } protected: - // Spoofing the log module for testing purposes #pragma push_macro("LOG_MODULE") #undef LOG_MODULE @@ -121,7 +120,8 @@ namespace pcpp TEST_F(LoggerTest, GetSetLogLevel) { - EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Info) << "Initial setup should have initialized all modules to Info"; + EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Info) + << "Initial setup should have initialized all modules to Info"; m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Debug); @@ -154,7 +154,7 @@ namespace pcpp EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Error Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); - + invokeErrorLog("Error Log Message"); } @@ -218,7 +218,7 @@ namespace pcpp // Verifies that all expectations on the mock have been met and clears them. ::testing::Mock::VerifyAndClearExpectations(m_LogCallbackMock.get()); - + m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Module Level Log Suppression Debug", _ /* Filename */, @@ -231,4 +231,4 @@ namespace pcpp invokeDebugLog("Module Level Log Suppression Debug"); invokeErrorLog("Module Level Log Suppression Error"); } -} // namespace pcpp \ No newline at end of file +} // namespace pcpp diff --git a/Tests/Common++Test/Tests/SystemUtilsTests.cpp b/Tests/Common++Test/Tests/SystemUtilsTests.cpp index 0b7fb31b66..129c1e7ba7 100644 --- a/Tests/Common++Test/Tests/SystemUtilsTests.cpp +++ b/Tests/Common++Test/Tests/SystemUtilsTests.cpp @@ -44,4 +44,4 @@ namespace pcpp EXPECT_EQ(cores, expectedCores); }; -} // namespace pcpp \ No newline at end of file +} // namespace pcpp From 3c7285b7a9f388c735a4dd60a2a06a76fb70cf43 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 3 Apr 2025 18:18:01 +0300 Subject: [PATCH 45/80] Added const to MacAddress::Broadcast static variable. --- Common++/header/MacAddress.h | 2 +- Common++/src/MacAddress.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common++/header/MacAddress.h b/Common++/header/MacAddress.h index 82a7dd96af..c9e86f8e06 100644 --- a/Common++/header/MacAddress.h +++ b/Common++/header/MacAddress.h @@ -145,7 +145,7 @@ namespace pcpp /// A static value representing a zero value of MAC address, meaning address of value "00:00:00:00:00:00" static const MacAddress Zero; /// A static value representing a broadcast MAC address, meaning address of value "ff:ff:ff:ff:ff:ff" - static MacAddress Broadcast; + static const MacAddress Broadcast; private: std::array m_Address{}; diff --git a/Common++/src/MacAddress.cpp b/Common++/src/MacAddress.cpp index 65576c90a3..b56121b4f2 100644 --- a/Common++/src/MacAddress.cpp +++ b/Common++/src/MacAddress.cpp @@ -5,7 +5,7 @@ namespace pcpp const MacAddress MacAddress::Zero(0, 0, 0, 0, 0, 0); - MacAddress MacAddress::Broadcast(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); + const MacAddress MacAddress::Broadcast(0xff, 0xff, 0xff, 0xff, 0xff, 0xff); std::string MacAddress::toString() const { From e45d5a9a89a400475bb95ccd116dfe49b4727877 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Thu, 3 Apr 2025 18:18:56 +0300 Subject: [PATCH 46/80] Added Broadcast unit test. --- Tests/Common++Test/Tests/MacAddressTests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp index eab5e5b075..ad268b22be 100644 --- a/Tests/Common++Test/Tests/MacAddressTests.cpp +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -119,5 +119,6 @@ namespace pcpp TEST(MacAddressTest, ConstantHelpers) { EXPECT_EQ(MacAddress::Zero, MacAddress(0, 0, 0, 0, 0, 0)); + EXPECT_EQ(MacAddress::Broadcast, MacAddress(0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); }; } // namespace pcpp From 6fb03e85022f42a19d7107b6c965e834e7126f81 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:13:20 +0300 Subject: [PATCH 47/80] Bump googletest to v1.16.0 --- Tests/Common++Test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index fa0df6fc00..d074abcb7b 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -5,7 +5,7 @@ include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.0) + GIT_TAG v1.16.0) if(WIN32) # Prevent overriding the parent project's compiler/linker settings. From 67226666cf3f7bb0bed455afda81561afd6457e2 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:15:02 +0300 Subject: [PATCH 48/80] Added unit tests for DynamicObjectPool --- Tests/Common++Test/Tests/ObjectPoolTests.cpp | 55 ++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Tests/Common++Test/Tests/ObjectPoolTests.cpp diff --git a/Tests/Common++Test/Tests/ObjectPoolTests.cpp b/Tests/Common++Test/Tests/ObjectPoolTests.cpp new file mode 100644 index 0000000000..c7bea92a83 --- /dev/null +++ b/Tests/Common++Test/Tests/ObjectPoolTests.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +#include "ObjectPool.h" + +namespace pcpp +{ + namespace internal + { + + TEST(DynamicObjectPoolTest, BasicUsage) + { + DynamicObjectPool pool(10); // Create a pool with limit 10 objects + EXPECT_EQ(pool.maxSize(), 10); + EXPECT_EQ(pool.size(), 0); + + auto obj1 = pool.acquireObject(); // Acquire an object from the pool + EXPECT_NE(obj1, nullptr); + EXPECT_EQ(*obj1, 0); // Default initialized to 0 + EXPECT_EQ(pool.size(), 0); + *obj1 = 42; // Modify the object + + // Save the address of the object before releasing it + int* obj1Raw = obj1.get(); + pool.releaseObject(std::move(obj1)); + EXPECT_EQ(pool.size(), 1); + + auto obj2 = pool.acquireObject(); + EXPECT_EQ(obj1Raw, obj2.get()); // Should return the same object + pool.clear(); // Clear the pool + } + + TEST(DynamicObjectPoolTest, Preallocation) + { + DynamicObjectPool pool(10, 5); // Create a pool with limit 10 and preallocate 5 objects + EXPECT_EQ(pool.maxSize(), 10); + EXPECT_EQ(pool.size(), 5); + } + + TEST(DynamicObjectPoolTest, MaxPoolSize) + { + DynamicObjectPool pool(2); // Create a pool with limit 2 objects + + for (int i = 0; i < 4; ++i) + { + auto obj = std::make_unique(i); + pool.releaseObject(std::move(obj)); // Release objects to the pool + EXPECT_LE(pool.size(), 2); // Pool should free released objects if it exceeds the limit + } + } + } // namespace internal +} // namespace pcpp \ No newline at end of file From 453943a5110677b3d8f680cb6755e3d63987faec Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:15:19 +0300 Subject: [PATCH 49/80] cmake formatting. --- Tests/Common++Test/CMakeLists.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index d074abcb7b..e5f78da8fa 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -18,14 +18,15 @@ FetchContent_MakeAvailable(googletest) add_executable( Common++Test - main.cpp - Tests/GeneralUtilsTests.cpp - Tests/IPAddressTests.cpp - Tests/LoggerTests.cpp - Tests/LRUListTests.cpp - Tests/MacAddressTests.cpp - Tests/PointerVectorTests.cpp - Tests/SystemUtilsTests.cpp) + "main.cpp" + "Tests/GeneralUtilsTests.cpp" + "Tests/IPAddressTests.cpp" + "Tests/LoggerTests.cpp" + "Tests/LRUListTests.cpp" + "Tests/MacAddressTests.cpp" + "Tests/ObjectPoolTests.cpp" + "Tests/PointerVectorTests.cpp" + "Tests/SystemUtilsTests.cpp") target_link_libraries( Common++Test From 21f16f56ddcb0e7195cee98445c66387a1883b0e Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:16:52 +0300 Subject: [PATCH 50/80] Include cleanup --- Tests/Common++Test/Tests/ObjectPoolTests.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/Common++Test/Tests/ObjectPoolTests.cpp b/Tests/Common++Test/Tests/ObjectPoolTests.cpp index c7bea92a83..1a37250d7f 100644 --- a/Tests/Common++Test/Tests/ObjectPoolTests.cpp +++ b/Tests/Common++Test/Tests/ObjectPoolTests.cpp @@ -1,6 +1,3 @@ -#include -#include -#include #include #include From 4df5ddb1c6349f7f2828cb02ae632f4c8c650b70 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:27:42 +0300 Subject: [PATCH 51/80] Added precompiled header --- Tests/Common++Test/CMakeLists.txt | 3 ++- Tests/Common++Test/Tests/GeneralUtilsTests.cpp | 5 ++--- Tests/Common++Test/Tests/IPAddressTests.cpp | 5 ++--- Tests/Common++Test/Tests/LRUListTests.cpp | 4 +--- Tests/Common++Test/Tests/LoggerTests.cpp | 8 ++------ Tests/Common++Test/Tests/MacAddressTests.cpp | 5 ++--- Tests/Common++Test/Tests/ObjectPoolTests.cpp | 3 +-- Tests/Common++Test/Tests/PointerVectorTests.cpp | 6 ++---- Tests/Common++Test/Tests/SystemUtilsTests.cpp | 3 +-- .../{Utils => header}/MemoryLeakDetectorFixture.hpp | 0 Tests/Common++Test/header/pch.h | 7 +++++++ 11 files changed, 22 insertions(+), 27 deletions(-) rename Tests/Common++Test/{Utils => header}/MemoryLeakDetectorFixture.hpp (100%) create mode 100644 Tests/Common++Test/header/pch.h diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index e5f78da8fa..2c72358016 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -35,7 +35,8 @@ target_link_libraries( gtest gmock) -target_include_directories(Common++Test PRIVATE $) +target_include_directories(Common++Test PRIVATE $) +target_precompile_headers(Common++Test PRIVATE $) if(MSVC) # This executable requires getopt.h not available on VStudio diff --git a/Tests/Common++Test/Tests/GeneralUtilsTests.cpp b/Tests/Common++Test/Tests/GeneralUtilsTests.cpp index b56c49dc45..1a3ba4c3c2 100644 --- a/Tests/Common++Test/Tests/GeneralUtilsTests.cpp +++ b/Tests/Common++Test/Tests/GeneralUtilsTests.cpp @@ -1,7 +1,6 @@ -#include +#include "pch.h" + #include -#include -#include #include "GeneralUtils.h" diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index 1653443c23..b7d3128f7a 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -1,8 +1,7 @@ -#include +#include "pch.h" + #include #include -#include -#include #include "IpAddress.h" diff --git a/Tests/Common++Test/Tests/LRUListTests.cpp b/Tests/Common++Test/Tests/LRUListTests.cpp index 86483b59ba..e8a227f5a3 100644 --- a/Tests/Common++Test/Tests/LRUListTests.cpp +++ b/Tests/Common++Test/Tests/LRUListTests.cpp @@ -1,6 +1,4 @@ -#include -#include -#include +#include "pch.h" #include "LRUList.h" diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index 64665ffc50..efb8d58a78 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -1,10 +1,6 @@ -#include -#include -#include +#include "pch.h" + #include -#include -#include -#include #include "Logger.h" diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp index ad268b22be..60e46f3c5e 100644 --- a/Tests/Common++Test/Tests/MacAddressTests.cpp +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -1,8 +1,7 @@ -#include +#include "pch.h" + #include #include -#include -#include #include "MacAddress.h" diff --git a/Tests/Common++Test/Tests/ObjectPoolTests.cpp b/Tests/Common++Test/Tests/ObjectPoolTests.cpp index 1a37250d7f..3eaaccc61b 100644 --- a/Tests/Common++Test/Tests/ObjectPoolTests.cpp +++ b/Tests/Common++Test/Tests/ObjectPoolTests.cpp @@ -1,5 +1,4 @@ -#include -#include +#include "pch.h" #include "ObjectPool.h" diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index fb62a26daf..ceacadc4dd 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -1,9 +1,7 @@ -#include +#include "pch.h" + #include -#include #include -#include -#include #include "MemoryLeakDetectorFixture.hpp" diff --git a/Tests/Common++Test/Tests/SystemUtilsTests.cpp b/Tests/Common++Test/Tests/SystemUtilsTests.cpp index 129c1e7ba7..8bba647c15 100644 --- a/Tests/Common++Test/Tests/SystemUtilsTests.cpp +++ b/Tests/Common++Test/Tests/SystemUtilsTests.cpp @@ -1,5 +1,4 @@ -#include -#include +#include "pch.h" #include "SystemUtils.h" diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp similarity index 100% rename from Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp rename to Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp diff --git a/Tests/Common++Test/header/pch.h b/Tests/Common++Test/header/pch.h new file mode 100644 index 0000000000..bb5a5e479b --- /dev/null +++ b/Tests/Common++Test/header/pch.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +#include +#include From 2b9a1488ac6356cfb3848c621685a835448d63a4 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:42:55 +0300 Subject: [PATCH 52/80] Added unit tests for timespec to timeval conversions. --- Tests/Common++Test/CMakeLists.txt | 3 +- .../Tests/TimespecTimevalTests.cpp | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Tests/Common++Test/Tests/TimespecTimevalTests.cpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 2c72358016..48551c1609 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -26,7 +26,8 @@ add_executable( "Tests/MacAddressTests.cpp" "Tests/ObjectPoolTests.cpp" "Tests/PointerVectorTests.cpp" - "Tests/SystemUtilsTests.cpp") + "Tests/SystemUtilsTests.cpp" + "Tests/TimespecTimevalTests.cpp") target_link_libraries( Common++Test diff --git a/Tests/Common++Test/Tests/TimespecTimevalTests.cpp b/Tests/Common++Test/Tests/TimespecTimevalTests.cpp new file mode 100644 index 0000000000..d22a3b85c0 --- /dev/null +++ b/Tests/Common++Test/Tests/TimespecTimevalTests.cpp @@ -0,0 +1,51 @@ +#include "pch.h" + +#include "TimespecTimeval.h" + +namespace pcpp +{ + namespace internal + { + TEST(TimespecTimevalConversion, TimevalToTimespecMacro) + { + timeval tv; + tv.tv_sec = 5000; + tv.tv_usec = 45888; + timespec ts; + TIMEVAL_TO_TIMESPEC(&tv, &ts); + EXPECT_EQ(ts.tv_sec, tv.tv_sec); + EXPECT_EQ(ts.tv_nsec, tv.tv_usec * 1000); + } + + TEST(TimespecTimevalConversion, TimespecToTimespecMacro) + { + timespec ts; + ts.tv_sec = 5000; + ts.tv_nsec = 45888; + timeval tv; + TIMESPEC_TO_TIMEVAL(&tv, &ts); + EXPECT_EQ(tv.tv_sec, ts.tv_sec); + EXPECT_EQ(tv.tv_usec, ts.tv_nsec / 1000); + } + + TEST(TimespecTimevalConversion, TimevalToTimespec) + { + timeval tv; + tv.tv_sec = 5000; + tv.tv_usec = 45; + timespec ts = toTimespec(tv); + EXPECT_EQ(ts.tv_sec, tv.tv_sec); + EXPECT_EQ(ts.tv_nsec, tv.tv_usec * 1000); + } + + TEST(TimespecTimevalConversion, TimespecToTimeval) + { + timespec ts; + ts.tv_sec = 5000; + ts.tv_nsec = 45888; + timeval tv = toTimeval(ts); + EXPECT_EQ(tv.tv_sec, ts.tv_sec); + EXPECT_EQ(tv.tv_usec, ts.tv_nsec / 1000); + } + } // namespace internal +} // namespace pcpp \ No newline at end of file From 3b4d4d37b8a0934aec85d4688e418fdb4fdfb5f7 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:48:35 +0300 Subject: [PATCH 53/80] Updated logger tests. --- Tests/Common++Test/Tests/LoggerTests.cpp | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index efb8d58a78..08af467613 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -19,12 +19,12 @@ namespace pcpp { public: MOCK_METHOD(void, call, - (pcpp::Logger::LogLevel logLevel, const std::string& logMessage, const std::string& fileName, + (pcpp::LogLevel logLevel, const std::string& logMessage, const std::string& fileName, const std::string& method, const int line), (const)); // Redirects the call to the mock method - void operator()(pcpp::Logger::LogLevel logLevel, const std::string& logMessage, const std::string& fileName, + void operator()(pcpp::LogLevel logLevel, const std::string& logMessage, const std::string& fileName, const std::string& method, const int line) const { call(logLevel, logMessage, fileName, method, line); @@ -48,7 +48,7 @@ namespace pcpp // Enable all logs and set them to Info level by default m_Logger.enableLogs(); - m_Logger.setAllModulesToLogLevel(Logger::Info); + m_Logger.setAllModulesToLogLevel(LogLevel::Info); // Setup log callback mock m_LogCallbackMock = std::unique_ptr(new LogCallbackMock()); @@ -58,7 +58,7 @@ namespace pcpp { // Reset log callback trampoline m_Logger.enableLogs(); - m_Logger.setAllModulesToLogLevel(Logger::Info); + m_Logger.setAllModulesToLogLevel(LogLevel::Info); m_Logger.resetLogPrinter(); // Reset log callback mock @@ -87,7 +87,7 @@ namespace pcpp #pragma pop_macro("LOG_MODULE") - static void logPrinterTrampoline(Logger::LogLevel logLevel, const std::string& logMessage, + static void logPrinterTrampoline(LogLevel logLevel, const std::string& logMessage, const std::string& fileName, const std::string& method, const int line) { if (m_LogCallbackMock != nullptr) @@ -109,18 +109,18 @@ namespace pcpp TEST_F(LoggerTest, LogLevelAsString) { - EXPECT_EQ(Logger::logLevelAsString(Logger::Error), "ERROR"); - EXPECT_EQ(Logger::logLevelAsString(Logger::Info), "INFO"); - EXPECT_EQ(Logger::logLevelAsString(Logger::Debug), "DEBUG"); + EXPECT_EQ(Logger::logLevelAsString(LogLevel::Error), "ERROR"); + EXPECT_EQ(Logger::logLevelAsString(LogLevel::Info), "INFO"); + EXPECT_EQ(Logger::logLevelAsString(LogLevel::Debug), "DEBUG"); } TEST_F(LoggerTest, GetSetLogLevel) { - EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Info) + EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), LogLevel::Info) << "Initial setup should have initialized all modules to Info"; m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); - EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Debug); + EXPECT_EQ(m_Logger.getLogLevel(SpoofedLogModule), LogLevel::Debug); EXPECT_TRUE(m_Logger.isDebugEnabled(SpoofedLogModule)); } @@ -128,14 +128,14 @@ namespace pcpp { for (int module = 1; module < NumOfLogModules; module++) { - ASSERT_EQ(m_Logger.getLogLevel(static_cast(module)), Logger::Info); + ASSERT_EQ(m_Logger.getLogLevel(static_cast(module)), LogLevel::Info); } - m_Logger.setAllModulesToLogLevel(Logger::Debug); + m_Logger.setAllModulesToLogLevel(LogLevel::Debug); for (int module = 1; module < NumOfLogModules; module++) { - EXPECT_EQ(m_Logger.getLogLevel(static_cast(module)), Logger::Debug); + EXPECT_EQ(m_Logger.getLogLevel(static_cast(module)), LogLevel::Debug); } } @@ -143,12 +143,12 @@ namespace pcpp { using testing::_; - ASSERT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Info) + ASSERT_EQ(m_Logger.getLogLevel(SpoofedLogModule), LogLevel::Info) << "Initial setup should have initialized all modules to Info"; // Expect a call to the log callback mock EXPECT_CALL(*m_LogCallbackMock, - call(Logger::Error, "Error Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) + call(LogLevel::Error, "Error Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); invokeErrorLog("Error Log Message"); @@ -158,12 +158,12 @@ namespace pcpp { using testing::_; - m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); - ASSERT_EQ(m_Logger.getLogLevel(SpoofedLogModule), Logger::Debug); + m_Logger.setLogLevel(SpoofedLogModule, LogLevel::Debug); + ASSERT_EQ(m_Logger.getLogLevel(SpoofedLogModule), LogLevel::Debug); // Expect a call to the log callback mock EXPECT_CALL(*m_LogCallbackMock, - call(Logger::Debug, "Debug Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) + call(LogLevel::Debug, "Debug Log Message", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); invokeDebugLog("Debug Log Message"); @@ -177,7 +177,7 @@ namespace pcpp EXPECT_FALSE(m_Logger.logsEnabled()); // Expect no calls to the log callback mock - EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Global Log Suppression Error", _ /* Filename */, + EXPECT_CALL(*m_LogCallbackMock, call(LogLevel::Debug, "Global Log Suppression Error", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(0); @@ -189,7 +189,7 @@ namespace pcpp m_Logger.enableLogs(); EXPECT_TRUE(m_Logger.logsEnabled()); - EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Global Log Suppression Error", _ /* Filename */, + EXPECT_CALL(*m_LogCallbackMock, call(LogLevel::Error, "Global Log Suppression Error", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); @@ -200,12 +200,12 @@ namespace pcpp { using ::testing::_; - m_Logger.setLogLevel(SpoofedLogModule, Logger::Error); + m_Logger.setLogLevel(SpoofedLogModule, LogLevel::Error); - EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Module Level Log Suppression Debug", _ /* Filename */, + EXPECT_CALL(*m_LogCallbackMock, call(LogLevel::Debug, "Module Level Log Suppression Debug", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(0); - EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Module Level Log Suppression Error", _ /* Filename */, + EXPECT_CALL(*m_LogCallbackMock, call(LogLevel::Error, "Module Level Log Suppression Error", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); @@ -215,12 +215,12 @@ namespace pcpp // Verifies that all expectations on the mock have been met and clears them. ::testing::Mock::VerifyAndClearExpectations(m_LogCallbackMock.get()); - m_Logger.setLogLevel(SpoofedLogModule, Logger::Debug); + m_Logger.setLogLevel(SpoofedLogModule, LogLevel::Debug); - EXPECT_CALL(*m_LogCallbackMock, call(Logger::Debug, "Module Level Log Suppression Debug", _ /* Filename */, + EXPECT_CALL(*m_LogCallbackMock, call(LogLevel::Debug, "Module Level Log Suppression Debug", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); - EXPECT_CALL(*m_LogCallbackMock, call(Logger::Error, "Module Level Log Suppression Error", _ /* Filename */, + EXPECT_CALL(*m_LogCallbackMock, call(LogLevel::Error, "Module Level Log Suppression Error", _ /* Filename */, _ /* method */, _ /* line number */)) .Times(1); From 782623d080ca66c1309f061952e51b9d0b7c9a63 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:49:23 +0300 Subject: [PATCH 54/80] Lint --- Tests/Common++Test/Tests/LoggerTests.cpp | 4 ++-- Tests/Common++Test/Tests/ObjectPoolTests.cpp | 6 +++--- Tests/Common++Test/Tests/TimespecTimevalTests.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index 08af467613..26657a9623 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -87,8 +87,8 @@ namespace pcpp #pragma pop_macro("LOG_MODULE") - static void logPrinterTrampoline(LogLevel logLevel, const std::string& logMessage, - const std::string& fileName, const std::string& method, const int line) + static void logPrinterTrampoline(LogLevel logLevel, const std::string& logMessage, const std::string& fileName, + const std::string& method, const int line) { if (m_LogCallbackMock != nullptr) { diff --git a/Tests/Common++Test/Tests/ObjectPoolTests.cpp b/Tests/Common++Test/Tests/ObjectPoolTests.cpp index 3eaaccc61b..9bffa96e5d 100644 --- a/Tests/Common++Test/Tests/ObjectPoolTests.cpp +++ b/Tests/Common++Test/Tests/ObjectPoolTests.cpp @@ -31,7 +31,7 @@ namespace pcpp TEST(DynamicObjectPoolTest, Preallocation) { - DynamicObjectPool pool(10, 5); // Create a pool with limit 10 and preallocate 5 objects + DynamicObjectPool pool(10, 5); // Create a pool with limit 10 and preallocate 5 objects EXPECT_EQ(pool.maxSize(), 10); EXPECT_EQ(pool.size(), 5); } @@ -39,7 +39,7 @@ namespace pcpp TEST(DynamicObjectPoolTest, MaxPoolSize) { DynamicObjectPool pool(2); // Create a pool with limit 2 objects - + for (int i = 0; i < 4; ++i) { auto obj = std::make_unique(i); @@ -48,4 +48,4 @@ namespace pcpp } } } // namespace internal -} // namespace pcpp \ No newline at end of file +} // namespace pcpp diff --git a/Tests/Common++Test/Tests/TimespecTimevalTests.cpp b/Tests/Common++Test/Tests/TimespecTimevalTests.cpp index d22a3b85c0..0a0b507d57 100644 --- a/Tests/Common++Test/Tests/TimespecTimevalTests.cpp +++ b/Tests/Common++Test/Tests/TimespecTimevalTests.cpp @@ -48,4 +48,4 @@ namespace pcpp EXPECT_EQ(tv.tv_usec, ts.tv_nsec / 1000); } } // namespace internal -} // namespace pcpp \ No newline at end of file +} // namespace pcpp From 62d48da94883302c703f73a2485d8f12662a7ed2 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 28 Jun 2025 22:57:40 +0300 Subject: [PATCH 55/80] Version print formatting. --- Tests/Common++Test/main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Tests/Common++Test/main.cpp b/Tests/Common++Test/main.cpp index 9197bc0933..7ed86df9d6 100644 --- a/Tests/Common++Test/main.cpp +++ b/Tests/Common++Test/main.cpp @@ -7,9 +7,11 @@ int main(int argc, char* argv[]) { - std::cout << "PcapPlusPlus version: " << pcpp::getPcapPlusPlusVersionFull() << '\n' - << "Built: " << pcpp::getBuildDateTime() << '\n' - << "Built from: " << pcpp::getGitInfo() << std::endl; + std::cout << "PcapPlusPlus Common++Test" + "\nPcapPlusPlus version: " + << pcpp::getPcapPlusPlusVersionFull() // + << "\nBuilt: " << pcpp::getBuildDateTime() // + << "\nBuilt from: " << pcpp::getGitInfo() << std::endl; ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); From bf81cbe7fdc2dfcdf7bd7661653e090f3434f674 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 14:55:24 +0300 Subject: [PATCH 56/80] Added todo for googletest fetch content. --- Tests/Common++Test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 48551c1609..91a2d7ee7b 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.14) include(FetchContent) +# TODO: This may have issues with brew as it doesn't allow the use of FetchContent. FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git From 5f8a7637e76e056778261d8003ebb1264c345061 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 15:32:17 +0300 Subject: [PATCH 57/80] Added common unit test to run_tests CI script. --- ci/run_tests/run_tests.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ci/run_tests/run_tests.py b/ci/run_tests/run_tests.py index df4f3fe373..f530d72208 100644 --- a/ci/run_tests/run_tests.py +++ b/ci/run_tests/run_tests.py @@ -21,6 +21,16 @@ def tcp_replay_worker(interface: str, tcpreplay_dir: str): tcpreplay_proc.kill() +def run_common_tests(args: list[str], use_sudo: bool): + cmd_line = ["sudo"] if use_sudo else [] + cmd_line += [os.path.join("Bin", "Common++Test"), *args] + + completed_process = subprocess.run(cmd_line, cwd="Tests/Common++Test") + + if completed_process.returncode != 0: + raise RuntimeError(f"Error while executing Common++ tests: {completed_process}") + + def run_packet_tests(args: list[str], use_sudo: bool): cmd_line = ["sudo"] if use_sudo else [] cmd_line += [os.path.join("Bin", "Packet++Test"), *args] @@ -56,10 +66,16 @@ def main(): "--test-suites", nargs="+", type=str, - default=["packet", "pcap"], - choices=["packet", "pcap"], + default=["common", "packet", "pcap"], + choices=["common", "packet", "pcap"], help="test suites to use", ) + parser.add_argument( + "--common-test-args", + type=str, + default="", + help="common++ test arguments", + ) parser.add_argument( "--packet-test-args", type=str, @@ -80,6 +96,9 @@ def main(): ) args = parser.parse_args() + if "common" in args.test_suites: + run_common_tests(args.common_test_args.split(), args.use_sudo) + if "packet" in args.test_suites: run_packet_tests(args.packet_test_args.split(), args.use_sudo) From dae7b6b2ac9fcc2f0b0af76013207740f0a1ff1f Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 15:41:59 +0300 Subject: [PATCH 58/80] Lint --- Tests/Common++Test/CMakeLists.txt | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 91a2d7ee7b..f80fa01fad 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -3,16 +3,11 @@ cmake_minimum_required(VERSION 3.14) include(FetchContent) # TODO: This may have issues with brew as it doesn't allow the use of FetchContent. -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.16.0) +FetchContent_Declare(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.16.0) if(WIN32) # Prevent overriding the parent project's compiler/linker settings. - set(gtest_force_shared_crt - ON - CACHE BOOL "" FORCE) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) endif() FetchContent_MakeAvailable(googletest) @@ -28,14 +23,10 @@ add_executable( "Tests/ObjectPoolTests.cpp" "Tests/PointerVectorTests.cpp" "Tests/SystemUtilsTests.cpp" - "Tests/TimespecTimevalTests.cpp") + "Tests/TimespecTimevalTests.cpp" +) -target_link_libraries( - Common++Test - PRIVATE Common++ - memplumber - gtest - gmock) +target_link_libraries(Common++Test PRIVATE Common++ memplumber gtest gmock) target_include_directories(Common++Test PRIVATE $) target_precompile_headers(Common++Test PRIVATE $) @@ -51,7 +42,4 @@ set_property(TARGET Common++Test PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CM enable_testing() -add_test( - NAME Common++Test - COMMAND $ - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/) +add_test(NAME Common++Test COMMAND $ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/) From 40efcd528a00045ab3c6a66fff4784f4cf7789fc Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 16:13:59 +0300 Subject: [PATCH 59/80] Updated packet only to run common + packet suites. --- .github/workflows/build_and_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 42fe53a7df..2c6220432b 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -215,7 +215,7 @@ jobs: - name: Test PcapPlusPlus run: | . .venv/bin/activate - python3 ci/run_tests/run_tests.py --interface eth0 --test-suites "packet" + python3 ci/run_tests/run_tests.py --interface eth0 --test-suites "common" "packet" - name: Check installation run: | From b76fa62c7e27347d884d769ef4b2d27a401abc60 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 16:29:27 +0300 Subject: [PATCH 60/80] Fixed explicit ctor --- Tests/Common++Test/Tests/PointerVectorTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index ceacadc4dd..7ccee66361 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -12,7 +12,7 @@ namespace pcpp class TestObject { public: - TestObject(int value) : m_Value(value) + explicit TestObject(int value) : m_Value(value) {} int getValue() const { From 247da32abc1ea3cb92d1e3c46315e47e599b4104 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 16:47:22 +0300 Subject: [PATCH 61/80] Updated run_tests_windows to have separate functions for calls to subprocess. --- ci/run_tests/run_tests_windows.py | 146 ++++++++++++++++-------------- 1 file changed, 80 insertions(+), 66 deletions(-) diff --git a/ci/run_tests/run_tests_windows.py b/ci/run_tests/run_tests_windows.py index 532241bfeb..69a12b62f9 100644 --- a/ci/run_tests/run_tests_windows.py +++ b/ci/run_tests/run_tests_windows.py @@ -62,6 +62,82 @@ def find_interface(): return None, None +def run_common_tests(args: list[str]): + raise NotImplementedError + +def run_packet_tests(args: list[str]): + return subprocess.run( + os.path.join("Bin", "Packet++Test"), + cwd=os.path.join("Tests", "Packet++Test"), + shell=True, + check=True, # Raise exception if the worker returns in non-zero status code + ) + +def run_packet_coverage(): + return subprocess.run( + [ + "OpenCppCoverage.exe", + "--verbose", + "--sources", + "Packet++", + "--sources", + "Pcap++", + "--sources", + "Common++", + "--excluded_sources", + "Tests", + "--export_type", + "cobertura:Packet++Coverage.xml", + "--", + os.path.join("Bin", "Packet++Test"), + ], + cwd=os.path.join("Tests", "Packet++Test"), + shell=True, + check=True, # Raise exception if the worker returns in non-zero status code + ) + +def run_pcap_tests(ip_address: str, skip_tests: list[str]): + return subprocess.run( + [ + os.path.join("Bin", "Pcap++Test"), + "-i", + ip_address, + "-x", + ";".join(skip_tests), + ], + cwd=os.path.join("Tests", "Pcap++Test"), + shell=True, + check=True, # Raise exception if the worker returns in non-zero status code + ) + +def run_pcap_coverage(ip_address: str, skip_tests: list[str]): + return subprocess.run( + [ + "OpenCppCoverage.exe", + "--verbose", + "--sources", + "Packet++", + "--sources", + "Pcap++", + "--sources", + "Common++", + "--excluded_sources", + "Tests", + "--export_type", + "cobertura:Pcap++Coverage.xml", + "--", + os.path.join("Bin", "Pcap++Test"), + "-i", + ip_address, + "-x", + ";".join(skip_tests), + ], + cwd=os.path.join("Tests", "Pcap++Test"), + shell=True, + check=True, # Raise exception if the worker returns in non-zero status code + ) + + def main(): parser = argparse.ArgumentParser() parser.add_argument( @@ -94,77 +170,15 @@ def main(): tcpreplay_proc = subprocess.Popen(tcpreplay_cmd, shell=True, cwd=TCPREPLAY_PATH) if args.coverage: - completed_process = subprocess.run( - [ - "OpenCppCoverage.exe", - "--verbose", - "--sources", - "Packet++", - "--sources", - "Pcap++", - "--sources", - "Common++", - "--excluded_sources", - "Tests", - "--export_type", - "cobertura:Packet++Coverage.xml", - "--", - os.path.join("Bin", "Packet++Test"), - ], - cwd=os.path.join("Tests", "Packet++Test"), - shell=True, - ) + run_packet_coverage() else: - completed_process = subprocess.run( - os.path.join("Bin", "Packet++Test"), - cwd=os.path.join("Tests", "Packet++Test"), - shell=True, - ) - if completed_process.returncode != 0: - print("Error while executing Packet++ tests: " + str(completed_process)) - exit(completed_process.returncode) + run_packet_tests() skip_tests = ["TestRemoteCapture"] + args.skip_tests if args.coverage: - completed_process = subprocess.run( - [ - "OpenCppCoverage.exe", - "--verbose", - "--sources", - "Packet++", - "--sources", - "Pcap++", - "--sources", - "Common++", - "--excluded_sources", - "Tests", - "--export_type", - "cobertura:Pcap++Coverage.xml", - "--", - os.path.join("Bin", "Pcap++Test"), - "-i", - ip_address, - "-x", - ";".join(skip_tests), - ], - cwd=os.path.join("Tests", "Pcap++Test"), - shell=True, - ) + run_pcap_coverage(ip_address, skip_tests) else: - completed_process = subprocess.run( - [ - os.path.join("Bin", "Pcap++Test"), - "-i", - ip_address, - "-x", - ";".join(skip_tests), - ], - cwd=os.path.join("Tests", "Pcap++Test"), - shell=True, - ) - if completed_process.returncode != 0: - print("Error while executing Pcap++ tests: " + str(completed_process)) - exit(completed_process.returncode) + run_pcap_tests(ip_address, skip_tests) finally: subprocess.call(["taskkill", "/F", "/T", "/PID", str(tcpreplay_proc.pid)]) From 463b63249a35cc06c1ea9208a5712865f09d4311 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 16:56:39 +0300 Subject: [PATCH 62/80] Added common test to windows CI. --- ci/run_tests/run_tests_windows.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ci/run_tests/run_tests_windows.py b/ci/run_tests/run_tests_windows.py index 69a12b62f9..335d5b372c 100644 --- a/ci/run_tests/run_tests_windows.py +++ b/ci/run_tests/run_tests_windows.py @@ -62,10 +62,18 @@ def find_interface(): return None, None -def run_common_tests(args: list[str]): +def run_common_tests(): + return subprocess.run( + os.path.join("Bin", "Common++Test"), + cwd=os.path.join("Tests", "Common++Test"), + shell=True, + check=True, # Raise exception if the worker returns in non-zero status code + ) + +def run_common_coverage(): raise NotImplementedError -def run_packet_tests(args: list[str]): +def run_packet_tests(): return subprocess.run( os.path.join("Bin", "Packet++Test"), cwd=os.path.join("Tests", "Packet++Test"), @@ -172,6 +180,7 @@ def main(): if args.coverage: run_packet_coverage() else: + run_common_tests() run_packet_tests() skip_tests = ["TestRemoteCapture"] + args.skip_tests From bc03910c1ac022e1d559ccd8271bf923198bcbad Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 16:59:06 +0300 Subject: [PATCH 63/80] Lint --- ci/run_tests/run_tests_windows.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ci/run_tests/run_tests_windows.py b/ci/run_tests/run_tests_windows.py index 335d5b372c..44e26d691a 100644 --- a/ci/run_tests/run_tests_windows.py +++ b/ci/run_tests/run_tests_windows.py @@ -67,20 +67,23 @@ def run_common_tests(): os.path.join("Bin", "Common++Test"), cwd=os.path.join("Tests", "Common++Test"), shell=True, - check=True, # Raise exception if the worker returns in non-zero status code + check=True, # Raise exception if the worker returns in non-zero status code ) + def run_common_coverage(): raise NotImplementedError + def run_packet_tests(): return subprocess.run( os.path.join("Bin", "Packet++Test"), cwd=os.path.join("Tests", "Packet++Test"), shell=True, - check=True, # Raise exception if the worker returns in non-zero status code + check=True, # Raise exception if the worker returns in non-zero status code ) + def run_packet_coverage(): return subprocess.run( [ @@ -101,9 +104,10 @@ def run_packet_coverage(): ], cwd=os.path.join("Tests", "Packet++Test"), shell=True, - check=True, # Raise exception if the worker returns in non-zero status code + check=True, # Raise exception if the worker returns in non-zero status code ) + def run_pcap_tests(ip_address: str, skip_tests: list[str]): return subprocess.run( [ @@ -115,9 +119,10 @@ def run_pcap_tests(ip_address: str, skip_tests: list[str]): ], cwd=os.path.join("Tests", "Pcap++Test"), shell=True, - check=True, # Raise exception if the worker returns in non-zero status code + check=True, # Raise exception if the worker returns in non-zero status code ) + def run_pcap_coverage(ip_address: str, skip_tests: list[str]): return subprocess.run( [ @@ -142,7 +147,7 @@ def run_pcap_coverage(ip_address: str, skip_tests: list[str]): ], cwd=os.path.join("Tests", "Pcap++Test"), shell=True, - check=True, # Raise exception if the worker returns in non-zero status code + check=True, # Raise exception if the worker returns in non-zero status code ) From 44f6094b0ac29022a83a1c934aeda350602169a3 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 17:04:57 +0300 Subject: [PATCH 64/80] Delayed startup of tcpreplay until pcap++ tests. --- ci/run_tests/run_tests_windows.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ci/run_tests/run_tests_windows.py b/ci/run_tests/run_tests_windows.py index 44e26d691a..9e2ed3d51c 100644 --- a/ci/run_tests/run_tests_windows.py +++ b/ci/run_tests/run_tests_windows.py @@ -176,18 +176,18 @@ def main(): exit(1) print(f"Interface is {tcpreplay_interface} and IP address is {ip_address}") + if args.coverage: + run_packet_coverage() + else: + run_common_tests() + run_packet_tests() + try: tcpreplay_cmd = ( f'tcpreplay.exe -i "{tcpreplay_interface}" --mbps=10 -l 0 {PCAP_FILE_PATH}' ) tcpreplay_proc = subprocess.Popen(tcpreplay_cmd, shell=True, cwd=TCPREPLAY_PATH) - if args.coverage: - run_packet_coverage() - else: - run_common_tests() - run_packet_tests() - skip_tests = ["TestRemoteCapture"] + args.skip_tests if args.coverage: run_pcap_coverage(ip_address, skip_tests) From 3d57ddd4c74d4b4044420510df681a312f9fcbaa Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 12 Jul 2025 18:05:56 +0300 Subject: [PATCH 65/80] Added tests for new functions. --- Tests/Common++Test/Tests/IPAddressTests.cpp | 53 ++++++++++++++++ Tests/Common++Test/Tests/MacAddressTests.cpp | 63 ++++++++++++++++---- 2 files changed, 103 insertions(+), 13 deletions(-) diff --git a/Tests/Common++Test/Tests/IPAddressTests.cpp b/Tests/Common++Test/Tests/IPAddressTests.cpp index b7d3128f7a..37968b7686 100644 --- a/Tests/Common++Test/Tests/IPAddressTests.cpp +++ b/Tests/Common++Test/Tests/IPAddressTests.cpp @@ -206,6 +206,59 @@ namespace pcpp EXPECT_FALSE(addr6 < addr4); } + TEST(IPv6AddressTest, CopyToBuffer) + { + IPv6Address addr("2001:db8:85a3::8a2e:370:7334"); + std::array expected = { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; + + // Test query mode + EXPECT_EQ(addr.copyTo(nullptr, 0), 16); + + // Test with null buffer and non-zero size + EXPECT_THROW(addr.copyTo(nullptr, 1), std::invalid_argument); + + std::array buffer{}; + + // Test with smaller buffer. + EXPECT_EQ(addr.copyTo(buffer.data(), 5), 16); + EXPECT_THAT(buffer, ::testing::Each(::testing::Eq(0))); + + // Test with precise buffer + buffer.fill(0); + EXPECT_EQ(addr.copyTo(buffer.data(), 16), 16); + EXPECT_EQ(std::memcmp(buffer.data(), expected.data(), 16), 0); + EXPECT_TRUE(std::all_of(buffer.begin() + 16, buffer.end(), [](uint8_t x) { return x == 0; })); + + // Test with a buffer that is larger + buffer.fill(0); + EXPECT_EQ(addr.copyTo(buffer.data(), buffer.size()), 16); + EXPECT_EQ(std::memcmp(buffer.data(), expected.data(), 16), 0); + EXPECT_TRUE(std::all_of(buffer.begin() + 16, buffer.end(), [](uint8_t x) { return x == 0; })); + } + + TEST(IPv6AddressTest, CopyToBufferNewBuffer) + { + IPv6Address addr("2001:db8:85a3::8a2e:370:7334"); + std::array expected = { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }; + + uint8_t* newBuffer = nullptr; + size_t newBufferSize = 0; + + EXPECT_THROW(addr.copyToNewBuffer(nullptr, newBufferSize), std::invalid_argument) + << "IPv6Address::copyToNewBuffer does not throw for null buffer pointer."; + + EXPECT_TRUE(addr.copyToNewBuffer(&newBuffer, newBufferSize)); + std::unique_ptr bufferGuard(newBuffer); + + ASSERT_NE(newBuffer, nullptr) << "IPv6Address::copyToNewBuffer did not allocate a new buffer."; + ASSERT_EQ(newBufferSize, 16) << "IPv6Address::copyToNewBuffer did not return the correct size."; + + EXPECT_EQ(std::memcmp(newBuffer, expected.data(), 16), 0) + << "IPv6Address::copyToNewBuffer did not copy the address correctly."; + } + TEST(IPv6AddressTest, MatchNetworkMethodWithIPv6Network) { IPv6Address addr4("2001:db8:85a3::8a2e:370:7334"); diff --git a/Tests/Common++Test/Tests/MacAddressTests.cpp b/Tests/Common++Test/Tests/MacAddressTests.cpp index 60e46f3c5e..fd58bbaeaa 100644 --- a/Tests/Common++Test/Tests/MacAddressTests.cpp +++ b/Tests/Common++Test/Tests/MacAddressTests.cpp @@ -88,23 +88,60 @@ namespace pcpp EXPECT_EQ(mac.toString(), "01:02:03:04:05:06"); } - TEST(MacAddressTest, CopyToAllocatedArray) + TEST(MacAddressTest, CopyToBuffer) { - pcpp::MacAddress mac(1, 2, 3, 4, 5, 6); - uint8_t* arr = nullptr; - mac.copyTo(&arr); - std::array expected = { 1, 2, 3, 4, 5, 6 }; - EXPECT_EQ(std::memcmp(arr, expected.data(), 6), 0); - delete[] arr; + pcpp::MacAddress macAddr(1, 2, 3, 4, 5, 6); + + constexpr size_t expectedRequiredBytes = 6; + std::array expected = { 1, 2, 3, 4, 5, 6 }; + + // Test query mode + EXPECT_EQ(macAddr.copyTo(nullptr, 0), 6); + + // Test with null buffer and non-zero size + EXPECT_THROW(macAddr.copyTo(nullptr, 1), std::invalid_argument); + + std::array buffer{}; + + // Test with smaller buffer. + EXPECT_EQ(macAddr.copyTo(buffer.data(), 5), expectedRequiredBytes); + EXPECT_THAT(buffer, ::testing::Each(::testing::Eq(0))); + + // Test with precise buffer + buffer.fill(0); + EXPECT_EQ(macAddr.copyTo(buffer.data(), expectedRequiredBytes), expectedRequiredBytes); + EXPECT_EQ(std::memcmp(buffer.data(), expected.data(), expectedRequiredBytes), 0); + EXPECT_TRUE(std::all_of(buffer.begin() + 6, buffer.end(), [](uint8_t x) { return x == 0; })); + + // Test with a buffer that is larger + buffer.fill(0); + EXPECT_EQ(macAddr.copyTo(buffer.data(), buffer.size()), expectedRequiredBytes); + EXPECT_EQ(std::memcmp(buffer.data(), expected.data(), expectedRequiredBytes), 0); + EXPECT_TRUE(std::all_of(buffer.begin() + 6, buffer.end(), [](uint8_t x) { return x == 0; })); } - TEST(MacAddressTest, CopyToPreAllocatedArray) + TEST(MacAddressTest, CopyToNewBuffer) { - pcpp::MacAddress mac(1, 2, 3, 4, 5, 6); - std::array arr; - mac.copyTo(arr.data()); - std::array expected = { 1, 2, 3, 4, 5, 6 }; - EXPECT_EQ(arr, expected); + pcpp::MacAddress macAddr(1, 2, 3, 4, 5, 6); + + constexpr size_t expectedRequiredBytes = 6; + std::array expected = { 1, 2, 3, 4, 5, 6 }; + + uint8_t* newBuffer = nullptr; + size_t newBufferSize = 0; + + EXPECT_THROW(macAddr.copyToNewBuffer(nullptr, newBufferSize), std::invalid_argument) + << "IPv6Address::copyToNewBuffer does not throw for null buffer pointer."; + + EXPECT_TRUE(macAddr.copyToNewBuffer(&newBuffer, newBufferSize)); + std::unique_ptr bufferGuard(newBuffer); + + ASSERT_NE(newBuffer, nullptr) << "IPv6Address::copyToNewBuffer did not allocate a new buffer."; + ASSERT_EQ(newBufferSize, expectedRequiredBytes) + << "IPv6Address::copyToNewBuffer did not return the correct size."; + + EXPECT_EQ(std::memcmp(newBuffer, expected.data(), expectedRequiredBytes), 0) + << "IPv6Address::copyToNewBuffer did not copy the address correctly."; } TEST(MacAddressTest, OutputStreamOperator) From 2b9a0bafd5213677e5b45462a6cb9e2eb488b73f Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Tue, 29 Jul 2025 20:32:32 +0300 Subject: [PATCH 66/80] Fixed memory leak fixture not respecting mem leak checks. --- .../header/MemoryLeakDetectorFixture.hpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp index f1a50e9995..24cfae9021 100644 --- a/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp +++ b/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp @@ -39,15 +39,20 @@ namespace pcpp void TearDown() override { - std::size_t memLeakCount = 0; - std::uint64_t memLeakSize = 0; - MemPlumber::memLeakCheck(memLeakCount, memLeakSize); - MemPlumber::stopAndFreeAllMemory(); - - if (memLeakCount > 0 || memLeakSize > 0) + if(!skipMemLeakCheck) { - FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize << " [bytes] leaked"; + std::size_t memLeakCount = 0; + std::uint64_t memLeakSize = 0; + MemPlumber::memLeakCheck(memLeakCount, memLeakSize); + MemPlumber::stopAndFreeAllMemory(); + + if (memLeakCount > 0 || memLeakSize > 0) + { + FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize + << " [bytes] leaked"; + } } + Base::TearDown(); } From 7a1d6d73d9c0d9acd33fa80a478c7a4326fce005 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Tue, 29 Jul 2025 21:20:42 +0300 Subject: [PATCH 67/80] Changed MemoryLeak Fixture to default fixture under TEST macro. --- Tests/Common++Test/CMakeLists.txt | 6 +- .../Common++Test/Tests/PointerVectorTests.cpp | 32 +++----- .../Utils/MemoryLeakDetectorFixture.cpp | 10 +++ .../Utils/MemoryLeakDetectorFixture.hpp | 79 +++++++++++++++++++ .../header/MemoryLeakDetectorFixture.hpp | 66 ---------------- Tests/Common++Test/header/pch.h | 7 -- Tests/Common++Test/pch.h | 11 +++ 7 files changed, 116 insertions(+), 95 deletions(-) create mode 100644 Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp create mode 100644 Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp delete mode 100644 Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp delete mode 100644 Tests/Common++Test/header/pch.h create mode 100644 Tests/Common++Test/pch.h diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index f80fa01fad..a8fc31f521 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -24,12 +24,12 @@ add_executable( "Tests/PointerVectorTests.cpp" "Tests/SystemUtilsTests.cpp" "Tests/TimespecTimevalTests.cpp" -) + "Utils/MemoryLeakDetectorFixture.cpp") target_link_libraries(Common++Test PRIVATE Common++ memplumber gtest gmock) -target_include_directories(Common++Test PRIVATE $) -target_precompile_headers(Common++Test PRIVATE $) +target_include_directories(Common++Test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_precompile_headers(Common++Test PRIVATE "pch.h") if(MSVC) # This executable requires getopt.h not available on VStudio diff --git a/Tests/Common++Test/Tests/PointerVectorTests.cpp b/Tests/Common++Test/Tests/PointerVectorTests.cpp index 7ccee66361..bf0d419675 100644 --- a/Tests/Common++Test/Tests/PointerVectorTests.cpp +++ b/Tests/Common++Test/Tests/PointerVectorTests.cpp @@ -3,8 +3,6 @@ #include #include -#include "MemoryLeakDetectorFixture.hpp" - #include "PointerVector.h" namespace pcpp @@ -27,17 +25,13 @@ namespace pcpp int m_Value; }; - class PointerVectorTest : public MemoryLeakDetectorTest - { - }; - - TEST_F(PointerVectorTest, DefaultConstructor) + TEST(PointerVectorTest, DefaultConstructor) { pcpp::PointerVector vec; EXPECT_EQ(vec.size(), 0); } - TEST_F(PointerVectorTest, CopyConstructor) + TEST(PointerVectorTest, CopyConstructor) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -49,7 +43,7 @@ namespace pcpp EXPECT_EQ(copyVec.at(1)->getValue(), 2); } - TEST_F(PointerVectorTest, MoveConstructor) + TEST(PointerVectorTest, MoveConstructor) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -62,7 +56,7 @@ namespace pcpp EXPECT_EQ(vec.size(), 0); } - TEST_F(PointerVectorTest, CopyAssignmentOperator) + TEST(PointerVectorTest, CopyAssignmentOperator) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -75,7 +69,7 @@ namespace pcpp EXPECT_EQ(copyVec.at(1)->getValue(), 2); } - TEST_F(PointerVectorTest, MoveAssignmentOperator) + TEST(PointerVectorTest, MoveAssignmentOperator) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -89,7 +83,7 @@ namespace pcpp EXPECT_EQ(vec.size(), 0); } - TEST_F(PointerVectorTest, PushBack) + TEST(PointerVectorTest, PushBack) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -100,7 +94,7 @@ namespace pcpp EXPECT_EQ(vec.at(1)->getValue(), 2); } - TEST_F(PointerVectorTest, PushBackUniquePtr) + TEST(PointerVectorTest, PushBackUniquePtr) { pcpp::PointerVector vec; vec.pushBack(std::unique_ptr(new TestObject(1))); @@ -111,7 +105,7 @@ namespace pcpp EXPECT_EQ(vec.at(1)->getValue(), 2); } - TEST_F(PointerVectorTest, Clear) + TEST(PointerVectorTest, Clear) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -121,7 +115,7 @@ namespace pcpp EXPECT_EQ(vec.size(), 0); } - TEST_F(PointerVectorTest, Erase) + TEST(PointerVectorTest, Erase) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -137,7 +131,7 @@ namespace pcpp EXPECT_EQ(vec.at(1)->getValue(), 3); } - TEST_F(PointerVectorTest, GetAndDetach) + TEST(PointerVectorTest, GetAndDetach) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -149,7 +143,7 @@ namespace pcpp EXPECT_EQ(vec.at(0)->getValue(), 2); } - TEST_F(PointerVectorTest, At) + TEST(PointerVectorTest, At) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -159,7 +153,7 @@ namespace pcpp EXPECT_EQ(vec.at(1)->getValue(), 2); } - TEST_F(PointerVectorTest, FrontBack) + TEST(PointerVectorTest, FrontBack) { pcpp::PointerVector vec; vec.pushBack(new TestObject(1)); @@ -169,7 +163,7 @@ namespace pcpp EXPECT_EQ(vec.back()->getValue(), 2); } - TEST_F(PointerVectorTest, PushBackNullptr) + TEST(PointerVectorTest, PushBackNullptr) { pcpp::PointerVector vec; TestObject* obj = nullptr; // Using nullptr directly in pushBack is a compile time error. diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp new file mode 100644 index 0000000000..dd5397b9d2 --- /dev/null +++ b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp @@ -0,0 +1,10 @@ +#include "MemoryLeakDetectorFixture.hpp" + +namespace pcpp +{ + namespace test + { + bool MemoryLeakDetectorTest::skipMemLeakCheck = false; + std::once_flag MemoryLeakDetectorTest::m_MSVC_WarningPrinted; + } // namespace testing +} // namespace pcpp \ No newline at end of file diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp new file mode 100644 index 0000000000..6e5690c8b5 --- /dev/null +++ b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include + +#include + +namespace pcpp +{ + namespace test + { + class MemoryLeakDetectorTest : public ::testing::Test + { + using Base = ::testing::Test; + + public: + static void SetUpTestSuite() + { +#ifdef NDEBUG + // TODO: Do we still need this? The issue seems to be closed? + skipMemLeakCheck = true; + std::call_once(m_MSVC_WarningPrinted, [] { + std::cout + << "Disabling memory leak check in MSVC Release builds due to caching logic in stream objects that looks like a memory leak:\n" + " https://github.com/cpputest/cpputest/issues/786#issuecomment-148921958" + << std::endl; + }); +#else + skipMemLeakCheck = false; +#endif + } + + protected: + void SetUp() override + { + Base::SetUp(); + + if (!skipMemLeakCheck) + { + MemPlumber::start(); + } + } + + void TearDown() override + { + if (!skipMemLeakCheck) + { + std::size_t memLeakCount = 0; + std::uint64_t memLeakSize = 0; + MemPlumber::memLeakCheck(memLeakCount, memLeakSize); + MemPlumber::stopAndFreeAllMemory(); + + if (memLeakCount > 0 || memLeakSize > 0) + { + FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize + << " [bytes] leaked"; + } + } + + Base::TearDown(); + } + + private: + static bool skipMemLeakCheck; + static std::once_flag m_MSVC_WarningPrinted; + }; + } // namespace test + +} // namespace pcpp + +// Macro to define a test case in the MemoryLeakDetectorTest suite +// The macro is copied from the Google Test framework GTEST_TEST macro definition in gtest.h +#define PTF_MEMLEAK_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, pcpp::test::MemoryLeakDetectorTest, \ + ::testing::internal::GetTypeId()) + +#ifndef PTF_NO_TEST_OVERRIDE +# define TEST(test_suite_name, test_name) PTF_MEMLEAK_TEST(test_suite_name, test_name) +#endif // !PTF_NO_TEST_OVERRIDE diff --git a/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp deleted file mode 100644 index 24cfae9021..0000000000 --- a/Tests/Common++Test/header/MemoryLeakDetectorFixture.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -#include - -namespace pcpp -{ - class MemoryLeakDetectorTest : public ::testing::Test - { - using Base = ::testing::Test; - - public: - static void SetUpTestSuite() - { -#ifdef NDEBUG - // TODO: Do we still need this? The issue seems to be closed? - skipMemLeakCheck = true; - std::call_once(m_MSVC_WarningPrinted, [] { - std::cout - << "Disabling memory leak check in MSVC Release builds due to caching logic in stream objects that looks like a memory leak:\n" - " https://github.com/cpputest/cpputest/issues/786#issuecomment-148921958" - << std::endl; - }); -#else - skipMemLeakCheck = false; -#endif - } - - protected: - void SetUp() override - { - Base::SetUp(); - - if (!skipMemLeakCheck) - { - MemPlumber::start(); - } - } - - void TearDown() override - { - if(!skipMemLeakCheck) - { - std::size_t memLeakCount = 0; - std::uint64_t memLeakSize = 0; - MemPlumber::memLeakCheck(memLeakCount, memLeakSize); - MemPlumber::stopAndFreeAllMemory(); - - if (memLeakCount > 0 || memLeakSize > 0) - { - FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize - << " [bytes] leaked"; - } - } - - Base::TearDown(); - } - - private: - static bool skipMemLeakCheck; - static std::once_flag m_MSVC_WarningPrinted; - }; - - bool MemoryLeakDetectorTest::skipMemLeakCheck = false; - std::once_flag MemoryLeakDetectorTest::m_MSVC_WarningPrinted; -} // namespace pcpp diff --git a/Tests/Common++Test/header/pch.h b/Tests/Common++Test/header/pch.h deleted file mode 100644 index bb5a5e479b..0000000000 --- a/Tests/Common++Test/header/pch.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include -#include - -#include -#include diff --git a/Tests/Common++Test/pch.h b/Tests/Common++Test/pch.h new file mode 100644 index 0000000000..49ca568075 --- /dev/null +++ b/Tests/Common++Test/pch.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +#include +#include + +// If PTF_NO_TEST_OVERRIDE is not defined, the header overrides the default Google Test +// test macro to include memory leak detection functionality. +#include "Utils/MemoryLeakDetectorFixture.hpp" From a3fddb8b1a34906d78ed313699f698ffde6087e4 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Tue, 29 Jul 2025 21:23:17 +0300 Subject: [PATCH 68/80] Temporarely disabled memory leak fixture testing due to false positives from google test. --- Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp index 6e5690c8b5..0a07770ac7 100644 --- a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp +++ b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp @@ -26,7 +26,8 @@ namespace pcpp << std::endl; }); #else - skipMemLeakCheck = false; + // GTest sometimes allocates memory? which isn't freed before TearDown is called causing false positives and crashes. + skipMemLeakCheck = true; #endif } From 68eaf83f5de5227c3953bc796deb1beba51f0e2a Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Tue, 29 Jul 2025 23:52:09 +0300 Subject: [PATCH 69/80] Changed MemoryLeakFixture into a gtest listener. --- Tests/Common++Test/CMakeLists.txt | 2 +- .../Utils/MemoryLeakDetectorFixture.cpp | 10 --- .../Utils/MemoryLeakDetectorFixture.hpp | 80 ------------------- .../Common++Test/Utils/MemoryLeakListener.cpp | 29 +++++++ .../Common++Test/Utils/MemoryLeakListener.hpp | 16 ++++ Tests/Common++Test/main.cpp | 22 +++++ Tests/Common++Test/pch.h | 4 - 7 files changed, 68 insertions(+), 95 deletions(-) delete mode 100644 Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp delete mode 100644 Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp create mode 100644 Tests/Common++Test/Utils/MemoryLeakListener.cpp create mode 100644 Tests/Common++Test/Utils/MemoryLeakListener.hpp diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index a8fc31f521..900691c026 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -24,7 +24,7 @@ add_executable( "Tests/PointerVectorTests.cpp" "Tests/SystemUtilsTests.cpp" "Tests/TimespecTimevalTests.cpp" - "Utils/MemoryLeakDetectorFixture.cpp") + "Utils/MemoryLeakListener.cpp") target_link_libraries(Common++Test PRIVATE Common++ memplumber gtest gmock) diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp deleted file mode 100644 index dd5397b9d2..0000000000 --- a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "MemoryLeakDetectorFixture.hpp" - -namespace pcpp -{ - namespace test - { - bool MemoryLeakDetectorTest::skipMemLeakCheck = false; - std::once_flag MemoryLeakDetectorTest::m_MSVC_WarningPrinted; - } // namespace testing -} // namespace pcpp \ No newline at end of file diff --git a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp b/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp deleted file mode 100644 index 0a07770ac7..0000000000 --- a/Tests/Common++Test/Utils/MemoryLeakDetectorFixture.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace pcpp -{ - namespace test - { - class MemoryLeakDetectorTest : public ::testing::Test - { - using Base = ::testing::Test; - - public: - static void SetUpTestSuite() - { -#ifdef NDEBUG - // TODO: Do we still need this? The issue seems to be closed? - skipMemLeakCheck = true; - std::call_once(m_MSVC_WarningPrinted, [] { - std::cout - << "Disabling memory leak check in MSVC Release builds due to caching logic in stream objects that looks like a memory leak:\n" - " https://github.com/cpputest/cpputest/issues/786#issuecomment-148921958" - << std::endl; - }); -#else - // GTest sometimes allocates memory? which isn't freed before TearDown is called causing false positives and crashes. - skipMemLeakCheck = true; -#endif - } - - protected: - void SetUp() override - { - Base::SetUp(); - - if (!skipMemLeakCheck) - { - MemPlumber::start(); - } - } - - void TearDown() override - { - if (!skipMemLeakCheck) - { - std::size_t memLeakCount = 0; - std::uint64_t memLeakSize = 0; - MemPlumber::memLeakCheck(memLeakCount, memLeakSize); - MemPlumber::stopAndFreeAllMemory(); - - if (memLeakCount > 0 || memLeakSize > 0) - { - FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize - << " [bytes] leaked"; - } - } - - Base::TearDown(); - } - - private: - static bool skipMemLeakCheck; - static std::once_flag m_MSVC_WarningPrinted; - }; - } // namespace test - -} // namespace pcpp - -// Macro to define a test case in the MemoryLeakDetectorTest suite -// The macro is copied from the Google Test framework GTEST_TEST macro definition in gtest.h -#define PTF_MEMLEAK_TEST(test_suite_name, test_name) \ - GTEST_TEST_(test_suite_name, test_name, pcpp::test::MemoryLeakDetectorTest, \ - ::testing::internal::GetTypeId()) - -#ifndef PTF_NO_TEST_OVERRIDE -# define TEST(test_suite_name, test_name) PTF_MEMLEAK_TEST(test_suite_name, test_name) -#endif // !PTF_NO_TEST_OVERRIDE diff --git a/Tests/Common++Test/Utils/MemoryLeakListener.cpp b/Tests/Common++Test/Utils/MemoryLeakListener.cpp new file mode 100644 index 0000000000..b6821e4e2e --- /dev/null +++ b/Tests/Common++Test/Utils/MemoryLeakListener.cpp @@ -0,0 +1,29 @@ +#include "MemoryLeakListener.hpp" + +#include + +namespace pcpp +{ + namespace test + { + void MemoryLeakListener::OnTestStart(const ::testing::TestInfo& testInfo) + { + MemPlumber::start(); + } + + void MemoryLeakListener::OnTestEnd(const ::testing::TestInfo& testInfo) + { + std::size_t memLeakCount = 0; + std::uint64_t memLeakSize = 0; + MemPlumber::memLeakCheck(memLeakCount, memLeakSize); + MemPlumber::stop(); + // MemPlumber::stopAndDropTrackedMemory(); + + if (memLeakCount > 0 || memLeakSize > 0) + { + FAIL() << "Memory leak found! " << memLeakCount << " objects and " << memLeakSize << " [bytes] leaked"; + } + } + + } // namespace testing +} // namespace pcpp \ No newline at end of file diff --git a/Tests/Common++Test/Utils/MemoryLeakListener.hpp b/Tests/Common++Test/Utils/MemoryLeakListener.hpp new file mode 100644 index 0000000000..afa4719f7b --- /dev/null +++ b/Tests/Common++Test/Utils/MemoryLeakListener.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace pcpp +{ + namespace test + { + class MemoryLeakListener : public ::testing::EmptyTestEventListener + { + void OnTestStart(const ::testing::TestInfo& testInfo) override; + void OnTestEnd(const ::testing::TestInfo& testInfo) override; + }; + } // namespace test + +} // namespace pcpp diff --git a/Tests/Common++Test/main.cpp b/Tests/Common++Test/main.cpp index 7ed86df9d6..db71efcdb3 100644 --- a/Tests/Common++Test/main.cpp +++ b/Tests/Common++Test/main.cpp @@ -3,7 +3,9 @@ #include #include +#include "Logger.h" #include "PcapPlusPlusVersion.h" +#include "Utils/MemoryLeakListener.hpp" int main(int argc, char* argv[]) { @@ -14,5 +16,25 @@ int main(int argc, char* argv[]) << "\nBuilt from: " << pcpp::getGitInfo() << std::endl; ::testing::InitGoogleMock(&argc, argv); + + // The logger singleton looks like a memory leak. Invoke it before starting the memory check + // Disables context pooling to avoid false positives in the memory leak check, as the contexts persist in the pool. + pcpp::Logger::getInstance().useContextPooling(false); + + auto& eventListeners = ::testing::UnitTest::GetInstance()->listeners(); + +#ifdef NDEBUG + // TODO: Do we still need this? The issue seems to be closed? + std::cout + << "Disabling memory leak check in MSVC Release builds due to caching logic in stream objects that looks like a memory leak:\n" + " https://github.com/cpputest/cpputest/issues/786#issuecomment-148921958" + << std::endl; +#else + // GTest sometimes allocates memory? which isn't freed before TearDown is called causing false positives and + // crashes. + + // eventListeners.Append(new pcpp::test::MemoryLeakListener()); +#endif + return RUN_ALL_TESTS(); } diff --git a/Tests/Common++Test/pch.h b/Tests/Common++Test/pch.h index 49ca568075..bb5a5e479b 100644 --- a/Tests/Common++Test/pch.h +++ b/Tests/Common++Test/pch.h @@ -5,7 +5,3 @@ #include #include - -// If PTF_NO_TEST_OVERRIDE is not defined, the header overrides the default Google Test -// test macro to include memory leak detection functionality. -#include "Utils/MemoryLeakDetectorFixture.hpp" From 36bea655643c1916f9815803c7357d4a117bdeb6 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 30 Jul 2025 00:04:48 +0300 Subject: [PATCH 70/80] Updated log tests to utilize functor object instead of static function. --- Tests/Common++Test/Tests/LoggerTests.cpp | 31 ++++++------------------ 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index 26657a9623..6afa9a7c3f 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -1,7 +1,7 @@ #include "pch.h" #include - +#include #include "Logger.h" namespace pcpp @@ -43,20 +43,20 @@ namespace pcpp { Base::SetUp(); - // Setup log callback trampoline - m_Logger.setLogPrinter(&LoggerTest::logPrinterTrampoline); + // Setup log callback mock + m_LogCallbackMock = std::make_unique(); + + // Setup log callback to the mock + m_Logger.setLogPrinter(std::cref(*m_LogCallbackMock)); // Enable all logs and set them to Info level by default m_Logger.enableLogs(); m_Logger.setAllModulesToLogLevel(LogLevel::Info); - - // Setup log callback mock - m_LogCallbackMock = std::unique_ptr(new LogCallbackMock()); } void TearDown() override { - // Reset log callback trampoline + // Reset log callback m_Logger.enableLogs(); m_Logger.setAllModulesToLogLevel(LogLevel::Info); m_Logger.resetLogPrinter(); @@ -87,26 +87,11 @@ namespace pcpp #pragma pop_macro("LOG_MODULE") - static void logPrinterTrampoline(LogLevel logLevel, const std::string& logMessage, const std::string& fileName, - const std::string& method, const int line) - { - if (m_LogCallbackMock != nullptr) - { - // Dereference the pointer and call the mock with the parameters. - (*m_LogCallbackMock)(logLevel, logMessage, fileName, method, line); - } - else - { - throw std::runtime_error("Log Trampoline Error: Log callback not set"); - } - } - static std::unique_ptr m_LogCallbackMock; Logger& m_Logger; + std::unique_ptr m_LogCallbackMock; }; - std::unique_ptr LoggerTest::m_LogCallbackMock = nullptr; - TEST_F(LoggerTest, LogLevelAsString) { EXPECT_EQ(Logger::logLevelAsString(LogLevel::Error), "ERROR"); From 480f802ba215d3a930478d5a623a4cbdbaf58daa Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Wed, 30 Jul 2025 00:14:37 +0300 Subject: [PATCH 71/80] Reverted on test end back to free all memory. --- Tests/Common++Test/Utils/MemoryLeakListener.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Common++Test/Utils/MemoryLeakListener.cpp b/Tests/Common++Test/Utils/MemoryLeakListener.cpp index b6821e4e2e..adc7cd27e2 100644 --- a/Tests/Common++Test/Utils/MemoryLeakListener.cpp +++ b/Tests/Common++Test/Utils/MemoryLeakListener.cpp @@ -16,8 +16,8 @@ namespace pcpp std::size_t memLeakCount = 0; std::uint64_t memLeakSize = 0; MemPlumber::memLeakCheck(memLeakCount, memLeakSize); - MemPlumber::stop(); - // MemPlumber::stopAndDropTrackedMemory(); + // TODO: This causes issues because it frees memory that might be used by the test framework + MemPlumber::stopAndFreeAllMemory(); if (memLeakCount > 0 || memLeakSize > 0) { From 86a0e5b093bdb355ec9f844999bd96c33bbe9a9c Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Fri, 1 Aug 2025 10:26:59 +0300 Subject: [PATCH 72/80] Fixed visibility. --- Tests/Common++Test/Utils/MemoryLeakListener.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Common++Test/Utils/MemoryLeakListener.hpp b/Tests/Common++Test/Utils/MemoryLeakListener.hpp index afa4719f7b..c530e3f6c3 100644 --- a/Tests/Common++Test/Utils/MemoryLeakListener.hpp +++ b/Tests/Common++Test/Utils/MemoryLeakListener.hpp @@ -8,6 +8,7 @@ namespace pcpp { class MemoryLeakListener : public ::testing::EmptyTestEventListener { + public: void OnTestStart(const ::testing::TestInfo& testInfo) override; void OnTestEnd(const ::testing::TestInfo& testInfo) override; }; From a6cd38b5ce16e75f310090384208396a2730c12c Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Fri, 1 Aug 2025 10:30:24 +0300 Subject: [PATCH 73/80] Lint --- Tests/Common++Test/CMakeLists.txt | 3 ++- Tests/Common++Test/Tests/LoggerTests.cpp | 1 - Tests/Common++Test/Utils/MemoryLeakListener.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Common++Test/CMakeLists.txt b/Tests/Common++Test/CMakeLists.txt index 900691c026..449649fe2c 100644 --- a/Tests/Common++Test/CMakeLists.txt +++ b/Tests/Common++Test/CMakeLists.txt @@ -24,7 +24,8 @@ add_executable( "Tests/PointerVectorTests.cpp" "Tests/SystemUtilsTests.cpp" "Tests/TimespecTimevalTests.cpp" - "Utils/MemoryLeakListener.cpp") + "Utils/MemoryLeakListener.cpp" +) target_link_libraries(Common++Test PRIVATE Common++ memplumber gtest gmock) diff --git a/Tests/Common++Test/Tests/LoggerTests.cpp b/Tests/Common++Test/Tests/LoggerTests.cpp index 6afa9a7c3f..fa8c9a9170 100644 --- a/Tests/Common++Test/Tests/LoggerTests.cpp +++ b/Tests/Common++Test/Tests/LoggerTests.cpp @@ -87,7 +87,6 @@ namespace pcpp #pragma pop_macro("LOG_MODULE") - Logger& m_Logger; std::unique_ptr m_LogCallbackMock; }; diff --git a/Tests/Common++Test/Utils/MemoryLeakListener.cpp b/Tests/Common++Test/Utils/MemoryLeakListener.cpp index adc7cd27e2..4614e278e0 100644 --- a/Tests/Common++Test/Utils/MemoryLeakListener.cpp +++ b/Tests/Common++Test/Utils/MemoryLeakListener.cpp @@ -17,7 +17,7 @@ namespace pcpp std::uint64_t memLeakSize = 0; MemPlumber::memLeakCheck(memLeakCount, memLeakSize); // TODO: This causes issues because it frees memory that might be used by the test framework - MemPlumber::stopAndFreeAllMemory(); + MemPlumber::stopAndFreeAllMemory(); if (memLeakCount > 0 || memLeakSize > 0) { @@ -25,5 +25,5 @@ namespace pcpp } } - } // namespace testing -} // namespace pcpp \ No newline at end of file + } // namespace test +} // namespace pcpp From ac73ed8243a47702a377c107444be980a555f46c Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sat, 2 Aug 2025 20:37:41 +0300 Subject: [PATCH 74/80] Fix cppcheck warnings. --- Tests/Common++Test/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/Common++Test/main.cpp b/Tests/Common++Test/main.cpp index db71efcdb3..0c90039441 100644 --- a/Tests/Common++Test/main.cpp +++ b/Tests/Common++Test/main.cpp @@ -21,8 +21,6 @@ int main(int argc, char* argv[]) // Disables context pooling to avoid false positives in the memory leak check, as the contexts persist in the pool. pcpp::Logger::getInstance().useContextPooling(false); - auto& eventListeners = ::testing::UnitTest::GetInstance()->listeners(); - #ifdef NDEBUG // TODO: Do we still need this? The issue seems to be closed? std::cout @@ -33,6 +31,7 @@ int main(int argc, char* argv[]) // GTest sometimes allocates memory? which isn't freed before TearDown is called causing false positives and // crashes. + // auto& eventListeners = ::testing::UnitTest::GetInstance()->listeners(); // eventListeners.Append(new pcpp::test::MemoryLeakListener()); #endif From a0f005abec1bb412e59516cc730903c9c039c7ac Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 4 Aug 2025 11:43:14 +0300 Subject: [PATCH 75/80] Commented out memory leak warning as it is disabled in all modes. --- Tests/Common++Test/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Common++Test/main.cpp b/Tests/Common++Test/main.cpp index 0c90039441..77e413978f 100644 --- a/Tests/Common++Test/main.cpp +++ b/Tests/Common++Test/main.cpp @@ -23,10 +23,12 @@ int main(int argc, char* argv[]) #ifdef NDEBUG // TODO: Do we still need this? The issue seems to be closed? + /* std::cout << "Disabling memory leak check in MSVC Release builds due to caching logic in stream objects that looks like a memory leak:\n" " https://github.com/cpputest/cpputest/issues/786#issuecomment-148921958" << std::endl; + */ #else // GTest sometimes allocates memory? which isn't freed before TearDown is called causing false positives and // crashes. From 789a17eebc4d7349fbe421f3b085929fb495ba29 Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Mon, 4 Aug 2025 12:05:04 +0300 Subject: [PATCH 76/80] Added googletest 1.16 to 3rdParty dependencies. --- 3rdParty/CMakeLists.txt | 1 + 3rdParty/googletest-1.16.0/CMakeLists.txt | 11 + .../googletest-1.16.0/googletest/.gitignore | 89 + .../googletest/CMakeLists.txt | 36 + .../googletest/CONTRIBUTING.md | 141 + .../googletest-1.16.0/googletest/CONTRIBUTORS | 66 + 3rdParty/googletest-1.16.0/googletest/LICENSE | 28 + .../googletest-1.16.0/googletest/README.md | 142 + .../googletest/googlemock/CMakeLists.txt | 210 + .../googletest/googlemock/README.md | 40 + .../googletest/googlemock/cmake/gmock.pc.in | 10 + .../googlemock/cmake/gmock_main.pc.in | 10 + .../googletest/googlemock/docs/README.md | 4 + .../googlemock/include/gmock/gmock-actions.h | 2360 +++++ .../include/gmock/gmock-cardinalities.h | 159 + .../include/gmock/gmock-function-mocker.h | 519 ++ .../googlemock/include/gmock/gmock-matchers.h | 5691 ++++++++++++ .../include/gmock/gmock-more-actions.h | 660 ++ .../include/gmock/gmock-more-matchers.h | 120 + .../include/gmock/gmock-nice-strict.h | 277 + .../include/gmock/gmock-spec-builders.h | 2146 +++++ .../googlemock/include/gmock/gmock.h | 97 + .../include/gmock/internal/custom/README.md | 18 + .../internal/custom/gmock-generated-actions.h | 7 + .../gmock/internal/custom/gmock-matchers.h | 37 + .../gmock/internal/custom/gmock-port.h | 40 + .../gmock/internal/gmock-internal-utils.h | 489 ++ .../include/gmock/internal/gmock-port.h | 140 + .../include/gmock/internal/gmock-pp.h | 279 + .../googletest/googlemock/src/gmock-all.cc | 46 + .../googlemock/src/gmock-cardinalities.cc | 155 + .../googlemock/src/gmock-internal-utils.cc | 258 + .../googlemock/src/gmock-matchers.cc | 478 + .../googlemock/src/gmock-spec-builders.cc | 792 ++ .../googletest/googlemock/src/gmock.cc | 225 + .../googletest/googlemock/src/gmock_main.cc | 73 + .../googletest/googlemock/test/BUILD.bazel | 118 + .../googlemock/test/gmock-actions_test.cc | 2217 +++++ .../test/gmock-cardinalities_test.cc | 424 + .../test/gmock-function-mocker_test.cc | 998 +++ .../test/gmock-internal-utils_test.cc | 766 ++ .../test/gmock-matchers-arithmetic_test.cc | 1516 ++++ .../test/gmock-matchers-comparisons_test.cc | 2427 +++++ .../test/gmock-matchers-containers_test.cc | 3155 +++++++ .../test/gmock-matchers-misc_test.cc | 1882 ++++ .../googlemock/test/gmock-matchers_test.h | 192 + .../test/gmock-more-actions_test.cc | 1588 ++++ .../googlemock/test/gmock-nice-strict_test.cc | 541 ++ .../googlemock/test/gmock-port_test.cc | 42 + .../googlemock/test/gmock-pp-string_test.cc | 205 + .../googlemock/test/gmock-pp_test.cc | 83 + .../test/gmock-spec-builders_test.cc | 2600 ++++++ .../googlemock/test/gmock_all_test.cc | 49 + .../googlemock/test/gmock_ex_test.cc | 80 + .../googlemock/test/gmock_leak_test.py | 113 + .../googlemock/test/gmock_leak_test_.cc | 99 + .../googlemock/test/gmock_link2_test.cc | 38 + .../googlemock/test/gmock_link_test.cc | 38 + .../googlemock/test/gmock_link_test.h | 693 ++ .../googlemock/test/gmock_output_test.py | 190 + .../googlemock/test/gmock_output_test_.cc | 286 + .../test/gmock_output_test_golden.txt | 335 + .../googlemock/test/gmock_stress_test.cc | 227 + .../googletest/googlemock/test/gmock_test.cc | 179 + .../googlemock/test/gmock_test_utils.py | 91 + .../googletest/googletest/CMakeLists.txt | 330 + .../googletest/googletest/README.md | 231 + .../googletest/cmake/Config.cmake.in | 13 + .../googletest/googletest/cmake/gtest.pc.in | 9 + .../googletest/cmake/gtest_main.pc.in | 10 + .../googletest/cmake/internal_utils.cmake | 334 + .../googletest/cmake/libgtest.la.in | 21 + .../googletest/googletest/docs/README.md | 4 + .../include/gtest/gtest-assertion-result.h | 237 + .../include/gtest/gtest-death-test.h | 345 + .../googletest/include/gtest/gtest-matchers.h | 923 ++ .../googletest/include/gtest/gtest-message.h | 251 + .../include/gtest/gtest-param-test.h | 546 ++ .../googletest/include/gtest/gtest-printers.h | 1236 +++ .../googletest/include/gtest/gtest-spi.h | 250 + .../include/gtest/gtest-test-part.h | 192 + .../include/gtest/gtest-typed-test.h | 335 + .../googletest/include/gtest/gtest.h | 2338 +++++ .../include/gtest/gtest_pred_impl.h | 279 + .../googletest/include/gtest/gtest_prod.h | 60 + .../include/gtest/internal/custom/README.md | 44 + .../gtest/internal/custom/gtest-port.h | 37 + .../gtest/internal/custom/gtest-printers.h | 42 + .../include/gtest/internal/custom/gtest.h | 37 + .../internal/gtest-death-test-internal.h | 306 + .../include/gtest/internal/gtest-filepath.h | 233 + .../include/gtest/internal/gtest-internal.h | 1521 ++++ .../include/gtest/internal/gtest-param-util.h | 1030 +++ .../include/gtest/internal/gtest-port-arch.h | 124 + .../include/gtest/internal/gtest-port.h | 2544 ++++++ .../include/gtest/internal/gtest-string.h | 178 + .../include/gtest/internal/gtest-type-util.h | 220 + .../googletest/samples/prime_tables.h | 125 + .../googletest/googletest/samples/sample1.cc | 66 + .../googletest/googletest/samples/sample1.h | 41 + .../googletest/samples/sample10_unittest.cc | 138 + .../googletest/samples/sample1_unittest.cc | 148 + .../googletest/googletest/samples/sample2.cc | 54 + .../googletest/googletest/samples/sample2.h | 79 + .../googletest/samples/sample2_unittest.cc | 107 + .../googletest/samples/sample3-inl.h | 171 + .../googletest/samples/sample3_unittest.cc | 146 + .../googletest/googletest/samples/sample4.cc | 50 + .../googletest/googletest/samples/sample4.h | 53 + .../googletest/samples/sample4_unittest.cc | 53 + .../googletest/samples/sample5_unittest.cc | 189 + .../googletest/samples/sample6_unittest.cc | 214 + .../googletest/samples/sample7_unittest.cc | 113 + .../googletest/samples/sample8_unittest.cc | 154 + .../googletest/samples/sample9_unittest.cc | 148 + .../googletest/googletest/src/gtest-all.cc | 49 + .../googletest/src/gtest-assertion-result.cc | 77 + .../googletest/src/gtest-death-test.cc | 1587 ++++ .../googletest/src/gtest-filepath.cc | 414 + .../googletest/src/gtest-internal-inl.h | 1230 +++ .../googletest/src/gtest-matchers.cc | 98 + .../googletest/googletest/src/gtest-port.cc | 1434 +++ .../googletest/src/gtest-printers.cc | 555 ++ .../googletest/src/gtest-test-part.cc | 106 + .../googletest/src/gtest-typed-test.cc | 108 + .../googletest/googletest/src/gtest.cc | 6997 +++++++++++++++ .../googletest/googletest/src/gtest_main.cc | 66 + .../googletest/googletest/test/BUILD.bazel | 594 ++ .../googletest-break-on-failure-unittest.py | 195 + .../googletest-break-on-failure-unittest_.cc | 83 + .../test/googletest-catch-exceptions-test.py | 315 + .../test/googletest-catch-exceptions-test_.cc | 289 + .../googletest/test/googletest-color-test.py | 130 + .../googletest/test/googletest-color-test_.cc | 60 + .../test/googletest-death-test-test.cc | 1512 ++++ .../test/googletest-death-test_ex_test.cc | 91 + .../test/googletest-env-var-test.py | 120 + .../test/googletest-env-var-test_.cc | 130 + .../test/googletest-failfast-unittest.py | 461 + .../test/googletest-failfast-unittest_.cc | 166 + .../test/googletest-filepath-test.cc | 671 ++ .../test/googletest-filter-unittest.py | 746 ++ .../test/googletest-filter-unittest_.cc | 106 + .../googletest-global-environment-unittest.py | 141 + ...googletest-global-environment-unittest_.cc | 58 + .../test/googletest-json-outfiles-test.py | 180 + .../test/googletest-json-output-unittest.py | 914 ++ .../test/googletest-list-tests-unittest.py | 225 + .../test/googletest-list-tests-unittest_.cc | 143 + .../test/googletest-listener-test.cc | 509 ++ .../test/googletest-message-test.cc | 184 + .../test/googletest-options-test.cc | 225 + .../googletest-output-test-golden-lin.txt | 1201 +++ .../googletest/test/googletest-output-test.py | 385 + .../test/googletest-output-test_.cc | 1058 +++ ...oogletest-param-test-invalid-name1-test.py | 63 + ...ogletest-param-test-invalid-name1-test_.cc | 46 + ...oogletest-param-test-invalid-name2-test.py | 63 + ...ogletest-param-test-invalid-name2-test_.cc | 52 + .../test/googletest-param-test-test.cc | 1173 +++ .../test/googletest-param-test-test.h | 49 + .../test/googletest-param-test2-test.cc | 58 + .../googletest/test/googletest-port-test.cc | 1301 +++ .../test/googletest-printers-test.cc | 2058 +++++ .../test/googletest-setuptestsuite-test.py | 58 + .../test/googletest-setuptestsuite-test_.cc | 44 + .../test/googletest-shuffle-test.py | 378 + .../test/googletest-shuffle-test_.cc | 99 + .../test/googletest-test-part-test.cc | 220 + .../test/googletest-throw-on-failure-test.py | 166 + .../test/googletest-throw-on-failure-test_.cc | 71 + .../test/googletest-uninitialized-test.py | 70 + .../test/googletest-uninitialized-test_.cc | 39 + .../googletest/test/gtest-typed-test2_test.cc | 39 + .../googletest/test/gtest-typed-test_test.cc | 423 + .../googletest/test/gtest-typed-test_test.h | 57 + .../test/gtest-unittest-api_test.cc | 328 + .../googletest/test/gtest_all_test.cc | 46 + .../test/gtest_assert_by_exception_test.cc | 112 + .../googletest/test/gtest_dirs_test.cc | 101 + .../googletest/test/gtest_environment_test.cc | 187 + .../googletest/test/gtest_help_test.py | 183 + .../googletest/test/gtest_help_test_.cc | 44 + .../googletest/test/gtest_json_test_utils.py | 67 + .../test/gtest_list_output_unittest.py | 289 + .../test/gtest_list_output_unittest_.cc | 77 + .../googletest/test/gtest_main_unittest.cc | 42 + .../googletest/test/gtest_no_test_unittest.cc | 54 + .../test/gtest_pred_impl_unittest.cc | 2070 +++++ .../test/gtest_premature_exit_test.cc | 128 + .../googletest/test/gtest_prod_test.cc | 56 + .../googletest/test/gtest_repeat_test.cc | 220 + .../test/gtest_skip_check_output_test.py | 60 + ...test_skip_environment_check_output_test.py | 55 + .../gtest_skip_in_environment_setup_test.cc | 50 + .../googletest/test/gtest_skip_test.cc | 51 + .../googletest/test/gtest_sole_header_test.cc | 54 + .../googletest/test/gtest_stress_test.cc | 245 + .../gtest_test_macro_stack_footprint_test.cc | 89 + .../googletest/test/gtest_test_utils.py | 262 + .../googletest/test/gtest_testbridge_test.py | 63 + .../googletest/test/gtest_testbridge_test_.cc | 42 + .../test/gtest_throw_on_failure_ex_test.cc | 90 + .../googletest/test/gtest_unittest.cc | 7824 +++++++++++++++++ .../test/gtest_xml_outfile1_test_.cc | 43 + .../test/gtest_xml_outfile2_test_.cc | 77 + .../test/gtest_xml_outfiles_test.py | 147 + .../test/gtest_xml_output_unittest.py | 513 ++ .../test/gtest_xml_output_unittest_.cc | 217 + .../googletest/test/gtest_xml_test_utils.py | 242 + .../googletest/googletest/test/production.cc | 35 + .../googletest/googletest/test/production.h | 55 + Tests/Common++Test/CMakeLists.txt | 12 - 213 files changed, 97693 insertions(+), 12 deletions(-) create mode 100644 3rdParty/googletest-1.16.0/CMakeLists.txt create mode 100644 3rdParty/googletest-1.16.0/googletest/.gitignore create mode 100644 3rdParty/googletest-1.16.0/googletest/CMakeLists.txt create mode 100644 3rdParty/googletest-1.16.0/googletest/CONTRIBUTING.md create mode 100644 3rdParty/googletest-1.16.0/googletest/CONTRIBUTORS create mode 100644 3rdParty/googletest-1.16.0/googletest/LICENSE create mode 100644 3rdParty/googletest-1.16.0/googletest/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/CMakeLists.txt create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock.pc.in create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock_main.pc.in create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/docs/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-actions.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-cardinalities.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-function-mocker.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-matchers.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-more-actions.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-more-matchers.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-nice-strict.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-spec-builders.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/custom/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/custom/gmock-generated-actions.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/custom/gmock-matchers.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/custom/gmock-port.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/gmock-internal-utils.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/gmock-port.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/internal/gmock-pp.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock-all.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock-cardinalities.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock-internal-utils.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock-matchers.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock-spec-builders.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/src/gmock_main.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/BUILD.bazel create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-actions_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-cardinalities_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-function-mocker_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-internal-utils_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-matchers-arithmetic_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-matchers-comparisons_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-matchers-containers_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-matchers-misc_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-matchers_test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-more-actions_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-nice-strict_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-port_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-pp-string_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-pp_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock-spec-builders_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_all_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_ex_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_leak_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_leak_test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_link2_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_link_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_link_test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_output_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_output_test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_output_test_golden.txt create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_stress_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googlemock/test/gmock_test_utils.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/CMakeLists.txt create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/cmake/Config.cmake.in create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/cmake/gtest.pc.in create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/cmake/gtest_main.pc.in create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/cmake/internal_utils.cmake create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/cmake/libgtest.la.in create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/docs/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-assertion-result.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-death-test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-matchers.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-message.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-param-test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-printers.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-spi.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-test-part.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest-typed-test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest_pred_impl.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/gtest_prod.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/custom/README.md create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/custom/gtest-port.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/custom/gtest-printers.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/custom/gtest.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-death-test-internal.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-filepath.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-internal.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-param-util.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-port-arch.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-port.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-string.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/include/gtest/internal/gtest-type-util.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/prime_tables.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample1.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample1.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample10_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample1_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample2.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample2.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample2_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample3-inl.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample3_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample4.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample4.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample4_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample5_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample6_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample7_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample8_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/samples/sample9_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-all.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-assertion-result.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-death-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-filepath.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-internal-inl.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-matchers.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-port.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-printers.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-test-part.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest-typed-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/src/gtest_main.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/BUILD.bazel create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-break-on-failure-unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-break-on-failure-unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-catch-exceptions-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-catch-exceptions-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-color-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-color-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-death-test-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-death-test_ex_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-env-var-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-env-var-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-failfast-unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-failfast-unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-filepath-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-filter-unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-filter-unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-global-environment-unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-global-environment-unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-json-outfiles-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-json-output-unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-list-tests-unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-list-tests-unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-listener-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-message-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-options-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-output-test-golden-lin.txt create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-output-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-output-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test-invalid-name1-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test-invalid-name1-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test-invalid-name2-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test-invalid-name2-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test-test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-param-test2-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-port-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-printers-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-setuptestsuite-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-setuptestsuite-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-shuffle-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-shuffle-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-test-part-test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-throw-on-failure-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-throw-on-failure-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-uninitialized-test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/googletest-uninitialized-test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest-typed-test2_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest-typed-test_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest-typed-test_test.h create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest-unittest-api_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_all_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_assert_by_exception_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_dirs_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_environment_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_help_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_help_test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_json_test_utils.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_list_output_unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_list_output_unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_main_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_no_test_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_pred_impl_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_premature_exit_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_prod_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_repeat_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_skip_check_output_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_skip_environment_check_output_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_skip_in_environment_setup_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_skip_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_sole_header_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_stress_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_test_macro_stack_footprint_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_test_utils.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_testbridge_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_testbridge_test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_throw_on_failure_ex_test.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_unittest.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_xml_outfile1_test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_xml_outfile2_test_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_xml_outfiles_test.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_xml_output_unittest.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_xml_output_unittest_.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/gtest_xml_test_utils.py create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/production.cc create mode 100644 3rdParty/googletest-1.16.0/googletest/googletest/test/production.h diff --git a/3rdParty/CMakeLists.txt b/3rdParty/CMakeLists.txt index 26fe30f166..2ef0e65c44 100644 --- a/3rdParty/CMakeLists.txt +++ b/3rdParty/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(hash-library) add_subdirectory(json) add_subdirectory(LightPcapNg) add_subdirectory(MemPlumber/MemPlumber) +add_subdirectory(googletest-1.16.0) if(PCAPPP_INSTALL) install( diff --git a/3rdParty/googletest-1.16.0/CMakeLists.txt b/3rdParty/googletest-1.16.0/CMakeLists.txt new file mode 100644 index 0000000000..cc1484c7f7 --- /dev/null +++ b/3rdParty/googletest-1.16.0/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.14) + +if(WIN32) + # Prevent overriding the parent project's compiler/linker settings. + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +endif() + +# Disable installation of googletest +set(INSTALL_GTEST OFF) + +add_subdirectory(googletest) diff --git a/3rdParty/googletest-1.16.0/googletest/.gitignore b/3rdParty/googletest-1.16.0/googletest/.gitignore new file mode 100644 index 0000000000..f0df39db1d --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/.gitignore @@ -0,0 +1,89 @@ +# Ignore CI build directory +build/ +xcuserdata +cmake-build-debug/ +.idea/ +bazel-bin +bazel-genfiles +bazel-googletest +bazel-out +bazel-testlogs +MODULE.bazel.lock +# python +*.pyc + +# Visual Studio files +.vs +*.sdf +*.opensdf +*.VC.opendb +*.suo +*.user +_ReSharper.Caches/ +Win32-Debug/ +Win32-Release/ +x64-Debug/ +x64-Release/ + +# VSCode files +.cache/ +cmake-variants.yaml + +# Ignore autoconf / automake files +Makefile.in +aclocal.m4 +configure +build-aux/ +autom4te.cache/ +googletest/m4/libtool.m4 +googletest/m4/ltoptions.m4 +googletest/m4/ltsugar.m4 +googletest/m4/ltversion.m4 +googletest/m4/lt~obsolete.m4 +googlemock/m4 + +# Ignore generated directories. +googlemock/fused-src/ +googletest/fused-src/ + +# macOS files +.DS_Store +googletest/.DS_Store +googletest/xcode/.DS_Store + +# Ignore cmake generated directories and files. +CMakeFiles +CTestTestfile.cmake +Makefile +cmake_install.cmake +googlemock/CMakeFiles +googlemock/CTestTestfile.cmake +googlemock/Makefile +googlemock/cmake_install.cmake +googlemock/gtest +/bin +/googlemock/gmock.dir +/googlemock/gmock_main.dir +/googlemock/RUN_TESTS.vcxproj.filters +/googlemock/RUN_TESTS.vcxproj +/googlemock/INSTALL.vcxproj.filters +/googlemock/INSTALL.vcxproj +/googlemock/gmock_main.vcxproj.filters +/googlemock/gmock_main.vcxproj +/googlemock/gmock.vcxproj.filters +/googlemock/gmock.vcxproj +/googlemock/gmock.sln +/googlemock/ALL_BUILD.vcxproj.filters +/googlemock/ALL_BUILD.vcxproj +/lib +/Win32 +/ZERO_CHECK.vcxproj.filters +/ZERO_CHECK.vcxproj +/RUN_TESTS.vcxproj.filters +/RUN_TESTS.vcxproj +/INSTALL.vcxproj.filters +/INSTALL.vcxproj +/googletest-distribution.sln +/CMakeCache.txt +/ALL_BUILD.vcxproj.filters +/ALL_BUILD.vcxproj diff --git a/3rdParty/googletest-1.16.0/googletest/CMakeLists.txt b/3rdParty/googletest-1.16.0/googletest/CMakeLists.txt new file mode 100644 index 0000000000..15c4f0fda5 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/CMakeLists.txt @@ -0,0 +1,36 @@ +# Note: CMake support is community-based. The maintainers do not use CMake +# internally. + +cmake_minimum_required(VERSION 3.13) + +project(googletest-distribution) +set(GOOGLETEST_VERSION 1.16.0) + +if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX) + set(CMAKE_CXX_EXTENSIONS OFF) +endif() + +enable_testing() + +include(CMakeDependentOption) +include(GNUInstallDirs) + +# Note that googlemock target already builds googletest. +option(BUILD_GMOCK "Builds the googlemock subproject" ON) +option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON) +option(GTEST_HAS_ABSL "Use Abseil and RE2. Requires Abseil and RE2 to be separately added to the build." OFF) + +if(GTEST_HAS_ABSL) + if(NOT TARGET absl::base) + find_package(absl REQUIRED) + endif() + if(NOT TARGET re2::re2) + find_package(re2 REQUIRED) + endif() +endif() + +if(BUILD_GMOCK) + add_subdirectory( googlemock ) +else() + add_subdirectory( googletest ) +endif() diff --git a/3rdParty/googletest-1.16.0/googletest/CONTRIBUTING.md b/3rdParty/googletest-1.16.0/googletest/CONTRIBUTING.md new file mode 100644 index 0000000000..ab5a47bf55 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/CONTRIBUTING.md @@ -0,0 +1,141 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your patches! Before we can take them, we have to jump a +couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement +(CLA). + +* If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an + [individual CLA](https://developers.google.com/open-source/cla/individual). +* If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a + [corporate CLA](https://developers.google.com/open-source/cla/corporate). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Are you a Googler? + +If you are a Googler, please make an attempt to submit an internal contribution +rather than a GitHub Pull Request. If you are not able to submit internally, a +PR is acceptable as an alternative. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the + [issue tracker](https://github.com/google/googletest/issues). +2. Please don't mix more than one logical change per submittal, because it + makes the history hard to follow. If you want to make a change that doesn't + have a corresponding issue in the issue tracker, please create one. +3. Also, coordinate with team members that are listed on the issue in question. + This ensures that work isn't being duplicated and communicating your plan + early also generally leads to better patches. +4. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement + ([see details above](#contributor-license-agreements)). +5. Fork the desired repo, develop and test your code changes. +6. Ensure that your code adheres to the existing style in the sample to which + you are contributing. +7. Ensure that your code has an appropriate set of unit tests which all pass. +8. Submit a pull request. + +## The Google Test and Google Mock Communities + +The Google Test community exists primarily through the +[discussion group](https://groups.google.com/group/googletestframework) and the +GitHub repository. Likewise, the Google Mock community exists primarily through +their own [discussion group](https://groups.google.com/group/googlemock). You +are definitely encouraged to contribute to the discussion and you can also help +us to keep the effectiveness of the group high by following and promoting the +guidelines listed here. + +### Please Be Friendly + +Showing courtesy and respect to others is a vital part of the Google culture, +and we strongly encourage everyone participating in Google Test development to +join us in accepting nothing less. Of course, being courteous is not the same as +failing to constructively disagree with each other, but it does mean that we +should be respectful of each other when enumerating the 42 technical reasons +that a particular proposal may not be the best choice. There's never a reason to +be antagonistic or dismissive toward anyone who is sincerely trying to +contribute to a discussion. + +Sure, C++ testing is serious business and all that, but it's also a lot of fun. +Let's keep it that way. Let's strive to be one of the friendliest communities in +all of open source. + +As always, discuss Google Test in the official GoogleTest discussion group. You +don't have to actually submit code in order to sign up. Your participation +itself is a valuable contribution. + +## Style + +To keep the source consistent, readable, diffable and easy to merge, we use a +fairly rigid coding style, as defined by the +[google-styleguide](https://github.com/google/styleguide) project. All patches +will be expected to conform to the style outlined +[here](https://google.github.io/styleguide/cppguide.html). Use +[.clang-format](https://github.com/google/googletest/blob/main/.clang-format) to +check your formatting. + +## Requirements for Contributors + +If you plan to contribute a patch, you need to build Google Test, Google Mock, +and their own tests from a git checkout, which has further requirements: + +* [Python](https://www.python.org/) v3.6 or newer (for running some of the + tests and re-generating certain source files from templates) +* [CMake](https://cmake.org/) v2.8.12 or newer + +## Developing Google Test and Google Mock + +This section discusses how to make your own changes to the Google Test project. + +### Testing Google Test and Google Mock Themselves + +To make sure your changes work as intended and don't break existing +functionality, you'll want to compile and run Google Test and GoogleMock's own +tests. For that you can use CMake: + +``` +mkdir mybuild +cd mybuild +cmake -Dgtest_build_tests=ON -Dgmock_build_tests=ON ${GTEST_REPO_DIR} +``` + +To choose between building only Google Test or Google Mock, you may modify your +cmake command to be one of each + +``` +cmake -Dgtest_build_tests=ON ${GTEST_DIR} # sets up Google Test tests +cmake -Dgmock_build_tests=ON ${GMOCK_DIR} # sets up Google Mock tests +``` + +Make sure you have Python installed, as some of Google Test's tests are written +in Python. If the cmake command complains about not being able to find Python +(`Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)`), try telling it +explicitly where your Python executable can be found: + +``` +cmake -DPYTHON_EXECUTABLE=path/to/python ... +``` + +Next, you can build Google Test and / or Google Mock and all desired tests. On +\*nix, this is usually done by + +``` +make +``` + +To run the tests, do + +``` +make test +``` + +All tests should pass. diff --git a/3rdParty/googletest-1.16.0/googletest/CONTRIBUTORS b/3rdParty/googletest-1.16.0/googletest/CONTRIBUTORS new file mode 100644 index 0000000000..ccea41ea81 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/CONTRIBUTORS @@ -0,0 +1,66 @@ +# This file contains a list of people who've made non-trivial +# contribution to the Google C++ Testing Framework project. People +# who commit code to the project are encouraged to add their names +# here. Please keep the list sorted by first names. + +Ajay Joshi +Balázs Dán +Benoit Sigoure +Bharat Mediratta +Bogdan Piloca +Chandler Carruth +Chris Prince +Chris Taylor +Dan Egnor +Dave MacLachlan +David Anderson +Dean Sturtevant +Eric Roman +Gene Volovich +Hady Zalek +Hal Burch +Jeffrey Yasskin +Jim Keller +Joe Walnes +Jon Wray +Jói Sigurðsson +Keir Mierle +Keith Ray +Kenton Varda +Kostya Serebryany +Krystian Kuzniarek +Lev Makhlis +Manuel Klimek +Mario Tanev +Mark Paskin +Markus Heule +Martijn Vels +Matthew Simmons +Mika Raento +Mike Bland +Miklós Fazekas +Neal Norwitz +Nermin Ozkiranartli +Owen Carlsen +Paneendra Ba +Pasi Valminen +Patrick Hanna +Patrick Riley +Paul Menage +Peter Kaminski +Piotr Kaminski +Preston Jackson +Rainer Klaffenboeck +Russ Cox +Russ Rufer +Sean Mcafee +Sigurður Ásgeirsson +Soyeon Kim +Sverre Sundsdal +Szymon Sobik +Takeshi Yoshino +Tracy Bialik +Vadim Berman +Vlad Losev +Wolfgang Klier +Zhanyong Wan diff --git a/3rdParty/googletest-1.16.0/googletest/LICENSE b/3rdParty/googletest-1.16.0/googletest/LICENSE new file mode 100644 index 0000000000..1941a11f8c --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/LICENSE @@ -0,0 +1,28 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/3rdParty/googletest-1.16.0/googletest/README.md b/3rdParty/googletest-1.16.0/googletest/README.md new file mode 100644 index 0000000000..151b3263b6 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/README.md @@ -0,0 +1,142 @@ +# GoogleTest + +### Announcements + +#### Live at Head + +GoogleTest now follows the +[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support). +We recommend +[updating to the latest commit in the `main` branch as often as possible](https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-live-at-head-and-how-do-i-do-it). +We do publish occasional semantic versions, tagged with +`v${major}.${minor}.${patch}` (e.g. `v1.16.0`). + +#### Documentation Updates + +Our documentation is now live on GitHub Pages at +https://google.github.io/googletest/. We recommend browsing the documentation on +GitHub Pages rather than directly in the repository. + +#### Release 1.16.0 + +[Release 1.16.0](https://github.com/google/googletest/releases/tag/v1.16.0) is +now available. + +The 1.16.x branch requires at least C++14. + +#### Continuous Integration + +We use Google's internal systems for continuous integration. + +#### Coming Soon + +* We are planning to take a dependency on + [Abseil](https://github.com/abseil/abseil-cpp). + +## Welcome to **GoogleTest**, Google's C++ test framework! + +This repository is a merger of the formerly separate GoogleTest and GoogleMock +projects. These were so closely related that it makes sense to maintain and +release them together. + +### Getting Started + +See the [GoogleTest User's Guide](https://google.github.io/googletest/) for +documentation. We recommend starting with the +[GoogleTest Primer](https://google.github.io/googletest/primer.html). + +More information about building GoogleTest can be found at +[googletest/README.md](googletest/README.md). + +## Features + +* xUnit test framework: \ + Googletest is based on the [xUnit](https://en.wikipedia.org/wiki/XUnit) + testing framework, a popular architecture for unit testing +* Test discovery: \ + Googletest automatically discovers and runs your tests, eliminating the need + to manually register your tests +* Rich set of assertions: \ + Googletest provides a variety of assertions, such as equality, inequality, + exceptions, and more, making it easy to test your code +* User-defined assertions: \ + You can define your own assertions with Googletest, making it simple to + write tests that are specific to your code +* Death tests: \ + Googletest supports death tests, which verify that your code exits in a + certain way, making it useful for testing error-handling code +* Fatal and non-fatal failures: \ + You can specify whether a test failure should be treated as fatal or + non-fatal with Googletest, allowing tests to continue running even if a + failure occurs +* Value-parameterized tests: \ + Googletest supports value-parameterized tests, which run multiple times with + different input values, making it useful for testing functions that take + different inputs +* Type-parameterized tests: \ + Googletest also supports type-parameterized tests, which run with different + data types, making it useful for testing functions that work with different + data types +* Various options for running tests: \ + Googletest provides many options for running tests including running + individual tests, running tests in a specific order and running tests in + parallel + +## Supported Platforms + +GoogleTest follows Google's +[Foundational C++ Support Policy](https://opensource.google/documentation/policies/cplusplus-support). +See +[this table](https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md) +for a list of currently supported versions of compilers, platforms, and build +tools. + +## Who Is Using GoogleTest? + +In addition to many internal projects at Google, GoogleTest is also used by the +following notable projects: + +* The [Chromium projects](https://www.chromium.org/) (behind the Chrome + browser and Chrome OS). +* The [LLVM](https://llvm.org/) compiler. +* [Protocol Buffers](https://github.com/google/protobuf), Google's data + interchange format. +* The [OpenCV](https://opencv.org/) computer vision library. + +## Related Open Source Projects + +[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based +automated test-runner and Graphical User Interface with powerful features for +Windows and Linux platforms. + +[GoogleTest UI](https://github.com/ospector/gtest-gbar) is a test runner that +runs your test binary, allows you to track its progress via a progress bar, and +displays a list of test failures. Clicking on one shows failure text. GoogleTest +UI is written in C#. + +[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event +listener for GoogleTest that implements the +[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test +result output. If your test runner understands TAP, you may find it useful. + +[gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that +runs tests from your binary in parallel to provide significant speed-up. + +[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter) +is a VS Code extension allowing to view GoogleTest in a tree view and run/debug +your tests. + +[C++ TestMate](https://github.com/matepek/vscode-catch2-test-adapter) is a VS +Code extension allowing to view GoogleTest in a tree view and run/debug your +tests. + +[Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser +that generates stub code for GoogleTest. + +## Contributing Changes + +Please read +[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/main/CONTRIBUTING.md) +for details on how to contribute to this project. + +Happy testing! diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/CMakeLists.txt b/3rdParty/googletest-1.16.0/googletest/googlemock/CMakeLists.txt new file mode 100644 index 0000000000..99b2411f36 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/CMakeLists.txt @@ -0,0 +1,210 @@ +######################################################################## +# Note: CMake support is community-based. The maintainers do not use CMake +# internally. +# +# CMake build script for Google Mock. +# +# To run the tests for Google Mock itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. + +option(gmock_build_tests "Build all of Google Mock's own tests." OFF) + +# A directory to find Google Test sources. +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") + set(gtest_dir gtest) +else() + set(gtest_dir ../googletest) +endif() + +# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). +include("${gtest_dir}/cmake/hermetic_build.cmake" OPTIONAL) + +if (COMMAND pre_project_set_up_hermetic_build) + # Google Test also calls hermetic setup functions from add_subdirectory, + # although its changes will not affect things at the current scope. + pre_project_set_up_hermetic_build() +endif() + +######################################################################## +# +# Project-wide settings + +# Name of the project. +# +# CMake files in this project can refer to the root source directory +# as ${gmock_SOURCE_DIR} and to the root binary directory as +# ${gmock_BINARY_DIR}. +# Language "C" is required for find_package(Threads). +cmake_minimum_required(VERSION 3.13) +project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C) + +if (COMMAND set_up_hermetic_build) + set_up_hermetic_build() +endif() + +# Instructs CMake to process Google Test's CMakeLists.txt and add its +# targets to the current scope. We are placing Google Test's binary +# directory in a subdirectory of our own as VC compilation may break +# if they are the same (the default). +add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/${gtest_dir}") + + +# These commands only run if this is the main project +if(CMAKE_PROJECT_NAME STREQUAL "gmock" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution") + # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to + # make it prominent in the GUI. + option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) +else() + mark_as_advanced(gmock_build_tests) +endif() + +# Although Google Test's CMakeLists.txt calls this function, the +# changes there don't affect the current scope. Therefore we have to +# call it again here. +config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake + +# Adds Google Mock's and Google Test's header directories to the search path. +# Get Google Test's include dirs from the target, gtest_SOURCE_DIR is broken +# when using fetch-content with the name "GTest". +get_target_property(gtest_include_dirs gtest INCLUDE_DIRECTORIES) +set(gmock_build_include_dirs + "${gmock_SOURCE_DIR}/include" + "${gmock_SOURCE_DIR}" + "${gtest_include_dirs}") +include_directories(${gmock_build_include_dirs}) + +######################################################################## +# +# Defines the gmock & gmock_main libraries. User tests should link +# with one of them. + +# Google Mock libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that Google Mock can be compiled by +# a user aggressive about warnings. +if (MSVC) + cxx_library(gmock + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc) + + cxx_library(gmock_main + "${cxx_strict}" + "${gtest_dir}/src/gtest-all.cc" + src/gmock-all.cc + src/gmock_main.cc) +else() + cxx_library(gmock "${cxx_strict}" src/gmock-all.cc) + target_link_libraries(gmock PUBLIC gtest) + set_target_properties(gmock PROPERTIES VERSION ${GOOGLETEST_VERSION}) + cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc) + target_link_libraries(gmock_main PUBLIC gmock) + set_target_properties(gmock_main PROPERTIES VERSION ${GOOGLETEST_VERSION}) +endif() + +string(REPLACE ";" "$" dirs "${gmock_build_include_dirs}") +target_include_directories(gmock SYSTEM INTERFACE + "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") +target_include_directories(gmock_main SYSTEM INTERFACE + "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") + +######################################################################## +# +# Install rules. +install_project(gmock gmock_main) + +######################################################################## +# +# Google Mock's own tests. +# +# You can skip this section if you aren't interested in testing +# Google Mock itself. +# +# The tests are not built by default. To build them, set the +# gmock_build_tests option to ON. You can do it by running ccmake +# or specifying the -Dgmock_build_tests=ON flag when running cmake. + +if (gmock_build_tests) + # This must be set in the root directory for the tests to be run by + # 'make test' or ctest. + enable_testing() + + if (MINGW OR CYGWIN) + add_compile_options("-Wa,-mbig-obj") + endif() + + ############################################################ + # C++ tests built with standard compiler flags. + + cxx_test(gmock-actions_test gmock_main) + cxx_test(gmock-cardinalities_test gmock_main) + cxx_test(gmock_ex_test gmock_main) + cxx_test(gmock-function-mocker_test gmock_main) + cxx_test(gmock-internal-utils_test gmock_main) + cxx_test(gmock-matchers-arithmetic_test gmock_main) + cxx_test(gmock-matchers-comparisons_test gmock_main) + cxx_test(gmock-matchers-containers_test gmock_main) + cxx_test(gmock-matchers-misc_test gmock_main) + cxx_test(gmock-more-actions_test gmock_main) + cxx_test(gmock-nice-strict_test gmock_main) + cxx_test(gmock-port_test gmock_main) + cxx_test(gmock-spec-builders_test gmock_main) + cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) + cxx_test(gmock_test gmock_main) + + if (DEFINED GTEST_HAS_PTHREAD) + cxx_test(gmock_stress_test gmock) + endif() + + # gmock_all_test is commented to save time building and running tests. + # Uncomment if necessary. + # cxx_test(gmock_all_test gmock_main) + + ############################################################ + # C++ tests built with non-standard compiler flags. + + if (MSVC) + cxx_library(gmock_main_no_exception "${cxx_no_exception}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + else() + cxx_library(gmock_main_no_exception "${cxx_no_exception}" src/gmock_main.cc) + target_link_libraries(gmock_main_no_exception PUBLIC gmock) + + cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" src/gmock_main.cc) + target_link_libraries(gmock_main_no_rtti PUBLIC gmock) + endif() + cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" + gmock_main_no_exception test/gmock-more-actions_test.cc) + + cxx_test_with_flags(gmock_no_rtti_test "${cxx_no_rtti}" + gmock_main_no_rtti test/gmock-spec-builders_test.cc) + + cxx_shared_library(shared_gmock_main "${cxx_default}" + "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) + + # Tests that a binary can be built with Google Mock as a shared library. On + # some system configurations, it may not possible to run the binary without + # knowing more details about the system configurations. We do not try to run + # this binary. To get a more robust shared library coverage, configure with + # -DBUILD_SHARED_LIBS=ON. + cxx_executable_with_flags(shared_gmock_test_ "${cxx_default}" + shared_gmock_main test/gmock-spec-builders_test.cc) + set_target_properties(shared_gmock_test_ + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + + ############################################################ + # Python tests. + + cxx_executable(gmock_leak_test_ test gmock_main) + py_test(gmock_leak_test) + + cxx_executable(gmock_output_test_ test gmock) + py_test(gmock_output_test) +endif() diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/README.md b/3rdParty/googletest-1.16.0/googletest/googlemock/README.md new file mode 100644 index 0000000000..e1103b16bb --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/README.md @@ -0,0 +1,40 @@ +# Googletest Mocking (gMock) Framework + +### Overview + +Google's framework for writing and using C++ mock classes. It can help you +derive better designs of your system and write better tests. + +It is inspired by: + +* [jMock](http://www.jmock.org/) +* [EasyMock](https://easymock.org/) +* [Hamcrest](https://code.google.com/p/hamcrest/) + +It is designed with C++'s specifics in mind. + +gMock: + +- Provides a declarative syntax for defining mocks. +- Can define partial (hybrid) mocks, which are a cross of real and mock + objects. +- Handles functions of arbitrary types and overloaded functions. +- Comes with a rich set of matchers for validating function arguments. +- Uses an intuitive syntax for controlling the behavior of a mock. +- Does automatic verification of expectations (no record-and-replay needed). +- Allows arbitrary (partial) ordering constraints on function calls to be + expressed. +- Lets a user extend it by defining new matchers and actions. +- Does not use exceptions. +- Is easy to learn and use. + +Details and examples can be found here: + +* [gMock for Dummies](https://google.github.io/googletest/gmock_for_dummies.html) +* [Legacy gMock FAQ](https://google.github.io/googletest/gmock_faq.html) +* [gMock Cookbook](https://google.github.io/googletest/gmock_cook_book.html) +* [gMock Cheat Sheet](https://google.github.io/googletest/gmock_cheat_sheet.html) + +GoogleMock is a part of +[GoogleTest C++ testing framework](https://github.com/google/googletest/) and a +subject to the same requirements. diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock.pc.in b/3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock.pc.in new file mode 100644 index 0000000000..23c67b5c88 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock.pc.in @@ -0,0 +1,10 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ + +Name: gmock +Description: GoogleMock (without main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gtest = @PROJECT_VERSION@ +Libs: -L${libdir} -lgmock @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock_main.pc.in b/3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock_main.pc.in new file mode 100644 index 0000000000..66ffea7f44 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/cmake/gmock_main.pc.in @@ -0,0 +1,10 @@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ + +Name: gmock_main +Description: GoogleMock (with main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gmock = @PROJECT_VERSION@ +Libs: -L${libdir} -lgmock_main @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/docs/README.md b/3rdParty/googletest-1.16.0/googletest/googlemock/docs/README.md new file mode 100644 index 0000000000..1bc57b799c --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/docs/README.md @@ -0,0 +1,4 @@ +# Content Moved + +We are working on updates to the GoogleTest documentation, which has moved to +the top-level [docs](../../docs) directory. diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-actions.h b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-actions.h new file mode 100644 index 0000000000..aa47079948 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-actions.h @@ -0,0 +1,2360 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// The ACTION* family of macros can be used in a namespace scope to +// define custom actions easily. The syntax: +// +// ACTION(name) { statements; } +// +// will define an action with the given name that executes the +// statements. The value returned by the statements will be used as +// the return value of the action. Inside the statements, you can +// refer to the K-th (0-based) argument of the mock function by +// 'argK', and refer to its type by 'argK_type'. For example: +// +// ACTION(IncrementArg1) { +// arg1_type temp = arg1; +// return ++(*temp); +// } +// +// allows you to write +// +// ...WillOnce(IncrementArg1()); +// +// You can also refer to the entire argument tuple and its type by +// 'args' and 'args_type', and refer to the mock function type and its +// return type by 'function_type' and 'return_type'. +// +// Note that you don't need to specify the types of the mock function +// arguments. However rest assured that your code is still type-safe: +// you'll get a compiler error if *arg1 doesn't support the ++ +// operator, or if the type of ++(*arg1) isn't compatible with the +// mock function's return type, for example. +// +// Sometimes you'll want to parameterize the action. For that you can use +// another macro: +// +// ACTION_P(name, param_name) { statements; } +// +// For example: +// +// ACTION_P(Add, n) { return arg0 + n; } +// +// will allow you to write: +// +// ...WillOnce(Add(5)); +// +// Note that you don't need to provide the type of the parameter +// either. If you need to reference the type of a parameter named +// 'foo', you can write 'foo_type'. For example, in the body of +// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type +// of 'n'. +// +// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support +// multi-parameter actions. +// +// For the purpose of typing, you can view +// +// ACTION_Pk(Foo, p1, ..., pk) { ... } +// +// as shorthand for +// +// template +// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } +// +// In particular, you can provide the template type arguments +// explicitly when invoking Foo(), as in Foo(5, false); +// although usually you can rely on the compiler to infer the types +// for you automatically. You can assign the result of expression +// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. +// +// You can also overload actions with different numbers of parameters: +// +// ACTION_P(Plus, a) { ... } +// ACTION_P2(Plus, a, b) { ... } +// +// While it's tempting to always use the ACTION* macros when defining +// a new action, you should also consider implementing ActionInterface +// or using MakePolymorphicAction() instead, especially if you need to +// use the action a lot. While these approaches require more work, +// they give you more control on the types of the mock function +// arguments and the action parameters, which in general leads to +// better compiler error messages that pay off in the long run. They +// also allow overloading actions based on parameter types (as opposed +// to just based on the number of parameters). +// +// CAVEAT: +// +// ACTION*() can only be used in a namespace scope as templates cannot be +// declared inside of a local class. +// Users can, however, define any local functors (e.g. a lambda) that +// can be used as actions. +// +// MORE INFORMATION: +// +// To learn more about using these macros, please search for 'ACTION' on +// https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ + +#ifndef _WIN32_WCE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gmock/internal/gmock-pp.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4100) + +namespace testing { + +// To implement an action Foo, define: +// 1. a class FooAction that implements the ActionInterface interface, and +// 2. a factory function that creates an Action object from a +// const FooAction*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Action objects can now be copied like plain values. + +namespace internal { + +// BuiltInDefaultValueGetter::Get() returns a +// default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. +// +// This primary template is used when kDefaultConstructible is true. +template +struct BuiltInDefaultValueGetter { + static T Get() { return T(); } +}; +template +struct BuiltInDefaultValueGetter { + static T Get() { + Assert(false, __FILE__, __LINE__, + "Default action undefined for the function return type."); +#if defined(__GNUC__) || defined(__clang__) + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(0); +#else + return Invalid(); + // The above statement will never be reached, but is required in + // order for this function to compile. +#endif + } +}; + +// BuiltInDefaultValue::Get() returns the "built-in" default value +// for type T, which is NULL when T is a raw pointer type, 0 when T is +// a numeric type, false when T is bool, or "" when T is string or +// std::string. In addition, in C++11 and above, it turns a +// default-constructed T value if T is default constructible. For any +// other type T, the built-in default T value is undefined, and the +// function will abort the process. +template +class BuiltInDefaultValue { + public: + // This function returns true if and only if type T has a built-in default + // value. + static bool Exists() { return ::std::is_default_constructible::value; } + + static T Get() { + return BuiltInDefaultValueGetter< + T, ::std::is_default_constructible::value>::Get(); + } +}; + +// This partial specialization says that we use the same built-in +// default value for T and const T. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return BuiltInDefaultValue::Exists(); } + static T Get() { return BuiltInDefaultValue::Get(); } +}; + +// This partial specialization defines the default values for pointer +// types. +template +class BuiltInDefaultValue { + public: + static bool Exists() { return true; } + static T* Get() { return nullptr; } +}; + +// The following specializations define the default values for +// specific types we care about. +#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ + template <> \ + class BuiltInDefaultValue { \ + public: \ + static bool Exists() { return true; } \ + static type Get() { return value; } \ + } + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); + +// There's no need for a default action for signed wchar_t, as that +// type is the same as wchar_t for gcc, and invalid for MSVC. +// +// There's also no need for a default action for unsigned wchar_t, as +// that type is the same as unsigned int for gcc, and invalid for +// MSVC. +#if GMOCK_WCHAR_T_IS_NATIVE_ +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT +#endif + +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long long, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long long, 0); // NOLINT +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); +GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); + +#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ + +// Partial implementations of metaprogramming types from the standard library +// not available in C++11. + +template +struct negation + // NOLINTNEXTLINE + : std::integral_constant {}; + +// Base case: with zero predicates the answer is always true. +template +struct conjunction : std::true_type {}; + +// With a single predicate, the answer is that predicate. +template +struct conjunction : P1 {}; + +// With multiple predicates the answer is the first predicate if that is false, +// and we recurse otherwise. +template +struct conjunction + : std::conditional, P1>::type {}; + +template +struct disjunction : std::false_type {}; + +template +struct disjunction : P1 {}; + +template +struct disjunction + // NOLINTNEXTLINE + : std::conditional, P1>::type {}; + +template +using void_t = void; + +// Detects whether an expression of type `From` can be implicitly converted to +// `To` according to [conv]. In C++17, [conv]/3 defines this as follows: +// +// An expression e can be implicitly converted to a type T if and only if +// the declaration T t=e; is well-formed, for some invented temporary +// variable t ([dcl.init]). +// +// [conv]/2 implies we can use function argument passing to detect whether this +// initialization is valid. +// +// Note that this is distinct from is_convertible, which requires this be valid: +// +// To test() { +// return declval(); +// } +// +// In particular, is_convertible doesn't give the correct answer when `To` and +// `From` are the same non-moveable type since `declval` will be an rvalue +// reference, defeating the guaranteed copy elision that would otherwise make +// this function work. +// +// REQUIRES: `From` is not cv void. +template +struct is_implicitly_convertible { + private: + // A function that accepts a parameter of type T. This can be called with type + // U successfully only if U is implicitly convertible to T. + template + static void Accept(T); + + // A function that creates a value of type T. + template + static T Make(); + + // An overload be selected when implicit conversion from T to To is possible. + template (Make()))> + static std::true_type TestImplicitConversion(int); + + // A fallback overload selected in all other cases. + template + static std::false_type TestImplicitConversion(...); + + public: + using type = decltype(TestImplicitConversion(0)); + static constexpr bool value = type::value; +}; + +// Like std::invoke_result_t from C++17, but works only for objects with call +// operators (not e.g. member function pointers, which we don't need specific +// support for in OnceAction because std::function deals with them). +template +using call_result_t = decltype(std::declval()(std::declval()...)); + +template +struct is_callable_r_impl : std::false_type {}; + +// Specialize the struct for those template arguments where call_result_t is +// well-formed. When it's not, the generic template above is chosen, resulting +// in std::false_type. +template +struct is_callable_r_impl>, R, F, Args...> + : std::conditional< + std::is_void::value, // + std::true_type, // + is_implicitly_convertible, R>>::type {}; + +// Like std::is_invocable_r from C++17, but works only for objects with call +// operators. See the note on call_result_t. +template +using is_callable_r = is_callable_r_impl; + +// Like std::as_const from C++17. +template +typename std::add_const::type& as_const(T& t) { + return t; +} + +} // namespace internal + +// Specialized for function types below. +template +class OnceAction; + +// An action that can only be used once. +// +// This is accepted by WillOnce, which doesn't require the underlying action to +// be copy-constructible (only move-constructible), and promises to invoke it as +// an rvalue reference. This allows the action to work with move-only types like +// std::move_only_function in a type-safe manner. +// +// For example: +// +// // Assume we have some API that needs to accept a unique pointer to some +// // non-copyable object Foo. +// void AcceptUniquePointer(std::unique_ptr foo); +// +// // We can define an action that provides a Foo to that API. Because It +// // has to give away its unique pointer, it must not be called more than +// // once, so its call operator is &&-qualified. +// struct ProvideFoo { +// std::unique_ptr foo; +// +// void operator()() && { +// AcceptUniquePointer(std::move(Foo)); +// } +// }; +// +// // This action can be used with WillOnce. +// EXPECT_CALL(mock, Call) +// .WillOnce(ProvideFoo{std::make_unique(...)}); +// +// // But a call to WillRepeatedly will fail to compile. This is correct, +// // since the action cannot correctly be used repeatedly. +// EXPECT_CALL(mock, Call) +// .WillRepeatedly(ProvideFoo{std::make_unique(...)}); +// +// A less-contrived example would be an action that returns an arbitrary type, +// whose &&-qualified call operator is capable of dealing with move-only types. +template +class OnceAction final { + private: + // True iff we can use the given callable type (or lvalue reference) directly + // via StdFunctionAdaptor. + template + using IsDirectlyCompatible = internal::conjunction< + // It must be possible to capture the callable in StdFunctionAdaptor. + std::is_constructible::type, Callable>, + // The callable must be compatible with our signature. + internal::is_callable_r::type, + Args...>>; + + // True iff we can use the given callable type via StdFunctionAdaptor once we + // ignore incoming arguments. + template + using IsCompatibleAfterIgnoringArguments = internal::conjunction< + // It must be possible to capture the callable in a lambda. + std::is_constructible::type, Callable>, + // The callable must be invocable with zero arguments, returning something + // convertible to Result. + internal::is_callable_r::type>>; + + public: + // Construct from a callable that is directly compatible with our mocked + // signature: it accepts our function type's arguments and returns something + // convertible to our result type. + template ::type>>, + IsDirectlyCompatible> // + ::value, + int>::type = 0> + OnceAction(Callable&& callable) // NOLINT + : function_(StdFunctionAdaptor::type>( + {}, std::forward(callable))) {} + + // As above, but for a callable that ignores the mocked function's arguments. + template ::type>>, + // Exclude callables for which the overload above works. + // We'd rather provide the arguments if possible. + internal::negation>, + IsCompatibleAfterIgnoringArguments>::value, + int>::type = 0> + OnceAction(Callable&& callable) // NOLINT + // Call the constructor above with a callable + // that ignores the input arguments. + : OnceAction(IgnoreIncomingArguments::type>{ + std::forward(callable)}) {} + + // We are naturally copyable because we store only an std::function, but + // semantically we should not be copyable. + OnceAction(const OnceAction&) = delete; + OnceAction& operator=(const OnceAction&) = delete; + OnceAction(OnceAction&&) = default; + + // Invoke the underlying action callable with which we were constructed, + // handing it the supplied arguments. + Result Call(Args... args) && { + return function_(std::forward(args)...); + } + + private: + // An adaptor that wraps a callable that is compatible with our signature and + // being invoked as an rvalue reference so that it can be used as an + // StdFunctionAdaptor. This throws away type safety, but that's fine because + // this is only used by WillOnce, which we know calls at most once. + // + // Once we have something like std::move_only_function from C++23, we can do + // away with this. + template + class StdFunctionAdaptor final { + public: + // A tag indicating that the (otherwise universal) constructor is accepting + // the callable itself, instead of e.g. stealing calls for the move + // constructor. + struct CallableTag final {}; + + template + explicit StdFunctionAdaptor(CallableTag, F&& callable) + : callable_(std::make_shared(std::forward(callable))) {} + + // Rather than explicitly returning Result, we return whatever the wrapped + // callable returns. This allows for compatibility with existing uses like + // the following, when the mocked function returns void: + // + // EXPECT_CALL(mock_fn_, Call) + // .WillOnce([&] { + // [...] + // return 0; + // }); + // + // Such a callable can be turned into std::function. If we use an + // explicit return type of Result here then it *doesn't* work with + // std::function, because we'll get a "void function should not return a + // value" error. + // + // We need not worry about incompatible result types because the SFINAE on + // OnceAction already checks this for us. std::is_invocable_r_v itself makes + // the same allowance for void result types. + template + internal::call_result_t operator()( + ArgRefs&&... args) const { + return std::move(*callable_)(std::forward(args)...); + } + + private: + // We must put the callable on the heap so that we are copyable, which + // std::function needs. + std::shared_ptr callable_; + }; + + // An adaptor that makes a callable that accepts zero arguments callable with + // our mocked arguments. + template + struct IgnoreIncomingArguments { + internal::call_result_t operator()(Args&&...) { + return std::move(callable)(); + } + + Callable callable; + }; + + std::function function_; +}; + +// When an unexpected function call is encountered, Google Mock will +// let it return a default value if the user has specified one for its +// return type, or if the return type has a built-in default value; +// otherwise Google Mock won't know what value to return and will have +// to abort the process. +// +// The DefaultValue class allows a user to specify the +// default value for a type T that is both copyable and publicly +// destructible (i.e. anything that can be used as a function return +// type). The usage is: +// +// // Sets the default value for type T to be foo. +// DefaultValue::Set(foo); +template +class DefaultValue { + public: + // Sets the default value for type T; requires T to be + // copy-constructable and have a public destructor. + static void Set(T x) { + delete producer_; + producer_ = new FixedValueProducer(x); + } + + // Provides a factory function to be called to generate the default value. + // This method can be used even if T is only move-constructible, but it is not + // limited to that case. + typedef T (*FactoryFunction)(); + static void SetFactory(FactoryFunction factory) { + delete producer_; + producer_ = new FactoryValueProducer(factory); + } + + // Unsets the default value for type T. + static void Clear() { + delete producer_; + producer_ = nullptr; + } + + // Returns true if and only if the user has set the default value for type T. + static bool IsSet() { return producer_ != nullptr; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T if the user has set one; + // otherwise returns the built-in default value. Requires that Exists() + // is true, which ensures that the return value is well-defined. + static T Get() { + return producer_ == nullptr ? internal::BuiltInDefaultValue::Get() + : producer_->Produce(); + } + + private: + class ValueProducer { + public: + virtual ~ValueProducer() = default; + virtual T Produce() = 0; + }; + + class FixedValueProducer : public ValueProducer { + public: + explicit FixedValueProducer(T value) : value_(value) {} + T Produce() override { return value_; } + + private: + const T value_; + FixedValueProducer(const FixedValueProducer&) = delete; + FixedValueProducer& operator=(const FixedValueProducer&) = delete; + }; + + class FactoryValueProducer : public ValueProducer { + public: + explicit FactoryValueProducer(FactoryFunction factory) + : factory_(factory) {} + T Produce() override { return factory_(); } + + private: + const FactoryFunction factory_; + FactoryValueProducer(const FactoryValueProducer&) = delete; + FactoryValueProducer& operator=(const FactoryValueProducer&) = delete; + }; + + static ValueProducer* producer_; +}; + +// This partial specialization allows a user to set default values for +// reference types. +template +class DefaultValue { + public: + // Sets the default value for type T&. + static void Set(T& x) { // NOLINT + address_ = &x; + } + + // Unsets the default value for type T&. + static void Clear() { address_ = nullptr; } + + // Returns true if and only if the user has set the default value for type T&. + static bool IsSet() { return address_ != nullptr; } + + // Returns true if T has a default return value set by the user or there + // exists a built-in default value. + static bool Exists() { + return IsSet() || internal::BuiltInDefaultValue::Exists(); + } + + // Returns the default value for type T& if the user has set one; + // otherwise returns the built-in default value if there is one; + // otherwise aborts the process. + static T& Get() { + return address_ == nullptr ? internal::BuiltInDefaultValue::Get() + : *address_; + } + + private: + static T* address_; +}; + +// This specialization allows DefaultValue::Get() to +// compile. +template <> +class DefaultValue { + public: + static bool Exists() { return true; } + static void Get() {} +}; + +// Points to the user-set default value for type T. +template +typename DefaultValue::ValueProducer* DefaultValue::producer_ = nullptr; + +// Points to the user-set default value for type T&. +template +T* DefaultValue::address_ = nullptr; + +// Implement this interface to define an action for function type F. +template +class ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + ActionInterface() = default; + virtual ~ActionInterface() = default; + + // Performs the action. This method is not const, as in general an + // action can have side effects and be stateful. For example, a + // get-the-next-element-from-the-collection action will need to + // remember the current element. + virtual Result Perform(const ArgumentTuple& args) = 0; + + private: + ActionInterface(const ActionInterface&) = delete; + ActionInterface& operator=(const ActionInterface&) = delete; +}; + +template +class Action; + +// An Action is a copyable and IMMUTABLE (except by assignment) +// object that represents an action to be taken when a mock function of type +// R(Args...) is called. The implementation of Action is just a +// std::shared_ptr to const ActionInterface. Don't inherit from Action! You +// can view an object implementing ActionInterface as a concrete action +// (including its current state), and an Action object as a handle to it. +template +class Action { + private: + using F = R(Args...); + + // Adapter class to allow constructing Action from a legacy ActionInterface. + // New code should create Actions from functors instead. + struct ActionAdapter { + // Adapter must be copyable to satisfy std::function requirements. + ::std::shared_ptr> impl_; + + template + typename internal::Function::Result operator()(InArgs&&... args) { + return impl_->Perform( + ::std::forward_as_tuple(::std::forward(args)...)); + } + }; + + template + using IsCompatibleFunctor = std::is_constructible, G>; + + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + // Constructs a null Action. Needed for storing Action objects in + // STL containers. + Action() = default; + + // Construct an Action from a specified callable. + // This cannot take std::function directly, because then Action would not be + // directly constructible from lambda (it would require two conversions). + template < + typename G, + typename = typename std::enable_if, std::is_constructible, + G>>::value>::type> + Action(G&& fun) { // NOLINT + Init(::std::forward(fun), IsCompatibleFunctor()); + } + + // Constructs an Action from its implementation. + explicit Action(ActionInterface* impl) + : fun_(ActionAdapter{::std::shared_ptr>(impl)}) {} + + // This constructor allows us to turn an Action object into an + // Action, as long as F's arguments can be implicitly converted + // to Func's and Func's return type can be implicitly converted to F's. + template + Action(const Action& action) // NOLINT + : fun_(action.fun_) {} + + // Returns true if and only if this is the DoDefault() action. + bool IsDoDefault() const { return fun_ == nullptr; } + + // Performs the action. Note that this method is const even though + // the corresponding method in ActionInterface is not. The reason + // is that a const Action means that it cannot be re-bound to + // another concrete action, not that the concrete action it binds to + // cannot change state. (Think of the difference between a const + // pointer and a pointer to const.) + Result Perform(ArgumentTuple args) const { + if (IsDoDefault()) { + internal::IllegalDoDefault(__FILE__, __LINE__); + } + return internal::Apply(fun_, ::std::move(args)); + } + + // An action can be used as a OnceAction, since it's obviously safe to call it + // once. + operator OnceAction() const { // NOLINT + // Return a OnceAction-compatible callable that calls Perform with the + // arguments it is provided. We could instead just return fun_, but then + // we'd need to handle the IsDoDefault() case separately. + struct OA { + Action action; + + R operator()(Args... args) && { + return action.Perform( + std::forward_as_tuple(std::forward(args)...)); + } + }; + + return OA{*this}; + } + + private: + template + friend class Action; + + template + void Init(G&& g, ::std::true_type) { + fun_ = ::std::forward(g); + } + + template + void Init(G&& g, ::std::false_type) { + fun_ = IgnoreArgs::type>{::std::forward(g)}; + } + + template + struct IgnoreArgs { + template + Result operator()(const InArgs&...) const { + return function_impl(); + } + + FunctionImpl function_impl; + }; + + // fun_ is an empty function if and only if this is the DoDefault() action. + ::std::function fun_; +}; + +// The PolymorphicAction class template makes it easy to implement a +// polymorphic action (i.e. an action that can be used in mock +// functions of than one type, e.g. Return()). +// +// To define a polymorphic action, a user first provides a COPYABLE +// implementation class that has a Perform() method template: +// +// class FooAction { +// public: +// template +// Result Perform(const ArgumentTuple& args) const { +// // Processes the arguments and returns a result, using +// // std::get(args) to get the N-th (0-based) argument in the tuple. +// } +// ... +// }; +// +// Then the user creates the polymorphic action using +// MakePolymorphicAction(object) where object has type FooAction. See +// the definition of Return(void) and SetArgumentPointee(value) for +// complete examples. +template +class PolymorphicAction { + public: + explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} + + template + operator Action() const { + return Action(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + Result Perform(const ArgumentTuple& args) override { + return impl_.template Perform(args); + } + + private: + Impl impl_; + }; + + Impl impl_; +}; + +// Creates an Action from its implementation and returns it. The +// created Action object owns the implementation. +template +Action MakeAction(ActionInterface* impl) { + return Action(impl); +} + +// Creates a polymorphic action from its implementation. This is +// easier to use than the PolymorphicAction constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicAction(foo); +// vs +// PolymorphicAction(foo); +template +inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { + return PolymorphicAction(impl); +} + +namespace internal { + +// Helper struct to specialize ReturnAction to execute a move instead of a copy +// on return. Useful for move-only types, but could be used on any type. +template +struct ByMoveWrapper { + explicit ByMoveWrapper(T value) : payload(std::move(value)) {} + T payload; +}; + +// The general implementation of Return(R). Specializations follow below. +template +class ReturnAction final { + public: + explicit ReturnAction(R value) : value_(std::move(value)) {} + + template >, // + negation>, // + std::is_convertible, // + std::is_move_constructible>::value>::type> + operator OnceAction() && { // NOLINT + return Impl(std::move(value_)); + } + + template >, // + negation>, // + std::is_convertible, // + std::is_copy_constructible>::value>::type> + operator Action() const { // NOLINT + return Impl(value_); + } + + private: + // Implements the Return(x) action for a mock function that returns type U. + template + class Impl final { + public: + // The constructor used when the return value is allowed to move from the + // input value (i.e. we are converting to OnceAction). + explicit Impl(R&& input_value) + : state_(new State(std::move(input_value))) {} + + // The constructor used when the return value is not allowed to move from + // the input value (i.e. we are converting to Action). + explicit Impl(const R& input_value) : state_(new State(input_value)) {} + + U operator()() && { return std::move(state_->value); } + U operator()() const& { return state_->value; } + + private: + // We put our state on the heap so that the compiler-generated copy/move + // constructors work correctly even when U is a reference-like type. This is + // necessary only because we eagerly create State::value (see the note on + // that symbol for details). If we instead had only the input value as a + // member then the default constructors would work fine. + // + // For example, when R is std::string and U is std::string_view, value is a + // reference to the string backed by input_value. The copy constructor would + // copy both, so that we wind up with a new input_value object (with the + // same contents) and a reference to the *old* input_value object rather + // than the new one. + struct State { + explicit State(const R& input_value_in) + : input_value(input_value_in), + // Make an implicit conversion to Result before initializing the U + // object we store, avoiding calling any explicit constructor of U + // from R. + // + // This simulates the language rules: a function with return type U + // that does `return R()` requires R to be implicitly convertible to + // U, and uses that path for the conversion, even U Result has an + // explicit constructor from R. + value(ImplicitCast_(internal::as_const(input_value))) {} + + // As above, but for the case where we're moving from the ReturnAction + // object because it's being used as a OnceAction. + explicit State(R&& input_value_in) + : input_value(std::move(input_value_in)), + // For the same reason as above we make an implicit conversion to U + // before initializing the value. + // + // Unlike above we provide the input value as an rvalue to the + // implicit conversion because this is a OnceAction: it's fine if it + // wants to consume the input value. + value(ImplicitCast_(std::move(input_value))) {} + + // A copy of the value originally provided by the user. We retain this in + // addition to the value of the mock function's result type below in case + // the latter is a reference-like type. See the std::string_view example + // in the documentation on Return. + R input_value; + + // The value we actually return, as the type returned by the mock function + // itself. + // + // We eagerly initialize this here, rather than lazily doing the implicit + // conversion automatically each time Perform is called, for historical + // reasons: in 2009-11, commit a070cbd91c (Google changelist 13540126) + // made the Action conversion operator eagerly convert the R value to + // U, but without keeping the R alive. This broke the use case discussed + // in the documentation for Return, making reference-like types such as + // std::string_view not safe to use as U where the input type R is a + // value-like type such as std::string. + // + // The example the commit gave was not very clear, nor was the issue + // thread (https://github.com/google/googlemock/issues/86), but it seems + // the worry was about reference-like input types R that flatten to a + // value-like type U when being implicitly converted. An example of this + // is std::vector::reference, which is often a proxy type with an + // reference to the underlying vector: + // + // // Helper method: have the mock function return bools according + // // to the supplied script. + // void SetActions(MockFunction& mock, + // const std::vector& script) { + // for (size_t i = 0; i < script.size(); ++i) { + // EXPECT_CALL(mock, Call(i)).WillOnce(Return(script[i])); + // } + // } + // + // TEST(Foo, Bar) { + // // Set actions using a temporary vector, whose operator[] + // // returns proxy objects that references that will be + // // dangling once the call to SetActions finishes and the + // // vector is destroyed. + // MockFunction mock; + // SetActions(mock, {false, true}); + // + // EXPECT_FALSE(mock.AsStdFunction()(0)); + // EXPECT_TRUE(mock.AsStdFunction()(1)); + // } + // + // This eager conversion helps with a simple case like this, but doesn't + // fully make these types work in general. For example the following still + // uses a dangling reference: + // + // TEST(Foo, Baz) { + // MockFunction()> mock; + // + // // Return the same vector twice, and then the empty vector + // // thereafter. + // auto action = Return(std::initializer_list{ + // "taco", "burrito", + // }); + // + // EXPECT_CALL(mock, Call) + // .WillOnce(action) + // .WillOnce(action) + // .WillRepeatedly(Return(std::vector{})); + // + // EXPECT_THAT(mock.AsStdFunction()(), + // ElementsAre("taco", "burrito")); + // EXPECT_THAT(mock.AsStdFunction()(), + // ElementsAre("taco", "burrito")); + // EXPECT_THAT(mock.AsStdFunction()(), IsEmpty()); + // } + // + U value; + }; + + const std::shared_ptr state_; + }; + + R value_; +}; + +// A specialization of ReturnAction when R is ByMoveWrapper for some T. +// +// This version applies the type system-defeating hack of moving from T even in +// the const call operator, checking at runtime that it isn't called more than +// once, since the user has declared their intent to do so by using ByMove. +template +class ReturnAction> final { + public: + explicit ReturnAction(ByMoveWrapper wrapper) + : state_(new State(std::move(wrapper.payload))) {} + + T operator()() const { + GTEST_CHECK_(!state_->called) + << "A ByMove() action must be performed at most once."; + + state_->called = true; + return std::move(state_->value); + } + + private: + // We store our state on the heap so that we are copyable as required by + // Action, despite the fact that we are stateful and T may not be copyable. + struct State { + explicit State(T&& value_in) : value(std::move(value_in)) {} + + T value; + bool called = false; + }; + + const std::shared_ptr state_; +}; + +// Implements the ReturnNull() action. +class ReturnNullAction { + public: + // Allows ReturnNull() to be used in any pointer-returning function. In C++11 + // this is enforced by returning nullptr, and in non-C++11 by asserting a + // pointer type on compile time. + template + static Result Perform(const ArgumentTuple&) { + return nullptr; + } +}; + +// Implements the Return() action. +class ReturnVoidAction { + public: + // Allows Return() to be used in any void-returning function. + template + static void Perform(const ArgumentTuple&) { + static_assert(std::is_void::value, "Result should be void."); + } +}; + +// Implements the polymorphic ReturnRef(x) action, which can be used +// in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefAction { + public: + // Constructs a ReturnRefAction object from the reference to be returned. + explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT + + // This template type conversion operator allows ReturnRef(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRef(x) when Return(x) + // should be used, and generates some helpful error message. + static_assert(std::is_reference::value, + "use Return instead of ReturnRef to return a value"); + return Action(new Impl(ref_)); + } + + private: + // Implements the ReturnRef(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(T& ref) : ref_(ref) {} // NOLINT + + Result Perform(const ArgumentTuple&) override { return ref_; } + + private: + T& ref_; + }; + + T& ref_; +}; + +// Implements the polymorphic ReturnRefOfCopy(x) action, which can be +// used in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefOfCopyAction { + public: + // Constructs a ReturnRefOfCopyAction object from the reference to + // be returned. + explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT + + // This template type conversion operator allows ReturnRefOfCopy(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRefOfCopy(x) when Return(x) + // should be used, and generates some helpful error message. + static_assert(std::is_reference::value, + "use Return instead of ReturnRefOfCopy to return a value"); + return Action(new Impl(value_)); + } + + private: + // Implements the ReturnRefOfCopy(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const T& value) : value_(value) {} // NOLINT + + Result Perform(const ArgumentTuple&) override { return value_; } + + private: + T value_; + }; + + const T value_; +}; + +// Implements the polymorphic ReturnRoundRobin(v) action, which can be +// used in any function that returns the element_type of v. +template +class ReturnRoundRobinAction { + public: + explicit ReturnRoundRobinAction(std::vector values) { + GTEST_CHECK_(!values.empty()) + << "ReturnRoundRobin requires at least one element."; + state_->values = std::move(values); + } + + template + T operator()(Args&&...) const { + return state_->Next(); + } + + private: + struct State { + T Next() { + T ret_val = values[i++]; + if (i == values.size()) i = 0; + return ret_val; + } + + std::vector values; + size_t i = 0; + }; + std::shared_ptr state_ = std::make_shared(); +}; + +// Implements the polymorphic DoDefault() action. +class DoDefaultAction { + public: + // This template type conversion operator allows DoDefault() to be + // used in any function. + template + operator Action() const { + return Action(); + } // NOLINT +}; + +// Implements the Assign action to set a given pointer referent to a +// particular value. +template +class AssignAction { + public: + AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} + + template + void Perform(const ArgumentTuple& /* args */) const { + *ptr_ = value_; + } + + private: + T1* const ptr_; + const T2 value_; +}; + +#ifndef GTEST_OS_WINDOWS_MOBILE + +// Implements the SetErrnoAndReturn action to simulate return from +// various system calls and libc functions. +template +class SetErrnoAndReturnAction { + public: + SetErrnoAndReturnAction(int errno_value, T result) + : errno_(errno_value), result_(result) {} + template + Result Perform(const ArgumentTuple& /* args */) const { + errno = errno_; + return result_; + } + + private: + const int errno_; + const T result_; +}; + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Implements the SetArgumentPointee(x) action for any function +// whose N-th argument (0-based) is a pointer to x's type. +template +struct SetArgumentPointeeAction { + A value; + + template + void operator()(const Args&... args) const { + *::std::get(std::tie(args...)) = value; + } +}; + +// Implements the Invoke(object_ptr, &Class::Method) action. +template +struct InvokeMethodAction { + Class* const obj_ptr; + const MethodPtr method_ptr; + + template + auto operator()(Args&&... args) const + -> decltype((obj_ptr->*method_ptr)(std::forward(args)...)) { + return (obj_ptr->*method_ptr)(std::forward(args)...); + } +}; + +// Implements the InvokeWithoutArgs(f) action. The template argument +// FunctionImpl is the implementation type of f, which can be either a +// function pointer or a functor. InvokeWithoutArgs(f) can be used as an +// Action as long as f's type is compatible with F. +template +struct InvokeWithoutArgsAction { + FunctionImpl function_impl; + + // Allows InvokeWithoutArgs(f) to be used as any action whose type is + // compatible with f. + template + auto operator()(const Args&...) -> decltype(function_impl()) { + return function_impl(); + } +}; + +// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. +template +struct InvokeMethodWithoutArgsAction { + Class* const obj_ptr; + const MethodPtr method_ptr; + + using ReturnType = + decltype((std::declval()->*std::declval())()); + + template + ReturnType operator()(const Args&...) const { + return (obj_ptr->*method_ptr)(); + } +}; + +// Implements the IgnoreResult(action) action. +template +class IgnoreResultAction { + public: + explicit IgnoreResultAction(const A& action) : action_(action) {} + + template + operator Action() const { + // Assert statement belongs here because this is the best place to verify + // conditions on F. It produces the clearest error messages + // in most compilers. + // Impl really belongs in this scope as a local class but can't + // because MSVC produces duplicate symbols in different translation units + // in this case. Until MS fixes that bug we put Impl into the class scope + // and put the typedef both here (for use in assert statement) and + // in the Impl class. But both definitions must be the same. + typedef typename internal::Function::Result Result; + + // Asserts at compile time that F returns void. + static_assert(std::is_void::value, "Result type should be void."); + + return Action(new Impl(action_)); + } + + private: + template + class Impl : public ActionInterface { + public: + typedef typename internal::Function::Result Result; + typedef typename internal::Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const A& action) : action_(action) {} + + void Perform(const ArgumentTuple& args) override { + // Performs the action and ignores its result. + action_.Perform(args); + } + + private: + // Type OriginalFunction is the same as F except that its return + // type is IgnoredValue. + typedef + typename internal::Function::MakeResultIgnoredValue OriginalFunction; + + const Action action_; + }; + + const A action_; +}; + +template +struct WithArgsAction { + InnerAction inner_action; + + // The signature of the function as seen by the inner action, given an out + // action with the given result and argument types. + template + using InnerSignature = + R(typename std::tuple_element>::type...); + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>...)>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + struct OA { + OnceAction> inner_action; + + R operator()(Args&&... args) && { + return std::move(inner_action) + .Call(std::get( + std::forward_as_tuple(std::forward(args)...))...); + } + }; + + return OA{std::move(inner_action)}; + } + + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>...)>>::value, + int>::type = 0> + operator Action() const { // NOLINT + Action> converted(inner_action); + + return [converted](Args&&... args) -> R { + return converted.Perform(std::forward_as_tuple( + std::get(std::forward_as_tuple(std::forward(args)...))...)); + }; + } +}; + +template +class DoAllAction; + +// Base case: only a single action. +template +class DoAllAction { + public: + struct UserConstructorTag {}; + + template + explicit DoAllAction(UserConstructorTag, T&& action) + : final_action_(std::forward(action)) {} + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + // We support conversion to OnceAction whenever the sub-action does. + template >::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return std::move(final_action_); + } + + // We also support conversion to OnceAction whenever the sub-action supports + // conversion to Action (since any Action can also be a OnceAction). + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation< + std::is_convertible>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return Action(std::move(final_action_)); + } + + // We support conversion to Action whenever the sub-action does. + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible>::value, + int>::type = 0> + operator Action() const { // NOLINT + return final_action_; + } + + private: + FinalAction final_action_; +}; + +// Recursive case: support N actions by calling the initial action and then +// calling through to the base class containing N-1 actions. +template +class DoAllAction + : private DoAllAction { + private: + using Base = DoAllAction; + + // The type of reference that should be provided to an initial action for a + // mocked function parameter of type T. + // + // There are two quirks here: + // + // * Unlike most forwarding functions, we pass scalars through by value. + // This isn't strictly necessary because an lvalue reference would work + // fine too and be consistent with other non-reference types, but it's + // perhaps less surprising. + // + // For example if the mocked function has signature void(int), then it + // might seem surprising for the user's initial action to need to be + // convertible to Action. This is perhaps less + // surprising for a non-scalar type where there may be a performance + // impact, or it might even be impossible, to pass by value. + // + // * More surprisingly, `const T&` is often not a const reference type. + // By the reference collapsing rules in C++17 [dcl.ref]/6, if T refers to + // U& or U&& for some non-scalar type U, then InitialActionArgType is + // U&. In other words, we may hand over a non-const reference. + // + // So for example, given some non-scalar type Obj we have the following + // mappings: + // + // T InitialActionArgType + // ------- ----------------------- + // Obj const Obj& + // Obj& Obj& + // Obj&& Obj& + // const Obj const Obj& + // const Obj& const Obj& + // const Obj&& const Obj& + // + // In other words, the initial actions get a mutable view of an non-scalar + // argument if and only if the mock function itself accepts a non-const + // reference type. They are never given an rvalue reference to an + // non-scalar type. + // + // This situation makes sense if you imagine use with a matcher that is + // designed to write through a reference. For example, if the caller wants + // to fill in a reference argument and then return a canned value: + // + // EXPECT_CALL(mock, Call) + // .WillOnce(DoAll(SetArgReferee<0>(17), Return(19))); + // + template + using InitialActionArgType = + typename std::conditional::value, T, const T&>::type; + + public: + struct UserConstructorTag {}; + + template + explicit DoAllAction(UserConstructorTag, T&& initial_action, + U&&... other_actions) + : Base({}, std::forward(other_actions)...), + initial_action_(std::forward(initial_action)) {} + + // We support conversion to OnceAction whenever both the initial action and + // the rest support conversion to OnceAction. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + // Return an action that first calls the initial action with arguments + // filtered through InitialActionArgType, then forwards arguments directly + // to the base class to deal with the remaining actions. + struct OA { + OnceAction...)> initial_action; + OnceAction remaining_actions; + + R operator()(Args... args) && { + std::move(initial_action) + .Call(static_cast>(args)...); + + return std::move(remaining_actions).Call(std::forward(args)...); + } + }; + + return OA{ + std::move(initial_action_), + std::move(static_cast(*this)), + }; + } + + // We also support conversion to OnceAction whenever the initial action + // supports conversion to Action (since any Action can also be a OnceAction). + // + // The remaining sub-actions must also be compatible, but we don't need to + // special case them because the base class deals with them. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation...)>>>, + std::is_convertible...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return DoAll( + Action...)>(std::move(initial_action_)), + std::move(static_cast(*this))); + } + + // We support conversion to Action whenever both the initial action and the + // rest support conversion to Action. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + std::is_convertible...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator Action() const { // NOLINT + // Return an action that first calls the initial action with arguments + // filtered through InitialActionArgType, then forwards arguments directly + // to the base class to deal with the remaining actions. + struct OA { + Action...)> initial_action; + Action remaining_actions; + + R operator()(Args... args) const { + initial_action.Perform(std::forward_as_tuple( + static_cast>(args)...)); + + return remaining_actions.Perform( + std::forward_as_tuple(std::forward(args)...)); + } + }; + + return OA{ + initial_action_, + static_cast(*this), + }; + } + + private: + InitialAction initial_action_; +}; + +template +struct ReturnNewAction { + T* operator()() const { + return internal::Apply( + [](const Params&... unpacked_params) { + return new T(unpacked_params...); + }, + params); + } + std::tuple params; +}; + +template +struct ReturnArgAction { + template ::type> + auto operator()(Args&&... args) const + -> decltype(std::get( + std::forward_as_tuple(std::forward(args)...))) { + return std::get(std::forward_as_tuple(std::forward(args)...)); + } +}; + +template +struct SaveArgAction { + Ptr pointer; + + template + void operator()(const Args&... args) const { + *pointer = std::get(std::tie(args...)); + } +}; + +template +struct SaveArgPointeeAction { + Ptr pointer; + + template + void operator()(const Args&... args) const { + *pointer = *std::get(std::tie(args...)); + } +}; + +template +struct SetArgRefereeAction { + T value; + + template + void operator()(Args&&... args) const { + using argk_type = + typename ::std::tuple_element>::type; + static_assert(std::is_lvalue_reference::value, + "Argument must be a reference type."); + std::get(std::tie(args...)) = value; + } +}; + +template +struct SetArrayArgumentAction { + I1 first; + I2 last; + + template + void operator()(const Args&... args) const { + auto value = std::get(std::tie(args...)); + for (auto it = first; it != last; ++it, (void)++value) { + *value = *it; + } + } +}; + +template +struct DeleteArgAction { + template + void operator()(const Args&... args) const { + delete std::get(std::tie(args...)); + } +}; + +template +struct ReturnPointeeAction { + Ptr pointer; + template + auto operator()(const Args&...) const -> decltype(*pointer) { + return *pointer; + } +}; + +#if GTEST_HAS_EXCEPTIONS +template +struct ThrowAction { + T exception; + // We use a conversion operator to adapt to any return type. + template + operator Action() const { // NOLINT + T copy = exception; + return [copy](Args...) -> R { throw copy; }; + } +}; +struct RethrowAction { + std::exception_ptr exception; + template + operator Action() const { // NOLINT + return [ex = exception](Args...) -> R { std::rethrow_exception(ex); }; + } +}; +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace internal + +// An Unused object can be implicitly constructed from ANY value. +// This is handy when defining actions that ignore some or all of the +// mock function arguments. For example, given +// +// MOCK_METHOD3(Foo, double(const string& label, double x, double y)); +// MOCK_METHOD3(Bar, double(int index, double x, double y)); +// +// instead of +// +// double DistanceToOriginWithLabel(const string& label, double x, double y) { +// return sqrt(x*x + y*y); +// } +// double DistanceToOriginWithIndex(int index, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXPECT_CALL(mock, Foo("abc", _, _)) +// .WillOnce(Invoke(DistanceToOriginWithLabel)); +// EXPECT_CALL(mock, Bar(5, _, _)) +// .WillOnce(Invoke(DistanceToOriginWithIndex)); +// +// you could write +// +// // We can declare any uninteresting argument as Unused. +// double DistanceToOrigin(Unused, double x, double y) { +// return sqrt(x*x + y*y); +// } +// ... +// EXPECT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); +// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); +typedef internal::IgnoredValue Unused; + +// Creates an action that does actions a1, a2, ..., sequentially in +// each invocation. All but the last action will have a readonly view of the +// arguments. +template +internal::DoAllAction::type...> DoAll( + Action&&... action) { + return internal::DoAllAction::type...>( + {}, std::forward(action)...); +} + +// WithArg(an_action) creates an action that passes the k-th +// (0-based) argument of the mock function to an_action and performs +// it. It adapts an action accepting one argument to one that accepts +// multiple arguments. For convenience, we also provide +// WithArgs(an_action) (defined below) as a synonym. +template +internal::WithArgsAction::type, k> WithArg( + InnerAction&& action) { + return {std::forward(action)}; +} + +// WithArgs(an_action) creates an action that passes +// the selected arguments of the mock function to an_action and +// performs it. It serves as an adaptor between actions with +// different argument lists. +template +internal::WithArgsAction::type, k, ks...> +WithArgs(InnerAction&& action) { + return {std::forward(action)}; +} + +// WithoutArgs(inner_action) can be used in a mock function with a +// non-empty argument list to perform inner_action, which takes no +// argument. In other words, it adapts an action accepting no +// argument to one that accepts (and ignores) arguments. +template +internal::WithArgsAction::type> WithoutArgs( + InnerAction&& action) { + return {std::forward(action)}; +} + +// Creates an action that returns a value. +// +// The returned type can be used with a mock function returning a non-void, +// non-reference type U as follows: +// +// * If R is convertible to U and U is move-constructible, then the action can +// be used with WillOnce. +// +// * If const R& is convertible to U and U is copy-constructible, then the +// action can be used with both WillOnce and WillRepeatedly. +// +// The mock expectation contains the R value from which the U return value is +// constructed (a move/copy of the argument to Return). This means that the R +// value will survive at least until the mock object's expectations are cleared +// or the mock object is destroyed, meaning that U can safely be a +// reference-like type such as std::string_view: +// +// // The mock function returns a view of a copy of the string fed to +// // Return. The view is valid even after the action is performed. +// MockFunction mock; +// EXPECT_CALL(mock, Call).WillOnce(Return(std::string("taco"))); +// const std::string_view result = mock.AsStdFunction()(); +// EXPECT_EQ("taco", result); +// +template +internal::ReturnAction Return(R value) { + return internal::ReturnAction(std::move(value)); +} + +// Creates an action that returns NULL. +inline PolymorphicAction ReturnNull() { + return MakePolymorphicAction(internal::ReturnNullAction()); +} + +// Creates an action that returns from a void function. +inline PolymorphicAction Return() { + return MakePolymorphicAction(internal::ReturnVoidAction()); +} + +// Creates an action that returns the reference to a variable. +template +inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT + return internal::ReturnRefAction(x); +} + +// Prevent using ReturnRef on reference to temporary. +template +internal::ReturnRefAction ReturnRef(R&&) = delete; + +// Creates an action that returns the reference to a copy of the +// argument. The copy is created when the action is constructed and +// lives as long as the action. +template +inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { + return internal::ReturnRefOfCopyAction(x); +} + +// DEPRECATED: use Return(x) directly with WillOnce. +// +// Modifies the parent action (a Return() action) to perform a move of the +// argument instead of a copy. +// Return(ByMove()) actions can only be executed once and will assert this +// invariant. +template +internal::ByMoveWrapper ByMove(R x) { + return internal::ByMoveWrapper(std::move(x)); +} + +// Creates an action that returns an element of `vals`. Calling this action will +// repeatedly return the next value from `vals` until it reaches the end and +// will restart from the beginning. +template +internal::ReturnRoundRobinAction ReturnRoundRobin(std::vector vals) { + return internal::ReturnRoundRobinAction(std::move(vals)); +} + +// Creates an action that returns an element of `vals`. Calling this action will +// repeatedly return the next value from `vals` until it reaches the end and +// will restart from the beginning. +template +internal::ReturnRoundRobinAction ReturnRoundRobin( + std::initializer_list vals) { + return internal::ReturnRoundRobinAction(std::vector(vals)); +} + +// Creates an action that does the default action for the give mock function. +inline internal::DoDefaultAction DoDefault() { + return internal::DoDefaultAction(); +} + +// Creates an action that sets the variable pointed by the N-th +// (0-based) function argument to 'value'. +template +internal::SetArgumentPointeeAction SetArgPointee(T value) { + return {std::move(value)}; +} + +// The following version is DEPRECATED. +template +internal::SetArgumentPointeeAction SetArgumentPointee(T value) { + return {std::move(value)}; +} + +// Creates an action that sets a pointer referent to a given value. +template +PolymorphicAction> Assign(T1* ptr, T2 val) { + return MakePolymorphicAction(internal::AssignAction(ptr, val)); +} + +#ifndef GTEST_OS_WINDOWS_MOBILE + +// Creates an action that sets errno and returns the appropriate error. +template +PolymorphicAction> SetErrnoAndReturn( + int errval, T result) { + return MakePolymorphicAction( + internal::SetErrnoAndReturnAction(errval, result)); +} + +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Various overloads for Invoke(). + +// Legacy function. +// Actions can now be implicitly constructed from callables. No need to create +// wrapper objects. +// This function exists for backwards compatibility. +template +typename std::decay::type Invoke(FunctionImpl&& function_impl) { + return std::forward(function_impl); +} + +// Creates an action that invokes the given method on the given object +// with the mock function's arguments. +template +internal::InvokeMethodAction Invoke(Class* obj_ptr, + MethodPtr method_ptr) { + return {obj_ptr, method_ptr}; +} + +// Creates an action that invokes 'function_impl' with no argument. +template +internal::InvokeWithoutArgsAction::type> +InvokeWithoutArgs(FunctionImpl function_impl) { + return {std::move(function_impl)}; +} + +// Creates an action that invokes the given method on the given object +// with no argument. +template +internal::InvokeMethodWithoutArgsAction InvokeWithoutArgs( + Class* obj_ptr, MethodPtr method_ptr) { + return {obj_ptr, method_ptr}; +} + +// Creates an action that performs an_action and throws away its +// result. In other words, it changes the return type of an_action to +// void. an_action MUST NOT return void, or the code won't compile. +template +inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { + return internal::IgnoreResultAction(an_action); +} + +// Creates a reference wrapper for the given L-value. If necessary, +// you can explicitly specify the type of the reference. For example, +// suppose 'derived' is an object of type Derived, ByRef(derived) +// would wrap a Derived&. If you want to wrap a const Base& instead, +// where Base is a base class of Derived, just write: +// +// ByRef(derived) +// +// N.B. ByRef is redundant with std::ref, std::cref and std::reference_wrapper. +// However, it may still be used for consistency with ByMove(). +template +inline ::std::reference_wrapper ByRef(T& l_value) { // NOLINT + return ::std::reference_wrapper(l_value); +} + +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +template +internal::ReturnNewAction::type...> ReturnNew( + Params&&... params) { + return {std::forward_as_tuple(std::forward(params)...)}; +} + +// Action ReturnArg() returns the k-th argument of the mock function. +template +internal::ReturnArgAction ReturnArg() { + return {}; +} + +// Action SaveArg(pointer) saves the k-th (0-based) argument of the +// mock function to *pointer. +template +internal::SaveArgAction SaveArg(Ptr pointer) { + return {pointer}; +} + +// Action SaveArgPointee(pointer) saves the value pointed to +// by the k-th (0-based) argument of the mock function to *pointer. +template +internal::SaveArgPointeeAction SaveArgPointee(Ptr pointer) { + return {pointer}; +} + +// Action SetArgReferee(value) assigns 'value' to the variable +// referenced by the k-th (0-based) argument of the mock function. +template +internal::SetArgRefereeAction::type> SetArgReferee( + T&& value) { + return {std::forward(value)}; +} + +// Action SetArrayArgument(first, last) copies the elements in +// source range [first, last) to the array pointed to by the k-th +// (0-based) argument, which can be either a pointer or an +// iterator. The action does not take ownership of the elements in the +// source range. +template +internal::SetArrayArgumentAction SetArrayArgument(I1 first, + I2 last) { + return {first, last}; +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +internal::DeleteArgAction DeleteArg() { + return {}; +} + +// This action returns the value pointed to by 'pointer'. +template +internal::ReturnPointeeAction ReturnPointee(Ptr pointer) { + return {pointer}; +} + +#if GTEST_HAS_EXCEPTIONS +// Action Throw(exception) can be used in a mock function of any type +// to throw the given exception. Any copyable value can be thrown, +// except for std::exception_ptr, which is likely a mistake if +// thrown directly. +template +typename std::enable_if< + !std::is_base_of::type>::value, + internal::ThrowAction::type>>::type +Throw(T&& exception) { + return {std::forward(exception)}; +} +// Action Rethrow(exception_ptr) can be used in a mock function of any type +// to rethrow any exception_ptr. Note that the same object is thrown each time. +inline internal::RethrowAction Rethrow(std::exception_ptr exception) { + return {std::move(exception)}; +} +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { + +// A macro from the ACTION* family (defined later in gmock-generated-actions.h) +// defines an action that can be used in a mock function. Typically, +// these actions only care about a subset of the arguments of the mock +// function. For example, if such an action only uses the second +// argument, it can be used in any mock function that takes >= 2 +// arguments where the type of the second argument is compatible. +// +// Therefore, the action implementation must be prepared to take more +// arguments than it needs. The ExcessiveArg type is used to +// represent those excessive arguments. In order to keep the compiler +// error messages tractable, we define it in the testing namespace +// instead of testing::internal. However, this is an INTERNAL TYPE +// and subject to change without notice, so a user MUST NOT USE THIS +// TYPE DIRECTLY. +struct ExcessiveArg {}; + +// Builds an implementation of an Action<> for some particular signature, using +// a class defined by an ACTION* macro. +template +struct ActionImpl; + +template +struct ImplBase { + struct Holder { + // Allows each copy of the Action<> to get to the Impl. + explicit operator const Impl&() const { return *ptr; } + std::shared_ptr ptr; + }; + using type = typename std::conditional::value, + Impl, Holder>::type; +}; + +template +struct ActionImpl : ImplBase::type { + using Base = typename ImplBase::type; + using function_type = R(Args...); + using args_type = std::tuple; + + ActionImpl() = default; // Only defined if appropriate for Base. + explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} {} + + R operator()(Args&&... arg) const { + static constexpr size_t kMaxArgs = + sizeof...(Args) <= 10 ? sizeof...(Args) : 10; + return Apply(std::make_index_sequence{}, + std::make_index_sequence<10 - kMaxArgs>{}, + args_type{std::forward(arg)...}); + } + + template + R Apply(std::index_sequence, std::index_sequence, + const args_type& args) const { + // Impl need not be specific to the signature of action being implemented; + // only the implementing function body needs to have all of the specific + // types instantiated. Up to 10 of the args that are provided by the + // args_type get passed, followed by a dummy of unspecified type for the + // remainder up to 10 explicit args. + static constexpr ExcessiveArg kExcessArg{}; + return static_cast(*this) + .template gmock_PerformImpl< + /*function_type=*/function_type, /*return_type=*/R, + /*args_type=*/args_type, + /*argN_type=*/ + typename std::tuple_element::type...>( + /*args=*/args, std::get(args)..., + ((void)excess_id, kExcessArg)...); + } +}; + +// Stores a default-constructed Impl as part of the Action<>'s +// std::function<>. The Impl should be trivial to copy. +template +::testing::Action MakeAction() { + return ::testing::Action(ActionImpl()); +} + +// Stores just the one given instance of Impl. +template +::testing::Action MakeAction(std::shared_ptr impl) { + return ::testing::Action(ActionImpl(std::move(impl))); +} + +#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ + , GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const arg##i##_type& arg##i +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ + GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const args_type& args GMOCK_PP_REPEAT( \ + GMOCK_INTERNAL_ARG_UNUSED, , 10) + +#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_ \ + const args_type& args GMOCK_PP_REPEAT(GMOCK_INTERNAL_ARG, , 10) + +#define GMOCK_INTERNAL_TEMPLATE_ARG(i, data, el) , typename arg##i##_type +#define GMOCK_ACTION_TEMPLATE_ARGS_NAMES_ \ + GMOCK_PP_TAIL(GMOCK_PP_REPEAT(GMOCK_INTERNAL_TEMPLATE_ARG, , 10)) + +#define GMOCK_INTERNAL_TYPENAME_PARAM(i, data, param) , typename param##_type +#define GMOCK_ACTION_TYPENAME_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPENAME_PARAM, , params)) + +#define GMOCK_INTERNAL_TYPE_PARAM(i, data, param) , param##_type +#define GMOCK_ACTION_TYPE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_PARAM, , params)) + +#define GMOCK_INTERNAL_TYPE_GVALUE_PARAM(i, data, param) \ + , param##_type gmock_p##i +#define GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_GVALUE_PARAM, , params)) + +#define GMOCK_INTERNAL_GVALUE_PARAM(i, data, param) \ + , std::forward(gmock_p##i) +#define GMOCK_ACTION_GVALUE_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GVALUE_PARAM, , params)) + +#define GMOCK_INTERNAL_INIT_PARAM(i, data, param) \ + , param(::std::forward(gmock_p##i)) +#define GMOCK_ACTION_INIT_PARAMS_(params) \ + GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_INIT_PARAM, , params)) + +#define GMOCK_INTERNAL_FIELD_PARAM(i, data, param) param##_type param; +#define GMOCK_ACTION_FIELD_PARAMS_(params) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_FIELD_PARAM, , params) + +#define GMOCK_INTERNAL_ACTION(name, full_name, params) \ + template \ + class full_name { \ + public: \ + explicit full_name(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ + : impl_(std::make_shared( \ + GMOCK_ACTION_GVALUE_PARAMS_(params))) {} \ + full_name(const full_name&) = default; \ + full_name(full_name&&) noexcept = default; \ + template \ + operator ::testing::Action() const { \ + return ::testing::internal::MakeAction(impl_); \ + } \ + \ + private: \ + class gmock_Impl { \ + public: \ + explicit gmock_Impl(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ + : GMOCK_ACTION_INIT_PARAMS_(params) {} \ + template \ + return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ + GMOCK_ACTION_FIELD_PARAMS_(params) \ + }; \ + std::shared_ptr impl_; \ + }; \ + template \ + inline full_name name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) GTEST_MUST_USE_RESULT_; \ + template \ + inline full_name name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \ + return full_name( \ + GMOCK_ACTION_GVALUE_PARAMS_(params)); \ + } \ + template \ + template \ + return_type \ + full_name::gmock_Impl::gmock_PerformImpl( \ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +} // namespace internal + +// Similar to GMOCK_INTERNAL_ACTION, but no bound parameters are stored. +#define ACTION(name) \ + class name##Action { \ + public: \ + explicit name##Action() noexcept {} \ + name##Action(const name##Action&) noexcept {} \ + template \ + operator ::testing::Action() const { \ + return ::testing::internal::MakeAction(); \ + } \ + \ + private: \ + class gmock_Impl { \ + public: \ + template \ + return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ + }; \ + }; \ + inline name##Action name() GTEST_MUST_USE_RESULT_; \ + inline name##Action name() { return name##Action(); } \ + template \ + return_type name##Action::gmock_Impl::gmock_PerformImpl( \ + GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const + +#define ACTION_P(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP, (__VA_ARGS__)) + +#define ACTION_P2(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP2, (__VA_ARGS__)) + +#define ACTION_P3(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP3, (__VA_ARGS__)) + +#define ACTION_P4(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP4, (__VA_ARGS__)) + +#define ACTION_P5(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP5, (__VA_ARGS__)) + +#define ACTION_P6(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP6, (__VA_ARGS__)) + +#define ACTION_P7(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP7, (__VA_ARGS__)) + +#define ACTION_P8(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP8, (__VA_ARGS__)) + +#define ACTION_P9(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP9, (__VA_ARGS__)) + +#define ACTION_P10(name, ...) \ + GMOCK_INTERNAL_ACTION(name, name##ActionP10, (__VA_ARGS__)) + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4100 + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-cardinalities.h b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-cardinalities.h new file mode 100644 index 0000000000..533e604f32 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-cardinalities.h @@ -0,0 +1,159 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements some commonly used cardinalities. More +// cardinalities can be defined by the user implementing the +// CardinalityInterface interface if necessary. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ + +#include + +#include +#include // NOLINT + +#include "gmock/internal/gmock-port.h" +#include "gtest/gtest.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// To implement a cardinality Foo, define: +// 1. a class FooCardinality that implements the +// CardinalityInterface interface, and +// 2. a factory function that creates a Cardinality object from a +// const FooCardinality*. +// +// The two-level delegation design follows that of Matcher, providing +// consistency for extension developers. It also eases ownership +// management as Cardinality objects can now be copied like plain values. + +// The implementation of a cardinality. +class CardinalityInterface { + public: + virtual ~CardinalityInterface() = default; + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + virtual int ConservativeLowerBound() const { return 0; } + virtual int ConservativeUpperBound() const { return INT_MAX; } + + // Returns true if and only if call_count calls will satisfy this + // cardinality. + virtual bool IsSatisfiedByCallCount(int call_count) const = 0; + + // Returns true if and only if call_count calls will saturate this + // cardinality. + virtual bool IsSaturatedByCallCount(int call_count) const = 0; + + // Describes self to an ostream. + virtual void DescribeTo(::std::ostream* os) const = 0; +}; + +// A Cardinality is a copyable and IMMUTABLE (except by assignment) +// object that specifies how many times a mock function is expected to +// be called. The implementation of Cardinality is just a std::shared_ptr +// to const CardinalityInterface. Don't inherit from Cardinality! +class GTEST_API_ Cardinality { + public: + // Constructs a null cardinality. Needed for storing Cardinality + // objects in STL containers. + Cardinality() = default; + + // Constructs a Cardinality from its implementation. + explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} + + // Conservative estimate on the lower/upper bound of the number of + // calls allowed. + int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } + int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } + + // Returns true if and only if call_count calls will satisfy this + // cardinality. + bool IsSatisfiedByCallCount(int call_count) const { + return impl_->IsSatisfiedByCallCount(call_count); + } + + // Returns true if and only if call_count calls will saturate this + // cardinality. + bool IsSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count); + } + + // Returns true if and only if call_count calls will over-saturate this + // cardinality, i.e. exceed the maximum number of allowed calls. + bool IsOverSaturatedByCallCount(int call_count) const { + return impl_->IsSaturatedByCallCount(call_count) && + !impl_->IsSatisfiedByCallCount(call_count); + } + + // Describes self to an ostream + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the given actual call count to an ostream. + static void DescribeActualCallCountTo(int actual_call_count, + ::std::ostream* os); + + private: + std::shared_ptr impl_; +}; + +// Creates a cardinality that allows at least n calls. +GTEST_API_ Cardinality AtLeast(int n); + +// Creates a cardinality that allows at most n calls. +GTEST_API_ Cardinality AtMost(int n); + +// Creates a cardinality that allows any number of calls. +GTEST_API_ Cardinality AnyNumber(); + +// Creates a cardinality that allows between min and max calls. +GTEST_API_ Cardinality Between(int min, int max); + +// Creates a cardinality that allows exactly n calls. +GTEST_API_ Cardinality Exactly(int n); + +// Creates a cardinality from its implementation. +inline Cardinality MakeCardinality(const CardinalityInterface* c) { + return Cardinality(c); +} + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-function-mocker.h b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-function-mocker.h new file mode 100644 index 0000000000..d2cb13cd83 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-function-mocker.h @@ -0,0 +1,519 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// This file implements MOCK_METHOD. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ + +#include +#include // IWYU pragma: keep +#include // IWYU pragma: keep + +#include "gmock/gmock-spec-builders.h" +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-pp.h" + +namespace testing { +namespace internal { +template +using identity_t = T; + +template +struct ThisRefAdjuster { + template + using AdjustT = typename std::conditional< + std::is_const::type>::value, + typename std::conditional::value, + const T&, const T&&>::type, + typename std::conditional::value, T&, + T&&>::type>::type; + + template + static AdjustT Adjust(const MockType& mock) { + return static_cast>(const_cast(mock)); + } +}; + +constexpr bool PrefixOf(const char* a, const char* b) { + return *a == 0 || (*a == *b && internal::PrefixOf(a + 1, b + 1)); +} + +template +constexpr bool StartsWith(const char (&prefix)[N], const char (&str)[M]) { + return N <= M && internal::PrefixOf(prefix, str); +} + +template +constexpr bool EndsWith(const char (&suffix)[N], const char (&str)[M]) { + return N <= M && internal::PrefixOf(suffix, str + M - N); +} + +template +constexpr bool Equals(const char (&a)[N], const char (&b)[M]) { + return N == M && internal::PrefixOf(a, b); +} + +template +constexpr bool ValidateSpec(const char (&spec)[N]) { + return internal::Equals("const", spec) || + internal::Equals("override", spec) || + internal::Equals("final", spec) || + internal::Equals("noexcept", spec) || + (internal::StartsWith("noexcept(", spec) && + internal::EndsWith(")", spec)) || + internal::Equals("ref(&)", spec) || + internal::Equals("ref(&&)", spec) || + (internal::StartsWith("Calltype(", spec) && + internal::EndsWith(")", spec)); +} + +} // namespace internal + +// The style guide prohibits "using" statements in a namespace scope +// inside a header file. However, the FunctionMocker class template +// is meant to be defined in the ::testing namespace. The following +// line is just a trick for working around a bug in MSVC 8.0, which +// cannot handle it if we define FunctionMocker in ::testing. +using internal::FunctionMocker; +} // namespace testing + +#define MOCK_METHOD(...) \ + GMOCK_INTERNAL_WARNING_PUSH() \ + GMOCK_INTERNAL_WARNING_CLANG(ignored, "-Wunused-member-function") \ + GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__) \ + GMOCK_INTERNAL_WARNING_POP() + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \ + GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ()) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \ + GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \ + GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \ + GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ + GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \ + GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ + GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ + GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \ + GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \ + GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Spec), \ + GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Spec), \ + GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \ + (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args))) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \ + GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) + +#define GMOCK_INTERNAL_WRONG_ARITY(...) \ + static_assert( \ + false, \ + "MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \ + "_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \ + "enclosed in parentheses. If _Ret is a type with unprotected commas, " \ + "it must also be enclosed in parentheses.") + +#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \ + static_assert( \ + GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \ + GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.") + +#define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \ + static_assert( \ + std::is_function<__VA_ARGS__>::value, \ + "Signature must be a function type, maybe return type contains " \ + "unprotected comma."); \ + static_assert( \ + ::testing::tuple_size::ArgumentTuple>::value == _N, \ + "This method does not take " GMOCK_PP_STRINGIZE( \ + _N) " arguments. Parenthesize all types with unprotected commas.") + +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec) + +#define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \ + _Override, _Final, _NoexceptSpec, \ + _CallType, _RefSpec, _Signature) \ + typename ::testing::internal::Function::Result \ + GMOCK_INTERNAL_EXPAND(_CallType) \ + _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \ + GMOCK_PP_IF(_Constness, const, ) \ + _RefSpec _NoexceptSpec GMOCK_PP_IF(_Override, override, ) \ + GMOCK_PP_IF(_Final, final, ) { \ + GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .SetOwnerAndName(this, #_MethodName); \ + return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \ + } \ + ::testing::MockSpec gmock_##_MethodName( \ + GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \ + GMOCK_PP_IF(_Constness, const, ) _RefSpec { \ + GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \ + return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ + .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \ + } \ + ::testing::MockSpec gmock_##_MethodName( \ + const ::testing::internal::WithoutMatchers&, \ + GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \ + GMOCK_PP_REMOVE_PARENS(_Signature)>*) const _RefSpec _NoexceptSpec { \ + return ::testing::internal::ThisRefAdjuster::Adjust(*this) \ + .gmock_##_MethodName(GMOCK_PP_REPEAT( \ + GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \ + } \ + mutable ::testing::FunctionMocker \ + GMOCK_MOCKER_(_N, _Constness, _MethodName) + +#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__ + +// Valid modifiers. +#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \ + GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple)) + +#define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \ + GMOCK_PP_HAS_COMMA( \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple)) + +#define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \ + GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple)) + +#define GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT, ~, _Tuple) + +#define GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT(_i, _, _elem) \ + GMOCK_PP_IF( \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)), \ + _elem, ) + +#define GMOCK_INTERNAL_GET_CALLTYPE_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE, ~, _Tuple) + +#define GMOCK_INTERNAL_CALLTYPE_SPEC_IF_CALLTYPE(_i, _, _elem) \ + GMOCK_PP_IF( \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem)), \ + GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) + +#define GMOCK_INTERNAL_GET_REF_SPEC(_Tuple) \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_REF_SPEC_IF_REF, ~, _Tuple) + +#define GMOCK_INTERNAL_REF_SPEC_IF_REF(_i, _, _elem) \ + GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \ + GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) + +#ifdef GMOCK_INTERNAL_STRICT_SPEC_ASSERT +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ + static_assert( \ + ::testing::internal::ValidateSpec(GMOCK_PP_STRINGIZE(_elem)), \ + "Token \'" GMOCK_PP_STRINGIZE( \ + _elem) "\' cannot be recognized as a valid specification " \ + "modifier. Is a ',' missing?"); +#else +#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ + static_assert( \ + (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)) + \ + GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem))) == 1, \ + GMOCK_PP_STRINGIZE( \ + _elem) " cannot be recognized as a valid specification modifier."); +#endif // GMOCK_INTERNAL_STRICT_SPEC_ASSERT + +// Modifiers implementation. +#define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_CONST_I_const , + +#define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override , + +#define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_FINAL_I_final , + +#define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept , + +#define GMOCK_INTERNAL_DETECT_REF(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_REF_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_REF_I_ref , + +#define GMOCK_INTERNAL_UNPACK_ref(x) x + +#define GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem) \ + GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CALLTYPE_I_, _elem) + +#define GMOCK_INTERNAL_DETECT_CALLTYPE_I_Calltype , + +#define GMOCK_INTERNAL_UNPACK_Calltype(...) __VA_ARGS__ + +// Note: The use of `identity_t` here allows _Ret to represent return types that +// would normally need to be specified in a different way. For example, a method +// returning a function pointer must be written as +// +// fn_ptr_return_t (*method(method_args_t...))(fn_ptr_args_t...) +// +// But we only support placing the return type at the beginning. To handle this, +// we wrap all calls in identity_t, so that a declaration will be expanded to +// +// identity_t method(method_args_t...) +// +// This allows us to work around the syntactic oddities of function/method +// types. +#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \ + ::testing::internal::identity_t( \ + GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args)) + +#define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \ + GMOCK_PP_IDENTITY) \ + (_elem) + +#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ + gmock_a##_i + +#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + ::std::forward(gmock_a##_i) + +#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + GMOCK_INTERNAL_MATCHER_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ + gmock_a##_i + +#define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \ + GMOCK_PP_COMMA_IF(_i) \ + gmock_a##_i + +#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \ + GMOCK_PP_COMMA_IF(_i) \ + ::testing::A() + +#define GMOCK_INTERNAL_ARG_O(_i, ...) \ + typename ::testing::internal::Function<__VA_ARGS__>::template Arg<_i>::type + +#define GMOCK_INTERNAL_MATCHER_O(_i, ...) \ + const ::testing::Matcher::template Arg<_i>::type>& + +#define MOCK_METHOD0(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 0, __VA_ARGS__) +#define MOCK_METHOD1(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 1, __VA_ARGS__) +#define MOCK_METHOD2(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 2, __VA_ARGS__) +#define MOCK_METHOD3(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 3, __VA_ARGS__) +#define MOCK_METHOD4(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 4, __VA_ARGS__) +#define MOCK_METHOD5(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 5, __VA_ARGS__) +#define MOCK_METHOD6(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 6, __VA_ARGS__) +#define MOCK_METHOD7(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 7, __VA_ARGS__) +#define MOCK_METHOD8(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 8, __VA_ARGS__) +#define MOCK_METHOD9(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 9, __VA_ARGS__) +#define MOCK_METHOD10(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, , m, 10, __VA_ARGS__) + +#define MOCK_CONST_METHOD0(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 0, __VA_ARGS__) +#define MOCK_CONST_METHOD1(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 1, __VA_ARGS__) +#define MOCK_CONST_METHOD2(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 2, __VA_ARGS__) +#define MOCK_CONST_METHOD3(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 3, __VA_ARGS__) +#define MOCK_CONST_METHOD4(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 4, __VA_ARGS__) +#define MOCK_CONST_METHOD5(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 5, __VA_ARGS__) +#define MOCK_CONST_METHOD6(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 6, __VA_ARGS__) +#define MOCK_CONST_METHOD7(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 7, __VA_ARGS__) +#define MOCK_CONST_METHOD8(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 8, __VA_ARGS__) +#define MOCK_CONST_METHOD9(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 9, __VA_ARGS__) +#define MOCK_CONST_METHOD10(m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, , m, 10, __VA_ARGS__) + +#define MOCK_METHOD0_T(m, ...) MOCK_METHOD0(m, __VA_ARGS__) +#define MOCK_METHOD1_T(m, ...) MOCK_METHOD1(m, __VA_ARGS__) +#define MOCK_METHOD2_T(m, ...) MOCK_METHOD2(m, __VA_ARGS__) +#define MOCK_METHOD3_T(m, ...) MOCK_METHOD3(m, __VA_ARGS__) +#define MOCK_METHOD4_T(m, ...) MOCK_METHOD4(m, __VA_ARGS__) +#define MOCK_METHOD5_T(m, ...) MOCK_METHOD5(m, __VA_ARGS__) +#define MOCK_METHOD6_T(m, ...) MOCK_METHOD6(m, __VA_ARGS__) +#define MOCK_METHOD7_T(m, ...) MOCK_METHOD7(m, __VA_ARGS__) +#define MOCK_METHOD8_T(m, ...) MOCK_METHOD8(m, __VA_ARGS__) +#define MOCK_METHOD9_T(m, ...) MOCK_METHOD9(m, __VA_ARGS__) +#define MOCK_METHOD10_T(m, ...) MOCK_METHOD10(m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T(m, ...) MOCK_CONST_METHOD0(m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T(m, ...) MOCK_CONST_METHOD1(m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T(m, ...) MOCK_CONST_METHOD2(m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T(m, ...) MOCK_CONST_METHOD3(m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T(m, ...) MOCK_CONST_METHOD4(m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T(m, ...) MOCK_CONST_METHOD5(m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T(m, ...) MOCK_CONST_METHOD6(m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T(m, ...) MOCK_CONST_METHOD7(m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T(m, ...) MOCK_CONST_METHOD8(m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T(m, ...) MOCK_CONST_METHOD9(m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T(m, ...) MOCK_CONST_METHOD10(m, __VA_ARGS__) + +#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 0, __VA_ARGS__) +#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 1, __VA_ARGS__) +#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 2, __VA_ARGS__) +#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 3, __VA_ARGS__) +#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 4, __VA_ARGS__) +#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 5, __VA_ARGS__) +#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 6, __VA_ARGS__) +#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 7, __VA_ARGS__) +#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 8, __VA_ARGS__) +#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 9, __VA_ARGS__) +#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 10, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 0, __VA_ARGS__) +#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 1, __VA_ARGS__) +#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 2, __VA_ARGS__) +#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 3, __VA_ARGS__) +#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 4, __VA_ARGS__) +#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 5, __VA_ARGS__) +#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 6, __VA_ARGS__) +#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 7, __VA_ARGS__) +#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 8, __VA_ARGS__) +#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 9, __VA_ARGS__) +#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ + GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 10, __VA_ARGS__) + +#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) + +#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) +#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ + MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) + +#define GMOCK_INTERNAL_MOCK_METHODN(constness, ct, Method, args_num, ...) \ + GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ + args_num, ::testing::internal::identity_t<__VA_ARGS__>); \ + GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ + args_num, Method, GMOCK_PP_NARG0(constness), 0, 0, , ct, , \ + (::testing::internal::identity_t<__VA_ARGS__>)) + +#define GMOCK_MOCKER_(arity, constness, Method) \ + GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) + +#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_ diff --git a/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-matchers.h b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-matchers.h new file mode 100644 index 0000000000..e979544c72 --- /dev/null +++ b/3rdParty/googletest-1.16.0/googletest/googlemock/include/gmock/gmock-matchers.h @@ -0,0 +1,5691 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Google Mock - a framework for writing C++ mock classes. +// +// The MATCHER* family of macros can be used in a namespace scope to +// define custom matchers easily. +// +// Basic Usage +// =========== +// +// The syntax +// +// MATCHER(name, description_string) { statements; } +// +// defines a matcher with the given name that executes the statements, +// which must return a bool to indicate if the match succeeds. Inside +// the statements, you can refer to the value being matched by 'arg', +// and refer to its type by 'arg_type'. +// +// The description string documents what the matcher does, and is used +// to generate the failure message when the match fails. Since a +// MATCHER() is usually defined in a header file shared by multiple +// C++ source files, we require the description to be a C-string +// literal to avoid possible side effects. It can be empty, in which +// case we'll use the sequence of words in the matcher name as the +// description. +// +// For example: +// +// MATCHER(IsEven, "") { return (arg % 2) == 0; } +// +// allows you to write +// +// // Expects mock_foo.Bar(n) to be called where n is even. +// EXPECT_CALL(mock_foo, Bar(IsEven())); +// +// or, +// +// // Verifies that the value of some_expression is even. +// EXPECT_THAT(some_expression, IsEven()); +// +// If the above assertion fails, it will print something like: +// +// Value of: some_expression +// Expected: is even +// Actual: 7 +// +// where the description "is even" is automatically calculated from the +// matcher name IsEven. +// +// Argument Type +// ============= +// +// Note that the type of the value being matched (arg_type) is +// determined by the context in which you use the matcher and is +// supplied to you by the compiler, so you don't need to worry about +// declaring it (nor can you). This allows the matcher to be +// polymorphic. For example, IsEven() can be used to match any type +// where the value of "(arg % 2) == 0" can be implicitly converted to +// a bool. In the "Bar(IsEven())" example above, if method Bar() +// takes an int, 'arg_type' will be int; if it takes an unsigned long, +// 'arg_type' will be unsigned long; and so on. +// +// Parameterizing Matchers +// ======================= +// +// Sometimes you'll want to parameterize the matcher. For that you +// can use another macro: +// +// MATCHER_P(name, param_name, description_string) { statements; } +// +// For example: +// +// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } +// +// will allow you to write: +// +// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); +// +// which may lead to this message (assuming n is 10): +// +// Value of: Blah("a") +// Expected: has absolute value 10 +// Actual: -9 +// +// Note that both the matcher description and its parameter are +// printed, making the message human-friendly. +// +// In the matcher definition body, you can write 'foo_type' to +// reference the type of a parameter named 'foo'. For example, in the +// body of MATCHER_P(HasAbsoluteValue, value) above, you can write +// 'value_type' to refer to the type of 'value'. +// +// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to +// support multi-parameter matchers. +// +// Describing Parameterized Matchers +// ================================= +// +// The last argument to MATCHER*() is a string-typed expression. The +// expression can reference all of the matcher's parameters and a +// special bool-typed variable named 'negation'. When 'negation' is +// false, the expression should evaluate to the matcher's description; +// otherwise it should evaluate to the description of the negation of +// the matcher. For example, +// +// using testing::PrintToString; +// +// MATCHER_P2(InClosedRange, low, hi, +// std::string(negation ? "is not" : "is") + " in range [" + +// PrintToString(low) + ", " + PrintToString(hi) + "]") { +// return low <= arg && arg <= hi; +// } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: is in range [4, 6] +// ... +// Expected: is not in range [2, 4] +// +// If you specify "" as the description, the failure message will +// contain the sequence of words in the matcher name followed by the +// parameter values printed as a tuple. For example, +// +// MATCHER_P2(InClosedRange, low, hi, "") { ... } +// ... +// EXPECT_THAT(3, InClosedRange(4, 6)); +// EXPECT_THAT(3, Not(InClosedRange(2, 4))); +// +// would generate two failures that contain the text: +// +// Expected: in closed range (4, 6) +// ... +// Expected: not (in closed range (2, 4)) +// +// Types of Matcher Parameters +// =========================== +// +// For the purpose of typing, you can view +// +// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } +// +// as shorthand for +// +// template +// FooMatcherPk +// Foo(p1_type p1, ..., pk_type pk) { ... } +// +// When you write Foo(v1, ..., vk), the compiler infers the types of +// the parameters v1, ..., and vk for you. If you are not happy with +// the result of the type inference, you can specify the types by +// explicitly instantiating the template, as in Foo(5, +// false). As said earlier, you don't get to (or need to) specify +// 'arg_type' as that's determined by the context in which the matcher +// is used. You can assign the result of expression Foo(p1, ..., pk) +// to a variable of type FooMatcherPk. This +// can be useful when composing matchers. +// +// While you can instantiate a matcher template with reference types, +// passing the parameters by pointer usually makes your code more +// readable. If, however, you still want to pass a parameter by +// reference, be aware that in the failure message generated by the +// matcher you will see the value of the referenced object but not its +// address. +// +// Explaining Match Results +// ======================== +// +// Sometimes the matcher description alone isn't enough to explain why +// the match has failed or succeeded. For example, when expecting a +// long string, it can be very helpful to also print the diff between +// the expected string and the actual one. To achieve that, you can +// optionally stream additional information to a special variable +// named result_listener, whose type is a pointer to class +// MatchResultListener: +// +// MATCHER_P(EqualsLongString, str, "") { +// if (arg == str) return true; +// +// *result_listener << "the difference: " +/// << DiffStrings(str, arg); +// return false; +// } +// +// Overloading Matchers +// ==================== +// +// You can overload matchers with different numbers of parameters: +// +// MATCHER_P(Blah, a, description_string1) { ... } +// MATCHER_P2(Blah, a, b, description_string2) { ... } +// +// Caveats +// ======= +// +// When defining a new matcher, you should also consider implementing +// MatcherInterface or using MakePolymorphicMatcher(). These +// approaches require more work than the MATCHER* macros, but also +// give you more control on the types of the value being matched and +// the matcher parameters, which may leads to better compiler error +// messages when the matcher is used wrong. They also allow +// overloading matchers based on parameter types (as opposed to just +// based on the number of parameters). +// +// MATCHER*() can only be used in a namespace scope as templates cannot be +// declared inside of a local class. +// +// More Information +// ================ +// +// To learn more about using these macros, please search for 'MATCHER' +// on +// https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md +// +// This file also implements some commonly used argument matchers. More +// matchers can be defined by the user implementing the +// MatcherInterface interface if necessary. +// +// See googletest/include/gtest/gtest-matchers.h for the definition of class +// Matcher, class MatcherInterface, and others. + +// IWYU pragma: private, include "gmock/gmock.h" +// IWYU pragma: friend gmock/.* + +#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ +#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // NOLINT +#include +#include +#include +#include +#include + +#include "gmock/internal/gmock-internal-utils.h" +#include "gmock/internal/gmock-port.h" +#include "gmock/internal/gmock-pp.h" +#include "gtest/gtest.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GMOCK_MAYBE_5046_ 5046 +#else +#define GMOCK_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// A match result listener that stores the explanation in a string. +class StringMatchResultListener : public MatchResultListener { + public: + StringMatchResultListener() : MatchResultListener(&ss_) {} + + // Returns the explanation accumulated so far. + std::string str() const { return ss_.str(); } + + // Clears the explanation accumulated so far. + void Clear() { ss_.str(""); } + + private: + ::std::stringstream ss_; + + StringMatchResultListener(const StringMatchResultListener&) = delete; + StringMatchResultListener& operator=(const StringMatchResultListener&) = + delete; +}; + +// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION +// and MUST NOT BE USED IN USER CODE!!! +namespace internal { + +// The MatcherCastImpl class template is a helper for implementing +// MatcherCast(). We need this helper in order to partially +// specialize the implementation of MatcherCast() (C++ allows +// class/struct templates to be partially specialized, but not +// function templates.). + +// This general version is used when MatcherCast()'s argument is a +// polymorphic matcher (i.e. something that can be converted to a +// Matcher but is not one yet; for example, Eq(value)) or a value (for +// example, "hello"). +template +class MatcherCastImpl { + public: + static Matcher Cast(const M& polymorphic_matcher_or_value) { + // M can be a polymorphic matcher, in which case we want to use + // its conversion operator to create Matcher. Or it can be a value + // that should be passed to the Matcher's constructor. + // + // We can't call Matcher(polymorphic_matcher_or_value) when M is a + // polymorphic matcher because it'll be ambiguous if T has an implicit + // constructor from M (this usually happens when T has an implicit + // constructor from any type). + // + // It won't work to unconditionally implicit_cast + // polymorphic_matcher_or_value to Matcher because it won't trigger + // a user-defined conversion from M to T if one exists (assuming M is + // a value). + return CastImpl(polymorphic_matcher_or_value, + std::is_convertible>{}, + std::is_convertible{}); + } + + private: + template + static Matcher CastImpl(const M& polymorphic_matcher_or_value, + std::true_type /* convertible_to_matcher */, + std::integral_constant) { + // M is implicitly convertible to Matcher, which means that either + // M is a polymorphic matcher or Matcher has an implicit constructor + // from M. In both cases using the implicit conversion will produce a + // matcher. + // + // Even if T has an implicit constructor from M, it won't be called because + // creating Matcher would require a chain of two user-defined conversions + // (first to create T from M and then to create Matcher from T). + return polymorphic_matcher_or_value; + } + + // M can't be implicitly converted to Matcher, so M isn't a polymorphic + // matcher. It's a value of a type implicitly convertible to T. Use direct + // initialization to create a matcher. + static Matcher CastImpl(const M& value, + std::false_type /* convertible_to_matcher */, + std::true_type /* convertible_to_T */) { + return Matcher(ImplicitCast_(value)); + } + + // M can't be implicitly converted to either Matcher or T. Attempt to use + // polymorphic matcher Eq(value) in this case. + // + // Note that we first attempt to perform an implicit cast on the value and + // only fall back to the polymorphic Eq() matcher afterwards because the + // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end + // which might be undefined even when Rhs is implicitly convertible to Lhs + // (e.g. std::pair vs. std::pair). + // + // We don't define this method inline as we need the declaration of Eq(). + static Matcher CastImpl(const M& value, + std::false_type /* convertible_to_matcher */, + std::false_type /* convertible_to_T */); +}; + +// This more specialized version is used when MatcherCast()'s argument +// is already a Matcher. This only compiles when type T can be +// statically converted to type U. +template +class MatcherCastImpl> { + public: + static Matcher Cast(const Matcher& source_matcher) { + return Matcher(new Impl(source_matcher)); + } + + private: + // If it's possible to implicitly convert a `const T&` to U, then `Impl` can + // take that as input to avoid a copy. Otherwise, such as when `T` is a + // non-const reference type or a type explicitly constructible only from a + // non-const reference, then `Impl` must use `T` as-is (potentially copying). + using ImplArgT = + typename std::conditional::value, + const T&, T>::type; + + class Impl : public MatcherInterface { + public: + explicit Impl(const Matcher& source_matcher) + : source_matcher_(source_matcher) {} + + // We delegate the matching logic to the source matcher. + bool MatchAndExplain(ImplArgT x, + MatchResultListener* listener) const override { + using FromType = typename std::remove_cv::type>::type>::type; + using ToType = typename std::remove_cv::type>::type>::type; + // Do not allow implicitly converting base*/& to derived*/&. + static_assert( + // Do not trigger if only one of them is a pointer. That implies a + // regular conversion and not a down_cast. + (std::is_pointer::type>::value != + std::is_pointer::type>::value) || + std::is_same::value || + !std::is_base_of::value, + "Can't implicitly convert from to "); + + // Do the cast to `U` explicitly if necessary. + // Otherwise, let implicit conversions do the trick. + using CastType = typename std::conditional< + std::is_convertible::value, ImplArgT&, U>::type; + + return source_matcher_.MatchAndExplain(static_cast(x), + listener); + } + + void DescribeTo(::std::ostream* os) const override { + source_matcher_.DescribeTo(os); + } + + void DescribeNegationTo(::std::ostream* os) const override { + source_matcher_.DescribeNegationTo(os); + } + + private: + const Matcher source_matcher_; + }; +}; + +// This even more specialized version is used for efficiently casting +// a matcher to its own type. +template +class MatcherCastImpl> { + public: + static Matcher Cast(const Matcher& matcher) { return matcher; } +}; + +// Template specialization for parameterless Matcher. +template +class MatcherBaseImpl { + public: + MatcherBaseImpl() = default; + + template + operator ::testing::Matcher() const { // NOLINT(runtime/explicit) + return ::testing::Matcher(new + typename Derived::template gmock_Impl()); + } +}; + +// Template specialization for Matcher with parameters. +template