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