Add property-based fuzz tests for QuicInlinedStringView

PiperOrigin-RevId: 770154077
diff --git a/build/source_list.bzl b/build/source_list.bzl
index 1c01d4a..0bbd9b2 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -1316,6 +1316,7 @@
     "quic/core/quic_framer_test.cc",
     "quic/core/quic_generic_session_test.cc",
     "quic/core/quic_idle_network_detector_test.cc",
+    "quic/core/quic_inlined_string_view_fuzz_test.cc",
     "quic/core/quic_inlined_string_view_test.cc",
     "quic/core/quic_interval_deque_test.cc",
     "quic/core/quic_interval_set_test.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 5ca530c..54bbd26 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -1317,6 +1317,7 @@
     "src/quiche/quic/core/quic_framer_test.cc",
     "src/quiche/quic/core/quic_generic_session_test.cc",
     "src/quiche/quic/core/quic_idle_network_detector_test.cc",
+    "src/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc",
     "src/quiche/quic/core/quic_inlined_string_view_test.cc",
     "src/quiche/quic/core/quic_interval_deque_test.cc",
     "src/quiche/quic/core/quic_interval_set_test.cc",
diff --git a/build/source_list.json b/build/source_list.json
index f35ce33..9830675 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -1316,6 +1316,7 @@
     "quiche/quic/core/quic_framer_test.cc",
     "quiche/quic/core/quic_generic_session_test.cc",
     "quiche/quic/core/quic_idle_network_detector_test.cc",
+    "quiche/quic/core/quic_inlined_string_view_fuzz_test.cc",
     "quiche/quic/core/quic_inlined_string_view_test.cc",
     "quiche/quic/core/quic_interval_deque_test.cc",
     "quiche/quic/core/quic_interval_set_test.cc",
diff --git a/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc b/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc
new file mode 100644
index 0000000..d330853
--- /dev/null
+++ b/quiche/quic/core/quic_inlined_string_view_fuzz_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2025 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cstddef>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/quic_inlined_string_view.h"
+#include "quiche/quic/core/quic_stream_send_buffer_inlining.h"
+#include "quiche/common/platform/api/quiche_fuzztest.h"
+#include "quiche/common/platform/api/quiche_test.h"
+
+namespace quic {
+namespace {
+
+// Defines methods that test properties of `QuicInlinedStringView<kSize>`.
+template <size_t kSize>
+class Properties {
+ public:
+  static void AccessorsAreCorrect(absl::string_view view) {
+    QuicInlinedStringView<kSize> quic_view(view);
+
+    // Copying the memory that `quic_view` points to enables ASAN to catch
+    // out-of-bounds accesses.
+    std::string copy(quic_view.view());
+
+    EXPECT_EQ(quic_view.empty(), view.empty());
+    EXPECT_EQ(quic_view.size(), view.size());
+    EXPECT_EQ(quic_view.view(), view);
+    EXPECT_EQ(quic_view.IsInlined(), view.size() < kSize);
+
+    QuicInlinedStringView<kSize> quic_view_copy(quic_view);
+    EXPECT_EQ(quic_view_copy.empty(), view.empty());
+    EXPECT_EQ(quic_view_copy.size(), view.size());
+    EXPECT_EQ(quic_view_copy.view(), view);
+    EXPECT_EQ(quic_view_copy.IsInlined(), view.size() < kSize);
+  }
+
+  static void IsEmptyAfterClear(absl::string_view view) {
+    QuicInlinedStringView<kSize> quic_view(view);
+    quic_view.clear();
+    EXPECT_TRUE(quic_view.empty());
+  }
+
+  static void DifferentDataPointersWhenInlined(absl::string_view view) {
+    QuicInlinedStringView<kSize> quic_view(view);
+    if (!quic_view.empty()) {
+      const bool pointers_equal = view.data() == quic_view.data();
+      EXPECT_EQ(!pointers_equal, quic_view.IsInlined());
+    } else {
+      EXPECT_EQ(quic_view.data(), nullptr);
+    }
+  }
+};
+
+// Below, we fuzz each property with different values of `kSize`.
+// - The value of 16 matches the `kSize` used by `BufferedSliceInlining`.
+// - The value of 24 was chosen to demonstrate that these properties hold for at
+//   least one other value.
+// - The value of 254 was chosen because it's the largest value supported by
+//   `QuicInlinedStringView`.
+constexpr size_t kRealisticSize =
+    decltype(BufferedSliceInlining::slice)::kMaxInlinedSize + 1;
+static_assert(kRealisticSize == 16);
+
+void NeverCrashes16(absl::string_view view) {
+  Properties<16>::AccessorsAreCorrect(view);
+}
+void NeverCrashes24(absl::string_view view) {
+  Properties<24>::AccessorsAreCorrect(view);
+}
+void NeverCrashes254(absl::string_view view) {
+  Properties<254>::AccessorsAreCorrect(view);
+}
+FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes16);
+FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes24);
+FUZZ_TEST(QuicInlinedStringViewTest, NeverCrashes254);
+
+void IsEmptyAfterClear16(absl::string_view view) {
+  Properties<16>::IsEmptyAfterClear(view);
+}
+void IsEmptyAfterClear24(absl::string_view view) {
+  Properties<24>::IsEmptyAfterClear(view);
+}
+void IsEmptyAfterClear254(absl::string_view view) {
+  Properties<254>::IsEmptyAfterClear(view);
+}
+FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear16);
+FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear24);
+FUZZ_TEST(QuicInlinedStringViewTest, IsEmptyAfterClear254);
+
+void DifferentDataPointersWhenInlined16(absl::string_view view) {
+  Properties<16>::DifferentDataPointersWhenInlined(view);
+}
+void DifferentDataPointersWhenInlined24(absl::string_view view) {
+  Properties<24>::DifferentDataPointersWhenInlined(view);
+}
+void DifferentDataPointersWhenInlined254(absl::string_view view) {
+  Properties<254>::DifferentDataPointersWhenInlined(view);
+}
+FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined16);
+FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined24);
+FUZZ_TEST(QuicInlinedStringViewTest, DifferentDataPointersWhenInlined254);
+
+}  // namespace
+}  // namespace quic