chromium/v8/test/unittests/heap/cppgc/member-unittest.cc

// 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/member.h"

#include <algorithm>
#include <vector>

#include "include/cppgc/allocation.h"
#include "include/cppgc/garbage-collected.h"
#include "include/cppgc/internal/member-storage.h"
#include "include/cppgc/internal/pointer-policies.h"
#include "include/cppgc/persistent.h"
#include "include/cppgc/sentinel-pointer.h"
#include "include/cppgc/type-traits.h"
#include "test/unittests/heap/cppgc/tests.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cppgc {
namespace internal {

namespace {

struct GCed : GarbageCollected<GCed> {};

struct DerivedMixin : GarbageCollectedMixin {};

struct DerivedGCed : GCed, DerivedMixin {};

// Compile tests.
static_assert;
static_assert;

static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;
static_assert;

struct CustomWriteBarrierPolicy {};
size_t CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered =;
size_t CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered =;

MemberWithCustomBarrier;

struct CustomCheckingPolicy {};
std::vector<GCed*> CustomCheckingPolicy::Cached;
size_t CustomCheckingPolicy::ChecksTriggered =;

MemberWithCustomChecking;

class MemberTest : public testing::TestSupportingAllocationOnly {};

}  // namespace

template <template <typename> class MemberType>
void EmptyTest() {}

TEST_F(MemberTest, Empty) {}

template <template <typename> class MemberType>
void AtomicCtorTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, AtomicCtor) {}

template <template <typename> class MemberType>
void ClearTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, Clear) {}

template <template <typename> class MemberType>
void ReleaseTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, Release) {}

template <template <typename> class MemberType1,
          template <typename> class MemberType2>
void SwapTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, Swap) {}

template <template <typename> class MemberType1,
          template <typename> class MemberType2>
void MoveTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, Move) {}

template <template <typename> class MemberType1,
          template <typename> class MemberType2>
void HeterogeneousConversionTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, HeterogeneousInterface) {}

template <template <typename> class MemberType,
          template <typename> class PersistentType>
void PersistentConversionTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, PersistentConversion) {}

template <template <typename> class MemberType1,
          template <typename> class MemberType2>
void EqualityTest(cppgc::Heap* heap) {}

TEST_F(MemberTest, EqualityTest) {}

TEST_F(MemberTest, HeterogeneousEqualityTest) {}

TEST_F(MemberTest, WriteBarrierTriggered) {}

TEST_F(MemberTest, CheckingPolicy) {}

namespace {

class MemberHeapTest : public testing::TestWithHeap {};

class GCedWithMembers final : public GarbageCollected<GCedWithMembers> {};
size_t GCedWithMembers::live_count_ =;

}  // namespace

TEST_F(MemberHeapTest, MemberRetainsObject) {}

TEST_F(MemberHeapTest, WeakMemberDoesNotRetainObject) {}

namespace {
class GCedWithConstWeakMember
    : public GarbageCollected<GCedWithConstWeakMember> {};
}  // namespace

TEST_F(MemberHeapTest, ConstWeakRefIsClearedOnGC) {}

#if V8_ENABLE_CHECKS

namespace {
class MemberHeapDeathTest : public testing::TestWithHeap {};

class LinkedNode final : public GarbageCollected<LinkedNode> {};

}  // namespace

// The following tests create multiple heaps per thread, which is not supported
// with pointer compression enabled.
#if !defined(CPPGC_POINTER_COMPRESSION)
TEST_F(MemberHeapDeathTest, CheckForOffHeapMemberCrashesOnReassignment) {
  std::vector<Member<LinkedNode>> off_heap_member;
  // Verification state is constructed on first assignment.
  off_heap_member.emplace_back(
      MakeGarbageCollected<LinkedNode>(GetAllocationHandle(), nullptr));
  {
    auto tmp_heap = cppgc::Heap::Create(platform_);
    auto* tmp_obj = MakeGarbageCollected<LinkedNode>(
        tmp_heap->GetAllocationHandle(), nullptr);
    EXPECT_DEATH_IF_SUPPORTED(off_heap_member[0] = tmp_obj, "");
  }
}

TEST_F(MemberHeapDeathTest, CheckForOnStackMemberCrashesOnReassignment) {
  Member<LinkedNode> stack_member;
  // Verification state is constructed on first assignment.
  stack_member =
      MakeGarbageCollected<LinkedNode>(GetAllocationHandle(), nullptr);
  {
    auto tmp_heap = cppgc::Heap::Create(platform_);
    auto* tmp_obj = MakeGarbageCollected<LinkedNode>(
        tmp_heap->GetAllocationHandle(), nullptr);
    EXPECT_DEATH_IF_SUPPORTED(stack_member = tmp_obj, "");
  }
}

TEST_F(MemberHeapDeathTest, CheckForOnHeapMemberCrashesOnInitialAssignment) {
  auto* obj = MakeGarbageCollected<LinkedNode>(GetAllocationHandle(), nullptr);
  {
    auto tmp_heap = cppgc::Heap::Create(platform_);
    EXPECT_DEATH_IF_SUPPORTED(
        // For regular on-heap Member references the verification state is
        // constructed eagerly on creating the reference.
        MakeGarbageCollected<LinkedNode>(tmp_heap->GetAllocationHandle(), obj),
        "");
  }
}
#endif  // defined(CPPGC_POINTER_COMPRESSION)

#if defined(CPPGC_POINTER_COMPRESSION)
TEST_F(MemberTest, CompressDecompress) {}
#endif  // defined(CPPGC_POINTER_COMPRESSION)

#endif  // V8_ENABLE_CHECKS

}  // namespace internal
}  // namespace cppgc