/*-------------------------------------------------------------------------
 * drawElements Quality Program EGL Module
 * ---------------------------------------
 *
 * Copyright 2015 The Android Open Source Project
 *
 * 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.
 *
 *//*!
 * \file
 * \brief Test negative use case of KHR_partial_update
 *//*--------------------------------------------------------------------*/

#include "teglNegativePartialUpdateTests.hpp"

#include "tcuTestLog.hpp"
#include "tcuSurface.hpp"

#include "egluCallLogWrapper.hpp"
#include "egluConfigFilter.hpp"
#include "egluNativeWindow.hpp"
#include "egluStrUtil.hpp"
#include "egluUnique.hpp"
#include "egluUtil.hpp"

#include "eglwLibrary.hpp"
#include "eglwEnums.hpp"

using namespace eglu;
using namespace eglw;
using tcu::TestLog;

namespace deqp
{
namespace egl
{
namespace
{

class NegativePartialUpdateTest : public TestCase
{
public:
    enum SurfaceType // used as a bit field when selecting a suitable EGL config
    {
        SURFACETYPE_WINDOW  = 1 << 0,
        SURFACETYPE_PBUFFER = 1 << 1
    };

    NegativePartialUpdateTest(EglTestContext &eglTestCtx, bool preserveBuffer, SurfaceType surfaceType,
                              const char *name, const char *description);
    ~NegativePartialUpdateTest(void);
    void init(void);
    void deinit(void);
    virtual IterateResult iterate(void) = 0;

protected:
    void expectError(eglw::EGLenum error);
    void expectBoolean(EGLBoolean expected, EGLBoolean got);
    inline void expectTrue(eglw::EGLBoolean got)
    {
        expectBoolean(EGL_TRUE, got);
    }
    inline void expectFalse(eglw::EGLBoolean got)
    {
        expectBoolean(EGL_FALSE, got);
    }

    const bool m_preserveBuffer;
    SurfaceType m_surfaceType;
    EGLDisplay m_eglDisplay;
    EGLConfig m_eglConfig;
    NativeWindow *m_window;
    EGLSurface m_eglSurface;
    EGLContext m_eglContext;
};

bool isWindow(const CandidateConfig &c)
{
    return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
}

bool isPbuffer(const CandidateConfig &c)
{
    return (c.surfaceType() & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT;
}

bool isES2Renderable(const CandidateConfig &c)
{
    return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
}

bool hasPreserveSwap(const CandidateConfig &c)
{
    return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
}

EGLConfig getEGLConfig(const Library &egl, EGLDisplay eglDisplay, unsigned surfaceTypes, bool preserveBuffer)
{
    FilterList filters;
    if ((surfaceTypes & NegativePartialUpdateTest::SURFACETYPE_WINDOW) != 0)
        filters << isWindow;
    if ((surfaceTypes & NegativePartialUpdateTest::SURFACETYPE_PBUFFER) != 0)
        filters << isPbuffer;
    if (((surfaceTypes & NegativePartialUpdateTest::SURFACETYPE_WINDOW) == 0) &&
        ((surfaceTypes & NegativePartialUpdateTest::SURFACETYPE_PBUFFER) == 0))
        DE_FATAL("Invalid surfaceType");

    filters << isES2Renderable;

    if (preserveBuffer)
        filters << hasPreserveSwap;

    return chooseSingleConfig(egl, eglDisplay, filters);
}

EGLContext initAndMakeCurrentEGLContext(const Library &egl, EGLDisplay eglDisplay, EGLSurface eglSurface,
                                        EGLConfig eglConfig, const EGLint *attribList)
{
    EGLContext eglContext = EGL_NO_CONTEXT;

    egl.bindAPI(EGL_OPENGL_ES_API);
    eglContext = egl.createContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attribList);
    EGLU_CHECK_MSG(egl, "eglCreateContext");
    TCU_CHECK(eglSurface != EGL_NO_SURFACE);
    egl.makeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
    EGLU_CHECK_MSG(egl, "eglMakeCurrent");

    return eglContext;
}

NegativePartialUpdateTest::NegativePartialUpdateTest(EglTestContext &eglTestCtx, bool preserveBuffer,
                                                     SurfaceType surfaceType, const char *name, const char *description)
    : TestCase(eglTestCtx, name, description)
    , m_preserveBuffer(preserveBuffer)
    , m_surfaceType(surfaceType)
    , m_eglDisplay(EGL_NO_DISPLAY)
    , m_window(DE_NULL)
    , m_eglSurface(EGL_NO_SURFACE)
    , m_eglContext(EGL_NO_CONTEXT)
{
}

NegativePartialUpdateTest::~NegativePartialUpdateTest(void)
{
    deinit();
}

void NegativePartialUpdateTest::init(void)
{
    const Library &egl                      = m_eglTestCtx.getLibrary();
    static const EGLint contextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
    const int width                         = 480;
    const int height                        = 480;

    m_eglDisplay = getAndInitDisplay(m_eglTestCtx.getNativeDisplay());

    if (!hasExtension(egl, m_eglDisplay, "EGL_KHR_partial_update"))
        TCU_THROW(NotSupportedError, "EGL_KHR_partial_update is not supported");

    if (m_surfaceType == SURFACETYPE_PBUFFER)
    {
        m_eglConfig                      = getEGLConfig(egl, m_eglDisplay, SURFACETYPE_PBUFFER, m_preserveBuffer);
        const EGLint pbufferAttribList[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
        m_eglSurface                     = egl.createPbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttribList);
    }
    else
    {
        m_eglConfig = getEGLConfig(egl, m_eglDisplay, SURFACETYPE_WINDOW | SURFACETYPE_PBUFFER, m_preserveBuffer);
        const NativeWindowFactory &factory =
            selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
        m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, m_eglConfig, DE_NULL,
                                        WindowParams(width, height, parseWindowVisibility(m_testCtx.getCommandLine())));
        m_eglSurface =
            createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, m_eglConfig, DE_NULL);
    }
    m_eglContext = initAndMakeCurrentEGLContext(egl, m_eglDisplay, m_eglSurface, m_eglConfig, contextAttribList);
}

void NegativePartialUpdateTest::deinit(void)
{
    const Library &egl = m_eglTestCtx.getLibrary();

    if (m_eglContext != EGL_NO_CONTEXT)
    {
        EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
        EGLU_CHECK_CALL(egl, destroyContext(m_eglDisplay, m_eglContext));
        m_eglContext = EGL_NO_CONTEXT;
    }

    if (m_eglSurface != EGL_NO_SURFACE)
    {
        EGLU_CHECK_CALL(egl, destroySurface(m_eglDisplay, m_eglSurface));
        m_eglSurface = EGL_NO_SURFACE;
    }

    if (m_eglDisplay != EGL_NO_DISPLAY)
    {
        EGLU_CHECK_CALL(egl, terminate(m_eglDisplay));
        m_eglDisplay = EGL_NO_DISPLAY;
    }

    delete m_window;
    m_window = DE_NULL;
}

void NegativePartialUpdateTest::expectError(EGLenum expected)
{
    const EGLenum err = m_eglTestCtx.getLibrary().getError();

    if (err != expected)
    {
        m_testCtx.getLog() << TestLog::Message << "// ERROR expected: " << eglu::getErrorStr(expected)
                           << ", Got: " << eglu::getErrorStr(err) << TestLog::EndMessage;
        if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
            m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid error");
    }
}

void NegativePartialUpdateTest::expectBoolean(EGLBoolean expected, EGLBoolean got)
{
    if (expected != got)
    {
        m_testCtx.getLog() << TestLog::Message << "// ERROR expected: " << eglu::getBooleanStr(expected)
                           << ", Got: " << eglu::getBooleanStr(got) << TestLog::EndMessage;
        if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
            m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid value");
    }
}

class NotPostableTest : public NegativePartialUpdateTest
{
public:
    NotPostableTest(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

NotPostableTest::NotPostableTest(EglTestContext &context)
    : NegativePartialUpdateTest(context, false, SURFACETYPE_PBUFFER, "not_postable_surface",
                                "Call setDamageRegion() on pbuffer")
{
}

TestCase::IterateResult NotPostableTest::iterate(void)
{
    const Library &egl = m_eglTestCtx.getLibrary();
    TestLog &log       = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    EGLint damageRegion[] = {10, 10, 10, 10};
    int bufferAge         = -1;

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    {
        tcu::ScopedLogSection(log, "Test1", "If the surface is pbuffer (not postable) --> EGL_BAD_MATCH");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
        EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion,
                                                  DE_LENGTH_OF_ARRAY(damageRegion) / 4));
        expectError(EGL_BAD_MATCH);
    }

    return STOP;
}

class NotCurrentSurfaceTest : public NegativePartialUpdateTest
{
public:
    NotCurrentSurfaceTest(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

NotCurrentSurfaceTest::NotCurrentSurfaceTest(EglTestContext &context)
    : NegativePartialUpdateTest(context, false, SURFACETYPE_WINDOW, "not_current_surface",
                                "Call setDamageRegion() on pbuffer")
{
}

TestCase::IterateResult NotCurrentSurfaceTest::iterate(void)
{
    const int impossibleBufferAge = -26084;
    const Library &egl            = m_eglTestCtx.getLibrary();
    const EGLint attribList[]     = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
    const eglu::UniqueSurface unusedPbuffer(egl, m_eglDisplay,
                                            egl.createPbufferSurface(m_eglDisplay, m_eglConfig, attribList));
    TestLog &log = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    EGLint damageRegion[] = {10, 10, 10, 10};
    int bufferAge         = impossibleBufferAge;

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, *unusedPbuffer, *unusedPbuffer, m_eglContext));
    {
        tcu::ScopedLogSection(
            log, "Test2.1",
            "If query buffer age on a surface that is not the current draw surface --> EGL_BAD_SURFACE");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
        expectFalse(wrapper.eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
        expectError(EGL_BAD_SURFACE);

        if (bufferAge != impossibleBufferAge)
        {
            log << tcu::TestLog::Message
                << "On failure, eglQuerySurface shouldn't change buffer age but buffer age has been changed to "
                << bufferAge << tcu::TestLog::EndMessage;
            m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, bufferAge shouldn't be changed");
        }
    }
    {
        tcu::ScopedLogSection(
            log, "Test2.2",
            "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion, 1));
        expectError(EGL_BAD_MATCH);
    }

    EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    {
        tcu::ScopedLogSection(
            log, "Test3.1",
            "If query buffer age on a surface that is not the current draw surface --> EGL_BAD_SURFACE");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
        expectFalse(wrapper.eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
        expectError(EGL_BAD_SURFACE);

        if (bufferAge != impossibleBufferAge)
        {
            log << tcu::TestLog::Message
                << "On failure, eglQuerySurface shouldn't change buffer age but buffer age has been changed to "
                << bufferAge << tcu::TestLog::EndMessage;
            m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, bufferAge shouldn't be changed");
        }
    }
    {
        tcu::ScopedLogSection(
            log, "Test3.2",
            "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion, 1));
        expectError(EGL_BAD_MATCH);
    }

    if (hasExtension(egl, m_eglDisplay, "EGL_KHR_surfaceless_context"))
    {
        EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglContext));
        {
            tcu::ScopedLogSection(
                log, "Test4.1",
                "If query buffer age on a surface that is not the current draw surface --> EGL_BAD_SURFACE");
            EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
            expectFalse(wrapper.eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
            expectError(EGL_BAD_SURFACE);

            if (bufferAge != impossibleBufferAge)
            {
                log << tcu::TestLog::Message
                    << "On failure, eglQuerySurface shouldn't change buffer age but buffer age has been changed to "
                    << bufferAge << tcu::TestLog::EndMessage;
                m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, bufferAge shouldn't be changed");
            }
        }
        {
            tcu::ScopedLogSection(
                log, "Test4.2",
                "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
            expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion, 1));
            expectError(EGL_BAD_MATCH);
        }
    }

    return STOP;
}

class BufferPreservedTest : public NegativePartialUpdateTest
{
public:
    BufferPreservedTest(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

BufferPreservedTest::BufferPreservedTest(EglTestContext &context)
    : NegativePartialUpdateTest(context, true, SURFACETYPE_WINDOW, "buffer_preserved",
                                "Call setDamageRegion() on pbuffer")
{
}

TestCase::IterateResult BufferPreservedTest::iterate(void)
{
    const Library &egl = m_eglTestCtx.getLibrary();
    TestLog &log       = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    EGLint damageRegion[] = {10, 10, 10, 10};
    int bufferAge         = -1;

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    {
        tcu::ScopedLogSection(log, "Test3", "If buffer_preserved --> EGL_BAD_MATCH");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
        EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion,
                                                  DE_LENGTH_OF_ARRAY(damageRegion) / 4));
        expectError(EGL_BAD_MATCH);
    }

    return STOP;
}

class SetTwiceTest : public NegativePartialUpdateTest
{
public:
    SetTwiceTest(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

SetTwiceTest::SetTwiceTest(EglTestContext &context)
    : NegativePartialUpdateTest(context, false, SURFACETYPE_WINDOW, "set_damage_region_twice",
                                "Call setDamageRegion() twice")
{
}

TestCase::IterateResult SetTwiceTest::iterate(void)
{
    const Library &egl = m_eglTestCtx.getLibrary();
    TestLog &log       = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    EGLint damageRegion[] = {10, 10, 10, 10};
    int bufferAge         = -1;

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    {
        tcu::ScopedLogSection(log, "Test4", "If call setDamageRegion() twice --> EGL_BAD_ACCESS");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
        EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
        expectTrue(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion,
                                                 DE_LENGTH_OF_ARRAY(damageRegion) / 4));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion,
                                                  DE_LENGTH_OF_ARRAY(damageRegion) / 4));
        expectError(EGL_BAD_ACCESS);
    }

    return STOP;
}

class NoAgeTest : public NegativePartialUpdateTest
{
public:
    NoAgeTest(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

NoAgeTest::NoAgeTest(EglTestContext &context)
    : NegativePartialUpdateTest(context, false, SURFACETYPE_WINDOW, "set_damage_region_before_query_age",
                                "Call setDamageRegion() without querying buffer age")
{
}

TestCase::IterateResult NoAgeTest::iterate(void)
{
    const Library &egl = m_eglTestCtx.getLibrary();
    TestLog &log       = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    EGLint damageRegion[] = {10, 10, 10, 10};

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    {
        tcu::ScopedLogSection(log, "Test5", "If buffer age is not queried --> EGL_BAD_ACCESS");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion,
                                                  DE_LENGTH_OF_ARRAY(damageRegion) / 4));
        expectError(EGL_BAD_ACCESS);
    }

    return STOP;
}

class PassNullTest : public NegativePartialUpdateTest
{
public:
    PassNullTest(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

PassNullTest::PassNullTest(EglTestContext &context)
    : NegativePartialUpdateTest(context, false, SURFACETYPE_WINDOW, "pass_null_0_as_params",
                                "Call setDamageRegion() with (NULL, 0)")
{
}

TestCase::IterateResult PassNullTest::iterate(void)
{
    const Library &egl = m_eglTestCtx.getLibrary();
    TestLog &log       = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    int bufferAge = -1;

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    {
        tcu::ScopedLogSection(log, "Test6", "If pass (null, 0) to setDamageRegion(), no error");
        EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
        EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
        expectTrue(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0));
        expectError(EGL_SUCCESS);
    }

    return STOP;
}

class NotCurrentSurfaceTest2 : public NegativePartialUpdateTest
{
public:
    NotCurrentSurfaceTest2(EglTestContext &context);
    TestCase::IterateResult iterate(void);
};

NotCurrentSurfaceTest2::NotCurrentSurfaceTest2(EglTestContext &context)
    : NegativePartialUpdateTest(context, false, SURFACETYPE_WINDOW, "not_current_surface2",
                                "Call setDamageRegion() on pbuffer")
{
}

TestCase::IterateResult NotCurrentSurfaceTest2::iterate(void)
{
    const Library &egl        = m_eglTestCtx.getLibrary();
    const EGLint attribList[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
    const eglu::UniqueSurface unusedPbuffer(egl, m_eglDisplay,
                                            egl.createPbufferSurface(m_eglDisplay, m_eglConfig, attribList));
    TestLog &log = m_testCtx.getLog();
    CallLogWrapper wrapper(egl, log);
    EGLint damageRegion[] = {10, 10, 10, 10};
    int bufferAge         = -1;

    wrapper.enableLogging(true);
    m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");

    EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
    EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));

    {
        tcu::ScopedLogSection(
            log, "Test7",
            "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
        EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, *unusedPbuffer, *unusedPbuffer, m_eglContext));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion, 1));
        expectError(EGL_BAD_MATCH);
    }
    {
        tcu::ScopedLogSection(
            log, "Test8",
            "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
        EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion, 1));
        expectError(EGL_BAD_MATCH);
    }
    if (hasExtension(egl, m_eglDisplay, "EGL_KHR_surfaceless_context"))
    {
        tcu::ScopedLogSection(
            log, "Test9",
            "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
        EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglContext));
        expectFalse(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, damageRegion, 1));
        expectError(EGL_BAD_MATCH);
    }

    return STOP;
}

} // namespace

NegativePartialUpdateTests::NegativePartialUpdateTests(EglTestContext &eglTestCtx)
    : TestCaseGroup(eglTestCtx, "negative_partial_update", "Negative partial update tests")
{
}

void NegativePartialUpdateTests::init(void)
{
    addChild(new NotPostableTest(m_eglTestCtx));
    addChild(new NotCurrentSurfaceTest(m_eglTestCtx));
    addChild(new BufferPreservedTest(m_eglTestCtx));
    addChild(new SetTwiceTest(m_eglTestCtx));
    addChild(new NoAgeTest(m_eglTestCtx));
    addChild(new PassNullTest(m_eglTestCtx));
    addChild(new NotCurrentSurfaceTest2(m_eglTestCtx));
}

} // namespace egl
} // namespace deqp
