dawn-cmake/src/tests/unittests/RefCountedTests.cpp
Corentin Wallez bfeb285dcf Fix BindGroupLayout leak in PipelineLayout default.
PipelineLayout was re-entering in NXT to create the default empty BGLs,
but forgot to remove the initial external refcount for them.

Fixing this showed an issue where it was impossible to externally
reference a RefCounted that had only internal references, fix this as
well and add a test.
2018-04-17 18:10:57 -04:00

197 lines
4.5 KiB
C++

// Copyright 2017 The NXT 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
//
// http://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 <gtest/gtest.h>
#include "backend/RefCounted.h"
using namespace backend;
struct RCTest : public RefCounted {
RCTest() {
}
RCTest(bool* deleted): deleted(deleted) {
}
~RCTest() override {
if (deleted != nullptr) {
*deleted = true;
}
}
RCTest* GetThis() {
return this;
}
bool* deleted = nullptr;
};
// Test that RCs start with one external ref, and removing it destroys the object.
TEST(RefCounted, StartsWithOneExternalRef) {
bool deleted = false;
auto test = new RCTest(&deleted);
test->Release();
ASSERT_TRUE(deleted);
}
// Test internal refs keep the RC alive.
TEST(RefCounted, InternalRefKeepsAlive) {
bool deleted = false;
auto test = new RCTest(&deleted);
test->ReferenceInternal();
test->Release();
ASSERT_FALSE(deleted);
test->ReleaseInternal();
ASSERT_TRUE(deleted);
}
// Test that when adding an external ref from 0, an internal ref is added
TEST(RefCounted, AddExternalRefFromZero) {
bool deleted = false;
auto test = new RCTest(&deleted);
test->ReferenceInternal();
test->Release();
ASSERT_FALSE(deleted);
// Reference adds an internal ref and release removes one
test->Reference();
test->Release();
ASSERT_FALSE(deleted);
test->ReleaseInternal();
ASSERT_TRUE(deleted);
}
// Test Ref remove internal reference when going out of scope
TEST(Ref, EndOfScopeRemovesInternalRef) {
bool deleted = false;
{
Ref<RCTest> test(new RCTest(&deleted));
test->Release();
}
ASSERT_TRUE(deleted);
}
// Test getting pointer out of the Ref
TEST(Ref, Gets) {
RCTest* original = new RCTest;
Ref<RCTest> test(original);
test->Release();
ASSERT_EQ(test.Get(), original);
ASSERT_EQ(&*test, original);
ASSERT_EQ(test->GetThis(), original);
}
// Test Refs default to null
TEST(Ref, DefaultsToNull) {
Ref<RCTest> test;
ASSERT_EQ(test.Get(), nullptr);
ASSERT_EQ(&*test, nullptr);
ASSERT_EQ(test->GetThis(), nullptr);
}
// Test Refs can be used inside ifs
TEST(Ref, BoolConversion) {
Ref<RCTest> empty;
Ref<RCTest> full(new RCTest);
full->Release();
if (!full || empty) {
ASSERT_TRUE(false);
}
}
// Test Ref's copy constructor
TEST(Ref, CopyConstructor) {
bool deleted = false;
RCTest* original = new RCTest(&deleted);
Ref<RCTest> source(original);
Ref<RCTest> destination(source);
original->Release();
ASSERT_EQ(source.Get(), original);
ASSERT_EQ(destination.Get(), original);
source = nullptr;
ASSERT_FALSE(deleted);
destination = nullptr;
ASSERT_TRUE(deleted);
}
// Test Ref's copy assignment
TEST(Ref, CopyAssignment) {
bool deleted = false;
RCTest* original = new RCTest(&deleted);
Ref<RCTest> source(original);
original->Release();
Ref<RCTest> destination;
destination = source;
ASSERT_EQ(source.Get(), original);
ASSERT_EQ(destination.Get(), original);
source = nullptr;
// This fails when address sanitizer is turned on
ASSERT_FALSE(deleted);
destination = nullptr;
ASSERT_TRUE(deleted);
}
// Test Ref's move constructor
TEST(Ref, MoveConstructor) {
bool deleted = false;
RCTest* original = new RCTest(&deleted);
Ref<RCTest> source(original);
Ref<RCTest> destination(std::move(source));
original->Release();
ASSERT_EQ(source.Get(), nullptr);
ASSERT_EQ(destination.Get(), original);
ASSERT_FALSE(deleted);
destination = nullptr;
ASSERT_TRUE(deleted);
}
// Test Ref's move assignment
TEST(Ref, MoveAssignment) {
bool deleted = false;
RCTest* original = new RCTest(&deleted);
Ref<RCTest> source(original);
original->Release();
Ref<RCTest> destination;
destination = std::move(source);
ASSERT_EQ(source.Get(), nullptr);
ASSERT_EQ(destination.Get(), original);
ASSERT_FALSE(deleted);
destination = nullptr;
ASSERT_TRUE(deleted);
}