xref: /aosp_15_r20/external/pigweed/pw_toolchain/no_destructor_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // 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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_toolchain/no_destructor.h"
16 
17 #include "pw_assert/check.h"
18 #include "pw_unit_test/framework.h"
19 
20 namespace pw {
21 namespace {
22 
23 class HasADestructor {
24  public:
HasADestructor(bool & destructor_called_flag)25   HasADestructor(bool& destructor_called_flag)
26       : destructor_called_(destructor_called_flag) {
27     destructor_called_ = false;
28   }
29 
~HasADestructor()30   ~HasADestructor() { destructor_called_ = true; }
31 
32  private:
33   bool& destructor_called_;
34 };
35 
36 class CrashInDestructor {
37  public:
MyAddress() const38   const CrashInDestructor* MyAddress() const { return this; }
39 
40   int some_value = 0;
41 
42  private:
~CrashInDestructor()43   ~CrashInDestructor() { PW_CRASH("This destructor should never execute!"); }
44 };
45 
46 class TrivialDestructor {
47  public:
TrivialDestructor(int initial_value)48   TrivialDestructor(int initial_value) : value(initial_value) {}
49 
50   int value;
51 };
52 
TEST(NoDestructor,ShouldNotCallDestructor)53 TEST(NoDestructor, ShouldNotCallDestructor) {
54   bool destructor_called = false;
55 
56   {
57     HasADestructor should_be_destroyed(destructor_called);
58   }
59 
60   EXPECT_TRUE(destructor_called);
61 
62   {
63     NoDestructor<HasADestructor> should_not_be_destroyed(destructor_called);
64   }
65 
66   EXPECT_FALSE(destructor_called);
67 }
68 
TEST(NoDestructor,MemberAccess)69 TEST(NoDestructor, MemberAccess) {
70   NoDestructor<CrashInDestructor> no_destructor;
71 
72   no_destructor->some_value = 123;
73   EXPECT_EQ(123, (*no_destructor).some_value);
74   EXPECT_EQ(no_destructor.operator->(), no_destructor->MyAddress());
75 }
76 
TEST(NoDestructor,TrivialDestructor)77 TEST(NoDestructor, TrivialDestructor) {
78   NoDestructor<TrivialDestructor> no_destructor(555);
79 
80   EXPECT_EQ(no_destructor->value, 555);
81   no_destructor->value = 123;
82   EXPECT_EQ(no_destructor->value, 123);
83 }
84 
TEST(NoDestructor,TrivialType)85 TEST(NoDestructor, TrivialType) {
86   NoDestructor<int> no_destructor;
87 
88   EXPECT_EQ(*no_destructor, 0);
89   *no_destructor = 123;
90   EXPECT_EQ(*no_destructor, 123);
91 }
92 
TEST(NoDestructor,FunctionStatic)93 TEST(NoDestructor, FunctionStatic) {
94   static NoDestructor<CrashInDestructor> function_static_no_destructor;
95 }
96 
97 NoDestructor<CrashInDestructor> global_no_destructor;
98 
99 static_assert(!std::is_trivially_destructible<CrashInDestructor>::value,
100               "Type should not be trivially destructible");
101 static_assert(
102     std::is_trivially_destructible<NoDestructor<CrashInDestructor>>::value,
103     "Wrapper should be trivially destructible");
104 
105 }  // namespace
106 }  // namespace pw
107