pw_digital_io_linux: Add test_utils.h for ASSERT_OK and friends

This is temporary until b/338094795 officially adds these to the light
testing framework.

Change-Id: Ia35e2dfd3f023795635f41e733c19e099603471f
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/209592
Reviewed-by: Erik Gilling <konkers@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Jonathon Reinhart <jrreinhart@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
diff --git a/pw_digital_io_linux/BUILD.bazel b/pw_digital_io_linux/BUILD.bazel
index 78bf76b..e6c025b 100644
--- a/pw_digital_io_linux/BUILD.bazel
+++ b/pw_digital_io_linux/BUILD.bazel
@@ -62,7 +62,10 @@
 
 pw_cc_test(
     name = "digital_io_test",
-    srcs = ["digital_io_test.cc"],
+    srcs = [
+        "digital_io_test.cc",
+        "test_utils.h",
+    ],
     linkopts = [
         "-Wl,--wrap=close",
         "-Wl,--wrap=ioctl",
diff --git a/pw_digital_io_linux/BUILD.gn b/pw_digital_io_linux/BUILD.gn
index 12f6e8c..cc2f5cd 100644
--- a/pw_digital_io_linux/BUILD.gn
+++ b/pw_digital_io_linux/BUILD.gn
@@ -58,7 +58,10 @@
 
 pw_test("digital_io_test") {
   enable_if = current_os == "linux"
-  sources = [ "digital_io_test.cc" ]
+  sources = [
+    "digital_io_test.cc",
+    "test_utils.h",
+  ]
   deps = [
     ":mock_vfs",
     ":pw_digital_io_linux",
diff --git a/pw_digital_io_linux/digital_io_test.cc b/pw_digital_io_linux/digital_io_test.cc
index 192fed5..7f8c6a1 100644
--- a/pw_digital_io_linux/digital_io_test.cc
+++ b/pw_digital_io_linux/digital_io_test.cc
@@ -25,6 +25,7 @@
 #include "pw_log/log.h"
 #include "pw_result/result.h"
 #include "pw_unit_test/framework.h"
+#include "test_utils.h"
 
 namespace pw::digital_io {
 namespace {
@@ -265,13 +266,11 @@
       /* index= */ 0,
       /* polarity= */ Polarity::kActiveHigh);
 
-  auto input_result = chip.GetInputLine(config);
-  ASSERT_EQ(OkStatus(), input_result.status());
-  auto input = std::move(input_result.value());
+  ASSERT_OK_AND_ASSIGN(auto input, chip.GetInputLine(config));
 
   // Enable the input, and ensure it is requested.
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
-  ASSERT_EQ(OkStatus(), input.Enable());
+  ASSERT_OK(input.Enable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kInput);
 
   Result<State> state;
@@ -279,17 +278,17 @@
   // Force the line high and assert it is seen as active (active high).
   line.ForcePhysicalState(true);
   state = input.GetState();
-  ASSERT_EQ(OkStatus(), state.status());
+  ASSERT_OK(state.status());
   ASSERT_EQ(State::kActive, state.value());
 
   // Force the line low and assert it is seen as inactive (active high).
   line.ForcePhysicalState(false);
   state = input.GetState();
-  ASSERT_EQ(OkStatus(), state.status());
+  ASSERT_OK(state.status());
   ASSERT_EQ(State::kInactive, state.value());
 
   // Disable the line and ensure it is no longer requested.
-  ASSERT_EQ(OkStatus(), input.Disable());
+  ASSERT_OK(input.Disable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
 }
 
@@ -301,13 +300,11 @@
       /* index= */ 0,
       /* polarity= */ Polarity::kActiveLow);
 
-  auto input_result = chip.GetInputLine(config);
-  ASSERT_EQ(OkStatus(), input_result.status());
-  auto input = std::move(input_result.value());
+  ASSERT_OK_AND_ASSIGN(auto input, chip.GetInputLine(config));
 
   // Enable the input, and ensure it is requested.
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
-  ASSERT_EQ(OkStatus(), input.Enable());
+  ASSERT_OK(input.Enable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kInput);
 
   Result<State> state;
@@ -315,17 +312,17 @@
   // Force the line high and assert it is seen as inactive (active low).
   line.ForcePhysicalState(true);
   state = input.GetState();
-  ASSERT_EQ(OkStatus(), state.status());
+  ASSERT_OK(state.status());
   ASSERT_EQ(State::kInactive, state.value());
 
   // Force the line low and assert it is seen as active (active low).
   line.ForcePhysicalState(false);
   state = input.GetState();
-  ASSERT_EQ(OkStatus(), state.status());
+  ASSERT_OK(state.status());
   ASSERT_EQ(State::kActive, state.value());
 
   // Disable the line and ensure it is no longer requested.
-  ASSERT_EQ(OkStatus(), input.Disable());
+  ASSERT_OK(input.Disable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
 }
 
@@ -338,28 +335,26 @@
       /* polarity= */ Polarity::kActiveHigh,
       /* default_state= */ State::kActive);
 
-  auto output_result = chip.GetOutputLine(config);
-  ASSERT_EQ(OkStatus(), output_result.status());
-  auto output = std::move(output_result.value());
+  ASSERT_OK_AND_ASSIGN(auto output, chip.GetOutputLine(config));
 
   // Enable the output, and ensure it is requested.
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
-  ASSERT_EQ(OkStatus(), output.Enable());
+  ASSERT_OK(output.Enable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kOutput);
 
   // Expect the line to go high, due to default_state=kActive (active high).
   ASSERT_TRUE(line.physical_state());
 
   // Set the output's state to inactive, and assert it goes low (active high).
-  ASSERT_EQ(OkStatus(), output.SetStateInactive());
+  ASSERT_OK(output.SetStateInactive());
   ASSERT_FALSE(line.physical_state());
 
   // Set the output's state to active, and assert it goes high (active high).
-  ASSERT_EQ(OkStatus(), output.SetStateActive());
+  ASSERT_OK(output.SetStateActive());
   ASSERT_TRUE(line.physical_state());
 
   // Disable the line and ensure it is no longer requested.
-  ASSERT_EQ(OkStatus(), output.Disable());
+  ASSERT_OK(output.Disable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
   // NOTE: We do not assert line.physical_state() here.
   // See the warning on LinuxDigitalOut in docs.rst.
@@ -374,28 +369,26 @@
       /* polarity= */ Polarity::kActiveLow,
       /* default_state= */ State::kActive);
 
-  auto output_result = chip.GetOutputLine(config);
-  ASSERT_EQ(OkStatus(), output_result.status());
-  auto output = std::move(output_result.value());
+  ASSERT_OK_AND_ASSIGN(auto output, chip.GetOutputLine(config));
 
   // Enable the output, and ensure it is requested.
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
-  ASSERT_EQ(OkStatus(), output.Enable());
+  ASSERT_OK(output.Enable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kOutput);
 
   // Expect the line to stay low, due to default_state=kActive (active low).
   ASSERT_FALSE(line.physical_state());
 
   // Set the output's state to inactive, and assert it goes high (active low).
-  ASSERT_EQ(OkStatus(), output.SetStateInactive());
+  ASSERT_OK(output.SetStateInactive());
   ASSERT_TRUE(line.physical_state());
 
   // Set the output's state to active, and assert it goes low (active low).
-  ASSERT_EQ(OkStatus(), output.SetStateActive());
+  ASSERT_OK(output.SetStateActive());
   ASSERT_FALSE(line.physical_state());
 
   // Disable the line and ensure it is no longer requested.
-  ASSERT_EQ(OkStatus(), output.Disable());
+  ASSERT_OK(output.Disable());
   ASSERT_EQ(line.requested(), Line::RequestedState::kNone);
   // NOTE: We do not assert line.physical_state() here.
   // See the warning on LinuxDigitalOut in docs.rst.
@@ -411,11 +404,9 @@
       /* polarity= */ Polarity::kActiveHigh,
       /* default_state= */ State::kInactive);
 
-  auto output_result = chip.GetOutputLine(config);
-  ASSERT_EQ(OkStatus(), output_result.status());
-  auto output = std::move(output_result.value());
+  ASSERT_OK_AND_ASSIGN(auto output, chip.GetOutputLine(config));
 
-  ASSERT_EQ(OkStatus(), output.Enable());
+  ASSERT_OK(output.Enable());
 
   // Expect the line to stay low, due to default_state=kInactive (active high).
   ASSERT_FALSE(line.physical_state());
@@ -424,14 +415,14 @@
 
   // Verify GetState() returns the expected state: inactive (default_state).
   state = output.GetState();
-  ASSERT_EQ(OkStatus(), state.status());
+  ASSERT_OK(state.status());
   ASSERT_EQ(State::kInactive, state.value());
 
   // Set the output's state to active, then verify GetState() returns the
   // new expected state.
-  ASSERT_EQ(OkStatus(), output.SetStateActive());
+  ASSERT_OK(output.SetStateActive());
   state = output.GetState();
-  ASSERT_EQ(OkStatus(), state.status());
+  ASSERT_OK(state.status());
   ASSERT_EQ(State::kActive, state.value());
 }
 
diff --git a/pw_digital_io_linux/test_utils.h b/pw_digital_io_linux/test_utils.h
new file mode 100644
index 0000000..57d9b14
--- /dev/null
+++ b/pw_digital_io_linux/test_utils.h
@@ -0,0 +1,46 @@
+// Copyright 2024 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 "pw_result/result.h"
+#include "pw_status/status.h"
+#include "pw_unit_test/framework.h"
+
+// TODO(b/338094795): Remove when these are available in the light framework.
+
+#ifndef ASSERT_OK
+#define ASSERT_OK(expr) ASSERT_EQ(expr, pw::OkStatus())
+#endif  // ASSERT_OK
+
+#ifndef EXPECT_OK
+#define EXPECT_OK(expr) EXPECT_EQ(expr, pw::OkStatus())
+#endif  // EXPECT_OK
+
+#ifndef ASSERT_OK_AND_ASSIGN
+
+#define ASSERT_OK_AND_ASSIGN(lhs, rexpr) \
+  ASSERT_OK_AND_ASSIGN_DETAIL(UNIQUE_IDENTIFIER_DETAIL(__LINE__), lhs, rexpr)
+
+// NOLINTBEGIN(bugprone-macro-parentheses)
+// The suggestion would produce bad code.
+#define ASSERT_OK_AND_ASSIGN_DETAIL(result, lhs, rexpr) \
+  auto result = (rexpr);                                \
+  ASSERT_EQ(result.status(), pw::OkStatus());           \
+  lhs = ::pw::internal::ConvertToValue(result)
+
+#define UNIQUE_IDENTIFIER_DETAIL(line) UNIQUE_IDENTIFIER_EXPANDED_DETAIL(line)
+#define UNIQUE_IDENTIFIER_EXPANDED_DETAIL(line) \
+  _assert_ok_and_assign_unique_name_##line
+
+#endif  // ASSERT_OK_AND_ASSIGN