// Copyright 2019 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_unit_test/framework.h" #include #include "pw_assert/check.h" #include "pw_result/result.h" #include "pw_status/status.h" #include "pw_status/status_with_size.h" namespace pw { namespace { TEST(PigweedTest, ExpectBool) { EXPECT_TRUE(true); EXPECT_FALSE(false); EXPECT_TRUE(1); EXPECT_TRUE(1203492); EXPECT_TRUE(-1); EXPECT_TRUE(0.1f); EXPECT_FALSE(0); EXPECT_FALSE(0.0f); EXPECT_FALSE(-0.0f); } TEST(PigweedTest, ExpectBasicComparisons) { EXPECT_EQ(1, 1 + 0); ASSERT_EQ(1, 1 + 0); EXPECT_EQ(0.0f, -0.0f); ASSERT_EQ(0.0f, -0.0f); EXPECT_NE(-1, 0); ASSERT_NE(-1, 0); EXPECT_GT(2, 1); ASSERT_GT(3, 0); EXPECT_GE(1, 1); ASSERT_GE(3, 0); EXPECT_LT(0, 1); ASSERT_LT(-2, 1209); EXPECT_LE(-1, 0); ASSERT_LE(-2, -2); } TEST(PigweedTest, ExpectNearComparisons) { EXPECT_NEAR(1, 2, 1); ASSERT_NEAR(1, 2, 1); EXPECT_NEAR(-5, 5, 10); ASSERT_NEAR(-5, 5, 10); int x = 17; int epsilon = 5; EXPECT_NEAR(x, 15, epsilon); ASSERT_NEAR(x, 15, epsilon); } TEST(PigweedTest, ExpectFloatComparisons) { EXPECT_FLOAT_EQ(5.0f, 10.0f / 2); ASSERT_FLOAT_EQ(5.0f, 10.0f / 2); EXPECT_FLOAT_EQ(-0.5f, -5.0f / 10); ASSERT_FLOAT_EQ(-0.5f, -5.0f / 10); float x = 17.0f / 20.0f; EXPECT_FLOAT_EQ(x, 17.0f / 20.0f); ASSERT_FLOAT_EQ(x, 17.0f / 20.0f); } TEST(PigweedTest, ExpectDoubleComparisons) { EXPECT_DOUBLE_EQ(5.0, 10.0 / 2); ASSERT_DOUBLE_EQ(5.0, 10.0 / 2); EXPECT_DOUBLE_EQ(-0.5, -5.0 / 10); ASSERT_DOUBLE_EQ(-0.5, -5.0 / 10); double x = 17.0 / 20.0; EXPECT_DOUBLE_EQ(x, 17.0 / 20.0); ASSERT_DOUBLE_EQ(x, 17.0 / 20.0); } TEST(PigweedTest, ExpectStringEquality) { EXPECT_STREQ("", ""); EXPECT_STREQ("Yes", "Yes"); char no[] = {'N', 'o', '\0'}; ASSERT_STREQ("No", no); EXPECT_STRNE("NO", "no"); ASSERT_STRNE("yes", no); const char* invalid_string = nullptr; EXPECT_STREQ(invalid_string, nullptr); EXPECT_STRNE("abc", nullptr); } TEST(PigweedTest, SucceedAndFailMacros) { SUCCEED(); // The ADD_FAILURE() and FAIL() macros cause a test to fail if they are // reached. Use them, but don't let them run so that this test still passes. if (false) { ADD_FAILURE(); FAIL(); } // Without braces, clang-tidy complains if these are multiple statements. if (false) ADD_FAILURE(); if (false) FAIL(); } TEST(PigweedTest, SkipMacro) { // Without a brace, clang-tidy complains if GTEST_SKIP is multiple statements. if (false) GTEST_SKIP(); GTEST_SKIP(); // This code should not run. EXPECT_TRUE(false); } TEST(PigweedTest, Logs) { EXPECT_TRUE(true) << "This message is ignored"; EXPECT_FALSE(false) << "This message is ignored"; EXPECT_EQ(0, 0) << "This message is ignored"; EXPECT_NE(0, 1) << "This message is ignored"; EXPECT_GT(1, 0) << "This message is ignored"; EXPECT_GE(0, 0) << "This message is ignored"; EXPECT_LT(0, 1) << "This message is ignored"; EXPECT_LE(0, 0) << "This message is ignored"; EXPECT_STREQ("", "") << "This message is ignored"; EXPECT_STRNE("", "?") << "This message is ignored"; ASSERT_TRUE(true) << "This message is ignored"; ASSERT_FALSE(false) << "This message is ignored"; ASSERT_EQ(0, 0) << "This message is ignored"; ASSERT_NE(0, 1) << "This message is ignored"; ASSERT_GT(1, 0) << "This message is ignored"; ASSERT_GE(0, 0) << "This message is ignored"; ASSERT_LT(0, 1) << "This message is ignored"; ASSERT_LE(0, 0) << "This message is ignored"; ASSERT_STREQ("", "") << "This message is ignored"; ASSERT_STRNE("", "?") << "This message is ignored"; if (false) { ADD_FAILURE() << "This failed!" << 123; GTEST_FAIL() << "This failed!" << 123 << '?'; GTEST_SKIP() << 1.0f << " skips!"; } GTEST_SUCCEED() << "This message is ignored"; } TEST(PigweedTest, PwOkMatchers) { PW_TEST_ASSERT_OK(OkStatus()); PW_TEST_ASSERT_OK(StatusWithSize(123)); PW_TEST_ASSERT_OK(Result(123)); PW_TEST_EXPECT_OK(OkStatus()); PW_TEST_EXPECT_OK(StatusWithSize(123)); PW_TEST_EXPECT_OK(Result(123)); PW_TEST_ASSERT_OK_AND_ASSIGN(auto val, Result(123)); EXPECT_EQ(val, 123); PW_TEST_ASSERT_OK_AND_ASSIGN(auto size, StatusWithSize(123U)); EXPECT_EQ(size, 123U); } TEST(AssertOkAndAssign, AssignsOkValueToNewLvalue) { const auto value = Result(5); PW_TEST_ASSERT_OK_AND_ASSIGN(int declare_and_assign, value); EXPECT_EQ(5, declare_and_assign); } TEST(AssertOkAndAssign, AssignsOkValueToExistingLvalue) { const auto value = Result(5); int existing_value = 0; PW_TEST_ASSERT_OK_AND_ASSIGN(existing_value, value); EXPECT_EQ(5, existing_value); } TEST(AssertOkAndAssign, AssignsExistingLvalueToConstReference) { const auto value = Result(5); PW_TEST_ASSERT_OK_AND_ASSIGN(const auto& ref, value); EXPECT_EQ(5, ref); } class CopyMoveCounter { public: CopyMoveCounter() = delete; CopyMoveCounter(int& copies, int& moves) : copies_(&copies), moves_(&moves) {} CopyMoveCounter(const CopyMoveCounter& other) : copies_(other.copies_), moves_(other.moves_) { ++(*copies_); } CopyMoveCounter(CopyMoveCounter&& other) : copies_(other.copies_), moves_(other.moves_) { ++(*moves_); } CopyMoveCounter& operator=(const CopyMoveCounter& other) { copies_ = other.copies_; moves_ = other.moves_; ++(*copies_); return *this; } CopyMoveCounter& operator=(CopyMoveCounter&& other) { copies_ = other.copies_; moves_ = other.moves_; ++(*moves_); return *this; } private: int* copies_; int* moves_; }; TEST(AssertOkAndAssign, OkRvalueDoesNotCopy) { int copies = 0; int moves = 0; PW_TEST_ASSERT_OK_AND_ASSIGN([[maybe_unused]] CopyMoveCounter cm, Result(CopyMoveCounter(copies, moves))); EXPECT_EQ(copies, 0); EXPECT_EQ(moves, 2); } TEST(AssertOkAndAssign, OkLvalueMovedDoesNotCopy) { int copies = 0; int moves = 0; Result result(CopyMoveCounter(copies, moves)); PW_TEST_ASSERT_OK_AND_ASSIGN([[maybe_unused]] CopyMoveCounter cm, std::move(result)); EXPECT_EQ(copies, 0); EXPECT_EQ(moves, 3); } TEST(AssertOkAndAssign, OkLvalueCopiesOnce) { int copies = 0; int moves = 0; Result result(CopyMoveCounter(copies, moves)); PW_TEST_ASSERT_OK_AND_ASSIGN([[maybe_unused]] CopyMoveCounter cm, result); EXPECT_EQ(copies, 1); EXPECT_EQ(moves, 2); } // The following test contents are disabled and is only for checking what // failure cases would look like. For example, when enabling the test, // the output is: // clang-format off // ERR pw_unit_test/framework_test.cc:294: Failure // ERR Expected: ::pw::internal::ConvertToStatus(Status::Unknown()) == pw::OkStatus() // ERR Actual: UNKNOWN == OK // ERR pw_unit_test/framework_test.cc:295: Failure // ERR Expected: ::pw::internal::ConvertToStatus(Status::Unknown()) == pw::OkStatus() // ERR Actual: UNKNOWN == OK // clang-format on TEST(TestMatchers, SampleFailures) { if (false) { PW_TEST_EXPECT_OK(Status::Unknown()); PW_TEST_ASSERT_OK(Status::Unknown()); } } class SkipOnSetUpTest : public ::testing::Test { public: void SetUp() override { GTEST_SKIP(); } }; TEST_F(SkipOnSetUpTest, FailTest) { // This code should not run because the test was skipped in SetUp(). EXPECT_TRUE(false); } class NonCopyable { public: NonCopyable(int value) : value_(value) {} NonCopyable(const NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; bool operator==(const NonCopyable& rhs) const { return value_ == rhs.value_; } bool operator!=(const NonCopyable& rhs) const { return value_ != rhs.value_; } operator bool() const { return value_ > 0; } private: const int value_; }; TEST(PigweedTest, NonCopyableType) { EXPECT_TRUE(NonCopyable(6)); EXPECT_FALSE(NonCopyable(-1)); const NonCopyable this_one(100); EXPECT_EQ(this_one, this_one); EXPECT_TRUE(this_one); EXPECT_EQ(NonCopyable(5), NonCopyable(5)); EXPECT_NE(NonCopyable(5), NonCopyable(6)); } bool Increment(int* i) { (*i)++; return true; } TEST(PigweedTest, MacroArgumentsOnlyAreEvaluatedOnce) { int i = 1; EXPECT_TRUE(Increment(&i)); EXPECT_EQ(i, 2); ASSERT_TRUE(Increment(&i)); EXPECT_EQ(i, 3); EXPECT_EQ(0x600dbeef, [&i]() { i += 1; return 0x600dbeef; }()); EXPECT_EQ(i, 4); } class ClassWithPrivateMethod { FRIEND_TEST(FixtureTest, FriendClass); private: int Return314() { return 314; } }; class FixtureTest : public ::testing::Test { public: FixtureTest() : string_("hello world") {} bool ReturnTrue() { return true; } int StringLength() { return std::strlen(string_); } protected: const char* string_; }; TEST_F(FixtureTest, CustomFixture) { EXPECT_TRUE(ReturnTrue()); EXPECT_EQ(StringLength(), 11); } TEST_F(FixtureTest, FriendClass) { EXPECT_EQ(ClassWithPrivateMethod().Return314(), 314); } class PigweedTestFixture : public ::testing::Test { protected: PigweedTestFixture() : cool_number_(35) {} int cool_number_; }; TEST_F(PigweedTestFixture, TheNumberIs35) { EXPECT_EQ(cool_number_, 35); cool_number_ += 1; EXPECT_EQ(cool_number_, 36); } TEST_F(PigweedTestFixture, YupTheNumberIs35) { EXPECT_EQ(cool_number_, 35); cool_number_ *= 100; EXPECT_EQ(cool_number_, 3500); } class Expectations : public ::testing::Test { protected: Expectations() : cool_number_(3) { PW_CHECK_INT_EQ(cool_number_, 3); } ~Expectations() override { PW_CHECK_INT_EQ(cool_number_, 14159); } int cool_number_; }; TEST_F(Expectations, SetCoolNumber) { cool_number_ = 14159; } class SetUpAndTearDown : public ::testing::Test { public: static int value; static void SetUpTestSuite() { value = 1; EXPECT_EQ(value, 1); value++; } static void TearDownTestSuite() { EXPECT_EQ(value, 7); value++; } protected: SetUpAndTearDown() { EXPECT_EQ(value, 2); value++; } ~SetUpAndTearDown() override { EXPECT_EQ(value, 6); value++; } void SetUp() override { EXPECT_EQ(value, 3); value++; } void TearDown() override { EXPECT_EQ(value, 5); value++; } }; int SetUpAndTearDown::value = 1; TEST_F(SetUpAndTearDown, MakeSureItIsSet) { EXPECT_EQ(value, 4); value++; } TEST(TestSuiteTearDown, MakeSureItRan) { EXPECT_EQ(SetUpAndTearDown::value, 8); } class Interleaved : public ::testing::Test { public: static void SetUpTestSuite() { suites_running++; } static void TearDownTestSuite() { suites_running--; } protected: static int suites_running; }; int Interleaved::suites_running = 0; class InterleavedA : public Interleaved {}; class InterleavedB : public Interleaved {}; TEST_F(InterleavedA, Test1) { ASSERT_EQ(suites_running, 1); } TEST_F(InterleavedB, Test1) { ASSERT_EQ(suites_running, 1); } TEST_F(Interleaved, Test12) { ASSERT_EQ(suites_running, 1); } TEST_F(InterleavedB, Test2) { ASSERT_EQ(suites_running, 1); } TEST_F(InterleavedA, Test2) { ASSERT_EQ(suites_running, 1); } } // namespace } // namespace pw