pw_status: StatusWithSize class

- Create StatusWithSize, which efficiently stores a Status and a
  non-negative integer.
- Add tests for Status and StatusWithSize.

Change-Id: I34ade117d890318d45a27664fe53303365f21f68
diff --git a/pw_status/status_with_size_test.cc b/pw_status/status_with_size_test.cc
new file mode 100644
index 0000000..7b07992
--- /dev/null
+++ b/pw_status/status_with_size_test.cc
@@ -0,0 +1,101 @@
+// 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_status/status_with_size.h"
+
+#include "gtest/gtest.h"
+
+namespace pw::string {
+namespace {
+
+static_assert(StatusWithSize::max_size() ==
+              (static_cast<size_t>(1) << (sizeof(size_t) * 8 - 5)) - 1);
+
+TEST(StatusWithSize, Default) {
+  StatusWithSize result;
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(Status::OK, result.status());
+  EXPECT_EQ(0u, result.size());
+}
+
+TEST(StatusWithSize, ConstructWithSize) {
+  StatusWithSize result = StatusWithSize(456);
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(Status::OK, result.status());
+  EXPECT_EQ(456u, result.size());
+}
+
+TEST(StatusWithSize, ConstructWithError) {
+  StatusWithSize result(Status::RESOURCE_EXHAUSTED, 123);
+  EXPECT_FALSE(result.ok());
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, result.status());
+  EXPECT_EQ(123u, result.size());
+}
+
+TEST(StatusWithSize, ConstructWithOkAndSize) {
+  StatusWithSize result(Status::OK, 99);
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(Status::OK, result.status());
+  EXPECT_EQ(99u, result.size());
+}
+
+TEST(StatusWithSize, AllStatusValues_ZeroSize) {
+  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(0u, result.size());
+  }
+}
+
+TEST(StatusWithSize, AllStatusValues_SameSize) {
+  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(static_cast<size_t>(i), result.size());
+  }
+}
+
+TEST(StatusWithSize, AllStatusValues_MaxSize) {
+  for (int i = 0; i < 32; ++i) {
+    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(result.max_size(), result.size());
+  }
+}
+
+TEST(StatusWithSize, Assignment) {
+  StatusWithSize result = StatusWithSize(Status::INTERNAL, 0x123);
+  EXPECT_FALSE(result.ok());
+  EXPECT_EQ(Status::INTERNAL, result.status());
+  EXPECT_EQ(0x123u, result.size());
+
+  result = StatusWithSize(300);
+  EXPECT_TRUE(result.ok());
+  EXPECT_EQ(Status::OK, result.status());
+  EXPECT_EQ(300u, result.size());
+}
+
+TEST(StatusWithSize, Constexpr) {
+  constexpr StatusWithSize result(Status::CANCELLED, 1234);
+  static_assert(Status::CANCELLED == result.status());
+  static_assert(!result.ok());
+  static_assert(1234u == result.size());
+}
+
+}  // namespace
+}  // namespace pw::string