Replaces bespoke call captures from mock gles with gmock (flutter/engine#56995)
test exempt: test only code ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/engine/blob/main/docs/testing/Testing-the-engine.md [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md
This commit is contained in:
parent
30289be8ba
commit
afb249fd2b
@ -12,12 +12,18 @@
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
TEST(BufferBindingsGLESTest, BindUniformData) {
|
||||
BufferBindingsGLES bindings;
|
||||
absl::flat_hash_map<std::string, GLint> uniform_bindings;
|
||||
uniform_bindings["SHADERMETADATA.FOOBAR"] = 1;
|
||||
bindings.SetUniformBindings(std::move(uniform_bindings));
|
||||
std::shared_ptr<MockGLES> mock_gl = MockGLES::Init();
|
||||
auto mock_gles_impl = std::make_unique<MockGLESImpl>();
|
||||
|
||||
EXPECT_CALL(*mock_gles_impl, Uniform1fv(_, _, _)).Times(1);
|
||||
|
||||
std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
|
||||
std::vector<BufferResource> bound_buffers;
|
||||
std::vector<TextureAndSampler> bound_textures;
|
||||
|
||||
@ -39,9 +45,6 @@ TEST(BufferBindingsGLESTest, BindUniformData) {
|
||||
EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), bound_textures,
|
||||
bound_buffers, Range{0, 0},
|
||||
Range{0, 1}));
|
||||
std::vector<std::string> captured_calls = mock_gl->GetCapturedCalls();
|
||||
EXPECT_TRUE(std::find(captured_calls.begin(), captured_calls.end(),
|
||||
"glUniform1fv") != captured_calls.end());
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
@ -33,9 +33,9 @@ TEST(CapabilitiesGLES, CanInitializeWithDefaults) {
|
||||
}
|
||||
|
||||
TEST(CapabilitiesGLES, SupportsDecalSamplerAddressMode) {
|
||||
auto const extensions = std::vector<const unsigned char*>{
|
||||
reinterpret_cast<const unsigned char*>("GL_KHR_debug"), //
|
||||
reinterpret_cast<const unsigned char*>("GL_EXT_texture_border_clamp"), //
|
||||
auto const extensions = std::vector<const char*>{
|
||||
"GL_KHR_debug", //
|
||||
"GL_EXT_texture_border_clamp", //
|
||||
};
|
||||
auto mock_gles = MockGLES::Init(extensions);
|
||||
auto capabilities = mock_gles->GetProcTable().GetCapabilities();
|
||||
@ -43,9 +43,9 @@ TEST(CapabilitiesGLES, SupportsDecalSamplerAddressMode) {
|
||||
}
|
||||
|
||||
TEST(CapabilitiesGLES, SupportsDecalSamplerAddressModeNotOES) {
|
||||
auto const extensions = std::vector<const unsigned char*>{
|
||||
reinterpret_cast<const unsigned char*>("GL_KHR_debug"), //
|
||||
reinterpret_cast<const unsigned char*>("GL_OES_texture_border_clamp"), //
|
||||
auto const extensions = std::vector<const char*>{
|
||||
"GL_KHR_debug", //
|
||||
"GL_OES_texture_border_clamp", //
|
||||
};
|
||||
auto mock_gles = MockGLES::Init(extensions);
|
||||
auto capabilities = mock_gles->GetProcTable().GetCapabilities();
|
||||
@ -53,10 +53,9 @@ TEST(CapabilitiesGLES, SupportsDecalSamplerAddressModeNotOES) {
|
||||
}
|
||||
|
||||
TEST(CapabilitiesGLES, SupportsFramebufferFetch) {
|
||||
auto const extensions = std::vector<const unsigned char*>{
|
||||
reinterpret_cast<const unsigned char*>("GL_KHR_debug"), //
|
||||
reinterpret_cast<const unsigned char*>(
|
||||
"GL_EXT_shader_framebuffer_fetch"), //
|
||||
auto const extensions = std::vector<const char*>{
|
||||
"GL_KHR_debug", //
|
||||
"GL_EXT_shader_framebuffer_fetch", //
|
||||
};
|
||||
auto mock_gles = MockGLES::Init(extensions);
|
||||
auto capabilities = mock_gles->GetProcTable().GetCapabilities();
|
||||
|
@ -10,38 +10,48 @@
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
TEST(GPUTracerGLES, CanFormatFramebufferErrorMessage) {
|
||||
auto const extensions = std::vector<const unsigned char*>{
|
||||
reinterpret_cast<const unsigned char*>("GL_KHR_debug"), //
|
||||
reinterpret_cast<const unsigned char*>("GL_EXT_disjoint_timer_query"), //
|
||||
auto const extensions = std::vector<const char*>{
|
||||
"GL_KHR_debug", //
|
||||
"GL_EXT_disjoint_timer_query", //
|
||||
};
|
||||
auto mock_gles = MockGLES::Init(extensions);
|
||||
auto mock_gles_impl = std::make_unique<MockGLESImpl>();
|
||||
|
||||
{
|
||||
::testing::InSequence seq;
|
||||
auto gen_queries = [](GLsizei n, GLuint* ids) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
ids[i] = i + 1;
|
||||
}
|
||||
};
|
||||
EXPECT_CALL(*mock_gles_impl, GenQueriesEXT(_, _)).WillOnce(gen_queries);
|
||||
EXPECT_CALL(*mock_gles_impl, BeginQueryEXT(GL_TIME_ELAPSED_EXT, _));
|
||||
EXPECT_CALL(*mock_gles_impl, EndQueryEXT(GL_TIME_ELAPSED_EXT));
|
||||
EXPECT_CALL(*mock_gles_impl,
|
||||
GetQueryObjectuivEXT(_, GL_QUERY_RESULT_AVAILABLE_EXT, _))
|
||||
.WillOnce([](GLuint id, GLenum target, GLuint* result) {
|
||||
*result = GL_TRUE;
|
||||
});
|
||||
EXPECT_CALL(*mock_gles_impl,
|
||||
GetQueryObjectui64vEXT(_, GL_QUERY_RESULT_EXT, _))
|
||||
.WillOnce([](GLuint id, GLenum target, GLuint64* result) {
|
||||
*result = 1000u;
|
||||
});
|
||||
EXPECT_CALL(*mock_gles_impl, DeleteQueriesEXT(_, _));
|
||||
EXPECT_CALL(*mock_gles_impl, GenQueriesEXT(_, _)).WillOnce(gen_queries);
|
||||
EXPECT_CALL(*mock_gles_impl, BeginQueryEXT(GL_TIME_ELAPSED_EXT, _));
|
||||
}
|
||||
std::shared_ptr<MockGLES> mock_gles =
|
||||
MockGLES::Init(std::move(mock_gles_impl), extensions);
|
||||
auto tracer =
|
||||
std::make_shared<GPUTracerGLES>(mock_gles->GetProcTable(), true);
|
||||
tracer->RecordRasterThread();
|
||||
tracer->MarkFrameStart(mock_gles->GetProcTable());
|
||||
tracer->MarkFrameEnd(mock_gles->GetProcTable());
|
||||
|
||||
auto calls = mock_gles->GetCapturedCalls();
|
||||
|
||||
std::vector<std::string> expected = {"glGenQueriesEXT", "glBeginQueryEXT",
|
||||
"glEndQueryEXT"};
|
||||
for (auto i = 0; i < 3; i++) {
|
||||
EXPECT_EQ(calls[i], expected[i]);
|
||||
}
|
||||
|
||||
// Begin second frame, which prompts the tracer to query the result
|
||||
// from the previous frame.
|
||||
tracer->MarkFrameStart(mock_gles->GetProcTable());
|
||||
|
||||
calls = mock_gles->GetCapturedCalls();
|
||||
std::vector<std::string> expected_b = {"glGetQueryObjectuivEXT",
|
||||
"glGetQueryObjectui64vEXT",
|
||||
"glDeleteQueriesEXT"};
|
||||
for (auto i = 0; i < 3; i++) {
|
||||
EXPECT_EQ(calls[i], expected_b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IMPELLER_DEBUG
|
||||
|
@ -19,18 +19,9 @@ static std::mutex g_test_lock;
|
||||
|
||||
static std::weak_ptr<MockGLES> g_mock_gles;
|
||||
|
||||
static ProcTableGLES::Resolver g_resolver;
|
||||
static std::vector<const char*> g_extensions;
|
||||
|
||||
static std::vector<const unsigned char*> g_extensions;
|
||||
|
||||
static const unsigned char* g_version;
|
||||
|
||||
// Has friend visibility into MockGLES to record calls.
|
||||
void RecordGLCall(const char* name) {
|
||||
if (auto mock_gles = g_mock_gles.lock()) {
|
||||
mock_gles->RecordCall(name);
|
||||
}
|
||||
}
|
||||
static const char* g_version;
|
||||
|
||||
template <typename T, typename U>
|
||||
struct CheckSameSignature : std::false_type {};
|
||||
@ -41,22 +32,34 @@ struct CheckSameSignature<Ret(Args...), Ret(Args...)> : std::true_type {};
|
||||
// This is a stub function that does nothing/records nothing.
|
||||
void doNothing() {}
|
||||
|
||||
auto const kMockVendor = (unsigned char*)"MockGLES";
|
||||
const auto kMockShadingLanguageVersion = (unsigned char*)"GLSL ES 1.0";
|
||||
auto const kExtensions = std::vector<const unsigned char*>{
|
||||
(unsigned char*)"GL_KHR_debug" //
|
||||
auto const kMockVendor = "MockGLES";
|
||||
const auto kMockShadingLanguageVersion = "GLSL ES 1.0";
|
||||
auto const kExtensions = std::vector<const char*>{
|
||||
"GL_KHR_debug" //
|
||||
};
|
||||
|
||||
namespace {
|
||||
template <typename Func, typename... Args>
|
||||
void CallMockMethod(Func func, Args&&... args) {
|
||||
if (auto mock_gles = g_mock_gles.lock()) {
|
||||
if (mock_gles->GetImpl()) {
|
||||
(mock_gles->GetImpl()->*func)(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
const unsigned char* mockGetString(GLenum name) {
|
||||
switch (name) {
|
||||
case GL_VENDOR:
|
||||
return kMockVendor;
|
||||
return reinterpret_cast<const unsigned char*>(kMockVendor);
|
||||
case GL_VERSION:
|
||||
return g_version;
|
||||
return reinterpret_cast<const unsigned char*>(g_version);
|
||||
case GL_SHADING_LANGUAGE_VERSION:
|
||||
return kMockShadingLanguageVersion;
|
||||
return reinterpret_cast<const unsigned char*>(
|
||||
kMockShadingLanguageVersion);
|
||||
default:
|
||||
return (unsigned char*)"";
|
||||
return reinterpret_cast<const unsigned char*>("");
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,9 +69,9 @@ static_assert(CheckSameSignature<decltype(mockGetString), //
|
||||
const unsigned char* mockGetStringi(GLenum name, GLuint index) {
|
||||
switch (name) {
|
||||
case GL_EXTENSIONS:
|
||||
return g_extensions[index];
|
||||
return reinterpret_cast<const unsigned char*>(g_extensions[index]);
|
||||
default:
|
||||
return (unsigned char*)"";
|
||||
return reinterpret_cast<const unsigned char*>("");
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,9 +105,7 @@ GLenum mockGetError() {
|
||||
static_assert(CheckSameSignature<decltype(mockGetError), //
|
||||
decltype(glGetError)>::value);
|
||||
|
||||
void mockPopDebugGroupKHR() {
|
||||
RecordGLCall("PopDebugGroupKHR");
|
||||
}
|
||||
void mockPopDebugGroupKHR() {}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockPopDebugGroupKHR), //
|
||||
decltype(glPopDebugGroupKHR)>::value);
|
||||
@ -112,79 +113,65 @@ static_assert(CheckSameSignature<decltype(mockPopDebugGroupKHR), //
|
||||
void mockPushDebugGroupKHR(GLenum source,
|
||||
GLuint id,
|
||||
GLsizei length,
|
||||
const GLchar* message) {
|
||||
RecordGLCall("PushDebugGroupKHR");
|
||||
}
|
||||
const GLchar* message) {}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockPushDebugGroupKHR), //
|
||||
decltype(glPushDebugGroupKHR)>::value);
|
||||
|
||||
void mockGenQueriesEXT(GLsizei n, GLuint* ids) {
|
||||
RecordGLCall("glGenQueriesEXT");
|
||||
for (auto i = 0; i < n; i++) {
|
||||
ids[i] = i + 1;
|
||||
}
|
||||
CallMockMethod(&IMockGLESImpl::GenQueriesEXT, n, ids);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockGenQueriesEXT), //
|
||||
decltype(glGenQueriesEXT)>::value);
|
||||
|
||||
void mockBeginQueryEXT(GLenum target, GLuint id) {
|
||||
RecordGLCall("glBeginQueryEXT");
|
||||
CallMockMethod(&IMockGLESImpl::BeginQueryEXT, target, id);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockBeginQueryEXT), //
|
||||
decltype(glBeginQueryEXT)>::value);
|
||||
|
||||
void mockEndQueryEXT(GLuint id) {
|
||||
RecordGLCall("glEndQueryEXT");
|
||||
CallMockMethod(&IMockGLESImpl::EndQueryEXT, id);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockEndQueryEXT), //
|
||||
decltype(glEndQueryEXT)>::value);
|
||||
|
||||
void mockGetQueryObjectuivEXT(GLuint id, GLenum target, GLuint* result) {
|
||||
RecordGLCall("glGetQueryObjectuivEXT");
|
||||
*result = GL_TRUE;
|
||||
CallMockMethod(&IMockGLESImpl::GetQueryObjectuivEXT, id, target, result);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockGetQueryObjectuivEXT), //
|
||||
decltype(glGetQueryObjectuivEXT)>::value);
|
||||
|
||||
void mockGetQueryObjectui64vEXT(GLuint id, GLenum target, GLuint64* result) {
|
||||
RecordGLCall("glGetQueryObjectui64vEXT");
|
||||
*result = 1000u;
|
||||
CallMockMethod(&IMockGLESImpl::GetQueryObjectui64vEXT, id, target, result);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockGetQueryObjectui64vEXT), //
|
||||
decltype(glGetQueryObjectui64vEXT)>::value);
|
||||
|
||||
void mockDeleteQueriesEXT(GLsizei size, const GLuint* queries) {
|
||||
RecordGLCall("glDeleteQueriesEXT");
|
||||
CallMockMethod(&IMockGLESImpl::DeleteQueriesEXT, size, queries);
|
||||
}
|
||||
|
||||
void mockDeleteTextures(GLsizei size, const GLuint* queries) {
|
||||
RecordGLCall("glDeleteTextures");
|
||||
CallMockMethod(&IMockGLESImpl::DeleteTextures, size, queries);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockDeleteQueriesEXT), //
|
||||
decltype(glDeleteQueriesEXT)>::value);
|
||||
|
||||
void mockUniform1fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
RecordGLCall("glUniform1fv");
|
||||
CallMockMethod(&IMockGLESImpl::Uniform1fv, location, count, value);
|
||||
}
|
||||
static_assert(CheckSameSignature<decltype(mockUniform1fv), //
|
||||
decltype(glUniform1fv)>::value);
|
||||
|
||||
void mockGenTextures(GLsizei n, GLuint* textures) {
|
||||
RecordGLCall("glGenTextures");
|
||||
if (auto mock_gles = g_mock_gles.lock()) {
|
||||
std::optional<uint64_t> next_texture;
|
||||
std::swap(mock_gles->next_texture_, next_texture);
|
||||
if (next_texture.has_value()) {
|
||||
textures[0] = next_texture.value();
|
||||
}
|
||||
}
|
||||
CallMockMethod(&IMockGLESImpl::GenTextures, n, textures);
|
||||
}
|
||||
|
||||
static_assert(CheckSameSignature<decltype(mockGenTextures), //
|
||||
@ -194,20 +181,35 @@ void mockObjectLabelKHR(GLenum identifier,
|
||||
GLuint name,
|
||||
GLsizei length,
|
||||
const GLchar* label) {
|
||||
RecordGLCall("glObjectLabelKHR");
|
||||
CallMockMethod(&IMockGLESImpl::ObjectLabelKHR, identifier, name, length,
|
||||
label);
|
||||
}
|
||||
static_assert(CheckSameSignature<decltype(mockObjectLabelKHR), //
|
||||
decltype(glObjectLabelKHR)>::value);
|
||||
|
||||
// static
|
||||
std::shared_ptr<MockGLES> MockGLES::Init(
|
||||
const std::optional<std::vector<const unsigned char*>>& extensions,
|
||||
std::unique_ptr<MockGLESImpl> impl,
|
||||
const std::optional<std::vector<const char*>>& extensions) {
|
||||
FML_CHECK(g_test_lock.try_lock())
|
||||
<< "MockGLES is already being used by another test.";
|
||||
g_extensions = extensions.value_or(kExtensions);
|
||||
g_version = "OpenGL ES 3.0";
|
||||
auto mock_gles = std::shared_ptr<MockGLES>(new MockGLES());
|
||||
mock_gles->impl_ = std::move(impl);
|
||||
g_mock_gles = mock_gles;
|
||||
return mock_gles;
|
||||
}
|
||||
|
||||
std::shared_ptr<MockGLES> MockGLES::Init(
|
||||
const std::optional<std::vector<const char*>>& extensions,
|
||||
const char* version_string,
|
||||
ProcTableGLES::Resolver resolver) {
|
||||
// If we cannot obtain a lock, MockGLES is already being used elsewhere.
|
||||
FML_CHECK(g_test_lock.try_lock())
|
||||
<< "MockGLES is already being used by another test.";
|
||||
g_version = (unsigned char*)version_string;
|
||||
g_extensions = extensions.value_or(kExtensions);
|
||||
g_version = version_string;
|
||||
auto mock_gles = std::shared_ptr<MockGLES>(new MockGLES(std::move(resolver)));
|
||||
g_mock_gles = mock_gles;
|
||||
return mock_gles;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "impeller/renderer/backend/gles/proc_table_gles.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -15,6 +16,60 @@ namespace testing {
|
||||
|
||||
extern const ProcTableGLES::Resolver kMockResolverGLES;
|
||||
|
||||
class IMockGLESImpl {
|
||||
public:
|
||||
virtual ~IMockGLESImpl() = default;
|
||||
virtual void DeleteTextures(GLsizei size, const GLuint* queries) {}
|
||||
virtual void GenTextures(GLsizei n, GLuint* textures) {}
|
||||
virtual void ObjectLabelKHR(GLenum identifier,
|
||||
GLuint name,
|
||||
GLsizei length,
|
||||
const GLchar* label) {}
|
||||
virtual void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
}
|
||||
virtual void GenQueriesEXT(GLsizei n, GLuint* ids) {}
|
||||
virtual void BeginQueryEXT(GLenum target, GLuint id) {}
|
||||
virtual void EndQueryEXT(GLuint id) {}
|
||||
virtual void GetQueryObjectuivEXT(GLuint id, GLenum target, GLuint* result) {}
|
||||
virtual void GetQueryObjectui64vEXT(GLuint id,
|
||||
GLenum target,
|
||||
GLuint64* result) {}
|
||||
virtual void DeleteQueriesEXT(GLsizei size, const GLuint* queries) {}
|
||||
};
|
||||
|
||||
class MockGLESImpl : public IMockGLESImpl {
|
||||
public:
|
||||
MOCK_METHOD(void,
|
||||
DeleteTextures,
|
||||
(GLsizei size, const GLuint* queries),
|
||||
(override));
|
||||
MOCK_METHOD(void, GenTextures, (GLsizei n, GLuint* textures), (override));
|
||||
MOCK_METHOD(
|
||||
void,
|
||||
ObjectLabelKHR,
|
||||
(GLenum identifier, GLuint name, GLsizei length, const GLchar* label),
|
||||
(override));
|
||||
MOCK_METHOD(void,
|
||||
Uniform1fv,
|
||||
(GLint location, GLsizei count, const GLfloat* value),
|
||||
(override));
|
||||
MOCK_METHOD(void, GenQueriesEXT, (GLsizei n, GLuint* ids), (override));
|
||||
MOCK_METHOD(void, BeginQueryEXT, (GLenum target, GLuint id), (override));
|
||||
MOCK_METHOD(void, EndQueryEXT, (GLuint id), (override));
|
||||
MOCK_METHOD(void,
|
||||
GetQueryObjectuivEXT,
|
||||
(GLuint id, GLenum target, GLuint* result),
|
||||
(override));
|
||||
MOCK_METHOD(void,
|
||||
GetQueryObjectui64vEXT,
|
||||
(GLuint id, GLenum target, GLuint64* result),
|
||||
(override));
|
||||
MOCK_METHOD(void,
|
||||
DeleteQueriesEXT,
|
||||
(GLsizei size, const GLuint* queries),
|
||||
(override));
|
||||
};
|
||||
|
||||
/// @brief Provides a mocked version of the |ProcTableGLES| class.
|
||||
///
|
||||
/// Typically, Open GLES at runtime will be provided the host's GLES bindings
|
||||
@ -25,32 +80,26 @@ extern const ProcTableGLES::Resolver kMockResolverGLES;
|
||||
/// See `README.md` for more information.
|
||||
class MockGLES final {
|
||||
public:
|
||||
static std::shared_ptr<MockGLES> Init(
|
||||
std::unique_ptr<MockGLESImpl> impl,
|
||||
const std::optional<std::vector<const char*>>& extensions = std::nullopt);
|
||||
|
||||
/// @brief Returns an initialized |MockGLES| instance.
|
||||
///
|
||||
/// This method overwrites mocked global GLES function pointers to record
|
||||
/// invocations on this instance of |MockGLES|. As such, it should only be
|
||||
/// called once per test.
|
||||
static std::shared_ptr<MockGLES> Init(
|
||||
const std::optional<std::vector<const unsigned char*>>& extensions =
|
||||
std::nullopt,
|
||||
const std::optional<std::vector<const char*>>& extensions = std::nullopt,
|
||||
const char* version_string = "OpenGL ES 3.0",
|
||||
ProcTableGLES::Resolver resolver = kMockResolverGLES);
|
||||
|
||||
/// @brief Returns a configured |ProcTableGLES| instance.
|
||||
const ProcTableGLES& GetProcTable() const { return proc_table_; }
|
||||
|
||||
/// @brief Returns a vector of the names of all recorded calls.
|
||||
///
|
||||
/// Calls are cleared after this method is called.
|
||||
std::vector<std::string> GetCapturedCalls() {
|
||||
std::vector<std::string> calls = captured_calls_;
|
||||
captured_calls_.clear();
|
||||
return calls;
|
||||
}
|
||||
|
||||
~MockGLES();
|
||||
|
||||
void SetNextTexture(uint64_t next_texture) { next_texture_ = next_texture; }
|
||||
IMockGLESImpl* GetImpl() { return impl_.get(); }
|
||||
|
||||
private:
|
||||
friend void RecordGLCall(const char* name);
|
||||
@ -58,11 +107,8 @@ class MockGLES final {
|
||||
|
||||
explicit MockGLES(ProcTableGLES::Resolver resolver = kMockResolverGLES);
|
||||
|
||||
void RecordCall(const char* name) { captured_calls_.emplace_back(name); }
|
||||
|
||||
ProcTableGLES proc_table_;
|
||||
std::vector<std::string> captured_calls_;
|
||||
std::optional<uint64_t> next_texture_;
|
||||
std::unique_ptr<IMockGLESImpl> impl_;
|
||||
|
||||
MockGLES(const MockGLES&) = delete;
|
||||
|
||||
|
@ -21,19 +21,6 @@ TEST(MockGLES, CanInitialize) {
|
||||
EXPECT_EQ(vendor, "MockGLES");
|
||||
}
|
||||
|
||||
// Tests we can call two functions and capture the calls.
|
||||
TEST(MockGLES, CapturesPushAndPopDebugGroup) {
|
||||
auto mock_gles = MockGLES::Init();
|
||||
|
||||
auto& gl = mock_gles->GetProcTable();
|
||||
gl.PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 0, -1, "test");
|
||||
gl.PopDebugGroupKHR();
|
||||
|
||||
auto calls = mock_gles->GetCapturedCalls();
|
||||
EXPECT_EQ(calls, std::vector<std::string>(
|
||||
{"PushDebugGroupKHR", "PopDebugGroupKHR"}));
|
||||
}
|
||||
|
||||
// Tests that if we call a function we have not mocked, it's OK.
|
||||
TEST(MockGLES, CanCallUnmockedFunction) {
|
||||
auto mock_gles = MockGLES::Init();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
#include "flutter/fml/synchronization/waitable_event.h"
|
||||
#include "flutter/testing/testing.h" // IWYU pragma: keep
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "impeller/renderer/backend/gles/handle_gles.h"
|
||||
#include "impeller/renderer/backend/gles/proc_table_gles.h"
|
||||
@ -15,6 +16,8 @@
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
class TestWorker : public ReactorGLES::Worker {
|
||||
public:
|
||||
bool CanReactorReactOnCurrentThreadNow(
|
||||
@ -46,31 +49,40 @@ TEST(ReactorGLES, CanAttachCleanupCallbacksToHandles) {
|
||||
}
|
||||
|
||||
TEST(ReactorGLES, DeletesHandlesDuringShutdown) {
|
||||
auto mock_gles = MockGLES::Init();
|
||||
auto mock_gles_impl = std::make_unique<MockGLESImpl>();
|
||||
|
||||
EXPECT_CALL(*mock_gles_impl, GenTextures(1, _))
|
||||
.WillOnce([](GLsizei size, GLuint* queries) { queries[0] = 1234; });
|
||||
EXPECT_CALL(*mock_gles_impl, DeleteTextures(1, ::testing::Pointee(1234)))
|
||||
.Times(1);
|
||||
|
||||
std::shared_ptr<MockGLES> mock_gles =
|
||||
MockGLES::Init(std::move(mock_gles_impl));
|
||||
ProcTableGLES::Resolver resolver = kMockResolverGLES;
|
||||
auto proc_table = std::make_unique<ProcTableGLES>(resolver);
|
||||
auto worker = std::make_shared<TestWorker>();
|
||||
auto reactor = std::make_shared<ReactorGLES>(std::move(proc_table));
|
||||
reactor->AddWorker(worker);
|
||||
|
||||
reactor->CreateHandle(HandleType::kTexture, 123);
|
||||
|
||||
reactor->CreateHandle(HandleType::kTexture);
|
||||
reactor.reset();
|
||||
|
||||
auto calls = mock_gles->GetCapturedCalls();
|
||||
EXPECT_TRUE(std::find(calls.begin(), calls.end(), "glDeleteTextures") !=
|
||||
calls.end());
|
||||
}
|
||||
|
||||
TEST(ReactorGLES, UntrackedHandle) {
|
||||
std::shared_ptr<MockGLES> mock_gles = MockGLES::Init();
|
||||
auto mock_gles_impl = std::make_unique<MockGLESImpl>();
|
||||
|
||||
EXPECT_CALL(*mock_gles_impl, GenTextures(1, _))
|
||||
.WillOnce([](GLsizei size, GLuint* queries) { queries[0] = 1234; });
|
||||
EXPECT_CALL(*mock_gles_impl, DeleteTextures(1, ::testing::Pointee(1234)))
|
||||
.Times(1);
|
||||
|
||||
std::shared_ptr<MockGLES> mock_gles =
|
||||
MockGLES::Init(std::move(mock_gles_impl));
|
||||
ProcTableGLES::Resolver resolver = kMockResolverGLES;
|
||||
auto proc_table = std::make_unique<ProcTableGLES>(resolver);
|
||||
auto worker = std::make_shared<TestWorker>();
|
||||
auto reactor = std::make_shared<ReactorGLES>(std::move(proc_table));
|
||||
reactor->AddWorker(worker);
|
||||
|
||||
mock_gles->SetNextTexture(1234u);
|
||||
HandleGLES handle = reactor->CreateUntrackedHandle(HandleType::kTexture);
|
||||
EXPECT_FALSE(handle.IsDead());
|
||||
std::optional<GLuint> glint = reactor->GetGLHandle(handle);
|
||||
@ -78,34 +90,30 @@ TEST(ReactorGLES, UntrackedHandle) {
|
||||
if (glint.has_value()) {
|
||||
EXPECT_EQ(1234u, *glint);
|
||||
}
|
||||
mock_gles->GetCapturedCalls();
|
||||
reactor->CollectHandle(handle);
|
||||
std::vector<std::string> calls = mock_gles->GetCapturedCalls();
|
||||
EXPECT_TRUE(std::find(calls.begin(), calls.end(), "glDeleteTextures") ==
|
||||
calls.end());
|
||||
// Without an operation nothing is cleaned up.
|
||||
EXPECT_TRUE(reactor->AddOperation([&](const ReactorGLES&) {}));
|
||||
EXPECT_TRUE(reactor->React());
|
||||
calls = mock_gles->GetCapturedCalls();
|
||||
EXPECT_FALSE(std::find(calls.begin(), calls.end(), "glDeleteTextures") ==
|
||||
calls.end());
|
||||
}
|
||||
|
||||
TEST(ReactorGLES, NameUntrackedHandle) {
|
||||
std::shared_ptr<MockGLES> mock_gles = MockGLES::Init();
|
||||
auto mock_gles_impl = std::make_unique<MockGLESImpl>();
|
||||
|
||||
EXPECT_CALL(*mock_gles_impl, GenTextures(1, _))
|
||||
.WillOnce([](GLsizei size, GLuint* queries) { queries[0] = 1234; });
|
||||
EXPECT_CALL(*mock_gles_impl,
|
||||
ObjectLabelKHR(_, 1234, _, ::testing::StrEq("hello, joe!")))
|
||||
.Times(1);
|
||||
|
||||
std::shared_ptr<MockGLES> mock_gles =
|
||||
MockGLES::Init(std::move(mock_gles_impl));
|
||||
ProcTableGLES::Resolver resolver = kMockResolverGLES;
|
||||
auto proc_table = std::make_unique<ProcTableGLES>(resolver);
|
||||
auto worker = std::make_shared<TestWorker>();
|
||||
auto reactor = std::make_shared<ReactorGLES>(std::move(proc_table));
|
||||
reactor->AddWorker(worker);
|
||||
|
||||
mock_gles->SetNextTexture(1234u);
|
||||
HandleGLES handle = reactor->CreateUntrackedHandle(HandleType::kTexture);
|
||||
mock_gles->GetCapturedCalls();
|
||||
reactor->SetDebugLabel(handle, "hello, joe!");
|
||||
std::vector<std::string> calls = mock_gles->GetCapturedCalls();
|
||||
EXPECT_TRUE(std::find(calls.begin(), calls.end(), "glObjectLabelKHR") !=
|
||||
calls.end());
|
||||
}
|
||||
|
||||
TEST(ReactorGLES, PerThreadOperationQueues) {
|
||||
|
@ -11,6 +11,8 @@
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
namespace {
|
||||
class TestWorker : public ReactorGLES::Worker {
|
||||
public:
|
||||
@ -22,20 +24,21 @@ class TestWorker : public ReactorGLES::Worker {
|
||||
} // namespace
|
||||
|
||||
TEST(UniqueHandleGLES, MakeUntracked) {
|
||||
auto mock_gles = MockGLES::Init();
|
||||
auto mock_gles_impl = std::make_unique<MockGLESImpl>();
|
||||
|
||||
EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)).Times(1);
|
||||
|
||||
std::shared_ptr<MockGLES> mock_gled =
|
||||
MockGLES::Init(std::move(mock_gles_impl));
|
||||
ProcTableGLES::Resolver resolver = kMockResolverGLES;
|
||||
auto proc_table = std::make_unique<ProcTableGLES>(resolver);
|
||||
auto worker = std::make_shared<TestWorker>();
|
||||
auto reactor = std::make_shared<ReactorGLES>(std::move(proc_table));
|
||||
reactor->AddWorker(worker);
|
||||
|
||||
mock_gles->GetCapturedCalls();
|
||||
UniqueHandleGLES handle =
|
||||
UniqueHandleGLES::MakeUntracked(reactor, HandleType::kTexture);
|
||||
EXPECT_FALSE(handle.Get().IsDead());
|
||||
std::vector<std::string> calls = mock_gles->GetCapturedCalls();
|
||||
EXPECT_TRUE(std::find(calls.begin(), calls.end(), "glGenTextures") !=
|
||||
calls.end());
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
Loading…
x
Reference in New Issue
Block a user