blob: c25d76a90f778d7dfb31b235ffe605375bd5a502 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
#include <fbl/no_destructor.h>
#include <zxtest/zxtest.h>
namespace {
TEST(NoDestructor, SimpleTest) {
// Set a boolean flag to true when the class instance is destructed.
class SetFlagOnDestruct {
public:
explicit SetFlagOnDestruct(bool* destructor_run) : destructor_run_(destructor_run) {}
~SetFlagOnDestruct() { *destructor_run_ = true; }
private:
bool* destructor_run_;
};
// A standard instance of "SetFlagOnDestruct" should set the flag.
bool destructed = false;
{
SetFlagOnDestruct x(&destructed);
EXPECT_FALSE(destructed);
}
EXPECT_TRUE(destructed);
// An instance wrapped by "gtl::NoDestructor" should not set the flag.
destructed = false;
{
fbl::NoDestructor<SetFlagOnDestruct> x(&destructed);
EXPECT_FALSE(destructed);
}
EXPECT_FALSE(destructed);
}
// A missing symbol, used to generate a linker error if code ends up in the final
// image.
extern "C" void __destructor_incorrectly_compiled_into_final_image();
TEST(NoDestructor, DestructorNotLinked) {
// This class will produce a linker error to a missing symbol if the destructor
// is emitted.
class DestructorWithLinkError {
public:
DestructorWithLinkError() = default;
~DestructorWithLinkError() { __destructor_incorrectly_compiled_into_final_image(); }
};
static fbl::NoDestructor<DestructorWithLinkError> value{};
}
// Ensure the getters function correctly.
TEST(NoDestructor, Get) {
struct Struct {
int a;
};
fbl::NoDestructor<Struct> value;
value->a = 1;
EXPECT_EQ(value->a, 1);
EXPECT_EQ(value.get()->a, 1);
EXPECT_EQ((*value).a, 1);
}
// Test object with non-standard alignment constraints.
TEST(NoDestructor, Alignment) {
struct alignas(128) LargeAlignment {
char data[128];
};
fbl::NoDestructor<LargeAlignment> object{};
EXPECT_EQ(alignof(decltype(object)), 128);
EXPECT_EQ(reinterpret_cast<uintptr_t>(object.get()) % 128, 0);
}
// Test object with copy construction.
TEST(NoDestructor, CopyConstruction) {
fbl::NoDestructor<int> x = int(42);
EXPECT_EQ(*x, 42);
}
// Test object with move construction.
TEST(NoDestructor, MoveConstruction) {
auto ptr = std::make_unique<int>(42);
fbl::NoDestructor<std::unique_ptr<int>> x = std::move(ptr);
EXPECT_EQ(**x, 42);
x->reset();
}
TEST(NoDestructor, NoExcept) {
// Ensure noexcept constructors are exposed as such.
static_assert(noexcept(fbl::NoDestructor<int>()));
// Ensure noexcept values propagate.
struct MaybeException {
MaybeException() noexcept(false) = default;
};
static_assert(!noexcept(fbl::NoDestructor<MaybeException>()));
}
} // namespace