1 // Copyright 2019 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/config.h"
16 #include "absl/container/fixed_array.h"
17 
18 #ifdef ABSL_HAVE_EXCEPTIONS
19 
20 #include <initializer_list>
21 
22 #include "gtest/gtest.h"
23 #include "absl/base/internal/exception_safety_testing.h"
24 
25 namespace absl {
26 ABSL_NAMESPACE_BEGIN
27 
28 namespace {
29 
30 constexpr size_t kInlined = 25;
31 constexpr size_t kSmallSize = kInlined / 2;
32 constexpr size_t kLargeSize = kInlined * 2;
33 
34 constexpr int kInitialValue = 5;
35 constexpr int kUpdatedValue = 10;
36 
37 using ::testing::TestThrowingCtor;
38 
39 using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
40 using ThrowAlloc =
41     testing::ThrowingAllocator<Thrower, testing::AllocSpec::kEverythingThrows>;
42 using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
43 using MoveThrowAlloc =
44     testing::ThrowingAllocator<MoveThrower,
45                                testing::AllocSpec::kEverythingThrows>;
46 
47 using FixedArr = absl::FixedArray<Thrower, kInlined>;
48 using FixedArrWithAlloc = absl::FixedArray<Thrower, kInlined, ThrowAlloc>;
49 
50 using MoveFixedArr = absl::FixedArray<MoveThrower, kInlined>;
51 using MoveFixedArrWithAlloc =
52     absl::FixedArray<MoveThrower, kInlined, MoveThrowAlloc>;
53 
TEST(FixedArrayExceptionSafety,CopyConstructor)54 TEST(FixedArrayExceptionSafety, CopyConstructor) {
55   auto small = FixedArr(kSmallSize);
56   TestThrowingCtor<FixedArr>(small);
57 
58   auto large = FixedArr(kLargeSize);
59   TestThrowingCtor<FixedArr>(large);
60 }
61 
TEST(FixedArrayExceptionSafety,CopyConstructorWithAlloc)62 TEST(FixedArrayExceptionSafety, CopyConstructorWithAlloc) {
63   auto small = FixedArrWithAlloc(kSmallSize);
64   TestThrowingCtor<FixedArrWithAlloc>(small);
65 
66   auto large = FixedArrWithAlloc(kLargeSize);
67   TestThrowingCtor<FixedArrWithAlloc>(large);
68 }
69 
TEST(FixedArrayExceptionSafety,MoveConstructor)70 TEST(FixedArrayExceptionSafety, MoveConstructor) {
71   TestThrowingCtor<FixedArr>(FixedArr(kSmallSize));
72   TestThrowingCtor<FixedArr>(FixedArr(kLargeSize));
73 
74   // TypeSpec::kNoThrowMove
75   TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kSmallSize));
76   TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kLargeSize));
77 }
78 
TEST(FixedArrayExceptionSafety,MoveConstructorWithAlloc)79 TEST(FixedArrayExceptionSafety, MoveConstructorWithAlloc) {
80   TestThrowingCtor<FixedArrWithAlloc>(FixedArrWithAlloc(kSmallSize));
81   TestThrowingCtor<FixedArrWithAlloc>(FixedArrWithAlloc(kLargeSize));
82 
83   // TypeSpec::kNoThrowMove
84   TestThrowingCtor<MoveFixedArrWithAlloc>(MoveFixedArrWithAlloc(kSmallSize));
85   TestThrowingCtor<MoveFixedArrWithAlloc>(MoveFixedArrWithAlloc(kLargeSize));
86 }
87 
TEST(FixedArrayExceptionSafety,SizeConstructor)88 TEST(FixedArrayExceptionSafety, SizeConstructor) {
89   TestThrowingCtor<FixedArr>(kSmallSize);
90   TestThrowingCtor<FixedArr>(kLargeSize);
91 }
92 
TEST(FixedArrayExceptionSafety,SizeConstructorWithAlloc)93 TEST(FixedArrayExceptionSafety, SizeConstructorWithAlloc) {
94   TestThrowingCtor<FixedArrWithAlloc>(kSmallSize);
95   TestThrowingCtor<FixedArrWithAlloc>(kLargeSize);
96 }
97 
TEST(FixedArrayExceptionSafety,SizeValueConstructor)98 TEST(FixedArrayExceptionSafety, SizeValueConstructor) {
99   TestThrowingCtor<FixedArr>(kSmallSize, Thrower());
100   TestThrowingCtor<FixedArr>(kLargeSize, Thrower());
101 }
102 
TEST(FixedArrayExceptionSafety,SizeValueConstructorWithAlloc)103 TEST(FixedArrayExceptionSafety, SizeValueConstructorWithAlloc) {
104   TestThrowingCtor<FixedArrWithAlloc>(kSmallSize, Thrower());
105   TestThrowingCtor<FixedArrWithAlloc>(kLargeSize, Thrower());
106 }
107 
TEST(FixedArrayExceptionSafety,IteratorConstructor)108 TEST(FixedArrayExceptionSafety, IteratorConstructor) {
109   auto small = FixedArr(kSmallSize);
110   TestThrowingCtor<FixedArr>(small.begin(), small.end());
111 
112   auto large = FixedArr(kLargeSize);
113   TestThrowingCtor<FixedArr>(large.begin(), large.end());
114 }
115 
TEST(FixedArrayExceptionSafety,IteratorConstructorWithAlloc)116 TEST(FixedArrayExceptionSafety, IteratorConstructorWithAlloc) {
117   auto small = FixedArrWithAlloc(kSmallSize);
118   TestThrowingCtor<FixedArrWithAlloc>(small.begin(), small.end());
119 
120   auto large = FixedArrWithAlloc(kLargeSize);
121   TestThrowingCtor<FixedArrWithAlloc>(large.begin(), large.end());
122 }
123 
TEST(FixedArrayExceptionSafety,InitListConstructor)124 TEST(FixedArrayExceptionSafety, InitListConstructor) {
125   constexpr int small_inlined = 3;
126   using SmallFixedArr = absl::FixedArray<Thrower, small_inlined>;
127 
128   TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{});
129   // Test inlined allocation
130   TestThrowingCtor<SmallFixedArr>(
131       std::initializer_list<Thrower>{Thrower{}, Thrower{}});
132   // Test out of line allocation
133   TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{
134       Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
135 }
136 
TEST(FixedArrayExceptionSafety,InitListConstructorWithAlloc)137 TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) {
138   constexpr int small_inlined = 3;
139   using SmallFixedArrWithAlloc =
140       absl::FixedArray<Thrower, small_inlined, ThrowAlloc>;
141 
142   TestThrowingCtor<SmallFixedArrWithAlloc>(std::initializer_list<Thrower>{});
143   // Test inlined allocation
144   TestThrowingCtor<SmallFixedArrWithAlloc>(
145       std::initializer_list<Thrower>{Thrower{}, Thrower{}});
146   // Test out of line allocation
147   TestThrowingCtor<SmallFixedArrWithAlloc>(std::initializer_list<Thrower>{
148       Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
149 }
150 
151 template <typename FixedArrT>
ReadMemory(FixedArrT * fixed_arr)152 testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
153   int sum = 0;
154   for (const auto& thrower : *fixed_arr) {
155     sum += thrower.Get();
156   }
157   return testing::AssertionSuccess() << "Values sum to [" << sum << "]";
158 }
159 
TEST(FixedArrayExceptionSafety,Fill)160 TEST(FixedArrayExceptionSafety, Fill) {
161   auto test_fill = testing::MakeExceptionSafetyTester()
162                        .WithContracts(ReadMemory<FixedArr>)
163                        .WithOperation([&](FixedArr* fixed_arr_ptr) {
164                          auto thrower =
165                              Thrower(kUpdatedValue, testing::nothrow_ctor);
166                          fixed_arr_ptr->fill(thrower);
167                        });
168 
169   EXPECT_TRUE(
170       test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue)))
171           .Test());
172   EXPECT_TRUE(
173       test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue)))
174           .Test());
175 }
176 
TEST(FixedArrayExceptionSafety,FillWithAlloc)177 TEST(FixedArrayExceptionSafety, FillWithAlloc) {
178   auto test_fill = testing::MakeExceptionSafetyTester()
179                        .WithContracts(ReadMemory<FixedArrWithAlloc>)
180                        .WithOperation([&](FixedArrWithAlloc* fixed_arr_ptr) {
181                          auto thrower =
182                              Thrower(kUpdatedValue, testing::nothrow_ctor);
183                          fixed_arr_ptr->fill(thrower);
184                        });
185 
186   EXPECT_TRUE(test_fill
187                   .WithInitialValue(
188                       FixedArrWithAlloc(kSmallSize, Thrower(kInitialValue)))
189                   .Test());
190   EXPECT_TRUE(test_fill
191                   .WithInitialValue(
192                       FixedArrWithAlloc(kLargeSize, Thrower(kInitialValue)))
193                   .Test());
194 }
195 
196 }  // namespace
197 
198 ABSL_NAMESPACE_END
199 }  // namespace absl
200 
201 #endif  // ABSL_HAVE_EXCEPTIONS
202