v8/test/unittests/heap/cppgc/finalizer-trait_unittest.cc
Michael Lippautz 9d75253764 cppgc: Hello world
"By my deeds I honor him. V8."

- Add basic build files for library and unittests.
- Integrate unittests also in existing V8 unittests for simplicity.

The CL also adds FinalizerTrait and unittests to allow building a
testing target that executes code.

FinalizerTrait is used to determine how managed C++ types are
finalized. The trait should not be overridable by users but needs to
be exposed on API-level to avoid including library-internal headers.

Bug: chromium:1056170
Change-Id: I64d91053410a17a7835e50547f58990625d2da28
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2108549
Reviewed-by: Hannes Payer <hpayer@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66834}
2020-03-23 21:42:56 +00:00

119 lines
3.3 KiB
C++

// Copyright 2020 the V8 project 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 "include/cppgc/finalizer-trait.h"
#include <type_traits>
#include "testing/gtest/include/gtest/gtest.h"
namespace cppgc {
namespace internal {
namespace {
// Trivially destructible types.
class TypeWithoutDestructor final {};
class TypeWithPrimitive final {
public:
int foo = 0;
};
class InvokeCounter {
public:
static size_t kCallcount;
static void Reset() { kCallcount = 0; }
static void Invoke() { kCallcount++; }
};
size_t InvokeCounter::kCallcount = 0;
// Regular C++ use cases.
class TypeWithDestructor final : public InvokeCounter {
public:
~TypeWithDestructor() { Invoke(); }
};
class TypeWithVirtualDestructorBase {
public:
virtual ~TypeWithVirtualDestructorBase() = default;
};
class TypeWithVirtualDestructorChild final
: public TypeWithVirtualDestructorBase,
public InvokeCounter {
public:
~TypeWithVirtualDestructorChild() final { Invoke(); }
};
// Manual dispatch to avoid vtables.
class TypeWithCustomFinalizationMethod final : public InvokeCounter {
public:
void FinalizeGarbageCollectedObject() { Invoke(); }
};
class TypeWithCustomFinalizationMethodAtBase {
public:
void FinalizeGarbageCollectedObject();
};
class TypeWithCustomFinalizationMethodAtBaseChild
: public TypeWithCustomFinalizationMethodAtBase,
public InvokeCounter {
public:
~TypeWithCustomFinalizationMethodAtBaseChild() { Invoke(); }
};
void TypeWithCustomFinalizationMethodAtBase::FinalizeGarbageCollectedObject() {
// The test knows that base is only inherited by a single child. In practice
// users can maintain a map of valid types in already existing storage.
static_cast<TypeWithCustomFinalizationMethodAtBaseChild*>(this)
->~TypeWithCustomFinalizationMethodAtBaseChild();
}
template <typename Type>
void ExpectFinalizerIsInvoked(Type* object) {
InvokeCounter::Reset();
EXPECT_NE(nullptr, FinalizerTrait<Type>::kCallback);
FinalizerTrait<Type>::kCallback(object);
EXPECT_EQ(1u, InvokeCounter::kCallcount);
operator delete(object);
}
} // namespace
TEST(FinalizerTrait, TypeWithoutDestructorHasNoFinalizer) {
static_assert(std::is_trivially_destructible<TypeWithoutDestructor>::value,
"trivially destructible");
EXPECT_EQ(nullptr, FinalizerTrait<TypeWithoutDestructor>::kCallback);
}
TEST(FinalizerTrait, TypeWithPrimitiveHasNoFinalizer) {
static_assert(std::is_trivially_destructible<TypeWithPrimitive>::value,
"trivially destructible");
EXPECT_EQ(nullptr, FinalizerTrait<TypeWithPrimitive>::kCallback);
}
TEST(FinalizerTrait, FinalizerForTypeWithDestructor) {
ExpectFinalizerIsInvoked(new TypeWithDestructor());
}
TEST(FinalizerTrait, FinalizerForTypeWithVirtualBaseDtor) {
TypeWithVirtualDestructorBase* base = new TypeWithVirtualDestructorChild();
ExpectFinalizerIsInvoked(base);
}
TEST(FinalizerTrait, FinalizerForCustomFinalizationMethod) {
ExpectFinalizerIsInvoked(new TypeWithCustomFinalizationMethod());
}
TEST(FinalizerTrait, FinalizerForCustomFinalizationMethodInBase) {
TypeWithCustomFinalizationMethodAtBase* base =
new TypeWithCustomFinalizationMethodAtBaseChild();
ExpectFinalizerIsInvoked(base);
}
} // namespace internal
} // namespace cppgc