pw_status: C version of Status

- Create pw_Status enum with all of the status codes.
- Have pw::Status implicitly convert to and from pw_Status to make
  transitioning between the plain enum and Status class seamless.

Change-Id: If4dd659ecfd24d031c838d304298e1a3ae385b63
diff --git a/pw_status/BUILD b/pw_status/BUILD
index d3ac94d..0dd9e6b 100644
--- a/pw_status/BUILD
+++ b/pw_status/BUILD
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 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
@@ -34,7 +34,10 @@
 
 pw_cc_test(
     name = "status_test",
-    srcs = ["status_test.cc"],
+    srcs = [
+        "status_test.c",
+        "status_test.cc",
+    ],
     deps = ["//pw_status"],
 )
 
diff --git a/pw_status/BUILD.gn b/pw_status/BUILD.gn
index c4e8a98..277ec33 100644
--- a/pw_status/BUILD.gn
+++ b/pw_status/BUILD.gn
@@ -43,6 +43,7 @@
     ":pw_status",
   ]
   sources = [
+    "status_test.c",
     "status_test.cc",
   ]
 }
diff --git a/pw_status/public/pw_status/status.h b/pw_status/public/pw_status/status.h
index 06bff9b..3196096 100644
--- a/pw_status/public/pw_status/status.h
+++ b/pw_status/public/pw_status/status.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 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
@@ -11,166 +11,202 @@
 // 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
 
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+// This is the pw_Status enum. pw_Status is used to return the status from an
+// operation.
+//
+// In C++, use the pw::Status class instead of the pw_Status enum. pw_Status and
+// Status implicitly convert to one another and can be passed cleanly between C
+// and C++ APIs.
+//
+// pw_Status uses the canonical Google error codes. The following was copied
+// from Tensorflow and prefixed with PW_STATUS_.
+typedef enum {
+  PW_STATUS_OK = 0,
+
+  // The operation was cancelled (typically by the caller).
+  PW_STATUS_CANCELLED = 1,
+
+  // Unknown error.  An example of where this error may be returned is
+  // if a Status value received from another address space belongs to
+  // an error-space that is not known in this address space.  Also,
+  // errors raised by APIs that do not return enough error information
+  // may be converted to this error.
+  PW_STATUS_UNKNOWN = 2,
+
+  // Client specified an invalid argument.  Note that this differs
+  // from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
+  // that are problematic regardless of the state of the system
+  // (e.g. a malformed file name).
+  PW_STATUS_INVALID_ARGUMENT = 3,
+
+  // Deadline expired before operation could complete.  For operations
+  // that change the state of the system, this error may be returned
+  // even if the operation has completed successfully.  For example, a
+  // successful response from a server could have been delayed long
+  // enough for the deadline to expire.
+  PW_STATUS_DEADLINE_EXCEEDED = 4,
+
+  // Some requested entity (e.g. file or directory) was not found.
+  // For privacy reasons, this code *may* be returned when the client
+  // does not have the access right to the entity.
+  PW_STATUS_NOT_FOUND = 5,
+
+  // Some entity that we attempted to create (e.g. file or directory)
+  // already exists.
+  PW_STATUS_ALREADY_EXISTS = 6,
+
+  // The caller does not have permission to execute the specified
+  // operation.  PERMISSION_DENIED must not be used for rejections
+  // caused by exhausting some resource (use RESOURCE_EXHAUSTED
+  // instead for those errors).  PERMISSION_DENIED must not be
+  // used if the caller cannot be identified (use UNAUTHENTICATED
+  // instead for those errors).
+  PW_STATUS_PERMISSION_DENIED = 7,
+
+  // The request does not have valid authentication credentials for the
+  // operation.
+  PW_STATUS_UNAUTHENTICATED = 16,
+
+  // Some resource has been exhausted, perhaps a per-user quota, or
+  // perhaps the entire filesystem is out of space.
+  PW_STATUS_RESOURCE_EXHAUSTED = 8,
+
+  // Operation was rejected because the system is not in a state
+  // required for the operation's execution.  For example, directory
+  // to be deleted may be non-empty, an rmdir operation is applied to
+  // a non-directory, etc.
+  //
+  // A litmus test that may help a service implementer in deciding
+  // between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+  //  (a) Use UNAVAILABLE if the client can retry just the failing call.
+  //  (b) Use ABORTED if the client should retry at a higher-level
+  //      (e.g. restarting a read-modify-write sequence).
+  //  (c) Use FAILED_PRECONDITION if the client should not retry until
+  //      the system state has been explicitly fixed.  E.g. if an "rmdir"
+  //      fails because the directory is non-empty, FAILED_PRECONDITION
+  //      should be returned since the client should not retry unless
+  //      they have first fixed up the directory by deleting files from it.
+  //  (d) Use FAILED_PRECONDITION if the client performs conditional
+  //      REST Get/Update/Delete on a resource and the resource on the
+  //      server does not match the condition. E.g. conflicting
+  //      read-modify-write on the same resource.
+  PW_STATUS_FAILED_PRECONDITION = 9,
+
+  // The operation was aborted, typically due to a concurrency issue
+  // like sequencer check failures, transaction aborts, etc.
+  //
+  // See litmus test above for deciding between FAILED_PRECONDITION,
+  // ABORTED, and UNAVAILABLE.
+  PW_STATUS_ABORTED = 10,
+
+  // Operation tried to iterate past the valid input range.  E.g. seeking or
+  // reading past end of file.
+  //
+  // Unlike INVALID_ARGUMENT, this error indicates a problem that may
+  // be fixed if the system state changes. For example, a 32-bit file
+  // system will generate INVALID_ARGUMENT if asked to read at an
+  // offset that is not in the range [0,2^32-1], but it will generate
+  // OUT_OF_RANGE if asked to read from an offset past the current
+  // file size.
+  //
+  // There is a fair bit of overlap between FAILED_PRECONDITION and
+  // OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
+  // error) when it applies so that callers who are iterating through
+  // a space can easily look for an OUT_OF_RANGE error to detect when
+  // they are done.
+  PW_STATUS_OUT_OF_RANGE = 11,
+
+  // Operation is not implemented or not supported/enabled in this service.
+  PW_STATUS_UNIMPLEMENTED = 12,
+
+  // Internal errors.  Means some invariants expected by underlying
+  // system has been broken.  If you see one of these errors,
+  // something is very broken.
+  PW_STATUS_INTERNAL = 13,
+
+  // The service is currently unavailable.  This is a most likely a
+  // transient condition and may be corrected by retrying with
+  // a backoff.
+  //
+  // See litmus test above for deciding between FAILED_PRECONDITION,
+  // ABORTED, and UNAVAILABLE.
+  PW_STATUS_UNAVAILABLE = 14,
+
+  // Unrecoverable data loss or corruption.
+  PW_STATUS_DATA_LOSS = 15,
+
+  // An extra enum entry to prevent people from writing code that
+  // fails to compile when a new code is added.
+  //
+  // Nobody should ever reference this enumeration entry. In particular,
+  // if you write C++ code that switches on this enumeration, add a default:
+  // case instead of a case that mentions this enumeration entry.
+  //
+  // Nobody should rely on the value listed here. It may change in the future.
+  PW_STATUS_DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_,
+} pw_Status;
+
+// Returns a null-terminated string representation of the pw_Status.
+const char* pw_StatusString(pw_Status status);
+
+#ifdef __cplusplus
+
+}  // extern "C"
+
 namespace pw {
 
+// The Status class is a thin, zero-cost abstraction around the pw_Status enum.
+// It initializes to Status::OK by default and adds ok() and str() methods.
+// Implicit conversions are permitted between pw_Status and pw::Status.
 class Status {
  public:
-  // These are the canonical Google error codes (copied from Tensorflow).
-  enum Code {
-    OK = 0,
+  using Code = pw_Status;
 
-    // The operation was cancelled (typically by the caller).
-    CANCELLED = 1,
+  // All of the pw_Status codes are available in the Status class as, e.g.
+  // pw::Status::OK or pw::Status::OUT_OF_RANGE.
+  static constexpr Code OK = PW_STATUS_OK;
+  static constexpr Code CANCELLED = PW_STATUS_CANCELLED;
+  static constexpr Code UNKNOWN = PW_STATUS_UNKNOWN;
+  static constexpr Code INVALID_ARGUMENT = PW_STATUS_INVALID_ARGUMENT;
+  static constexpr Code DEADLINE_EXCEEDED = PW_STATUS_DEADLINE_EXCEEDED;
+  static constexpr Code NOT_FOUND = PW_STATUS_NOT_FOUND;
+  static constexpr Code ALREADY_EXISTS = PW_STATUS_ALREADY_EXISTS;
+  static constexpr Code PERMISSION_DENIED = PW_STATUS_PERMISSION_DENIED;
+  static constexpr Code UNAUTHENTICATED = PW_STATUS_UNAUTHENTICATED;
+  static constexpr Code RESOURCE_EXHAUSTED = PW_STATUS_RESOURCE_EXHAUSTED;
+  static constexpr Code FAILED_PRECONDITION = PW_STATUS_FAILED_PRECONDITION;
+  static constexpr Code ABORTED = PW_STATUS_ABORTED;
+  static constexpr Code OUT_OF_RANGE = PW_STATUS_OUT_OF_RANGE;
+  static constexpr Code UNIMPLEMENTED = PW_STATUS_UNIMPLEMENTED;
+  static constexpr Code INTERNAL = PW_STATUS_INTERNAL;
+  static constexpr Code UNAVAILABLE = PW_STATUS_UNAVAILABLE;
+  static constexpr Code DATA_LOSS = PW_STATUS_DATA_LOSS;
 
-    // Unknown error.  An example of where this error may be returned is
-    // if a Status value received from another address space belongs to
-    // an error-space that is not known in this address space.  Also,
-    // errors raised by APIs that do not return enough error information
-    // may be converted to this error.
-    UNKNOWN = 2,
-
-    // Client specified an invalid argument.  Note that this differs
-    // from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
-    // that are problematic regardless of the state of the system
-    // (e.g. a malformed file name).
-    INVALID_ARGUMENT = 3,
-
-    // Deadline expired before operation could complete.  For operations
-    // that change the state of the system, this error may be returned
-    // even if the operation has completed successfully.  For example, a
-    // successful response from a server could have been delayed long
-    // enough for the deadline to expire.
-    DEADLINE_EXCEEDED = 4,
-
-    // Some requested entity (e.g. file or directory) was not found.
-    // For privacy reasons, this code *may* be returned when the client
-    // does not have the access right to the entity.
-    NOT_FOUND = 5,
-
-    // Some entity that we attempted to create (e.g. file or directory)
-    // already exists.
-    ALREADY_EXISTS = 6,
-
-    // The caller does not have permission to execute the specified
-    // operation.  PERMISSION_DENIED must not be used for rejections
-    // caused by exhausting some resource (use RESOURCE_EXHAUSTED
-    // instead for those errors).  PERMISSION_DENIED must not be
-    // used if the caller cannot be identified (use UNAUTHENTICATED
-    // instead for those errors).
-    PERMISSION_DENIED = 7,
-
-    // The request does not have valid authentication credentials for the
-    // operation.
-    UNAUTHENTICATED = 16,
-
-    // Some resource has been exhausted, perhaps a per-user quota, or
-    // perhaps the entire filesystem is out of space.
-    RESOURCE_EXHAUSTED = 8,
-
-    // Operation was rejected because the system is not in a state
-    // required for the operation's execution.  For example, directory
-    // to be deleted may be non-empty, an rmdir operation is applied to
-    // a non-directory, etc.
-    //
-    // A litmus test that may help a service implementer in deciding
-    // between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
-    //  (a) Use UNAVAILABLE if the client can retry just the failing call.
-    //  (b) Use ABORTED if the client should retry at a higher-level
-    //      (e.g. restarting a read-modify-write sequence).
-    //  (c) Use FAILED_PRECONDITION if the client should not retry until
-    //      the system state has been explicitly fixed.  E.g. if an "rmdir"
-    //      fails because the directory is non-empty, FAILED_PRECONDITION
-    //      should be returned since the client should not retry unless
-    //      they have first fixed up the directory by deleting files from it.
-    //  (d) Use FAILED_PRECONDITION if the client performs conditional
-    //      REST Get/Update/Delete on a resource and the resource on the
-    //      server does not match the condition. E.g. conflicting
-    //      read-modify-write on the same resource.
-    FAILED_PRECONDITION = 9,
-
-    // The operation was aborted, typically due to a concurrency issue
-    // like sequencer check failures, transaction aborts, etc.
-    //
-    // See litmus test above for deciding between FAILED_PRECONDITION,
-    // ABORTED, and UNAVAILABLE.
-    ABORTED = 10,
-
-    // Operation tried to iterate past the valid input range.  E.g. seeking or
-    // reading past end of file.
-    //
-    // Unlike INVALID_ARGUMENT, this error indicates a problem that may
-    // be fixed if the system state changes. For example, a 32-bit file
-    // system will generate INVALID_ARGUMENT if asked to read at an
-    // offset that is not in the range [0,2^32-1], but it will generate
-    // OUT_OF_RANGE if asked to read from an offset past the current
-    // file size.
-    //
-    // There is a fair bit of overlap between FAILED_PRECONDITION and
-    // OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
-    // error) when it applies so that callers who are iterating through
-    // a space can easily look for an OUT_OF_RANGE error to detect when
-    // they are done.
-    OUT_OF_RANGE = 11,
-
-    // Operation is not implemented or not supported/enabled in this service.
-    UNIMPLEMENTED = 12,
-
-    // Internal errors.  Means some invariants expected by underlying
-    // system has been broken.  If you see one of these errors,
-    // something is very broken.
-    INTERNAL = 13,
-
-    // The service is currently unavailable.  This is a most likely a
-    // transient condition and may be corrected by retrying with
-    // a backoff.
-    //
-    // See litmus test above for deciding between FAILED_PRECONDITION,
-    // ABORTED, and UNAVAILABLE.
-    UNAVAILABLE = 14,
-
-    // Unrecoverable data loss or corruption.
-    DATA_LOSS = 15,
-
-    // An extra enum entry to prevent people from writing code that
-    // fails to compile when a new code is added.
-    //
-    // Nobody should ever reference this enumeration entry. In particular,
-    // if you write C++ code that switches on this enumeration, add a default:
-    // case instead of a case that mentions this enumeration entry.
-    //
-    // Nobody should rely on the value listed here. It may change in the future.
-    DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_,
-  };
-
-  constexpr Status(Code code = Code::OK) : code_(code) {}
+  // Statuses are created with a Status::Code.
+  constexpr Status(Code code = OK) : code_(code) {}
 
   constexpr Status(const Status&) = default;
   constexpr Status& operator=(const Status&) = default;
 
-  constexpr Status& operator=(Code code) {
-    code_ = code;
-    return *this;
-  }
+  // Status implicitly converts to a Status::Code.
+  constexpr operator Code() const { return code_; }
 
-  constexpr Code code() const { return code_; }
-  constexpr bool ok() const { return code_ == Code::OK; }
+  // True if the status is Status::OK.
+  constexpr bool ok() const { return code_ == OK; }
 
-  // Returns a string representation of the Status::Code.
-  const char* str() const;
+  // Returns a null-terminated string representation of the Status.
+  const char* str() const { return pw_StatusString(code_); }
 
  private:
   Code code_;
 };
 
-constexpr bool operator==(Status lhs, Status rhs) {
-  return lhs.code() == rhs.code();
-}
-
-constexpr bool operator!=(Status lhs, Status rhs) {
-  return lhs.code() != rhs.code();
-}
-
 }  // namespace pw
+
+#endif  // __cplusplus
diff --git a/pw_status/public/pw_status/status_with_size.h b/pw_status/public/pw_status/status_with_size.h
index 95f544d..d3957b0 100644
--- a/pw_status/public/pw_status/status_with_size.h
+++ b/pw_status/public/pw_status/status_with_size.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 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
@@ -52,8 +52,7 @@
 
   // Creates a StatusWithSize with the provided status and size.
   explicit constexpr StatusWithSize(Status status, size_t size)
-      : StatusWithSize(size |
-                       (static_cast<size_t>(status.code()) << kStatusShift)) {}
+      : StatusWithSize(size | (static_cast<size_t>(status) << kStatusShift)) {}
 
   constexpr StatusWithSize(const StatusWithSize&) = default;
   constexpr StatusWithSize& operator=(const StatusWithSize&) = default;
diff --git a/pw_status/status.cc b/pw_status/status.cc
index 3a7e4fa..5047734 100644
--- a/pw_status/status.cc
+++ b/pw_status/status.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 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
@@ -14,15 +14,13 @@
 
 #include "pw_status/status.h"
 
-namespace pw {
-
 #define PW_CASE_RETURN_ENUM_STRING(value) \
-  case (value):                           \
+  case PW_STATUS_##value:                 \
     return #value
 
-const char* Status::str() const {
+extern "C" const char* pw_StatusString(pw_Status status) {
   // Status codes are ordered by assigned number (UNAUTHENTICATED is last).
-  switch (code_) {
+  switch (status) {
     PW_CASE_RETURN_ENUM_STRING(OK);
     PW_CASE_RETURN_ENUM_STRING(CANCELLED);
     PW_CASE_RETURN_ENUM_STRING(UNKNOWN);
@@ -46,5 +44,3 @@
 }
 
 #undef PW_CASE_RETURN_ENUM_STRING
-
-}  // namespace pw
diff --git a/pw_status/status_test.c b/pw_status/status_test.c
new file mode 100644
index 0000000..6a99679
--- /dev/null
+++ b/pw_status/status_test.c
@@ -0,0 +1,77 @@
+// Copyright 2020 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_status/status.h"
+
+#include <string.h>
+
+pw_Status PassStatusFromC(pw_Status status) { return status; }
+
+pw_Status PassStatusFromCpp(pw_Status status);
+
+#define CHECK_STATUS_FROM_CPP(status) \
+  (PW_STATUS_##status != PassStatusFromCpp(PW_STATUS_##status))
+
+int TestStatusFromC() {
+  int errors = 0;
+
+  errors += CHECK_STATUS_FROM_CPP(OK);
+  errors += CHECK_STATUS_FROM_CPP(CANCELLED);
+  errors += CHECK_STATUS_FROM_CPP(UNKNOWN);
+  errors += CHECK_STATUS_FROM_CPP(INVALID_ARGUMENT);
+  errors += CHECK_STATUS_FROM_CPP(DEADLINE_EXCEEDED);
+  errors += CHECK_STATUS_FROM_CPP(NOT_FOUND);
+  errors += CHECK_STATUS_FROM_CPP(ALREADY_EXISTS);
+  errors += CHECK_STATUS_FROM_CPP(PERMISSION_DENIED);
+  errors += CHECK_STATUS_FROM_CPP(UNAUTHENTICATED);
+  errors += CHECK_STATUS_FROM_CPP(RESOURCE_EXHAUSTED);
+  errors += CHECK_STATUS_FROM_CPP(FAILED_PRECONDITION);
+  errors += CHECK_STATUS_FROM_CPP(ABORTED);
+  errors += CHECK_STATUS_FROM_CPP(OUT_OF_RANGE);
+  errors += CHECK_STATUS_FROM_CPP(UNIMPLEMENTED);
+  errors += CHECK_STATUS_FROM_CPP(INTERNAL);
+  errors += CHECK_STATUS_FROM_CPP(UNAVAILABLE);
+  errors += CHECK_STATUS_FROM_CPP(DATA_LOSS);
+
+  return errors;
+}
+
+#undef CHECK_STATUS_FROM_CPP
+
+#define CHECK_STATUS_STRING(status) \
+  (strcmp(#status, pw_StatusString(PW_STATUS_##status)) != 0)
+
+int TestStatusStringsFromC() {
+  int errors = 0;
+
+  errors += CHECK_STATUS_STRING(OK);
+  errors += CHECK_STATUS_STRING(CANCELLED);
+  errors += CHECK_STATUS_STRING(DEADLINE_EXCEEDED);
+  errors += CHECK_STATUS_STRING(NOT_FOUND);
+  errors += CHECK_STATUS_STRING(ALREADY_EXISTS);
+  errors += CHECK_STATUS_STRING(PERMISSION_DENIED);
+  errors += CHECK_STATUS_STRING(UNAUTHENTICATED);
+  errors += CHECK_STATUS_STRING(RESOURCE_EXHAUSTED);
+  errors += CHECK_STATUS_STRING(FAILED_PRECONDITION);
+  errors += CHECK_STATUS_STRING(ABORTED);
+  errors += CHECK_STATUS_STRING(OUT_OF_RANGE);
+  errors += CHECK_STATUS_STRING(UNIMPLEMENTED);
+  errors += CHECK_STATUS_STRING(INTERNAL);
+  errors += CHECK_STATUS_STRING(UNAVAILABLE);
+  errors += CHECK_STATUS_STRING(DATA_LOSS);
+
+  return errors;
+}
+
+#undef CHECK_STATUS_STRING
diff --git a/pw_status/status_test.cc b/pw_status/status_test.cc
index b577cd6..98afa56 100644
--- a/pw_status/status_test.cc
+++ b/pw_status/status_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 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
@@ -29,13 +29,13 @@
 
 TEST(Status, ConstructWithStatusCode) {
   Status status(Status::ABORTED);
-  EXPECT_EQ(Status::ABORTED, status.code());
+  EXPECT_EQ(Status::ABORTED, status);
 }
 
 TEST(Status, AssignFromStatusCode) {
   Status status;
   status = Status::INTERNAL;
-  EXPECT_EQ(Status::INTERNAL, status.code());
+  EXPECT_EQ(Status::INTERNAL, status);
 }
 
 TEST(Status, CompareToStatusCode) {
@@ -77,5 +77,32 @@
   EXPECT_STREQ("INVALID STATUS", Status(static_cast<Status::Code>(30)).str());
 }
 
+// Functions for executing the C pw_Status tests.
+extern "C" {
+
+Status::Code PassStatusFromC(Status status);
+
+Status::Code PassStatusFromCpp(Status status) { return status; }
+
+int TestStatusFromC(void);
+
+int TestStatusStringsFromC(void);
+
+}  // extern "C"
+
+TEST(StatusCLinkage, CallCFunctionWithStatus) {
+  EXPECT_EQ(Status::ABORTED, PassStatusFromC(Status::ABORTED));
+  EXPECT_EQ(Status::UNKNOWN, PassStatusFromC(Status(Status::UNKNOWN)));
+
+  EXPECT_EQ(Status(Status::NOT_FOUND), PassStatusFromC(Status::NOT_FOUND));
+  EXPECT_EQ(Status(Status::OK), PassStatusFromC(Status(Status::OK)));
+}
+
+TEST(StatusCLinkage, TestStatusFromC) { EXPECT_EQ(0, TestStatusFromC()); }
+
+TEST(StatusCLinkage, TestStatusStringsFromC) {
+  EXPECT_EQ(0, TestStatusStringsFromC());
+}
+
 }  // namespace
 }  // namespace pw
diff --git a/pw_status/status_with_size_test.cc b/pw_status/status_with_size_test.cc
index 772f8fe..ee9d56e 100644
--- a/pw_status/status_with_size_test.cc
+++ b/pw_status/status_with_size_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 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
@@ -55,7 +55,7 @@
   for (int i = 0; i < 32; ++i) {
     StatusWithSize result(static_cast<Status::Code>(i), 0);
     EXPECT_EQ(result.ok(), i == 0);
-    EXPECT_EQ(i, static_cast<int>(result.status().code()));
+    EXPECT_EQ(i, static_cast<int>(result.status()));
     EXPECT_EQ(0u, result.size());
   }
 }
@@ -64,7 +64,7 @@
   for (int i = 0; i < 32; ++i) {
     StatusWithSize result(static_cast<Status::Code>(i), i);
     EXPECT_EQ(result.ok(), i == 0);
-    EXPECT_EQ(i, static_cast<int>(result.status().code()));
+    EXPECT_EQ(i, static_cast<int>(result.status()));
     EXPECT_EQ(static_cast<size_t>(i), result.size());
   }
 }
@@ -74,7 +74,7 @@
     StatusWithSize result(static_cast<Status::Code>(i),
                           StatusWithSize::max_size());
     EXPECT_EQ(result.ok(), i == 0);
-    EXPECT_EQ(i, static_cast<int>(result.status().code()));
+    EXPECT_EQ(i, static_cast<int>(result.status()));
     EXPECT_EQ(result.max_size(), result.size());
   }
 }