blob: 67f503b64500c32b9a14f25336c839d393dd587f [file] [log] [blame] [edit]
// Copyright 2026 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 "quiche/common/quiche_string_tuple.h"
#include <optional>
#include <utility>
#include <vector>
#include "absl/hash/hash.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quiche/common/platform/api/quiche_expect_bug.h"
#include "quiche/common/platform/api/quiche_test.h"
namespace quiche::test {
namespace {
using ::testing::ElementsAre;
using ::testing::IsEmpty;
class QuicheStringTupleTest : public QuicheTest {};
TEST_F(QuicheStringTupleTest, DefaultState) {
QuicheStringTuple<> tuple;
EXPECT_EQ(tuple.size(), 0);
EXPECT_TRUE(tuple.empty());
EXPECT_FALSE(tuple.Pop());
EXPECT_EQ(tuple.ValueAt(0), std::nullopt);
EXPECT_EQ(tuple.ValueAt(0xffffffff), std::nullopt);
EXPECT_EQ(tuple.begin(), tuple.end());
}
TEST_F(QuicheStringTupleTest, BasicOperations) {
QuicheStringTuple<> tuple;
EXPECT_TRUE(tuple.Add("foo"));
EXPECT_EQ(tuple.size(), 1);
EXPECT_TRUE(tuple.Add("bar"));
EXPECT_EQ(tuple.size(), 2);
EXPECT_TRUE(tuple.Pop());
EXPECT_EQ(tuple.size(), 1);
EXPECT_TRUE(tuple.Pop());
EXPECT_EQ(tuple.size(), 0);
EXPECT_FALSE(tuple.Pop());
}
TEST_F(QuicheStringTupleTest, EmptyElements) {
QuicheStringTuple<> tuple({"a", "", "bc", "d", "", "e", "f"});
EXPECT_THAT(tuple, ElementsAre("a", "", "bc", "d", "", "e", "f"));
}
TEST_F(QuicheStringTupleTest, Vector) {
QuicheStringTuple<> tuple;
EXPECT_TRUE(tuple.Add("foo"));
EXPECT_TRUE(tuple.Add(""));
EXPECT_TRUE(tuple.Add("bar"));
std::vector<absl::string_view> vec(tuple.begin(), tuple.end());
EXPECT_THAT(vec, ElementsAre("foo", "", "bar"));
}
TEST_F(QuicheStringTupleTest, Iterators) {
QuicheStringTuple<> tuple;
EXPECT_TRUE(tuple.Add("foo"));
EXPECT_TRUE(tuple.Add("bar"));
auto it = tuple.begin();
EXPECT_EQ(*it, "foo");
++it;
EXPECT_EQ(*it, "bar");
it++;
EXPECT_EQ(it, tuple.end());
--it;
EXPECT_EQ(*it, "bar");
it--;
EXPECT_EQ(*it, "foo");
}
TEST_F(QuicheStringTupleTest, Limits) {
QuicheStringTuple<6> tuple;
EXPECT_TRUE(tuple.Add("foo"));
EXPECT_TRUE(tuple.Add("bar"));
EXPECT_EQ(tuple.BytesLeft(), 0);
EXPECT_FALSE(tuple.Add("x"));
EXPECT_TRUE(tuple.Add(""));
EXPECT_THAT(tuple, ElementsAre("foo", "bar", ""));
}
TEST_F(QuicheStringTupleTest, Copy) {
QuicheStringTuple<> tuple({"foo", "bar"});
QuicheStringTuple<> tuple2 = tuple;
EXPECT_THAT(tuple, ElementsAre("foo", "bar"));
EXPECT_THAT(tuple2, ElementsAre("foo", "bar"));
EXPECT_EQ(tuple[0], tuple2[0]);
EXPECT_NE(tuple[0].data(), tuple2[0].data());
}
TEST_F(QuicheStringTupleTest, Move) {
QuicheStringTuple<> tuple({"foo", "bar"});
QuicheStringTuple<> tuple2 = std::move(tuple);
EXPECT_THAT(tuple, IsEmpty()); // NOLINT(bugprone-use-after-move)
EXPECT_THAT(tuple2, ElementsAre("foo", "bar"));
}
TEST_F(QuicheStringTupleTest, OutOfBoundsAccess) {
QuicheStringTuple<> tuple({"foo", "bar"});
EXPECT_EQ(tuple.ValueAt(2), std::nullopt);
EXPECT_QUICHE_BUG(tuple[2], "out-of-bounds");
EXPECT_QUICHE_BUG(*tuple.end(), "out-of-bounds");
}
TEST_F(QuicheStringTupleTest, InitializerListTooLarge) {
QuicheStringTuple<6> tuple({"foo", "bar"});
EXPECT_QUICHE_BUG(QuicheStringTuple<5> tuple2({"foo", "bar"}), "exceeds");
}
TEST_F(QuicheStringTupleTest, Ordering) {
QuicheStringTuple<> a({"a"});
QuicheStringTuple<> ab({"a", "b"});
QuicheStringTuple<> ac({"a", "c"});
QuicheStringTuple<> bb({"b", "b"});
EXPECT_EQ(ab, ab);
EXPECT_NE(a, ab);
EXPECT_LT(a, ab);
EXPECT_LT(ab, ac);
EXPECT_LT(ab, bb);
EXPECT_NE(QuicheStringTuple<>({"ab", "c"}), QuicheStringTuple<>({"a", "bc"}));
}
TEST_F(QuicheStringTupleTest, Hashing) {
QuicheStringTuple<> tuple1({"foo", "bar"});
QuicheStringTuple<> tuple2({"foo", "bar"});
EXPECT_EQ(absl::HashOf(tuple1), absl::HashOf(tuple2));
}
TEST_F(QuicheStringTupleTest, Stringify) {
QuicheStringTuple<> tuple({"foo", "\xff", "bar"});
EXPECT_EQ(absl::StrCat(tuple), R"({"foo", "\xff", "bar"})");
}
TEST_F(QuicheStringTupleTest, IsPrefix) {
QuicheStringTuple<> a({"a"});
QuicheStringTuple<> ab({"a", "b"});
QuicheStringTuple<> abc({"a", "b", "c"});
QuicheStringTuple<> ac({"a", "c"});
EXPECT_TRUE(abc.IsPrefix(abc));
EXPECT_TRUE(abc.IsPrefix(ab));
EXPECT_TRUE(abc.IsPrefix(a));
EXPECT_FALSE(abc.IsPrefix(ac));
EXPECT_FALSE(a.IsPrefix(abc));
}
} // namespace
} // namespace quiche::test