diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/strong_alias_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/rtc_base/strong_alias_unittest.cc | 362 |
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 |