From abed9b9072469a90001c5be8f4ca91835713480a Mon Sep 17 00:00:00 2001 From: ExMix Date: Tue, 24 Sep 2013 19:06:31 +0300 Subject: [PATCH] [drape] testing --- drape/drape_tests/buffer_tests.cpp | 105 ++++++++++++++ drape/drape_tests/failure_reporter.cpp | 36 +++++ drape/drape_tests/glfunctions.cpp | 166 ++++++++++++++++++++++ drape/drape_tests/glmock_functions.cpp | 23 +++ drape/drape_tests/glmock_functions.hpp | 54 +++++++ drape/drape_tests/testingmain.cpp | 128 +++++++++++++++++ drape/drape_tests/uniform_value_tests.cpp | 72 ++++++++++ 7 files changed, 584 insertions(+) create mode 100644 drape/drape_tests/buffer_tests.cpp create mode 100644 drape/drape_tests/failure_reporter.cpp create mode 100644 drape/drape_tests/glfunctions.cpp create mode 100644 drape/drape_tests/glmock_functions.cpp create mode 100644 drape/drape_tests/glmock_functions.hpp create mode 100644 drape/drape_tests/testingmain.cpp create mode 100644 drape/drape_tests/uniform_value_tests.cpp diff --git a/drape/drape_tests/buffer_tests.cpp b/drape/drape_tests/buffer_tests.cpp new file mode 100644 index 0000000000..ffc05423b9 --- /dev/null +++ b/drape/drape_tests/buffer_tests.cpp @@ -0,0 +1,105 @@ +#include "../../testing/testing.hpp" + +#include "glmock_functions.hpp" + +#include "../glbuffer.hpp" +#include "../data_buffer.hpp" +#include "../index_buffer.hpp" + +#include + +using namespace emul; +using ::testing::_; +using ::testing::Return; +using ::testing::IgnoreResult; + +UNIT_TEST(CreateDestroyDataBufferTest) +{ + EXPECTGL(glGenBuffer()).WillOnce(Return(1)); + EXPECTGL(glBindBuffer(1, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glBufferData(GLConst::GLArrayBuffer, 3 * 100 * sizeof(float), NULL, GLConst::GLStaticDraw)).Times(1); + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + GLBuffer * buffer = new DataBuffer(3 * sizeof(float), 100); + + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glDeleteBuffer(1)).Times(1); + delete buffer; +} + +UNIT_TEST(CreateDestroyIndexBufferTest) +{ + EXPECTGL(glGenBuffer()).WillOnce(Return(1)); + EXPECTGL(glBindBuffer(1, GLConst::GLElementArrayBuffer)).Times(1); + EXPECTGL(glBufferData(GLConst::GLElementArrayBuffer, 100 * sizeof(uint16_t), NULL, GLConst::GLStaticDraw)).Times(1); + EXPECTGL(glBindBuffer(0, GLConst::GLElementArrayBuffer)).Times(1); + GLBuffer * buffer = new IndexBuffer(100); + + EXPECTGL(glBindBuffer(0, GLConst::GLElementArrayBuffer)).Times(1); + EXPECTGL(glDeleteBuffer(1)).Times(1); + delete buffer; +} + +UNIT_TEST(UploadDataTest) +{ + EXPECTGL(glGenBuffer()).WillOnce(Return(1)); + EXPECTGL(glBindBuffer(1, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glBufferData(GLConst::GLArrayBuffer, 3 * 100 * sizeof(float), NULL, GLConst::GLStaticDraw)).Times(1); + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + GLBuffer * buffer = new GLBuffer(GLBuffer::ElementBuffer, 3 * sizeof(float), 100); + + float data[3 * 100]; + for (int i = 0; i < 3 * 100; ++i) + data[i] = (float)i; + + EXPECTGL(glBindBuffer(1, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glBufferSubData(GLConst::GLArrayBuffer, 3 * 100 * sizeof(float), data, 0)); + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + buffer->UploadData(data, 100); + + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glDeleteBuffer(1)).Times(1); + delete buffer; +} + +UNIT_TEST(ParticalUploadDataTest) +{ + EXPECTGL(glGenBuffer()).WillOnce(Return(1)); + EXPECTGL(glBindBuffer(1, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glBufferData(GLConst::GLArrayBuffer, 3 * 100 * sizeof(float), NULL, GLConst::GLStaticDraw)).Times(1); + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + GLBuffer * buffer = new GLBuffer(GLBuffer::ElementBuffer, 3 * sizeof(float), 100); + + TEST_EQUAL(buffer->GetCapacity(), 100, ()); + TEST_EQUAL(buffer->GetAvailableSize(), 100, ()); + TEST_EQUAL(buffer->GetCurrentSize(), 0, ()); + + float part1Data[3 * 30]; + for (int i = 0; i < 3 * 30; ++i) + part1Data[i] = (float)i; + + EXPECTGL(glBindBuffer(1, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glBufferSubData(GLConst::GLArrayBuffer, 3 * 30 * sizeof(float), part1Data, 0)); + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + buffer->UploadData(part1Data, 30); + + TEST_EQUAL(buffer->GetCapacity(), 100, ()); + TEST_EQUAL(buffer->GetAvailableSize(), 70, ()); + TEST_EQUAL(buffer->GetCurrentSize(), 30, ()); + + float part2Data[3 * 70]; + for (int i = 0; i < 3 * 100; ++i) + part2Data[i] = (float)i; + + EXPECTGL(glBindBuffer(1, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glBufferSubData(GLConst::GLArrayBuffer, 3 * 70 * sizeof(float), part2Data, 3 * 30 * sizeof(float))); + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + buffer->UploadData(part2Data , 70); + + TEST_EQUAL(buffer->GetCapacity(), 100, ()); + TEST_EQUAL(buffer->GetAvailableSize(), 0, ()); + TEST_EQUAL(buffer->GetCurrentSize(), 100, ()); + + EXPECTGL(glBindBuffer(0, GLConst::GLArrayBuffer)).Times(1); + EXPECTGL(glDeleteBuffer(1)).Times(1); + delete buffer; +} diff --git a/drape/drape_tests/failure_reporter.cpp b/drape/drape_tests/failure_reporter.cpp new file mode 100644 index 0000000000..c9040ed5fc --- /dev/null +++ b/drape/drape_tests/failure_reporter.cpp @@ -0,0 +1,36 @@ +#include + +#include "../../testing/testing.hpp" + +namespace testing +{ + namespace internal + { + class MwmFailureReporter : public FailureReporterInterface + { + bool m_throwed; + public: + MwmFailureReporter() + : m_throwed(false) {} + + virtual void ReportFailure(FailureType type, + const char* file, + int line, + const string& message) + { + if (!m_throwed) + { + m_throwed = true; + my::OnTestFailed(my::SrcPoint(file == NULL ? "" : file, + line, ""), message); + } + } + }; + + FailureReporterInterface * GetFailureReporter() + { + static MwmFailureReporter reporter; + return &reporter; + } + } +} diff --git a/drape/drape_tests/glfunctions.cpp b/drape/drape_tests/glfunctions.cpp new file mode 100644 index 0000000000..c358b02c50 --- /dev/null +++ b/drape/drape_tests/glfunctions.cpp @@ -0,0 +1,166 @@ +#include "../glfunctions.hpp" +#include "glmock_functions.hpp" + +#include "../../base/assert.hpp" + +using namespace emul; + +#define MOCK_CALL(f) GLMockFunctions::Instance().f; + +uint32_t GLFunctions::glGenBuffer() +{ + return MOCK_CALL(glGenBuffer()); +} + +void GLFunctions::glBindBuffer(uint32_t vbo, glConst target) +{ + MOCK_CALL(glBindBuffer(vbo, target)); +} + +void GLFunctions::glDeleteBuffer(uint32_t vbo) +{ + MOCK_CALL(glDeleteBuffer(vbo)); +} + +void GLFunctions::glBufferData(glConst target, uint32_t size, const void * data, glConst usage) +{ + MOCK_CALL(glBufferData(target, size, data, usage)); +} + +void GLFunctions::glBufferSubData(glConst target, uint32_t size, const void *data, uint32_t offset) +{ + MOCK_CALL(glBufferSubData(target, size, data, offset)); +} + +uint32_t GLFunctions::glCreateShader(glConst type) +{ + return MOCK_CALL(glCreateShader(type)); +} + +void GLFunctions::glShaderSource(uint32_t shaderID, const string & src) +{ + MOCK_CALL(glShaderSource(shaderID, src)); +} + +bool GLFunctions::glCompileShader(uint32_t shaderID, string & errorLog) +{ + return MOCK_CALL(glCompileShader(shaderID, errorLog)); +} + +void GLFunctions::glDeleteShader(uint32_t shaderID) +{ + MOCK_CALL(glDeleteShader(shaderID)); +} + +uint32_t GLFunctions::glCreateProgram() +{ + return MOCK_CALL(glCreateProgram()); +} + +void GLFunctions::glAttachShader(uint32_t programID, uint32_t shaderID) +{ + MOCK_CALL(glAttachShader(programID, shaderID)); +} + +void GLFunctions::glDetachShader(uint32_t programID, uint32_t shaderID) +{ + MOCK_CALL(glDetachShader(programID, shaderID)); +} + +bool GLFunctions::glLinkProgram(uint32_t programID, string & errorLog) +{ + return MOCK_CALL(glLinkProgram(programID, errorLog)); +} + +void GLFunctions::glDeleteProgram(uint32_t programID) +{ + MOCK_CALL(glDeleteProgram(programID)); +} + +void GLFunctions::glUseProgram(uint32_t programID) +{ + MOCK_CALL(glUseProgram(programID)); +} + +int8_t GLFunctions::glGetAttribLocation(uint32_t programID, const string & name) +{ + return 0; +} + +void GLFunctions::glBindAttribLocation(uint32_t programID, uint8_t index, const string & name) +{ + +} + +/// enable vertex attribute binding. To get attributeLocation need to call glGetAttributeLocation +void GLFunctions::glEnableVertexAttribute(int32_t attributeLocation) +{ + +} + +void GLFunctions::glVertexAttributePointer(int32_t attrLocation, + uint32_t count, + glConst type, + bool needNormalize, + uint32_t stride, + uint32_t offset) +{ + +} + +int8_t GLFunctions::glGetUniformLocation(uint32_t programID, const string & name) +{ + return MOCK_CALL(glGetUniformLocation(programID, name)); +} + +void GLFunctions::glUniformValuei(int8_t location, int32_t v) +{ + MOCK_CALL(glUniformValuei(location, v)); +} + +void GLFunctions::glUniformValuei(int8_t location, int32_t v1, int32_t v2) +{ + MOCK_CALL(glUniformValuei(location, v1, v2)); +} + +void GLFunctions::glUniformValuei(int8_t location, int32_t v1, int32_t v2, int32_t v3) +{ + MOCK_CALL(glUniformValuei(location, v1, v2, v3)); +} + +void GLFunctions::glUniformValuei(int8_t location, int32_t v1, int32_t v2, int32_t v3, int32_t v4) +{ + MOCK_CALL(glUniformValuei(location, v1, v2, v3, v4)); +} + +void GLFunctions::glUniformValuef(int8_t location, float v) +{ + MOCK_CALL(glUniformValuef(location, v)); +} + +void GLFunctions::glUniformValuef(int8_t location, float v1, float v2) +{ + MOCK_CALL(glUniformValuef(location, v1, v2)); +} + +void GLFunctions::glUniformValuef(int8_t location, float v1, float v2, float v3) +{ + MOCK_CALL(glUniformValuef(location, v1, v2, v3)); +} + +void GLFunctions::glUniformValuef(int8_t location, float v1, float v2, float v3, float v4) +{ + MOCK_CALL(glUniformValuef(location, v1, v2, v3, v4)); +} + +void GLFunctions::glUniformMatrix4x4Value(int8_t location, float * values) +{ + MOCK_CALL(glUniformMatrix4x4Value(location, values)); +} + +static uint32_t glGetCurrentProgram() +{ + return MOCK_CALL(glGetCurrentProgram()); +} + +void CheckGLError() {} diff --git a/drape/drape_tests/glmock_functions.cpp b/drape/drape_tests/glmock_functions.cpp new file mode 100644 index 0000000000..9fa86fe89d --- /dev/null +++ b/drape/drape_tests/glmock_functions.cpp @@ -0,0 +1,23 @@ +#include "glmock_functions.hpp" + +namespace emul +{ + void GLMockFunctions::Init(int * argc, char **argv) + { + ::testing::InitGoogleMock(argc, argv); + m_mock = new GLMockFunctions(); + } + + void GLMockFunctions::Teardown() + { + delete m_mock; + m_mock = NULL; + } + + GLMockFunctions & GLMockFunctions::Instance() + { + return *m_mock; + } + + GLMockFunctions * GLMockFunctions::m_mock; +} diff --git a/drape/drape_tests/glmock_functions.hpp b/drape/drape_tests/glmock_functions.hpp new file mode 100644 index 0000000000..46908a742e --- /dev/null +++ b/drape/drape_tests/glmock_functions.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "../glconstants.hpp" +#include "../../std/string.hpp" + +#include + +namespace emul +{ + class GLMockFunctions + { + public: + static void Init(int * argc, char ** argv); + static void Teardown(); + static GLMockFunctions & Instance(); + + MOCK_METHOD0(glGenBuffer, uint32_t()); + MOCK_METHOD2(glBindBuffer, void(uint32_t vbo, glConst target)); + MOCK_METHOD1(glDeleteBuffer, void(uint32_t vbo)); + MOCK_METHOD4(glBufferData, void(glConst target, uint32_t size, const void * data, glConst usage)); + MOCK_METHOD4(glBufferSubData, void(glConst target, uint32_t size, const void *data, uint32_t offset)); + + MOCK_METHOD2(glGetUniformLocation, int8_t(uint32_t programID, const string & name)); + MOCK_METHOD2(glUniformValuei, void(int8_t location, int32_t v)); + MOCK_METHOD3(glUniformValuei, void(int8_t location, int32_t v1, int32_t v2)); + MOCK_METHOD4(glUniformValuei, void(int8_t location, int32_t v1, int32_t v2, int32_t v3)); + MOCK_METHOD5(glUniformValuei, void(int8_t location, int32_t v1, int32_t v2, int32_t v3, int32_t v4)); + + MOCK_METHOD2(glUniformValuef, void(int8_t location, float v)); + MOCK_METHOD3(glUniformValuef, void(int8_t location, float v1, float v2)); + MOCK_METHOD4(glUniformValuef, void(int8_t location, float v1, float v2, float v3)); + MOCK_METHOD5(glUniformValuef, void(int8_t location, float v1, float v2, float v3, float v4)); + MOCK_METHOD2(glUniformMatrix4x4Value, void(int8_t location, float * values)); + MOCK_METHOD0(glGetCurrentProgram, uint32_t()); + + MOCK_METHOD1(glCreateShader, uint32_t(glConst type)); + MOCK_METHOD2(glShaderSource, void(uint32_t shaderID, const string & src)); + MOCK_METHOD2(glCompileShader, bool(uint32_t shaderID, string & errorLog)); + MOCK_METHOD1(glDeleteShader, void(uint32_t shaderID)); + + MOCK_METHOD0(glCreateProgram, uint32_t()); + MOCK_METHOD2(glAttachShader, void(uint32_t programID, uint32_t shaderID)); + MOCK_METHOD2(glDetachShader, void(uint32_t programID, uint32_t shaderID)); + MOCK_METHOD2(glLinkProgram, bool(uint32_t programID, string & errorLog)); + MOCK_METHOD1(glDeleteProgram, void(uint32_t programID)); + + MOCK_METHOD1(glUseProgram, void(uint32_t programID)); + + private: + static GLMockFunctions * m_mock; + }; +} + +#define EXPECTGL(x) EXPECT_CALL(emul::GLMockFunctions::Instance(), x) diff --git a/drape/drape_tests/testingmain.cpp b/drape/drape_tests/testingmain.cpp new file mode 100644 index 0000000000..3453e5cd0d --- /dev/null +++ b/drape/drape_tests/testingmain.cpp @@ -0,0 +1,128 @@ +#include "../../testing/testregister.hpp" +#include "../../testing/testing.hpp" +#include "../../base/logging.hpp" +#include "../../base/scope_guard.hpp" +#include "../../std/algorithm.hpp" +#include "../../std/iostream.hpp" +#include "../../std/string.hpp" +#include "../../std/vector.hpp" +#include "../../std/target_os.hpp" +#include "../../std/bind.hpp" + +#include "glmock_functions.hpp" + +#ifdef OMIM_UNIT_TEST_WITH_QT_EVENT_LOOP + #include + #ifdef OMIM_OS_MAC // on Mac OS X native run loop works only for QApplication :( + #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + #include + #else + #include + #endif + #define QAPP QApplication + #else + #include + #define QAPP QCoreApplication + #endif +#endif + +static bool g_bLastTestOK = true; + +int main(int argc, char * argv[]) +{ +#ifdef OMIM_UNIT_TEST_WITH_QT_EVENT_LOOP + QAPP theApp(argc, argv); + UNUSED_VALUE(theApp); +#else + UNUSED_VALUE(argc); + UNUSED_VALUE(argv); +#endif + + my::g_LogLevel = LINFO; + + emul::GLMockFunctions::Init(&argc, argv); + MY_SCOPE_GUARD(GLMockScope, bind(&emul::GLMockFunctions::Teardown)); + + vector testNames; + vector testResults; + int numFailedTests = 0; + + for (TestRegister * pTest = TestRegister::FirstRegister(); pTest; pTest = pTest->m_pNext) + { + string fileName(pTest->m_FileName); + string testName(pTest->m_TestName); + // Retrieve fine file name + { + int iFirstSlash = static_cast(fileName.size()) - 1; + while (iFirstSlash >= 0 && fileName[iFirstSlash] != '\\' && fileName[iFirstSlash] != '/') + --iFirstSlash; + if (iFirstSlash >= 0) + fileName.erase(0, iFirstSlash + 1); + } + + testNames.push_back(fileName + "::" + testName); + testResults.push_back(true); + } + + int iTest = 0; + for (TestRegister * pTest = TestRegister::FirstRegister(); pTest; ++iTest, pTest = pTest->m_pNext) + { + cerr << "Running " << testNames[iTest] << endl << flush; + if (!g_bLastTestOK) + { + // Somewhere else global variables have been reset. + cerr << "\n\nSOMETHING IS REALLY WRONG IN THE UNIT TEST FRAMEWORK!!!" << endl; + return 5; + } + try + { + // Run the test. + pTest->m_Fn(); + + if (g_bLastTestOK) + { + cerr << "OK" << endl; + } + else + { + // You can set Break here if test failed, + // but it is already set in OnTestFail - to fail immediately. + testResults[iTest] = false; + ++numFailedTests; + } + + } catch (TestFailureException const & ) + { + testResults[iTest] = false; + ++numFailedTests; + } catch (std::exception const & ex) + { + cerr << "FAILED" << endl << "<<>>" << endl; + testResults[iTest] = false; + ++numFailedTests; + } catch (...) + { + cerr << "FAILED" << endl << "<<>>" << endl; + testResults[iTest] = false; + ++numFailedTests; + } + g_bLastTestOK = true; + } + + if (numFailedTests == 0) + { + cerr << endl << "All tests passed." << endl << flush; + return 0; + } + else + { + cerr << endl << numFailedTests << " tests failed:" << endl; + for (size_t i = 0; i < testNames.size(); ++i) + { + if (!testResults[i]) + cerr << testNames[i] << endl; + } + cerr << "Some tests FAILED." << endl << flush; + return 1; + } +} diff --git a/drape/drape_tests/uniform_value_tests.cpp b/drape/drape_tests/uniform_value_tests.cpp new file mode 100644 index 0000000000..f8cf461408 --- /dev/null +++ b/drape/drape_tests/uniform_value_tests.cpp @@ -0,0 +1,72 @@ +#include "../../testing/testing.hpp" + +#include "../gpu_program.hpp" +#include "../uniform_value.hpp" + +#include "glmock_functions.hpp" + +#include + +using ::testing::_; +using ::testing::Return; +using ::testing::AnyOf; + +namespace +{ + class ShaderReferenceMock : public ShaderReference + { + public: + ShaderReferenceMock(const string & shaderSource, Type type) + : ShaderReference(shaderSource, type) {} + + MOCK_CONST_METHOD0(GetID, int()); + MOCK_METHOD0(Ref, void()); + MOCK_METHOD0(Deref, void()); + }; + + class GpuProgramMock : public GpuProgram + { + public: + GpuProgramMock() + : GpuProgram(ReferencePoiner(NULL), + ReferencePoiner(NULL)) + { + } + + GpuProgramMock(ReferencePoiner vertexShader, + ReferencePoiner fragmentShader) + : GpuProgram(vertexShader, fragmentShader) {} + + MOCK_METHOD0(Bind, void()); + MOCK_METHOD0(Unbind, void()); + + MOCK_CONST_METHOD1(GetUniformLocation, int8_t(const string & uniformName)); + }; +} + +UNIT_TEST(UniformValueTest) +{ + ShaderReferenceMock s1("", ShaderReference::VertexShader); + ShaderReferenceMock s2("", ShaderReference::FragmentShader); + + EXPECT_CALL(s1, Ref()).Times(1); + EXPECT_CALL(s2, Ref()).Times(1); + EXPECT_CALL(s1, GetID()).WillRepeatedly(Return(3)); + EXPECT_CALL(s2, GetID()).WillRepeatedly(Return(4)); + EXPECTGL(glCreateProgram()).WillOnce(Return(1)); + EXPECTGL(glAttachShader(1, AnyOf(3, 4))).Times(2); + EXPECTGL(glLinkProgram(1, _)).Times(1); + EXPECTGL(glDetachShader(1, AnyOf(3, 4))).Times(2); + EXPECT_CALL(s1, Deref()).Times(1); + EXPECT_CALL(s2, Deref()).Times(1); + + GpuProgramMock * mock = new GpuProgramMock(ReferencePoiner(&s1), + ReferencePoiner(&s2)); + + { + EXPECT_CALL(*mock, GetUniformLocation("position")).WillOnce(Return(3)); + EXPECTGL(glUniformValuei(3, 1)).Times(1); + UniformValue v("position", 1); + v.Apply(ReferencePoiner((GpuProgram *)mock)); + } +}