/* Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/** @file beginend-coverage.c
 *
 * Test that various functions correctly throw errors or not while
 * inside a glBegin()/glEnd() block, whether inside or outside a
 * display list.
 *
 * From the GL 1.0 specification section 2.6.3, "GL Commands within
 * Begin/End"
 *
 *     "The only GL commands that are allowed within any Begin/End
 *      pairs are the commands for specifying vertex coordinates,
 *      vertex color, normal coordinates, and texture coordinates
 *      (Vertex, Color, Index, Normal, TexCoord), EvalCoord and
 *      EvalPoint commands (see section 5.1), commands for specifying
 *      lighting material parameters (Material commands see section
 *      2.12.2), display list invocation commands (CallList and
 *      CallLists see section 5.4), and the EdgeFlag
 *      command. Executing Begin after Begin has already been executed
 *      but before an End is issued generates the INVALID OPERATION
 *      error, as does executing End without a previous corresponding
 *      Begin. Executing any other GL command within Begin/End results
 *      in the error INVALID OPERATION."
 */

#include "piglit-util-gl.h"

PIGLIT_GL_TEST_CONFIG_BEGIN

	config.supports_gl_compat_version = 10;

	config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
	config.khr_no_error_support = PIGLIT_HAS_ERRORS;

PIGLIT_GL_TEST_CONFIG_END

struct test {
	const char *name;
	void (*func)(void);
};

static uint32_t junk_storage[1024];
static void *junk = junk_storage;
static const int onei = 1;
static const float onef = 1.0;
static GLuint some_dlist;
static GLuint newlist_dlist;
static GLuint deletelists_dlist;
static GLuint fbo_attachment;
static GLint fbo_binding;

#define TEST_FUNC(name, args)			\
	static void test_##name(void)		\
	{					\
		name args;			\
	}
;
TEST_FUNC(glAccum, (GL_ADD, 1.0))
TEST_FUNC(glAlphaFunc, (GL_GREATER, 0.0))
TEST_FUNC(glArrayElement, (0))
TEST_FUNC(glBegin, (GL_POINTS))
TEST_FUNC(glBitmap, (1, 1, 0, 0, 0, 0, (const GLubyte *)junk))
TEST_FUNC(glBlendFunc, (GL_ZERO, GL_ZERO))
TEST_FUNC(glCallList, (some_dlist))
/* relies on ListBase == 0 */
TEST_FUNC(glCallLists, (1, GL_UNSIGNED_INT, &some_dlist))
TEST_FUNC(glClear, (GL_COLOR_BUFFER_BIT))
TEST_FUNC(glClearAccum, (0, 0, 0, 0))
TEST_FUNC(glClearColor, (0, 0, 0 ,0))
TEST_FUNC(glClearDepth, (0))
TEST_FUNC(glClearIndex, (0))
TEST_FUNC(glClearStencil, (0))
TEST_FUNC(glClipPlane, (GL_CLIP_PLANE0, junk))
TEST_FUNC(glColor3b, (0, 0, 0))
TEST_FUNC(glColor3bv, (junk))
TEST_FUNC(glColor3d, (0, 0, 0))
TEST_FUNC(glColor3dv, (junk))
TEST_FUNC(glColor3f, (0, 0, 0))
TEST_FUNC(glColor3fv, (junk))
TEST_FUNC(glColor3i, (0, 0, 0))
TEST_FUNC(glColor3iv, (junk))
TEST_FUNC(glColor3s, (0, 0, 0))
TEST_FUNC(glColor3sv, (junk))
TEST_FUNC(glColor3ub, (0, 0, 0))
TEST_FUNC(glColor3ubv, (junk))
TEST_FUNC(glColor3ui, (0, 0, 0))
TEST_FUNC(glColor3uiv, (junk))
TEST_FUNC(glColor3us, (0, 0, 0))
TEST_FUNC(glColor3usv, (junk))
TEST_FUNC(glColor4b, (0, 0, 0, 0))
TEST_FUNC(glColor4bv, (junk))
TEST_FUNC(glColor4d, (0, 0, 0, 0))
TEST_FUNC(glColor4dv, (junk))
TEST_FUNC(glColor4f, (0, 0, 0, 0))
TEST_FUNC(glColor4fv, (junk))
TEST_FUNC(glColor4i, (0, 0, 0, 0))
TEST_FUNC(glColor4iv, (junk))
TEST_FUNC(glColor4s, (0, 0, 0, 0))
TEST_FUNC(glColor4sv, (junk))
TEST_FUNC(glColor4ub, (0, 0, 0, 0))
TEST_FUNC(glColor4ubv, (junk))
TEST_FUNC(glColor4ui, (0, 0, 0, 0))
TEST_FUNC(glColor4uiv, (junk))
TEST_FUNC(glColor4us, (0, 0, 0, 0))
TEST_FUNC(glColor4usv, (junk))
TEST_FUNC(glColorMask, (0, 0, 0, 0))
TEST_FUNC(glColorMaterial, (GL_FRONT, GL_AMBIENT))
TEST_FUNC(glColorPointer, (4, GL_FLOAT, 0, junk))
TEST_FUNC(glCopyPixels, (0, 0, 1, 1, GL_COLOR))
TEST_FUNC(glCullFace, (GL_FRONT))
TEST_FUNC(glDepthFunc, (GL_GREATER))
TEST_FUNC(glDepthMask, (0))
TEST_FUNC(glDepthRange, (0, 1))
TEST_FUNC(glDeleteLists, (deletelists_dlist, 1))
TEST_FUNC(glDisable, (GL_DEPTH_TEST))
TEST_FUNC(glDisableClientState, (GL_VERTEX_ARRAY))
TEST_FUNC(glDrawArrays, (GL_POINTS, 0, 1))
TEST_FUNC(glDrawBuffer, (fbo_attachment))
TEST_FUNC(glDrawElements, (GL_POINTS, 1, GL_UNSIGNED_INT, junk))
TEST_FUNC(glDrawPixels, (1, 1, GL_RGBA, GL_FLOAT, junk))
TEST_FUNC(glEdgeFlag, (0))
TEST_FUNC(glEdgeFlagPointer, (0, junk))
TEST_FUNC(glEdgeFlagv, (junk))
TEST_FUNC(glEnable, (GL_DEPTH_TEST))
TEST_FUNC(glEnableClientState, (GL_VERTEX_ARRAY))
/* No particular test for End inside of a begin/end block, obviously. */
TEST_FUNC(glEndList, ())
TEST_FUNC(glFrontFace, (GL_CW))
TEST_FUNC(glGenLists, (1))
TEST_FUNC(glGetBooleanv, (GL_DEPTH_TEST, junk))
TEST_FUNC(glGetClipPlane, (0, junk))
TEST_FUNC(glGetDoublev, (GL_DEPTH_TEST, junk))
TEST_FUNC(glGetError, ())
TEST_FUNC(glGetFloatv, (GL_DEPTH_TEST, junk))
TEST_FUNC(glGetIntegerv, (GL_DEPTH_TEST, junk))
TEST_FUNC(glGetLightfv, (GL_LIGHT0, GL_SPOT_CUTOFF, junk))
TEST_FUNC(glGetLightiv, (GL_LIGHT0, GL_SPOT_CUTOFF, junk))
TEST_FUNC(glGetMaterialfv, (GL_FRONT, GL_AMBIENT, junk))
TEST_FUNC(glGetMaterialiv, (GL_FRONT, GL_AMBIENT, junk))
TEST_FUNC(glGetPolygonStipple, (junk))
TEST_FUNC(glGetString, (GL_EXTENSIONS))
TEST_FUNC(glGetPixelMapfv, (GL_PIXEL_MAP_S_TO_S, junk))
TEST_FUNC(glGetPixelMapuiv, (GL_PIXEL_MAP_S_TO_S, junk))
TEST_FUNC(glGetPixelMapusv, (GL_PIXEL_MAP_S_TO_S, junk))
TEST_FUNC(glGetPointerv, (GL_VERTEX_ARRAY_POINTER, junk))
TEST_FUNC(glGetTexEnvfv, (GL_TEXTURE_2D, GL_ALPHA_SCALE, junk))
TEST_FUNC(glGetTexEnviv, (GL_TEXTURE_2D, GL_ALPHA_SCALE, junk))
TEST_FUNC(glGetTexGendv, (GL_S, GL_OBJECT_PLANE, junk))
TEST_FUNC(glGetTexGenfv, (GL_S, GL_OBJECT_PLANE, junk))
TEST_FUNC(glGetTexGeniv, (GL_S, GL_OBJECT_PLANE, junk))
TEST_FUNC(glGetTexImage, (GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, junk))
TEST_FUNC(glGetTexLevelParameterfv, (GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, junk))
TEST_FUNC(glGetTexLevelParameteriv, (GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, junk))
TEST_FUNC(glGetTexParameterfv, (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, junk))
TEST_FUNC(glGetTexParameteriv, (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, junk))
TEST_FUNC(glFinish, ())
TEST_FUNC(glFlush, ())
TEST_FUNC(glFrustum, (0, 1, 0, 1, 0.1, 1))
TEST_FUNC(glHint, (GL_FOG_HINT, GL_NICEST))
TEST_FUNC(glIndexMask, (0))
TEST_FUNC(glIsEnabled, (GL_DEPTH_TEST))
TEST_FUNC(glIsList, (0))
TEST_FUNC(glIndexd, (0))
TEST_FUNC(glIndexdv, (junk))
TEST_FUNC(glIndexf, (0))
TEST_FUNC(glIndexfv, (junk))
TEST_FUNC(glIndexi, (0))
TEST_FUNC(glIndexiv, (junk))
TEST_FUNC(glIndexPointer, (GL_BYTE, 0, junk))
TEST_FUNC(glIndexs, (0))
TEST_FUNC(glIndexsv, (junk))
TEST_FUNC(glIndexub, (0))
TEST_FUNC(glIndexubv, (junk))
TEST_FUNC(glInterleavedArrays, (GL_V2F, 0, junk))
TEST_FUNC(glLightf, (GL_LIGHT0, GL_SPOT_CUTOFF, 0))
TEST_FUNC(glLightfv, (GL_LIGHT0, GL_SPOT_CUTOFF, junk))
TEST_FUNC(glLighti, (GL_LIGHT0, GL_SPOT_CUTOFF, 0))
TEST_FUNC(glLightiv, (GL_LIGHT0, GL_SPOT_CUTOFF, junk))
TEST_FUNC(glLightModelf, (GL_LIGHT_MODEL_AMBIENT, 0))
TEST_FUNC(glLightModelfv, (GL_LIGHT_MODEL_AMBIENT, junk))
TEST_FUNC(glLightModeli, (GL_LIGHT_MODEL_AMBIENT, 0))
TEST_FUNC(glLightModeliv, (GL_LIGHT_MODEL_AMBIENT, junk))
TEST_FUNC(glLineStipple, (0, 0))
TEST_FUNC(glLineWidth, (1))
TEST_FUNC(glListBase, (0))
TEST_FUNC(glLoadIdentity, ())
TEST_FUNC(glLoadMatrixd, (junk))
TEST_FUNC(glLoadMatrixf, (junk))
TEST_FUNC(glLogicOp, (GL_COPY))
TEST_FUNC(glMaterialf, (GL_FRONT, GL_AMBIENT, 0))
TEST_FUNC(glMaterialfv, (GL_FRONT, GL_AMBIENT, junk))
TEST_FUNC(glMateriali, (GL_FRONT, GL_AMBIENT, 0))
TEST_FUNC(glMaterialiv, (GL_FRONT, GL_AMBIENT, junk))
TEST_FUNC(glMatrixMode, (GL_MODELVIEW))
TEST_FUNC(glMultMatrixd, (junk))
TEST_FUNC(glMultMatrixf, (junk))
TEST_FUNC(glNewList, (newlist_dlist, GL_COMPILE))
TEST_FUNC(glNormal3d, (0, 0, 0))
TEST_FUNC(glNormal3f, (0, 0, 0))
TEST_FUNC(glNormal3i, (0, 0, 0))
TEST_FUNC(glNormal3s, (0, 0, 0))
TEST_FUNC(glNormal3dv, (junk))
TEST_FUNC(glNormal3fv, (junk))
TEST_FUNC(glNormal3iv, (junk))
TEST_FUNC(glNormal3sv, (junk))
TEST_FUNC(glNormalPointer, (GL_FLOAT, 0, junk))
TEST_FUNC(glOrtho, (0, 1, 0, 1, 0, 1))
TEST_FUNC(glReadPixels, (0, 0, 1, 1, GL_RGBA, GL_FLOAT, junk))
TEST_FUNC(glRotated, (0, 0, 0, 1))
TEST_FUNC(glRotatef, (0, 0, 0, 1))
TEST_FUNC(glScaled, (0, 0, 0))
TEST_FUNC(glScalef, (0, 0, 0))
TEST_FUNC(glShadeModel, (GL_SMOOTH))
TEST_FUNC(glTranslated, (0, 0, 0))
TEST_FUNC(glTranslatef, (0, 0, 0))
TEST_FUNC(glPixelMapfv, (GL_PIXEL_MAP_S_TO_S, 1, junk))
TEST_FUNC(glPixelMapuiv, (GL_PIXEL_MAP_S_TO_S, 1, junk))
TEST_FUNC(glPixelMapusv, (GL_PIXEL_MAP_S_TO_S, 1, junk))
TEST_FUNC(glPixelStoref, (GL_UNPACK_ROW_LENGTH, 0))
TEST_FUNC(glPixelStorei, (GL_UNPACK_ROW_LENGTH, 0))
TEST_FUNC(glPixelTransferf, (GL_MAP_COLOR, 0))
TEST_FUNC(glPixelTransferi, (GL_MAP_COLOR, 0))
TEST_FUNC(glPixelZoom, (0, 0))
TEST_FUNC(glPointSize, (1))
static void test_glPushAttrib(void) {
	glPushAttrib(GL_COLOR_BUFFER_BIT);
	glPopAttrib();
}
static void test_glPushClientAttrib(void) {
	glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
	glPopClientAttrib();
}
static void test_glPushMatrix(void) {
	glPushMatrix();
	glPopMatrix();
}
TEST_FUNC(glPolygonStipple, (junk))
TEST_FUNC(glRasterPos2d, (0, 0))
TEST_FUNC(glRasterPos2dv, (junk))
TEST_FUNC(glRasterPos2f, (0, 0))
TEST_FUNC(glRasterPos2fv, (junk))
TEST_FUNC(glRasterPos2i, (0, 0))
TEST_FUNC(glRasterPos2iv, (junk))
TEST_FUNC(glRasterPos2s, (0, 0))
TEST_FUNC(glRasterPos2sv, (junk))
TEST_FUNC(glRasterPos3d, (0, 0, 0))
TEST_FUNC(glRasterPos3dv, (junk))
TEST_FUNC(glRasterPos3f, (0, 0, 0))
TEST_FUNC(glRasterPos3fv, (junk))
TEST_FUNC(glRasterPos3i, (0, 0, 0))
TEST_FUNC(glRasterPos3iv, (junk))
TEST_FUNC(glRasterPos3s, (0, 0, 0))
TEST_FUNC(glRasterPos3sv, (junk))
TEST_FUNC(glReadBuffer, (fbo_attachment))
TEST_FUNC(glRectd, (0, 0, 0, 0))
TEST_FUNC(glRectdv, (junk, junk))
TEST_FUNC(glRectf, (0, 0, 0, 0))
TEST_FUNC(glRectfv, (junk, junk))
TEST_FUNC(glRecti, (0, 0, 0, 0))
TEST_FUNC(glRectiv, (junk, junk))
TEST_FUNC(glRects, (0, 0, 0, 0))
TEST_FUNC(glRectsv, (junk, junk))
TEST_FUNC(glRenderMode, (GL_RENDER))
TEST_FUNC(glScissor, (0, 0, 1, 1))
TEST_FUNC(glStencilFunc, (GL_ALWAYS, 0, 0))
TEST_FUNC(glStencilMask, (0))
TEST_FUNC(glStencilOp, (GL_REPLACE, GL_REPLACE, GL_REPLACE))
TEST_FUNC(glTexCoord1d, (0))
TEST_FUNC(glTexCoord1dv, (junk))
TEST_FUNC(glTexCoord1f, (0))
TEST_FUNC(glTexCoord1fv, (junk))
TEST_FUNC(glTexCoord1i, (0))
TEST_FUNC(glTexCoord1iv, (junk))
TEST_FUNC(glTexCoord1s, (0))
TEST_FUNC(glTexCoord1sv, (junk))
TEST_FUNC(glTexCoord2d, (0, 0))
TEST_FUNC(glTexCoord2dv, (junk))
TEST_FUNC(glTexCoord2f, (0, 0))
TEST_FUNC(glTexCoord2fv, (junk))
TEST_FUNC(glTexCoord2i, (0, 0))
TEST_FUNC(glTexCoord2iv, (junk))
TEST_FUNC(glTexCoord2s, (0, 0))
TEST_FUNC(glTexCoord2sv, (junk))
TEST_FUNC(glTexCoord3d, (0, 0, 0))
TEST_FUNC(glTexCoord3dv, (junk))
TEST_FUNC(glTexCoord3f, (0, 0, 0))
TEST_FUNC(glTexCoord3fv, (junk))
TEST_FUNC(glTexCoord3i, (0, 0, 0))
TEST_FUNC(glTexCoord3iv, (junk))
TEST_FUNC(glTexCoord3s, (0, 0, 0))
TEST_FUNC(glTexCoord3sv, (junk))
TEST_FUNC(glTexCoord4d, (0, 0, 0, 0))
TEST_FUNC(glTexCoord4dv, (junk))
TEST_FUNC(glTexCoord4f, (0, 0, 0, 0))
TEST_FUNC(glTexCoord4fv, (junk))
TEST_FUNC(glTexCoord4i, (0, 0, 0, 0))
TEST_FUNC(glTexCoord4iv, (junk))
TEST_FUNC(glTexCoord4s, (0, 0, 0, 0))
TEST_FUNC(glTexCoord4sv, (junk))
TEST_FUNC(glTexCoordPointer, (4, GL_FLOAT, 0, junk))
TEST_FUNC(glTexEnvf, (GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1))
TEST_FUNC(glTexEnvfv, (GL_TEXTURE_ENV, GL_ALPHA_SCALE, &onef))
TEST_FUNC(glTexEnvi, (GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1))
TEST_FUNC(glTexEnviv, (GL_TEXTURE_ENV, GL_ALPHA_SCALE, &onei))
TEST_FUNC(glTexGend, (GL_S, GL_OBJECT_PLANE, 0))
TEST_FUNC(glTexGendv, (GL_S, GL_OBJECT_PLANE, junk))
TEST_FUNC(glTexGenf, (GL_S, GL_OBJECT_PLANE, 0))
TEST_FUNC(glTexGenfv, (GL_S, GL_OBJECT_PLANE, junk))
TEST_FUNC(glTexGeni, (GL_S, GL_OBJECT_PLANE, 0))
TEST_FUNC(glTexGeniv, (GL_S, GL_OBJECT_PLANE, junk))
TEST_FUNC(glTexImage1D, (GL_TEXTURE_1D, 0, GL_RGBA, 1, 0, GL_RGBA, GL_FLOAT, NULL))
TEST_FUNC(glTexImage2D, (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_FLOAT, NULL))
TEST_FUNC(glTexParameterf, (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, 0))
TEST_FUNC(glTexParameterfv, (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, junk))
TEST_FUNC(glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, 0))
TEST_FUNC(glTexParameteriv, (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, junk))
TEST_FUNC(glVertex2d, (0, 0))
TEST_FUNC(glVertex2dv, (junk))
TEST_FUNC(glVertex2f, (0, 0))
TEST_FUNC(glVertex2fv, (junk))
TEST_FUNC(glVertex2i, (0, 0))
TEST_FUNC(glVertex2iv, (junk))
TEST_FUNC(glVertex2s, (0, 0))
TEST_FUNC(glVertex2sv, (junk))
TEST_FUNC(glVertex3d, (0, 0, 0))
TEST_FUNC(glVertex3dv, (junk))
TEST_FUNC(glVertex3f, (0, 0, 0))
TEST_FUNC(glVertex3fv, (junk))
TEST_FUNC(glVertex3i, (0, 0, 0))
TEST_FUNC(glVertex3iv, (junk))
TEST_FUNC(glVertex3s, (0, 0, 0))
TEST_FUNC(glVertex3sv, (junk))
TEST_FUNC(glVertex4d, (0, 0, 0, 0))
TEST_FUNC(glVertex4dv, (junk))
TEST_FUNC(glVertex4f, (0, 0, 0, 0))
TEST_FUNC(glVertex4fv, (junk))
TEST_FUNC(glVertex4i, (0, 0, 0, 0))
TEST_FUNC(glVertex4iv, (junk))
TEST_FUNC(glVertex4s, (0, 0, 0, 0))
TEST_FUNC(glVertex4sv, (junk))
TEST_FUNC(glVertexPointer, (4, GL_FLOAT, 0, junk))
TEST_FUNC(glViewport, (0, 0, 1, 1))

#define TEST(a) { #a, test_##a }

static struct test ok_tests[] = {
	TEST(glArrayElement),
	TEST(glCallList),
	TEST(glCallLists),
	TEST(glColor3b),
	TEST(glColor3bv),
	TEST(glColor3d),
	TEST(glColor3dv),
	TEST(glColor3f),
	TEST(glColor3fv),
	TEST(glColor3i),
	TEST(glColor3iv),
	TEST(glColor3s),
	TEST(glColor3sv),
	TEST(glColor3ub),
	TEST(glColor3ubv),
	TEST(glColor3ui),
	TEST(glColor3uiv),
	TEST(glColor3us),
	TEST(glColor3usv),
	TEST(glColor4b),
	TEST(glColor4bv),
	TEST(glColor4d),
	TEST(glColor4dv),
	TEST(glColor4f),
	TEST(glColor4fv),
	TEST(glColor4i),
	TEST(glColor4iv),
	TEST(glColor4s),
	TEST(glColor4sv),
	TEST(glColor4ub),
	TEST(glColor4ubv),
	TEST(glColor4ui),
	TEST(glColor4uiv),
	TEST(glColor4us),
	TEST(glColor4usv),
	TEST(glEdgeFlag),
	TEST(glEdgeFlagv),
	TEST(glIndexd),
	TEST(glIndexdv),
	TEST(glIndexf),
	TEST(glIndexfv),
	TEST(glIndexi),
	TEST(glIndexiv),
	TEST(glIndexs),
	TEST(glIndexsv),
	TEST(glIndexub),
	TEST(glIndexubv),
	TEST(glMaterialf),
	TEST(glMaterialfv),
	TEST(glMateriali),
	TEST(glMaterialiv),
	TEST(glNormal3d),
	TEST(glNormal3dv),
	TEST(glNormal3f),
	TEST(glNormal3fv),
	TEST(glNormal3i),
	TEST(glNormal3iv),
	TEST(glNormal3s),
	TEST(glNormal3sv),
	TEST(glTexCoord1d),
	TEST(glTexCoord1dv),
	TEST(glTexCoord1f),
	TEST(glTexCoord1fv),
	TEST(glTexCoord1i),
	TEST(glTexCoord1iv),
	TEST(glTexCoord1s),
	TEST(glTexCoord1sv),
	TEST(glTexCoord2d),
	TEST(glTexCoord2dv),
	TEST(glTexCoord2f),
	TEST(glTexCoord2fv),
	TEST(glTexCoord2i),
	TEST(glTexCoord2iv),
	TEST(glTexCoord2s),
	TEST(glTexCoord2sv),
	TEST(glTexCoord3d),
	TEST(glTexCoord3dv),
	TEST(glTexCoord3f),
	TEST(glTexCoord3fv),
	TEST(glTexCoord3i),
	TEST(glTexCoord3iv),
	TEST(glTexCoord3s),
	TEST(glTexCoord3sv),
	TEST(glTexCoord4d),
	TEST(glTexCoord4dv),
	TEST(glTexCoord4f),
	TEST(glTexCoord4fv),
	TEST(glTexCoord4i),
	TEST(glTexCoord4iv),
	TEST(glTexCoord4s),
	TEST(glTexCoord4sv),
	TEST(glVertex2d),
	TEST(glVertex2dv),
	TEST(glVertex2f),
	TEST(glVertex2fv),
	TEST(glVertex2i),
	TEST(glVertex2iv),
	TEST(glVertex2s),
	TEST(glVertex2sv),
	TEST(glVertex3d),
	TEST(glVertex3dv),
	TEST(glVertex3f),
	TEST(glVertex3fv),
	TEST(glVertex3i),
	TEST(glVertex3iv),
	TEST(glVertex3s),
	TEST(glVertex3sv),
	TEST(glVertex4d),
	TEST(glVertex4dv),
	TEST(glVertex4f),
	TEST(glVertex4fv),
	TEST(glVertex4i),
	TEST(glVertex4iv),
	TEST(glVertex4s),
	TEST(glVertex4sv),
};

static struct test error_tests[] = {
	TEST(glAlphaFunc),
	TEST(glBlendFunc),
	TEST(glBitmap),
	TEST(glClear),
	TEST(glClearAccum),
	TEST(glClearColor),
	TEST(glClearDepth),
	TEST(glClearIndex),
	TEST(glClearStencil),
	TEST(glClipPlane),
	TEST(glColorMask),
	TEST(glColorMaterial),
	TEST(glCopyPixels),
	TEST(glCullFace),
	TEST(glDepthFunc),
	TEST(glDepthMask),
	TEST(glDepthRange),
	TEST(glDisable),
	TEST(glDrawArrays),
	TEST(glDrawBuffer),
	TEST(glDrawElements),
	TEST(glDrawPixels),
	TEST(glEnable),
	TEST(glFrontFace),
	TEST(glFrustum),
	TEST(glHint),
	TEST(glIndexMask),
	TEST(glLightf),
	TEST(glLightfv),
	TEST(glLighti),
	TEST(glLightiv),
	TEST(glLightModelf),
	TEST(glLightModelfv),
	TEST(glLightModeli),
	TEST(glLightModeliv),
	TEST(glLineStipple),
	TEST(glLineWidth),
	TEST(glListBase),
	TEST(glLoadIdentity),
	TEST(glLoadMatrixd),
	TEST(glLoadMatrixf),
	TEST(glLogicOp),
	TEST(glMatrixMode),
	TEST(glMultMatrixd),
	TEST(glMultMatrixf),
	TEST(glOrtho),
	TEST(glRotated),
	TEST(glRotatef),
	TEST(glScaled),
	TEST(glScalef),
	TEST(glShadeModel),
	TEST(glTranslated),
	TEST(glTranslatef),
	TEST(glPixelMapfv),
	TEST(glPixelMapuiv),
	TEST(glPixelMapusv),
	TEST(glPixelTransferf),
	TEST(glPixelTransferi),
	TEST(glPixelZoom),
	TEST(glPointSize),
	TEST(glPushAttrib),
	TEST(glPushMatrix),
	TEST(glPolygonStipple),
	TEST(glRasterPos2d),
	TEST(glRasterPos2dv),
	TEST(glRasterPos2f),
	TEST(glRasterPos2fv),
	TEST(glRasterPos2i),
	TEST(glRasterPos2iv),
	TEST(glRasterPos2s),
	TEST(glRasterPos2sv),
	TEST(glRasterPos3d),
	TEST(glRasterPos3dv),
	TEST(glRasterPos3f),
	TEST(glRasterPos3fv),
	TEST(glRasterPos3i),
	TEST(glRasterPos3iv),
	TEST(glRasterPos3s),
	TEST(glRasterPos3sv),
	TEST(glReadBuffer),
	TEST(glRectd),
	TEST(glRectdv),
	TEST(glRectf),
	TEST(glRectfv),
	TEST(glRecti),
	TEST(glRectiv),
	TEST(glRects),
	TEST(glRectsv),
	TEST(glScissor),
	TEST(glStencilFunc),
	TEST(glStencilMask),
	TEST(glStencilOp),
	TEST(glTexEnvf),
	TEST(glTexEnvfv),
	TEST(glTexEnvi),
	TEST(glTexEnviv),
	TEST(glTexGend),
	TEST(glTexGendv),
	TEST(glTexGenf),
	TEST(glTexGenfv),
	TEST(glTexGeni),
	TEST(glTexGeniv),
	TEST(glTexImage1D),
	TEST(glTexImage2D),
	TEST(glTexParameterf),
	TEST(glTexParameterfv),
	TEST(glTexParameteri),
	TEST(glTexParameteriv),
	TEST(glViewport),
};

/* From the GL 1.2.1 specification, section 5.4 ("Display Lists"):
 *
 *     "Certain commands, when called while compiling a display list,
 *      are not compiled into the display list but are executed
 *      immediately. These are: IsList, GenLists, DeleteLists,
 *      FeedbackBuffer, SelectBuffer, RenderMode, VertexPointer,
 *      NormalPointer, ColorPointer, IndexPointer, TexCoordPointer,
 *      EdgeFlagPointer, InterleavedArrays, EnableClientState,
 *      DisableClientState, PushClientAttrib, PopClientAttrib,
 *      ReadPixels, PixelStore, GenTextures, DeleteTextures,
 *      AreTexturesResident, IsTexture, Flush, Finish, as well as
 *      IsEnabled and all of the Get commands (see Chapter 6)."
 *
 * The 1.0 spec didn't mention the Pointer or ClientAttrib functions,
 * but this appears to be a correction.
 */
static struct test nondlist_error_tests[] = {
	TEST(glColorPointer),
	TEST(glDeleteLists),
	TEST(glDisableClientState),
	TEST(glEdgeFlagPointer),
	TEST(glEnableClientState),
	TEST(glIndexPointer),
	TEST(glNewList),
	TEST(glNormalPointer),
	TEST(glGenLists),
	TEST(glGetBooleanv),
	TEST(glGetClipPlane),
	TEST(glGetDoublev),
	TEST(glGetError),
	TEST(glGetFloatv),
	TEST(glGetIntegerv),
	TEST(glGetLightfv),
	TEST(glGetLightiv),
	TEST(glGetMaterialfv),
	TEST(glGetMaterialiv),
	TEST(glGetPolygonStipple),
	TEST(glGetString),
	TEST(glGetPixelMapfv),
	TEST(glGetPixelMapuiv),
	TEST(glGetPixelMapusv),
	TEST(glGetPointerv),
	TEST(glGetTexEnvfv),
	TEST(glGetTexEnviv),
	TEST(glGetTexGendv),
	TEST(glGetTexGenfv),
	TEST(glGetTexGeniv),
	TEST(glGetTexImage),
	TEST(glGetTexLevelParameterfv),
	TEST(glGetTexLevelParameteriv),
	TEST(glGetTexParameterfv),
	TEST(glGetTexParameteriv),
	TEST(glFinish),
	TEST(glFlush),
	TEST(glInterleavedArrays),
	TEST(glIsEnabled),
	TEST(glIsList),
	TEST(glPixelStoref),
	TEST(glPixelStorei),
	TEST(glPushClientAttrib),
	TEST(glReadPixels),
	TEST(glRenderMode),
	TEST(glTexCoordPointer),
	TEST(glVertexPointer),
};

static struct test error_only_tests[] = {
	/* No accum buffer is bound */
	TEST(glAccum),
	/* If it doesn't error out, it would need state cleanup. */
	TEST(glBegin),
};

static struct test endlist_test = TEST(glEndList);

enum piglit_result
piglit_display()
{
	/* UNREACHED */
	return PIGLIT_FAIL;
}

static bool
test_beginend(struct test *test, GLenum expected_error)
{
	printf("  Testing within begin/end\n");

	glBegin(GL_POINTS);
	test->func();
	glEnd();
	if (!piglit_check_gl_error(expected_error)) {
		fprintf(stderr, "after glEnd()\n");
		return false;
	}

	return true;
}

static bool
test_dlist_exec(struct test *test, GLenum expected_error)
{
	GLuint dlist;

	printf("  Testing glCallList() inside begin/end\n");

	dlist = glGenLists(1);
	glNewList(dlist, GL_COMPILE);
	test->func();
	glEndList();
	/* Nothing was executed yet, so no error should be present. */
	if (!piglit_check_gl_error(GL_NO_ERROR)) {
		fprintf(stderr, "after glEndList()\n");
		return false;
	}

	glBegin(GL_POINTS);
	glCallList(dlist);
	glEnd();
	if (!piglit_check_gl_error(expected_error)) {
		fprintf(stderr, "after glCallList()\n");
		return false;
	}

	glDeleteLists(dlist, 1);

	return true;
}

static bool
test_dlist_compile(struct test *test, GLenum expected_error)
{
	GLuint dlist;

	printf("  Testing glNewList(GL_COMPILE) with begin/end inside\n");

	dlist = glGenLists(1);
	glNewList(dlist, GL_COMPILE);
	glBegin(GL_POINTS);
	test->func();
	glEnd();
	glEndList();
	/* Nothing was executed yet, so no error should be present. */
	if (!piglit_check_gl_error(GL_NO_ERROR)) {
		fprintf(stderr, "after glEndList()\n");
		return false;
	}

	glCallList(dlist);
	if (!piglit_check_gl_error(expected_error)) {
		fprintf(stderr, "after glCallList()\n");
		return false;
	}

	glDeleteLists(dlist, 1);

	return true;
}

static bool
test_dlist_compile_exec(struct test *test, GLenum expected_error)
{
	GLuint dlist;

	printf("  Testing glNewList(GL_COMPILE_AND_EXEC) with begin/end "
	       "inside\n");

	dlist = glGenLists(1);
	glNewList(dlist, GL_COMPILE_AND_EXECUTE);
	glBegin(GL_POINTS);
	test->func();
	glEnd();
	glEndList();
	if (!piglit_check_gl_error(expected_error)) {
		fprintf(stderr, "after glEndList()\n");
		return false;
	}

	glCallList(dlist);
	if (!piglit_check_gl_error(expected_error)) {
		fprintf(stderr, "after glCallList()\n");
		return false;
	}

	glDeleteLists(dlist, 1);

	return true;
}

static bool
test_dlist_compile_exec_after(struct test *test)
{
	GLuint dlist;

	printf("  Testing glNewList(GL_COMPILE_AND_EXEC) with Begin/End "
	       "inside and the command after End\n");

	dlist = glGenLists(1);
	glNewList(dlist, GL_COMPILE_AND_EXECUTE);
	glBegin(GL_POINTS);
	glEnd();
	test->func();
	glEndList();
	if (!piglit_check_gl_error(GL_NO_ERROR)) {
		fprintf(stderr, "after glEndList()\n");
		return false;
	}

	glCallList(dlist);
	if (!piglit_check_gl_error(GL_NO_ERROR)) {
		fprintf(stderr, "after glCallList()\n");
		return false;
	}

	glDeleteLists(dlist, 1);

	return true;
}

static bool
run_tests(struct test *tests, int num_tests, GLenum expected_error)
{
	int i;
	bool pass = true;

	for (i = 0; i < num_tests; i++) {
		bool test_pass = true;

		printf("testing %s()\n", tests[i].name);
		test_pass = test_pass &&
			test_beginend(&tests[i], expected_error);

		if (tests != nondlist_error_tests) {
			test_pass = test_pass &&
				test_dlist_compile(&tests[i], expected_error);
			test_pass = test_pass &&
				test_dlist_exec(&tests[i], expected_error);
			test_pass = test_pass &&
				test_dlist_compile_exec(&tests[i],
							expected_error);

			/* Sanity check that we can actually do our call in a
			 * display list without triggering an error (unless
			 * it's impossible)
			 */
			if (tests != error_only_tests) {
				test_pass = test_pass &&
					test_dlist_compile_exec_after(&tests[i]);
			}
		}

		piglit_report_subtest_result(test_pass ?
					     PIGLIT_PASS : PIGLIT_FAIL,
					     "%s", tests[i].name);

		pass = test_pass && pass;
	}

	return pass;
}

/**
 * Special-case testing for glEndList().
 *
 * If we call glEndList without a glNewList active, we will get
 * GL_INVALID_OPERATION anyway.  If we call glNewList in our begin/end
 * block, then we have a GL_INVALID_OPERATION from that.  So, to test
 * glEndList() throwing GL_INVALID_OPERATION inside a begin/end
 * specifically because it's inside a begin/end, we need the begin/end 
 */
bool
test_endlist()
{
	GLuint dlist;

	if (!test_beginend(&endlist_test, GL_INVALID_OPERATION))
		return false;

	/* We can't use test_dlist_compile_exec because that expects
	 * the command to be compiled.  We also need to distinguish
	 * the EndList inside the Begin/End failing like it's supposed
	 * to, from the one that's supposed to terminate the list
	 * failing in case the one inside Begin/End happened to
	 * execute.
	 */
	printf("  Testing glNewList(GL_COMPILE_AND_EXEC) with begin/end "
	       "inside\n");

	dlist = glGenLists(1);
	glNewList(dlist, GL_COMPILE_AND_EXECUTE);
	glBegin(GL_POINTS);
	glEndList();
	glEnd();
	if (!piglit_check_gl_error(GL_INVALID_OPERATION)) {
		fprintf(stderr, "after glEnd()\n");
		return false;
	}
	glEndList();

	return true;
}

static void
enumerate_subtests(void) {
	const char * subtests[ARRAY_SIZE(ok_tests) + ARRAY_SIZE(error_tests) +
			      ARRAY_SIZE(error_only_tests) +
			      ARRAY_SIZE(nondlist_error_tests) + 2];
	unsigned i = 0;
	for (unsigned j = 0; j < ARRAY_SIZE(ok_tests); ++j, ++i) {
		subtests[i] = ok_tests[j].name;
	}
	for (unsigned j = 0; j < ARRAY_SIZE(error_tests); ++j, ++i) {
		subtests[i] = error_tests[j].name;
	}
	for (unsigned j = 0; j < ARRAY_SIZE(error_only_tests); ++j, ++i) {
		subtests[i] = error_only_tests[j].name;
	}
	for (unsigned j = 0; j < ARRAY_SIZE(nondlist_error_tests); ++j, ++i) {
		subtests[i] = nondlist_error_tests[j].name;
	}
	subtests[i++] = "glEndList";
	subtests[i] = NULL;

	piglit_register_subtests(subtests);
}

void
piglit_init(int argc, char **argv)
{
	bool pass;

	enumerate_subtests();

	/* Set up some state to be used by our various test
	 * functions
	 */
	newlist_dlist = glGenLists(1);
	deletelists_dlist = glGenLists(1);

	some_dlist = glGenLists(1);
	glNewList(some_dlist, GL_COMPILE);
	glEndList();

	if (piglit_is_extension_supported("GL_ARB_framebuffer_object"))
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo_binding);
	else
		fbo_binding = 0;

	if (fbo_binding)
		fbo_attachment = GL_COLOR_ATTACHMENT0;
	else
		fbo_attachment = GL_FRONT;

	pass = run_tests(ok_tests, ARRAY_SIZE(ok_tests), GL_NO_ERROR);
	pass = run_tests(error_tests, ARRAY_SIZE(error_tests),
			 GL_INVALID_OPERATION) && pass;
	pass = run_tests(error_only_tests, ARRAY_SIZE(error_only_tests),
			 GL_INVALID_OPERATION) && pass;
	pass = run_tests(nondlist_error_tests, ARRAY_SIZE(nondlist_error_tests),
			 GL_INVALID_OPERATION) && pass;

	if (test_endlist()) {
		piglit_report_subtest_result(PIGLIT_PASS, "glEndList");
	} else {
		piglit_report_subtest_result(PIGLIT_FAIL, "glEndList");
		pass = false;
	}

	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
}
