blob: fd5f10d8e0f70b189358b793404fb1dbc67b557a [file] [log] [blame]
// Copyright 2013 The Flutter 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 <sys/types.h>
#include <functional>
#include <memory>
#include <utility>
#include "fml/synchronization/waitable_event.h"
#include "gtest/gtest.h"
#include "impeller/renderer/backend/vulkan/resource_manager_vk.h"
namespace impeller {
namespace testing {
// While expected to be a singleton per context, the class does not enforce it.
TEST(ResourceManagerVKTest, CreatesANewInstance) {
auto const a = ResourceManagerVK::Create();
auto const b = ResourceManagerVK::Create();
EXPECT_NE(a, b);
}
namespace {
// Invokes the provided callback when the destructor is called.
//
// Can be moved, but not copied.
class DeathRattle final {
public:
explicit DeathRattle(std::function<void()> callback)
: callback_(std::move(callback)) {}
DeathRattle(DeathRattle&&) = default;
DeathRattle& operator=(DeathRattle&&) = default;
~DeathRattle() { callback_(); }
private:
std::function<void()> callback_;
};
} // namespace
TEST(ResourceManagerVKTest, ReclaimMovesAResourceAndDestroysIt) {
auto const manager = ResourceManagerVK::Create();
auto waiter = fml::AutoResetWaitableEvent();
auto dead = false;
auto rattle = DeathRattle([&waiter]() { waiter.Signal(); });
// Not killed immediately.
EXPECT_FALSE(waiter.IsSignaledForTest());
{
auto resource = UniqueResourceVKT<DeathRattle>(manager, std::move(rattle));
}
waiter.Wait();
}
// Regression test for https://github.com/flutter/flutter/issues/134482.
TEST(ResourceManagerVKTest, TerminatesWhenOutOfScope) {
// Originally, this shared_ptr was never destroyed, and the thread never
// terminated. This test ensures that the thread terminates when the
// ResourceManagerVK is out of scope.
std::weak_ptr<ResourceManagerVK> manager;
{
auto shared = ResourceManagerVK::Create();
manager = shared;
}
// The thread should have terminated.
EXPECT_EQ(manager.lock(), nullptr);
}
TEST(ResourceManagerVKTest, IsThreadSafe) {
// In a typical app, there is a single ResourceManagerVK per app, shared b/w
// threads.
//
// This test ensures that the ResourceManagerVK is thread-safe.
std::weak_ptr<ResourceManagerVK> manager;
{
auto const manager = ResourceManagerVK::Create();
// Spawn two threads, and have them both put resources into the manager.
struct MockResource {};
std::thread thread1([&manager]() {
UniqueResourceVKT<MockResource>(manager, MockResource{});
});
std::thread thread2([&manager]() {
UniqueResourceVKT<MockResource>(manager, MockResource{});
});
thread1.join();
thread2.join();
}
// The thread should have terminated.
EXPECT_EQ(manager.lock(), nullptr);
}
} // namespace testing
} // namespace impeller