From 528761b180b217e0ccc4d7f4acf3a951ba3e4feb Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Mon, 2 Jan 2023 17:30:54 +0000 Subject: [PATCH 1/3] Unit test nullptr C-style strings Added unit tests for the cases of matching and serializing C-style strings (char*) that are nullptr. (As of this revision, these new tests correctly fail, except for the test of mock::equal; fix to follow.) --- test/test_constraints.cpp | 9 +++++++++ test/test_log.cpp | 8 ++++++++ test/test_matcher.cpp | 10 +++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test/test_constraints.cpp b/test/test_constraints.cpp index 11c43fd..92157df 100644 --- a/test/test_constraints.cpp +++ b/test/test_constraints.cpp @@ -80,6 +80,15 @@ BOOST_AUTO_TEST_CASE(equal_constraint_deref) } } +BOOST_AUTO_TEST_CASE(equal_null_c_string) +{ + const char* const null_str = nullptr; + + BOOST_CHECK(mock::equal(null_str).c_(null_str)); + BOOST_CHECK(!mock::equal(null_str).c_("non-null string")); + BOOST_CHECK(!mock::equal("non-null-string").c_(null_str)); +} + BOOST_AUTO_TEST_CASE(same_constraint) { { diff --git a/test/test_log.cpp b/test/test_log.cpp index c26d3bb..4c321fe 100644 --- a/test/test_log.cpp +++ b/test/test_log.cpp @@ -89,6 +89,14 @@ BOOST_AUTO_TEST_CASE(strings_are_serialized_with_double_quotes) BOOST_CHECK_EQUAL("\"string\"", to_string(std::string("string"))); } +BOOST_AUTO_TEST_CASE(null_c_strings_are_serialized_to_nullptr) +{ + const char* const null_str = nullptr; + BOOST_CHECK_EQUAL("nullptr", to_string(null_str)); + // Note the lack of double quotes in the output, as opposed to when the + // string "nullptr" is serialized. +} + namespace { struct non_serializable {}; diff --git a/test/test_matcher.cpp b/test/test_matcher.cpp index cc98be0..f7292b8 100644 --- a/test/test_matcher.cpp +++ b/test/test_matcher.cpp @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(ref_to_int_and_int_can_be_compared) namespace { struct fixture { - fixture() : text("same text"), actual(text.c_str()) + fixture() : text("same text"), actual(text.c_str()), null_str(nullptr) { const char* static_string = "same text"; BOOST_REQUIRE(actual != static_string); @@ -44,6 +44,7 @@ struct fixture } std::string text; const char* actual; + const char* null_str; }; } // namespace @@ -75,6 +76,13 @@ BOOST_FIXTURE_TEST_CASE(const_char_pointer_and_std_string_can_be_compared, fixtu BOOST_CHECK(!match(std::string("different text"), actual)); } +BOOST_FIXTURE_TEST_CASE(null_const_char_pointers_can_be_compared, fixture) +{ + BOOST_CHECK(match(null_str, null_str)); + BOOST_CHECK(!match(null_str, "non-null string")); + BOOST_CHECK(!match("non-null string", null_str)); +} + namespace { template std::string serialize(const T& t) From dd7340e5f75f60deeb1ce37b35440a111664fb68 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Mon, 2 Jan 2023 17:38:26 +0000 Subject: [PATCH 2/3] Avoid dereferencing nullptr C-style strings Added runtime checks for C-style strings (char*) being nullptr during matching and serialization. This fix prevents nullptr dereferences in the case that the null character pointer (as opposed to the null nullptr_t) is expected and in the case that a non-null string is expected but nullptr is actually passed. --- include/turtle/matcher.hpp | 7 ++++++- include/turtle/stream.hpp | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/turtle/matcher.hpp b/include/turtle/matcher.hpp index 7854d77..fc20a22 100644 --- a/include/turtle/matcher.hpp +++ b/include/turtle/matcher.hpp @@ -39,7 +39,12 @@ class matcher { public: explicit matcher(const char* expected) : expected_(expected) {} - bool operator()(const char* actual) { return std::strcmp(actual, expected_) == 0; } + bool operator()(const char* actual) + { + if (nullptr == actual || nullptr == expected_) + return actual == expected_; + return std::strcmp(actual, expected_) == 0; + } friend std::ostream& operator<<(std::ostream& s, const matcher& m) { return s << mock::format(m.expected_); } private: diff --git a/include/turtle/stream.hpp b/include/turtle/stream.hpp index 52991ed..e3bf273 100644 --- a/include/turtle/stream.hpp +++ b/include/turtle/stream.hpp @@ -106,7 +106,13 @@ namespace detail { { s << '"' << str << '"'; } - inline void serialize(stream& s, const char* const str) { s << '"' << str << '"'; } + inline void serialize(stream& s, const char* const str) + { + if (nullptr != str) + s << '"' << str << '"'; + else + s << "nullptr"; + } inline void serialize(stream& s, unsigned char c) { s << static_cast(c); } } // namespace detail } // namespace mock From e55342385ec812971bbe4cdb6903e3ee53f38278 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Tue, 3 Jan 2023 16:28:27 +0000 Subject: [PATCH 3/3] Review corrections Corrected stylistic mistakes and simplified a couple of the new tests. --- include/turtle/matcher.hpp | 2 +- include/turtle/stream.hpp | 2 +- test/test_log.cpp | 3 +-- test/test_matcher.cpp | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/turtle/matcher.hpp b/include/turtle/matcher.hpp index fc20a22..3bd9923 100644 --- a/include/turtle/matcher.hpp +++ b/include/turtle/matcher.hpp @@ -41,7 +41,7 @@ public: explicit matcher(const char* expected) : expected_(expected) {} bool operator()(const char* actual) { - if (nullptr == actual || nullptr == expected_) + if(!actual || !expected_) return actual == expected_; return std::strcmp(actual, expected_) == 0; } diff --git a/include/turtle/stream.hpp b/include/turtle/stream.hpp index e3bf273..979e6a7 100644 --- a/include/turtle/stream.hpp +++ b/include/turtle/stream.hpp @@ -108,7 +108,7 @@ namespace detail { } inline void serialize(stream& s, const char* const str) { - if (nullptr != str) + if(str) s << '"' << str << '"'; else s << "nullptr"; diff --git a/test/test_log.cpp b/test/test_log.cpp index 4c321fe..94db5c4 100644 --- a/test/test_log.cpp +++ b/test/test_log.cpp @@ -93,8 +93,7 @@ BOOST_AUTO_TEST_CASE(null_c_strings_are_serialized_to_nullptr) { const char* const null_str = nullptr; BOOST_CHECK_EQUAL("nullptr", to_string(null_str)); - // Note the lack of double quotes in the output, as opposed to when the - // string "nullptr" is serialized. + BOOST_CHECK_EQUAL("\"nullptr\"", to_string("nullptr")); } namespace { diff --git a/test/test_matcher.cpp b/test/test_matcher.cpp index f7292b8..547ecaa 100644 --- a/test/test_matcher.cpp +++ b/test/test_matcher.cpp @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(ref_to_int_and_int_can_be_compared) namespace { struct fixture { - fixture() : text("same text"), actual(text.c_str()), null_str(nullptr) + fixture() : text("same text"), actual(text.c_str()) { const char* static_string = "same text"; BOOST_REQUIRE(actual != static_string); @@ -44,7 +44,6 @@ struct fixture } std::string text; const char* actual; - const char* null_str; }; } // namespace @@ -76,8 +75,9 @@ BOOST_FIXTURE_TEST_CASE(const_char_pointer_and_std_string_can_be_compared, fixtu BOOST_CHECK(!match(std::string("different text"), actual)); } -BOOST_FIXTURE_TEST_CASE(null_const_char_pointers_can_be_compared, fixture) +BOOST_AUTO_TEST_CASE(null_const_char_pointers_can_be_compared) { + const char* const null_str = nullptr; BOOST_CHECK(match(null_str, null_str)); BOOST_CHECK(!match(null_str, "non-null string")); BOOST_CHECK(!match("non-null string", null_str));