Arbitrary Status Domain

PiperOrigin-RevId: 917993595
diff --git a/doc/domains-reference.md b/doc/domains-reference.md
index 32ea226..f8421fd 100644
--- a/doc/domains-reference.md
+++ b/doc/domains-reference.md
@@ -16,8 +16,9 @@
 
 ### Arbitrary Domains
 
-The `Arbitrary<T>()` domain is implemented for all native C++ types and for
-protocol buffers. Specifically, for the following types:
+The `Arbitrary<T>()` domain is implemented for all native C++ types,
+protocol buffers, and some Abseil types.
+Specifically, for the following types:
 
 -   Boolean type: `bool`.
 -   Character types: `char`, `signed char`, `unsigned char`.
@@ -43,7 +44,7 @@
 -   [Abseil time library types](https://abseil.io/docs/cpp/guides/time):
     `absl::Duration`, `absl::Time`.
 -   [Abseil status types](https://abseil.io/docs/cpp/guides/status):
-    `absl::StatusCode`.
+    `absl::StatusCode`, `absl::Status` (without support for payloads).
 
 Composite or container types, like `std::optional<T>` or `std::vector<T>`, are
 supported as long as the inner types are. For example,
diff --git a/domain_tests/BUILD b/domain_tests/BUILD
index ea40cd7..100fc80 100644
--- a/domain_tests/BUILD
+++ b/domain_tests/BUILD
@@ -88,6 +88,7 @@
         "@abseil-cpp//absl/random",
         "@abseil-cpp//absl/random:bit_gen_ref",
         "@abseil-cpp//absl/status",
+        "@abseil-cpp//absl/strings:cord",
         "@abseil-cpp//absl/time",
         "@com_google_fuzztest//fuzztest:domain_core",
         "@com_google_fuzztest//fuzztest/internal:serialization",
diff --git a/domain_tests/CMakeLists.txt b/domain_tests/CMakeLists.txt
index da7ef0f..ecf92b7 100644
--- a/domain_tests/CMakeLists.txt
+++ b/domain_tests/CMakeLists.txt
@@ -68,6 +68,7 @@
     "arbitrary_domains_test.cc"
   DEPS
     fuzztest::domain_testing
+    absl::cord
     absl::flat_hash_set
     absl::random_random
     absl::random_bit_gen_ref
diff --git a/domain_tests/arbitrary_domains_test.cc b/domain_tests/arbitrary_domains_test.cc
index 6b2829a..2af1c79 100644
--- a/domain_tests/arbitrary_domains_test.cc
+++ b/domain_tests/arbitrary_domains_test.cc
@@ -34,6 +34,7 @@
 #include "absl/random/bit_gen_ref.h"
 #include "absl/random/random.h"
 #include "absl/status/status.h"
+#include "absl/strings/cord.h"
 #include "absl/time/time.h"
 #include "./fuzztest/domain_core.h"  // IWYU pragma: keep
 #include "./domain_tests/domain_testing.h"
@@ -665,5 +666,43 @@
               Contains(Value(domain, absl::StatusCode::kInvalidArgument)));
 }
 
+TEST(ArbitraryStatusTest, GeneratesOkAndError) {
+  auto domain = Arbitrary<absl::Status>();
+  absl::BitGen prng;
+  bool found_ok = false;
+  bool found_error = false;
+
+  for (int i = 0; i < 100 && (!found_ok || !found_error); ++i) {
+    absl::Status s = domain.GetRandomValue(prng);
+    if (s.ok()) {
+      found_ok = true;
+    } else {
+      found_error = true;
+    }
+  }
+
+  EXPECT_TRUE(found_ok);
+  EXPECT_TRUE(found_error);
+}
+
+TEST(ArbitraryStatusTest, InitGeneratesSeeds) {
+  absl::Status seed = absl::InvalidArgumentError("seed message");
+  Domain<absl::Status> domain = Arbitrary<absl::Status>().WithSeeds({seed});
+
+  EXPECT_THAT(GenerateInitialValues(domain, 1000),
+              Contains(Value(domain, seed)));
+}
+
+TEST(ArbitraryStatusTest, FromValueAndGetValuePreserveCodeAndMessage) {
+  auto domain = Arbitrary<absl::Status>();
+  absl::Status status = absl::InvalidArgumentError("msg");
+  status.SetPayload("some_url", absl::Cord("payload"));
+  auto corpus_val = domain.FromValue(status);
+  ASSERT_TRUE(corpus_val.has_value());
+  absl::Status mapped_status = domain.GetValue(*corpus_val);
+  EXPECT_EQ(mapped_status.code(), status.code());
+  EXPECT_EQ(mapped_status.message(), status.message());
+}
+
 }  // namespace
 }  // namespace fuzztest
diff --git a/fuzztest/internal/domains/arbitrary_impl.h b/fuzztest/internal/domains/arbitrary_impl.h
index f5717cf..16bc2c6 100644
--- a/fuzztest/internal/domains/arbitrary_impl.h
+++ b/fuzztest/internal/domains/arbitrary_impl.h
@@ -22,6 +22,7 @@
 #include <limits>
 #include <memory>
 #include <optional>
+#include <string>
 #include <string_view>
 #include <tuple>
 #include <type_traits>
@@ -610,6 +611,33 @@
             InRangeImpl<StatusCodeUnderlyingT>(0, 16)) {}
 };
 
+// Arbitrary for absl::Status.
+// Note: This does not generate payloads. Payloads in seeds are ignored.
+template <>
+class ArbitraryImpl<absl::Status>
+    : public ReversibleMapImpl<
+          absl::Status (*)(absl::StatusCode, std::string),
+          std::optional<std::tuple<absl::StatusCode, std::string>> (*)(
+              absl::Status),
+          ArbitraryImpl<absl::StatusCode>, ArbitraryImpl<std::string>> {
+ public:
+  ArbitraryImpl()
+      : ReversibleMapImpl<
+            absl::Status (*)(absl::StatusCode, std::string),
+            std::optional<std::tuple<absl::StatusCode, std::string>> (*)(
+                absl::Status),
+            ArbitraryImpl<absl::StatusCode>, ArbitraryImpl<std::string>>(
+            [](absl::StatusCode code, std::string msg) {
+              return absl::Status(code, msg);
+            },
+            +[](absl::Status status)
+                -> std::optional<std::tuple<absl::StatusCode, std::string>> {
+              return std::optional{
+                  std::tuple{status.code(), std::string(status.message())}};
+            },
+            ArbitraryImpl<absl::StatusCode>(), ArbitraryImpl<std::string>()) {}
+};
+
 // Arbitrary for absl::BitGenRef.
 template <>
 class ArbitraryImpl<absl::BitGenRef>