tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

no_destructor_test.cc (5661B)


      1 // Copyright 2023 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/base/no_destructor.h"
     16 
     17 #include <array>
     18 #include <initializer_list>
     19 #include <string>
     20 #include <type_traits>
     21 #include <vector>
     22 
     23 #include "gmock/gmock.h"
     24 #include "gtest/gtest.h"
     25 #include "absl/base/config.h"
     26 #include "absl/base/internal/raw_logging.h"
     27 
     28 namespace {
     29 
     30 struct Blob {
     31  Blob() : val(42) {}
     32  Blob(int x, int y) : val(x + y) {}
     33  Blob(std::initializer_list<int> xs) {
     34    val = 0;
     35    for (auto& x : xs) val += x;
     36  }
     37 
     38  Blob(const Blob& /*b*/) = delete;
     39  Blob(Blob&& b) noexcept : val(b.val) {
     40    b.moved_out = true;
     41  }  // moving is fine
     42 
     43  // no crash: NoDestructor indeed does not destruct (the moved-out Blob
     44  // temporaries do get destroyed though)
     45  ~Blob() { ABSL_INTERNAL_CHECK(moved_out, "~Blob"); }
     46 
     47  int val;
     48  bool moved_out = false;
     49 };
     50 
     51 struct TypeWithDeletedDestructor {
     52  ~TypeWithDeletedDestructor() = delete;
     53 };
     54 
     55 TEST(NoDestructorTest, DestructorNeverCalled) {
     56  absl::NoDestructor<TypeWithDeletedDestructor> a;
     57  (void)a;
     58 }
     59 
     60 TEST(NoDestructorTest, Noncopyable) {
     61  using T = absl::NoDestructor<int>;
     62 
     63  EXPECT_FALSE((std::is_constructible<T, T>::value));
     64  EXPECT_FALSE((std::is_constructible<T, const T>::value));
     65  EXPECT_FALSE((std::is_constructible<T, T&>::value));
     66  EXPECT_FALSE((std::is_constructible<T, const T&>::value));
     67 
     68  EXPECT_FALSE((std::is_assignable<T&, T>::value));
     69  EXPECT_FALSE((std::is_assignable<T&, const T>::value));
     70  EXPECT_FALSE((std::is_assignable<T&, T&>::value));
     71  EXPECT_FALSE((std::is_assignable<T&, const T&>::value));
     72 }
     73 
     74 TEST(NoDestructorTest, Interface) {
     75  EXPECT_TRUE(std::is_trivially_destructible<absl::NoDestructor<Blob>>::value);
     76  EXPECT_TRUE(
     77      std::is_trivially_destructible<absl::NoDestructor<const Blob>>::value);
     78  {
     79    absl::NoDestructor<Blob> b;  // default c-tor
     80    // access: *, ->, get()
     81    EXPECT_EQ(42, (*b).val);
     82    (*b).val = 55;
     83    EXPECT_EQ(55, b->val);
     84    b->val = 66;
     85    EXPECT_EQ(66, b.get()->val);
     86    b.get()->val = 42;  // NOLINT
     87    EXPECT_EQ(42, (*b).val);
     88  }
     89  {
     90    absl::NoDestructor<const Blob> b(70, 7);  // regular c-tor, const
     91    EXPECT_EQ(77, (*b).val);
     92    EXPECT_EQ(77, b->val);
     93    EXPECT_EQ(77, b.get()->val);
     94  }
     95  {
     96    const absl::NoDestructor<Blob> b{
     97        {20, 28, 40}};  // init-list c-tor, deep const
     98    // This only works in clang, not in gcc:
     99    // const absl::NoDestructor<Blob> b({20, 28, 40});
    100    EXPECT_EQ(88, (*b).val);
    101    EXPECT_EQ(88, b->val);
    102    EXPECT_EQ(88, b.get()->val);
    103  }
    104 }
    105 
    106 TEST(NoDestructorTest, SfinaeRegressionAbstractArg) {
    107  struct Abstract {
    108    virtual ~Abstract() = default;
    109    virtual int foo() const = 0;
    110  };
    111 
    112  struct Concrete : Abstract {
    113    int foo() const override { return 17; }
    114  };
    115 
    116  struct UsesAbstractInConstructor {
    117    explicit UsesAbstractInConstructor(const Abstract& abstract)
    118        : i(abstract.foo()) {}
    119    int i;
    120  };
    121 
    122  Concrete input;
    123  absl::NoDestructor<UsesAbstractInConstructor> foo1(input);
    124  EXPECT_EQ(foo1->i, 17);
    125  absl::NoDestructor<UsesAbstractInConstructor> foo2(
    126      static_cast<const Abstract&>(input));
    127  EXPECT_EQ(foo2->i, 17);
    128 }
    129 
    130 // ========================================================================= //
    131 
    132 std::string* Str0() {
    133  static absl::NoDestructor<std::string> x;
    134  return x.get();
    135 }
    136 
    137 extern const std::string& Str2();
    138 
    139 const char* Str1() {
    140  static absl::NoDestructor<std::string> x(Str2() + "_Str1");
    141  return x->c_str();
    142 }
    143 
    144 const std::string& Str2() {
    145  static absl::NoDestructor<std::string> x("Str2");
    146  return *x;
    147 }
    148 
    149 const std::string& Str2Copy() {
    150  // Exercise copy construction
    151  static absl::NoDestructor<std::string> x(Str2());
    152  return *x;
    153 }
    154 
    155 typedef std::array<std::string, 3> MyArray;
    156 const MyArray& Array() {
    157  static absl::NoDestructor<MyArray> x{{{"foo", "bar", "baz"}}};
    158  // This only works in clang, not in gcc:
    159  // static absl::NoDestructor<MyArray> x({{"foo", "bar", "baz"}});
    160  return *x;
    161 }
    162 
    163 typedef std::vector<int> MyVector;
    164 const MyVector& Vector() {
    165  static absl::NoDestructor<MyVector> x{{1, 2, 3}};
    166  return *x;
    167 }
    168 
    169 const int& Int() {
    170  static absl::NoDestructor<int> x;
    171  return *x;
    172 }
    173 
    174 TEST(NoDestructorTest, StaticPattern) {
    175  EXPECT_TRUE(
    176      std::is_trivially_destructible<absl::NoDestructor<std::string>>::value);
    177  EXPECT_TRUE(
    178      std::is_trivially_destructible<absl::NoDestructor<MyArray>>::value);
    179  EXPECT_TRUE(
    180      std::is_trivially_destructible<absl::NoDestructor<MyVector>>::value);
    181  EXPECT_TRUE(std::is_trivially_destructible<absl::NoDestructor<int>>::value);
    182 
    183  EXPECT_EQ(*Str0(), "");
    184  Str0()->append("foo");
    185  EXPECT_EQ(*Str0(), "foo");
    186 
    187  EXPECT_EQ(std::string(Str1()), "Str2_Str1");
    188 
    189  EXPECT_EQ(Str2(), "Str2");
    190  EXPECT_EQ(Str2Copy(), "Str2");
    191 
    192  EXPECT_THAT(Array(), testing::ElementsAre("foo", "bar", "baz"));
    193 
    194  EXPECT_THAT(Vector(), testing::ElementsAre(1, 2, 3));
    195 
    196  EXPECT_EQ(0, Int());  // should get zero-initialized
    197 }
    198 
    199 TEST(NoDestructorTest, ClassTemplateArgumentDeduction) {
    200  absl::NoDestructor i(1);
    201  static_assert(std::is_same<decltype(i), absl::NoDestructor<int>>::value,
    202                "Expected deduced type to be int.");
    203 }
    204 
    205 }  // namespace