aboutsummaryrefslogtreecommitdiff
path: root/pw_unit_test
diff options
context:
space:
mode:
authorCarlos Chinchilla <cachinchilla@google.com>2023-11-06 20:11:31 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-11-06 20:11:31 +0000
commitf84b844862813d4989e0ca5f5968912b6bae2b3e (patch)
tree7e33f0ab844e8a0fa83aedbf1f1685ab5eeaa272 /pw_unit_test
parenta565608495205e2a7b095e275a26586b38cadef6 (diff)
downloadpigweed-f84b844862813d4989e0ca5f5968912b6bae2b3e.tar.gz
pw_unit_test: Add googletest test matchers
Add pw::Status test matchers for googletest to make it easy to test the status expectation when using googletest. Change-Id: Idd55560f565a67a5616113e737b66f832da65439 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/177878 Commit-Queue: Carlos Chinchilla <cachinchilla@google.com> Pigweed-Auto-Submit: Carlos Chinchilla <cachinchilla@google.com> Reviewed-by: Taylor Cramer <cramertj@google.com>
Diffstat (limited to 'pw_unit_test')
-rw-r--r--pw_unit_test/BUILD.bazel22
-rw-r--r--pw_unit_test/BUILD.gn19
-rw-r--r--pw_unit_test/CMakeLists.txt21
-rw-r--r--pw_unit_test/docs.rst4
-rw-r--r--pw_unit_test/googletest_test_matchers_test.cc144
-rw-r--r--pw_unit_test/public/pw_unit_test/googletest_test_matchers.h108
6 files changed, 317 insertions, 1 deletions
diff --git a/pw_unit_test/BUILD.bazel b/pw_unit_test/BUILD.bazel
index c4e5e5f4c..c67672f42 100644
--- a/pw_unit_test/BUILD.bazel
+++ b/pw_unit_test/BUILD.bazel
@@ -105,6 +105,28 @@ pw_cc_library(
)
pw_cc_library(
+ name = "googletest_test_matchers",
+ hdrs = ["public/pw_unit_test/googletest_test_matchers.h"],
+ includes = ["public"],
+ deps = [
+ "//pw_result",
+ "//pw_status",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+pw_cc_test(
+ name = "googletest_test_matchers_test",
+ srcs = ["googletest_test_matchers_test.cc"],
+ target_compatible_with = select({
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ deps = [
+ ":googletest_test_matchers",
+ ],
+)
+
+pw_cc_library(
name = "simple_printing_event_handler",
srcs = ["simple_printing_event_handler.cc"],
hdrs = [
diff --git a/pw_unit_test/BUILD.gn b/pw_unit_test/BUILD.gn
index ba516e113..714acec38 100644
--- a/pw_unit_test/BUILD.gn
+++ b/pw_unit_test/BUILD.gn
@@ -116,6 +116,22 @@ pw_source_set("googletest_handler_adapter") {
sources = [ "googletest_handler_adapter.cc" ]
}
+pw_source_set("googletest_test_matchers") {
+ public_configs = [ ":public_include_path" ]
+ public = [ "public/pw_unit_test/googletest_test_matchers.h" ]
+ public_deps = [
+ "$dir_pw_third_party/googletest",
+ dir_pw_result,
+ dir_pw_status,
+ ]
+}
+
+pw_test("googletest_test_matchers_test") {
+ enable_if = pw_unit_test_GOOGLETEST_BACKEND != ""
+ sources = [ "googletest_test_matchers_test.cc" ]
+ deps = [ ":googletest_test_matchers" ]
+}
+
# Library providing an event handler which outputs human-readable text.
pw_source_set("simple_printing_event_handler") {
public_deps = [
@@ -311,4 +327,7 @@ pw_test_group("tests") {
":framework_test",
":static_library_support_test",
]
+ if (dir_pw_third_party_googletest != "") {
+ tests += [ ":googletest_test_matchers_test" ]
+ }
}
diff --git a/pw_unit_test/CMakeLists.txt b/pw_unit_test/CMakeLists.txt
index f66f9dfdc..6892f46d0 100644
--- a/pw_unit_test/CMakeLists.txt
+++ b/pw_unit_test/CMakeLists.txt
@@ -74,6 +74,27 @@ pw_add_library(pw_unit_test.googletest_style_event_handler STATIC
googletest_style_event_handler.cc
)
+if(NOT ${pw_unit_test_GOOGLETEST_BACKEND} STREQUAL "")
+ pw_add_library(pw_unit_test.googletest_test_matchers INTERFACE
+ HEADERS
+ public/pw_unit_test/googletest_test_matchers.h
+ PUBLIC_INCLUDES
+ public
+ PUBLIC_DEPS
+ pw_result
+ pw_status
+ ${pw_unit_test_GOOGLETEST_BACKEND}
+ )
+ pw_add_test(pw_unit_test.googletest_test_matchers_test
+ SOURCES
+ googletest_test_matchers_test.cc
+ PRIVATE_DEPS
+ pw_unit_test.googletest_test_matchers
+ GROUPS
+ pw_unit_test
+ )
+endif()
+
pw_add_library(pw_unit_test.simple_printing_main STATIC
SOURCES
simple_printing_main.cc
diff --git a/pw_unit_test/docs.rst b/pw_unit_test/docs.rst
index e1dd9cc8a..0f89e76b5 100644
--- a/pw_unit_test/docs.rst
+++ b/pw_unit_test/docs.rst
@@ -38,7 +38,9 @@ GoogleTest compatibility
pw_unit_test implements a subset of GoogleTest. Supported features include:
* Test and test suite declarations.
-* Most ``EXPECT`` and ``ASSERT`` macros.
+* Most ``EXPECT`` and ``ASSERT`` macros, including ``EXPECT_OK`` and
+ ``ASSERT_OK`` for functions returning a status.
+* ``StatusIs`` matcher to expect a specific ``pw::Status`` other that `OK`.
* Stream-style expectation messages, such as
``EXPECT_EQ(val, 5) << "Inputs: " << input``. Messages are currently ignored.
diff --git a/pw_unit_test/googletest_test_matchers_test.cc b/pw_unit_test/googletest_test_matchers_test.cc
new file mode 100644
index 000000000..c7f8fde3e
--- /dev/null
+++ b/pw_unit_test/googletest_test_matchers_test.cc
@@ -0,0 +1,144 @@
+// Copyright 2023 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/googletest_test_matchers.h"
+
+#include <cstdlib>
+
+#include "pw_status/status.h"
+
+namespace pw::unit_test {
+namespace {
+
+TEST(TestMatchers, AssertOk) { ASSERT_OK(OkStatus()); }
+TEST(TestMatchers, AssertOkStatusWithSize) { ASSERT_OK(StatusWithSize(123)); }
+TEST(TestMatchers, AssertOkResult) { ASSERT_OK(Result<int>(123)); }
+
+TEST(TestMatchers, ExpectOk) { EXPECT_OK(OkStatus()); }
+TEST(TestMatchers, ExpectOkStatusWithSize) { EXPECT_OK(StatusWithSize(123)); }
+TEST(TestMatchers, ExpectOkResult) { EXPECT_OK(Result<int>(123)); }
+
+TEST(TestMatchers, StatusIsSuccess) {
+ EXPECT_THAT(OkStatus(), StatusIs(OkStatus()));
+ EXPECT_THAT(Status::Cancelled(), StatusIs(Status::Cancelled()));
+ EXPECT_THAT(Status::Unknown(), StatusIs(Status::Unknown()));
+ EXPECT_THAT(Status::InvalidArgument(), StatusIs(Status::InvalidArgument()));
+ EXPECT_THAT(Status::DeadlineExceeded(), StatusIs(Status::DeadlineExceeded()));
+ EXPECT_THAT(Status::NotFound(), StatusIs(Status::NotFound()));
+ EXPECT_THAT(Status::AlreadyExists(), StatusIs(Status::AlreadyExists()));
+ EXPECT_THAT(Status::PermissionDenied(), StatusIs(Status::PermissionDenied()));
+ EXPECT_THAT(Status::ResourceExhausted(),
+ StatusIs(Status::ResourceExhausted()));
+ EXPECT_THAT(Status::FailedPrecondition(),
+ StatusIs(Status::FailedPrecondition()));
+ EXPECT_THAT(Status::Aborted(), StatusIs(Status::Aborted()));
+ EXPECT_THAT(Status::OutOfRange(), StatusIs(Status::OutOfRange()));
+ EXPECT_THAT(Status::Unimplemented(), StatusIs(Status::Unimplemented()));
+ EXPECT_THAT(Status::Internal(), StatusIs(Status::Internal()));
+ EXPECT_THAT(Status::Unavailable(), StatusIs(Status::Unavailable()));
+ EXPECT_THAT(Status::DataLoss(), StatusIs(Status::DataLoss()));
+ EXPECT_THAT(Status::Unauthenticated(), StatusIs(Status::Unauthenticated()));
+}
+
+TEST(TestMatchers, StatusIsSuccessStatusWithSize) {
+ EXPECT_THAT(StatusWithSize(), StatusIs(OkStatus()));
+ EXPECT_THAT(StatusWithSize::Cancelled(), StatusIs(Status::Cancelled()));
+ EXPECT_THAT(StatusWithSize::Unknown(), StatusIs(Status::Unknown()));
+ EXPECT_THAT(StatusWithSize::InvalidArgument(),
+ StatusIs(Status::InvalidArgument()));
+ EXPECT_THAT(StatusWithSize::DeadlineExceeded(),
+ StatusIs(Status::DeadlineExceeded()));
+ EXPECT_THAT(StatusWithSize::NotFound(), StatusIs(Status::NotFound()));
+ EXPECT_THAT(StatusWithSize::AlreadyExists(),
+ StatusIs(Status::AlreadyExists()));
+ EXPECT_THAT(StatusWithSize::PermissionDenied(),
+ StatusIs(Status::PermissionDenied()));
+ EXPECT_THAT(StatusWithSize::ResourceExhausted(),
+ StatusIs(Status::ResourceExhausted()));
+ EXPECT_THAT(StatusWithSize::FailedPrecondition(),
+ StatusIs(Status::FailedPrecondition()));
+ EXPECT_THAT(StatusWithSize::Aborted(), StatusIs(Status::Aborted()));
+ EXPECT_THAT(StatusWithSize::OutOfRange(), StatusIs(Status::OutOfRange()));
+ EXPECT_THAT(StatusWithSize::Unimplemented(),
+ StatusIs(Status::Unimplemented()));
+ EXPECT_THAT(StatusWithSize::Internal(), StatusIs(Status::Internal()));
+ EXPECT_THAT(StatusWithSize::Unavailable(), StatusIs(Status::Unavailable()));
+ EXPECT_THAT(StatusWithSize::DataLoss(), StatusIs(Status::DataLoss()));
+ EXPECT_THAT(StatusWithSize::Unauthenticated(),
+ StatusIs(Status::Unauthenticated()));
+}
+
+TEST(TestMatchers, StatusIsSuccessOkResult) {
+ const Result<int> result = 46;
+ EXPECT_THAT(result, StatusIs(OkStatus()));
+}
+
+TEST(TestMatchers, StatusIsSuccessResult) {
+ EXPECT_THAT(Result<int>(Status::Cancelled()), StatusIs(Status::Cancelled()));
+ EXPECT_THAT(Result<int>(Status::Unknown()), StatusIs(Status::Unknown()));
+ EXPECT_THAT(Result<int>(Status::InvalidArgument()),
+ StatusIs(Status::InvalidArgument()));
+ EXPECT_THAT(Result<int>(Status::DeadlineExceeded()),
+ StatusIs(Status::DeadlineExceeded()));
+ EXPECT_THAT(Result<int>(Status::NotFound()), StatusIs(Status::NotFound()));
+ EXPECT_THAT(Result<int>(Status::AlreadyExists()),
+ StatusIs(Status::AlreadyExists()));
+ EXPECT_THAT(Result<int>(Status::PermissionDenied()),
+ StatusIs(Status::PermissionDenied()));
+ EXPECT_THAT(Result<int>(Status::ResourceExhausted()),
+ StatusIs(Status::ResourceExhausted()));
+ EXPECT_THAT(Result<int>(Status::FailedPrecondition()),
+ StatusIs(Status::FailedPrecondition()));
+ EXPECT_THAT(Result<int>(Status::Aborted()), StatusIs(Status::Aborted()));
+ EXPECT_THAT(Result<int>(Status::OutOfRange()),
+ StatusIs(Status::OutOfRange()));
+ EXPECT_THAT(Result<int>(Status::Unimplemented()),
+ StatusIs(Status::Unimplemented()));
+ EXPECT_THAT(Result<int>(Status::Internal()), StatusIs(Status::Internal()));
+ EXPECT_THAT(Result<int>(Status::Unavailable()),
+ StatusIs(Status::Unavailable()));
+ EXPECT_THAT(Result<int>(Status::DataLoss()), StatusIs(Status::DataLoss()));
+ EXPECT_THAT(Result<int>(Status::Unauthenticated()),
+ StatusIs(Status::Unauthenticated()));
+}
+
+// The following test is commented out and is only for checking what
+// failure cases would look like. For example, when uncommenting the test,
+// the output is:
+//
+// ERR pw_unit_test/googletest_test_matchers_test.cc:50: Failure
+// ERR Expected:
+// ERR Actual: Value of: OkStatus()
+// Expected: has status UNKNOWN
+// Actual: 4-byte object <00-00 00-00>, which has status OK
+
+// ERR pw_unit_test/googletest_test_matchers_test.cc:51: Failure
+// ERR Expected:
+// ERR Actual: Value of: Status::Unknown()
+// Expected: is OK
+// Actual: 4-byte object <02-00 00-00>, which has status UNKNOWN
+
+// ERR pw_unit_test/googletest_test_matchers_test.cc:52: Failure
+// ERR Expected:
+// ERR Actual: Value of: Status::Unknown()
+// Expected: is OK
+// Actual: 4-byte object <02-00 00-00>, which has status UNKNOWN
+//
+// TEST(TestMatchers, SampleFailures) {
+// EXPECT_THAT(OkStatus(), StatusIs(Status::Unknown()));
+// EXPECT_OK(Status::Unknown());
+// ASSERT_OK(Status::Unknown());
+// }
+
+} // namespace
+} // namespace pw::unit_test \ No newline at end of file
diff --git a/pw_unit_test/public/pw_unit_test/googletest_test_matchers.h b/pw_unit_test/public/pw_unit_test/googletest_test_matchers.h
new file mode 100644
index 000000000..bb912c389
--- /dev/null
+++ b/pw_unit_test/public/pw_unit_test/googletest_test_matchers.h
@@ -0,0 +1,108 @@
+// Copyright 2023 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.
+#pragma once
+
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "pw_result/result.h"
+#include "pw_status/status.h"
+#include "pw_status/status_with_size.h"
+
+namespace pw::unit_test {
+namespace internal {
+// Gets the pw::Status of different types of objects with a pw::Status for
+// Matchers that check the status.
+inline constexpr Status GetStatus(Status status) { return status; }
+
+inline constexpr Status GetStatus(StatusWithSize status_with_size) {
+ return status_with_size.status();
+}
+
+template <typename T>
+inline constexpr Status GetStatus(const Result<T>& result) {
+ return result.status();
+}
+
+// Implements IsOk().
+class IsOkMatcher {
+ public:
+ using is_gtest_matcher = void;
+
+ void DescribeTo(std::ostream* os) const { *os << "is OK"; }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "isn't OK"; }
+
+ template <typename T>
+ bool MatchAndExplain(T&& actual_value,
+ ::testing::MatchResultListener* listener) const {
+ const auto status = GetStatus(actual_value);
+ if (!status.ok()) {
+ *listener << "which has status " << pw_StatusString(status);
+ return false;
+ }
+ return true;
+ }
+};
+
+// Implements StatusIs().
+class StatusIsMatcher {
+ public:
+ explicit StatusIsMatcher(Status expected_status)
+ : expected_status_(expected_status) {}
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "has status " << pw_StatusString(expected_status_);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "does not have status " << pw_StatusString(expected_status_);
+ }
+
+ template <typename T>
+ bool MatchAndExplain(T&& actual_value,
+ ::testing::MatchResultListener* listener) const {
+ const auto status = GetStatus(actual_value);
+ if (status != expected_status_) {
+ *listener << "which has status " << pw_StatusString(status);
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ const Status expected_status_;
+};
+
+} // namespace internal
+
+/// Macros for testing the results of functions that return ``pw::Status``,
+/// ``pw::StatusWithSize``, or ``pw::Result<T>`` (for any T).
+#define EXPECT_OK(expression) EXPECT_THAT(expression, ::pw::unit_test::IsOk())
+#define ASSERT_OK(expression) ASSERT_THAT(expression, ::pw::unit_test::IsOk())
+
+/// Returns a gMock matcher that matches a `pw::Status`, `pw::StatusWithSize`,
+/// or `pw::Result<T>` (for any T) which is OK.
+inline internal::IsOkMatcher IsOk() { return {}; }
+
+/// Returns a gMock matcher that matches a `pw::Status`, `pw::StatusWithSize`,
+/// or `pw::Result<T>` (for any T) which has the given status.
+inline auto StatusIs(Status expected_status) {
+ return ::testing::MakePolymorphicMatcher(
+ internal::StatusIsMatcher(expected_status));
+}
+
+} // namespace pw::unit_test \ No newline at end of file