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 "gtest/gtest.h"
18 #include "pw_assert/check.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
TEST(NoDestructor,ShouldNotCallDestructor)46 TEST(NoDestructor, ShouldNotCallDestructor) {
47 bool destructor_called = false;
48
49 { HasADestructor should_be_destroyed(destructor_called); }
50
51 EXPECT_TRUE(destructor_called);
52
53 { NoDestructor<HasADestructor> should_not_be_destroyed(destructor_called); }
54
55 EXPECT_FALSE(destructor_called);
56 }
57
TEST(NoDestructor,MemberAccess)58 TEST(NoDestructor, MemberAccess) {
59 NoDestructor<CrashInDestructor> no_destructor;
60
61 no_destructor->some_value = 123;
62 EXPECT_EQ(123, (*no_destructor).some_value);
63 EXPECT_EQ(no_destructor.operator->(), no_destructor->MyAddress());
64 }
65
TEST(NoDestructor,TrivialType)66 TEST(NoDestructor, TrivialType) {
67 NoDestructor<int> no_destructor;
68
69 EXPECT_EQ(*no_destructor, 0);
70 *no_destructor = 123;
71 EXPECT_EQ(*no_destructor, 123);
72 }
73
TEST(NoDestructor,FunctionStatic)74 TEST(NoDestructor, FunctionStatic) {
75 static NoDestructor<CrashInDestructor> function_static_no_destructor;
76 }
77
78 NoDestructor<CrashInDestructor> global_no_destructor;
79
80 static_assert(!std::is_trivially_destructible<CrashInDestructor>::value,
81 "Type should not be trivially destructible");
82 static_assert(
83 std::is_trivially_destructible<NoDestructor<CrashInDestructor>>::value,
84 "Wrapper should be trivially destructible");
85
86 } // namespace
87 } // namespace pw
88