summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/rtc_base/strong_alias_unittest.cc')
-rw-r--r--third_party/libwebrtc/rtc_base/strong_alias_unittest.cc362
1 files changed, 362 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc b/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc
new file mode 100644
index 0000000000..a87bc4de37
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/strong_alias_unittest.cc
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2019 The Chromium Authors. All rights reserved.
+ * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/strong_alias.h"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/containers/flat_map.h"
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+// This is a copy of
+// https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias_unittest.cc
+// but adapted to use WebRTC's includes, remove unit tests that test the ostream
+// operator (it's removed in this port) and other adaptations to pass lint.
+
+namespace webrtc {
+namespace {
+
+// For test correctnenss, it's important that these getters return lexically
+// incrementing values as `index` grows.
+template <typename T>
+T GetExampleValue(int index);
+
+template <>
+int GetExampleValue<int>(int index) {
+ return 5 + index;
+}
+template <>
+uint64_t GetExampleValue<uint64_t>(int index) {
+ return 500U + index;
+}
+
+template <>
+std::string GetExampleValue<std::string>(int index) {
+ return std::string('a', index);
+}
+
+} // namespace
+
+template <typename T>
+class StrongAliasTest : public ::testing::Test {};
+
+using TestedTypes = ::testing::Types<int, uint64_t, std::string>;
+TYPED_TEST_SUITE(StrongAliasTest, TestedTypes);
+
+TYPED_TEST(StrongAliasTest, ValueAccessesUnderlyingValue) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+
+ // Const value getter.
+ const FooAlias const_alias(GetExampleValue<TypeParam>(1));
+ EXPECT_EQ(GetExampleValue<TypeParam>(1), const_alias.value());
+ static_assert(std::is_const<typename std::remove_reference<decltype(
+ const_alias.value())>::type>::value,
+ "Reference returned by const value getter should be const.");
+}
+
+TYPED_TEST(StrongAliasTest, ExplicitConversionToUnderlyingValue) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+
+ const FooAlias const_alias(GetExampleValue<TypeParam>(1));
+ EXPECT_EQ(GetExampleValue<TypeParam>(1), static_cast<TypeParam>(const_alias));
+}
+
+TYPED_TEST(StrongAliasTest, CanBeCopyConstructed) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ FooAlias alias(GetExampleValue<TypeParam>(0));
+ FooAlias copy_constructed = alias;
+ EXPECT_EQ(copy_constructed, alias);
+
+ FooAlias copy_assigned;
+ copy_assigned = alias;
+ EXPECT_EQ(copy_assigned, alias);
+}
+
+TYPED_TEST(StrongAliasTest, CanBeMoveConstructed) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ FooAlias alias(GetExampleValue<TypeParam>(0));
+ FooAlias move_constructed = std::move(alias);
+ EXPECT_EQ(move_constructed, FooAlias(GetExampleValue<TypeParam>(0)));
+
+ FooAlias alias2(GetExampleValue<TypeParam>(2));
+ FooAlias move_assigned;
+ move_assigned = std::move(alias2);
+ EXPECT_EQ(move_assigned, FooAlias(GetExampleValue<TypeParam>(2)));
+
+ // Check that FooAlias is nothrow move constructible. This matters for
+ // performance when used in std::vectors.
+ static_assert(std::is_nothrow_move_constructible<FooAlias>::value,
+ "Error: Alias is not nothow move constructible");
+}
+
+TYPED_TEST(StrongAliasTest, CanBeConstructedFromMoveOnlyType) {
+ // Note, using a move-only unique_ptr to T:
+ using FooAlias = StrongAlias<class FooTag, std::unique_ptr<TypeParam>>;
+
+ FooAlias a(std::make_unique<TypeParam>(GetExampleValue<TypeParam>(0)));
+ EXPECT_EQ(*a.value(), GetExampleValue<TypeParam>(0));
+
+ auto bare_value = std::make_unique<TypeParam>(GetExampleValue<TypeParam>(1));
+ FooAlias b(std::move(bare_value));
+ EXPECT_EQ(*b.value(), GetExampleValue<TypeParam>(1));
+}
+
+TYPED_TEST(StrongAliasTest, MutableOperatorArrow) {
+ // Note, using a move-only unique_ptr to T:
+ using Ptr = std::unique_ptr<TypeParam>;
+ using FooAlias = StrongAlias<class FooTag, Ptr>;
+
+ FooAlias a(std::make_unique<TypeParam>());
+ EXPECT_TRUE(a.value());
+
+ // Check that `a` can be modified through the use of operator->.
+ a->reset();
+
+ EXPECT_FALSE(a.value());
+}
+
+TYPED_TEST(StrongAliasTest, MutableOperatorStar) {
+ // Note, using a move-only unique_ptr to T:
+ using Ptr = std::unique_ptr<TypeParam>;
+ using FooAlias = StrongAlias<class FooTag, Ptr>;
+
+ FooAlias a(std::make_unique<TypeParam>());
+ FooAlias b(std::make_unique<TypeParam>());
+ EXPECT_TRUE(*a);
+ EXPECT_TRUE(*b);
+
+ // Check that both the mutable l-value and r-value overloads work and we can
+ // move out of the aliases.
+ { Ptr ignore(*std::move(a)); }
+ { Ptr ignore(std::move(*b)); }
+
+ EXPECT_FALSE(a.value());
+ EXPECT_FALSE(b.value());
+}
+
+TYPED_TEST(StrongAliasTest, MutableValue) {
+ // Note, using a move-only unique_ptr to T:
+ using Ptr = std::unique_ptr<TypeParam>;
+ using FooAlias = StrongAlias<class FooTag, Ptr>;
+
+ FooAlias a(std::make_unique<TypeParam>());
+ FooAlias b(std::make_unique<TypeParam>());
+ EXPECT_TRUE(a.value());
+ EXPECT_TRUE(b.value());
+
+ // Check that both the mutable l-value and r-value overloads work and we can
+ // move out of the aliases.
+ { Ptr ignore(std::move(a).value()); }
+ { Ptr ignore(std::move(b.value())); }
+
+ EXPECT_FALSE(a.value());
+ EXPECT_FALSE(b.value());
+}
+
+TYPED_TEST(StrongAliasTest, SizeSameAsUnderlyingType) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ static_assert(sizeof(FooAlias) == sizeof(TypeParam),
+ "StrongAlias should be as large as the underlying type.");
+}
+
+TYPED_TEST(StrongAliasTest, IsDefaultConstructible) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ static_assert(std::is_default_constructible<FooAlias>::value,
+ "Should be possible to default-construct a StrongAlias.");
+ static_assert(
+ std::is_trivially_default_constructible<FooAlias>::value ==
+ std::is_trivially_default_constructible<TypeParam>::value,
+ "Should be possible to trivially default-construct a StrongAlias iff the "
+ "underlying type is trivially default constructible.");
+}
+
+TEST(StrongAliasTest, TrivialTypeAliasIsStandardLayout) {
+ using FooAlias = StrongAlias<class FooTag, int>;
+ static_assert(std::is_standard_layout<FooAlias>::value,
+ "int-based alias should have standard layout. ");
+ static_assert(std::is_trivially_copyable<FooAlias>::value,
+ "int-based alias should be trivially copyable. ");
+}
+
+TYPED_TEST(StrongAliasTest, CannotBeCreatedFromDifferentAlias) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ using BarAlias = StrongAlias<class BarTag, TypeParam>;
+ static_assert(!std::is_constructible<FooAlias, BarAlias>::value,
+ "Should be impossible to construct FooAlias from a BarAlias.");
+ static_assert(!std::is_convertible<BarAlias, FooAlias>::value,
+ "Should be impossible to convert a BarAlias into FooAlias.");
+}
+
+TYPED_TEST(StrongAliasTest, CannotBeImplicitlyConverterToUnderlyingValue) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ static_assert(!std::is_convertible<FooAlias, TypeParam>::value,
+ "Should be impossible to implicitly convert a StrongAlias into "
+ "an underlying type.");
+}
+
+TYPED_TEST(StrongAliasTest, ComparesEqualToSameValue) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ // Comparison to self:
+ const FooAlias a = FooAlias(GetExampleValue<TypeParam>(0));
+ EXPECT_EQ(a, a);
+ EXPECT_FALSE(a != a);
+ EXPECT_TRUE(a >= a);
+ EXPECT_TRUE(a <= a);
+ EXPECT_FALSE(a > a);
+ EXPECT_FALSE(a < a);
+ // Comparison to other equal object:
+ const FooAlias b = FooAlias(GetExampleValue<TypeParam>(0));
+ EXPECT_EQ(a, b);
+ EXPECT_FALSE(a != b);
+ EXPECT_TRUE(a >= b);
+ EXPECT_TRUE(a <= b);
+ EXPECT_FALSE(a > b);
+ EXPECT_FALSE(a < b);
+}
+
+TYPED_TEST(StrongAliasTest, ComparesCorrectlyToDifferentValue) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ const FooAlias a = FooAlias(GetExampleValue<TypeParam>(0));
+ const FooAlias b = FooAlias(GetExampleValue<TypeParam>(1));
+ EXPECT_NE(a, b);
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(b >= a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_TRUE(b > a);
+ EXPECT_TRUE(a < b);
+}
+
+TEST(StrongAliasTest, CanBeDerivedFrom) {
+ // Aliases can be enriched by custom operations or validations if needed.
+ // Ideally, one could go from a 'using' declaration to a derived class to add
+ // those methods without the need to change any other code.
+ class CountryCode : public StrongAlias<CountryCode, std::string> {
+ public:
+ explicit CountryCode(const std::string& value)
+ : StrongAlias<CountryCode, std::string>::StrongAlias(value) {
+ if (value_.length() != 2) {
+ // Country code invalid!
+ value_.clear(); // is_null() will return true.
+ }
+ }
+
+ bool is_null() const { return value_.empty(); }
+ };
+
+ CountryCode valid("US");
+ EXPECT_FALSE(valid.is_null());
+
+ CountryCode invalid("United States");
+ EXPECT_TRUE(invalid.is_null());
+}
+
+TEST(StrongAliasTest, CanWrapComplexStructures) {
+ // A pair of strings implements odering and can, in principle, be used as
+ // a base of StrongAlias.
+ using PairOfStrings = std::pair<std::string, std::string>;
+ using ComplexAlias = StrongAlias<class FooTag, PairOfStrings>;
+
+ ComplexAlias a1{std::make_pair("aaa", "bbb")};
+ ComplexAlias a2{std::make_pair("ccc", "ddd")};
+ EXPECT_TRUE(a1 < a2);
+
+ EXPECT_TRUE(a1.value() == PairOfStrings("aaa", "bbb"));
+
+ // Note a caveat, an std::pair doesn't have an overload of operator<<, and it
+ // cannot be easily added since ADL rules would require it to be in the std
+ // namespace. So we can't print ComplexAlias.
+}
+
+TYPED_TEST(StrongAliasTest, CanBeKeysInFlatMap) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ webrtc::flat_map<FooAlias, std::string> map;
+
+ FooAlias k1(GetExampleValue<TypeParam>(0));
+ FooAlias k2(GetExampleValue<TypeParam>(1));
+
+ map[k1] = "value1";
+ map[k2] = "value2";
+
+ EXPECT_EQ(map[k1], "value1");
+ EXPECT_EQ(map[k2], "value2");
+}
+
+TYPED_TEST(StrongAliasTest, CanBeKeysInStdMap) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ std::map<FooAlias, std::string> map;
+
+ FooAlias k1(GetExampleValue<TypeParam>(0));
+ FooAlias k2(GetExampleValue<TypeParam>(1));
+
+ map[k1] = "value1";
+ map[k2] = "value2";
+
+ EXPECT_EQ(map[k1], "value1");
+ EXPECT_EQ(map[k2], "value2");
+}
+
+TYPED_TEST(StrongAliasTest, CanDifferentiateOverloads) {
+ using FooAlias = StrongAlias<class FooTag, TypeParam>;
+ using BarAlias = StrongAlias<class BarTag, TypeParam>;
+ class Scope {
+ public:
+ static std::string Overload(FooAlias) { return "FooAlias"; }
+ static std::string Overload(BarAlias) { return "BarAlias"; }
+ };
+ EXPECT_EQ("FooAlias", Scope::Overload(FooAlias()));
+ EXPECT_EQ("BarAlias", Scope::Overload(BarAlias()));
+}
+
+TEST(StrongAliasTest, EnsureConstexpr) {
+ using FooAlias = StrongAlias<class FooTag, int>;
+
+ // Check constructors.
+ static constexpr FooAlias kZero{};
+ static constexpr FooAlias kOne(1);
+
+ // Check operator*.
+ static_assert(*kZero == 0, "");
+ static_assert(*kOne == 1, "");
+
+ // Check value().
+ static_assert(kZero.value() == 0, "");
+ static_assert(kOne.value() == 1, "");
+
+ // Check explicit conversions to underlying type.
+ static_assert(static_cast<int>(kZero) == 0, "");
+ static_assert(static_cast<int>(kOne) == 1, "");
+
+ // Check comparison operations.
+ static_assert(kZero == kZero, "");
+ static_assert(kZero != kOne, "");
+ static_assert(kZero < kOne, "");
+ static_assert(kZero <= kOne, "");
+ static_assert(kOne > kZero, "");
+ static_assert(kOne >= kZero, "");
+}
+
+TEST(StrongAliasTest, BooleansAreEvaluatedAsBooleans) {
+ using BoolAlias = StrongAlias<class BoolTag, bool>;
+
+ BoolAlias happy(true);
+ BoolAlias sad(false);
+
+ EXPECT_TRUE(happy);
+ EXPECT_FALSE(sad);
+ EXPECT_TRUE(*happy);
+ EXPECT_FALSE(*sad);
+}
+} // namespace webrtc