Add negative test for EGL_KHR_partial_update

Check whether setDamageRegion() behaves correctly, i.e. return correct value
and raise correct error under invalid use case.

Change-Id: I68d070cccd4ce597b36230180526e3c9f8a7143a
diff --git a/Android.mk b/Android.mk
index 90ddbd9..8c865fa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -272,6 +272,7 @@
 	modules/egl/teglNativeColorMappingTests.cpp \
 	modules/egl/teglNativeCoordMappingTests.cpp \
 	modules/egl/teglNegativeApiTests.cpp \
+	moduels/egl/teglNegativePartialUpdateTests.cpp \
 	modules/egl/teglPreservingSwapTests.cpp \
 	modules/egl/teglPartialUpdateTests.cpp \
 	modules/egl/teglQueryConfigTests.cpp \
diff --git a/android/cts/master/src/egl-new-tests.txt b/android/cts/master/src/egl-new-tests.txt
index c864e83..6e1be0b 100644
--- a/android/cts/master/src/egl-new-tests.txt
+++ b/android/cts/master/src/egl-new-tests.txt
@@ -1,3 +1,4 @@
 # Feature Request 20761474
 dEQP-EGL.functional.buffer_age.*
 dEQP-EGL.functional.partial_update.*
+dEQP-EGL.functional.negative_partial_update.*
diff --git a/modules/egl/CMakeLists.txt b/modules/egl/CMakeLists.txt
index b9f57b9..6777eb7 100644
--- a/modules/egl/CMakeLists.txt
+++ b/modules/egl/CMakeLists.txt
@@ -43,6 +43,8 @@
 	teglNegativeApiTests.hpp
 	teglPartialUpdateTests.cpp
 	teglPartialUpdateTests.hpp
+	teglNegativePartialUpdateTests.cpp
+	teglNegativePartialUpdateTests.hpp
 	teglRenderCase.cpp
 	teglRenderCase.hpp
 	teglRenderTests.cpp
diff --git a/modules/egl/teglNegativePartialUpdateTests.cpp b/modules/egl/teglNegativePartialUpdateTests.cpp
new file mode 100644
index 0000000..26ae05c
--- /dev/null
+++ b/modules/egl/teglNegativePartialUpdateTests.cpp
@@ -0,0 +1,478 @@
+/*-------------------------------------------------------------------------
+ * 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 "egluNativeWindow.hpp"
+#include "egluUtil.hpp"
+#include "egluStrUtil.hpp"
+#include "egluConfigFilter.hpp"
+#include "egluCallLogWrapper.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
+	{
+		SURFACETYPE_WINDOW = 0,
+		SURFACETYPE_PBUFFER
+	};
+
+								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, NegativePartialUpdateTest::SurfaceType surfaceType, bool preserveBuffer)
+{
+	FilterList filters;
+	if (surfaceType == NegativePartialUpdateTest::SURFACETYPE_WINDOW)
+		filters << isWindow;
+	else if (surfaceType == NegativePartialUpdateTest::SURFACETYPE_PBUFFER)
+		filters << isPbuffer;
+	else
+		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");
+
+	m_eglConfig = getEGLConfig(egl, m_eglDisplay, m_surfaceType, m_preserveBuffer);
+
+	if (m_surfaceType == SURFACETYPE_PBUFFER)
+	{
+		const EGLint pbufferAttribList[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE };
+		m_eglSurface = egl.createPbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttribList);
+	}
+	else
+	{
+		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)
+{
+	TestLog&				log				= m_testCtx.getLog();
+	CallLogWrapper			wrapper			(m_eglTestCtx.getLibrary(), 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");
+		expectTrue(wrapper.eglQuerySurface(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();
+	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");
+	egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglContext);
+	{
+		tcu::ScopedLogSection(log, "Test2.1", "If query buffer age on a surface that is not the current draw surface --> EGL_BAD_SURFACE");
+		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);
+	}
+
+	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)
+{
+	TestLog&				log				= m_testCtx.getLog();
+	CallLogWrapper			wrapper			(m_eglTestCtx.getLibrary(), 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");
+
+		expectTrue(wrapper.eglSurfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
+		expectTrue(wrapper.eglQuerySurface(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)
+{
+	TestLog&				log				= m_testCtx.getLog();
+	CallLogWrapper			wrapper			(m_eglTestCtx.getLibrary(), 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");
+
+		expectTrue(wrapper.eglQuerySurface(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)
+{
+	TestLog&				log				= m_testCtx.getLog();
+	CallLogWrapper			wrapper			(m_eglTestCtx.getLibrary(), 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");
+		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)
+{
+	TestLog&				log				= m_testCtx.getLog();
+	CallLogWrapper			wrapper			(m_eglTestCtx.getLibrary(), 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");
+		expectTrue(wrapper.eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
+		expectTrue(wrapper.eglSetDamageRegionKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0));
+		expectError(EGL_BAD_ACCESS);
+	}
+
+	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();
+	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, "Test7", "If call setDamageRegion() on a surface that is not the current draw surface --> EGL_BAD_MATCH");
+		expectTrue(wrapper.eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
+		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;
+}
+
+} // anonymous
+
+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));
+}
+
+} // egl
+} // deqp
diff --git a/modules/egl/teglNegativePartialUpdateTests.hpp b/modules/egl/teglNegativePartialUpdateTests.hpp
new file mode 100644
index 0000000..100703e
--- /dev/null
+++ b/modules/egl/teglNegativePartialUpdateTests.hpp
@@ -0,0 +1,49 @@
+#ifndef _TEGLNEGATIVEPARTIALUPDATETESTS_HPP
+#define _TEGLNEGATIVEPARTIALUPDATETESTS_HPP
+/*-------------------------------------------------------------------------
+ * 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 test for KHR_partial_update
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "teglTestCase.hpp"
+
+namespace deqp
+{
+namespace egl
+{
+
+class NegativePartialUpdateTests : public TestCaseGroup
+{
+public:
+								NegativePartialUpdateTests		(EglTestContext& eglTestCtx);
+	void						init							(void);
+
+private:
+								NegativePartialUpdateTests		(const NegativePartialUpdateTests&);
+	NegativePartialUpdateTests&	operator=						(const NegativePartialUpdateTests&);
+
+};
+
+} // egl
+} // deqp
+
+#endif // _TEGLNEGATIVEPARTIALUPDATETESTS_HPP
diff --git a/modules/egl/teglTestPackage.cpp b/modules/egl/teglTestPackage.cpp
index baafe1e..291d51e 100644
--- a/modules/egl/teglTestPackage.cpp
+++ b/modules/egl/teglTestPackage.cpp
@@ -58,6 +58,7 @@
 #include "teglResizeTests.hpp"
 #include "teglBufferAgeTests.hpp"
 #include "teglPartialUpdateTests.hpp"
+#include "teglNegativePartialUpdateTests.hpp"
 
 namespace deqp
 {
@@ -128,6 +129,7 @@
 		addChild(new ResizeTests				(m_eglTestCtx));
 		addChild(new BufferAgeTests				(m_eglTestCtx));
 		addChild(new PartialUpdateTests			(m_eglTestCtx));
+		addChild(new NegativePartialUpdateTests	(m_eglTestCtx));
 	}
 };