// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/base/config.h" #include "absl/container/fixed_array.h" #ifdef ABSL_HAVE_EXCEPTIONS #include #include "gtest/gtest.h" #include "absl/base/internal/exception_safety_testing.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { constexpr size_t kInlined = 25; constexpr size_t kSmallSize = kInlined / 2; constexpr size_t kLargeSize = kInlined * 2; constexpr int kInitialValue = 5; constexpr int kUpdatedValue = 10; using ::testing::TestThrowingCtor; using Thrower = testing::ThrowingValue; using ThrowAlloc = testing::ThrowingAllocator; using MoveThrower = testing::ThrowingValue; using MoveThrowAlloc = testing::ThrowingAllocator; using FixedArr = absl::FixedArray; using FixedArrWithAlloc = absl::FixedArray; using MoveFixedArr = absl::FixedArray; using MoveFixedArrWithAlloc = absl::FixedArray; TEST(FixedArrayExceptionSafety, CopyConstructor) { auto small = FixedArr(kSmallSize); TestThrowingCtor(small); auto large = FixedArr(kLargeSize); TestThrowingCtor(large); } TEST(FixedArrayExceptionSafety, CopyConstructorWithAlloc) { auto small = FixedArrWithAlloc(kSmallSize); TestThrowingCtor(small); auto large = FixedArrWithAlloc(kLargeSize); TestThrowingCtor(large); } TEST(FixedArrayExceptionSafety, MoveConstructor) { TestThrowingCtor(FixedArr(kSmallSize)); TestThrowingCtor(FixedArr(kLargeSize)); // TypeSpec::kNoThrowMove TestThrowingCtor(MoveFixedArr(kSmallSize)); TestThrowingCtor(MoveFixedArr(kLargeSize)); } TEST(FixedArrayExceptionSafety, MoveConstructorWithAlloc) { TestThrowingCtor(FixedArrWithAlloc(kSmallSize)); TestThrowingCtor(FixedArrWithAlloc(kLargeSize)); // TypeSpec::kNoThrowMove TestThrowingCtor(MoveFixedArrWithAlloc(kSmallSize)); TestThrowingCtor(MoveFixedArrWithAlloc(kLargeSize)); } TEST(FixedArrayExceptionSafety, SizeConstructor) { TestThrowingCtor(kSmallSize); TestThrowingCtor(kLargeSize); } TEST(FixedArrayExceptionSafety, SizeConstructorWithAlloc) { TestThrowingCtor(kSmallSize); TestThrowingCtor(kLargeSize); } TEST(FixedArrayExceptionSafety, SizeValueConstructor) { TestThrowingCtor(kSmallSize, Thrower()); TestThrowingCtor(kLargeSize, Thrower()); } TEST(FixedArrayExceptionSafety, SizeValueConstructorWithAlloc) { TestThrowingCtor(kSmallSize, Thrower()); TestThrowingCtor(kLargeSize, Thrower()); } TEST(FixedArrayExceptionSafety, IteratorConstructor) { auto small = FixedArr(kSmallSize); TestThrowingCtor(small.begin(), small.end()); auto large = FixedArr(kLargeSize); TestThrowingCtor(large.begin(), large.end()); } TEST(FixedArrayExceptionSafety, IteratorConstructorWithAlloc) { auto small = FixedArrWithAlloc(kSmallSize); TestThrowingCtor(small.begin(), small.end()); auto large = FixedArrWithAlloc(kLargeSize); TestThrowingCtor(large.begin(), large.end()); } TEST(FixedArrayExceptionSafety, InitListConstructor) { constexpr int small_inlined = 3; using SmallFixedArr = absl::FixedArray; TestThrowingCtor(std::initializer_list{}); // Test inlined allocation TestThrowingCtor( std::initializer_list{Thrower{}, Thrower{}}); // Test out of line allocation TestThrowingCtor(std::initializer_list{ Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}}); } TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) { constexpr int small_inlined = 3; using SmallFixedArrWithAlloc = absl::FixedArray; TestThrowingCtor(std::initializer_list{}); // Test inlined allocation TestThrowingCtor( std::initializer_list{Thrower{}, Thrower{}}); // Test out of line allocation TestThrowingCtor(std::initializer_list{ Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}}); } template testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) { // Marked volatile to prevent optimization. Used for running asan tests. volatile int sum = 0; for (const auto& thrower : *fixed_arr) { sum += thrower.Get(); } return testing::AssertionSuccess() << "Values sum to [" << sum << "]"; } TEST(FixedArrayExceptionSafety, Fill) { auto test_fill = testing::MakeExceptionSafetyTester() .WithContracts(ReadMemory) .WithOperation([&](FixedArr* fixed_arr_ptr) { auto thrower = Thrower(kUpdatedValue, testing::nothrow_ctor); fixed_arr_ptr->fill(thrower); }); EXPECT_TRUE( test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue))) .Test()); EXPECT_TRUE( test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue))) .Test()); } TEST(FixedArrayExceptionSafety, FillWithAlloc) { auto test_fill = testing::MakeExceptionSafetyTester() .WithContracts(ReadMemory) .WithOperation([&](FixedArrWithAlloc* fixed_arr_ptr) { auto thrower = Thrower(kUpdatedValue, testing::nothrow_ctor); fixed_arr_ptr->fill(thrower); }); EXPECT_TRUE(test_fill .WithInitialValue( FixedArrWithAlloc(kSmallSize, Thrower(kInitialValue))) .Test()); EXPECT_TRUE(test_fill .WithInitialValue( FixedArrWithAlloc(kLargeSize, Thrower(kInitialValue))) .Test()); } } // namespace ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_HAVE_EXCEPTIONS