Move end2end and standalone tests to gl_tests and egl_tests

Also introduce a test_utils directory that contains helpers used for all
types of tests.

BUG=angleproject:892

Change-Id: I9e1bff895020ffd3a109162283971a290a1098bd
Reviewed-on: https://chromium-review.googlesource.com/270198
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
new file mode 100644
index 0000000..6e22bf0
--- /dev/null
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -0,0 +1,1151 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "test_utils/ANGLETest.h"
+
+#include "libANGLE/Context.h"
+#include "libANGLE/Program.h"
+
+using namespace angle;
+
+class GLSLTest : public ANGLETest
+{
+  protected:
+    GLSLTest()
+    {
+        setWindowWidth(128);
+        setWindowHeight(128);
+        setConfigRedBits(8);
+        setConfigGreenBits(8);
+        setConfigBlueBits(8);
+        setConfigAlphaBits(8);
+    }
+
+    virtual void SetUp()
+    {
+        ANGLETest::SetUp();
+
+        mSimpleVSSource = SHADER_SOURCE
+        (
+            attribute vec4 inputAttribute;
+            void main()
+            {
+                gl_Position = inputAttribute;
+            }
+        );
+    }
+
+    std::string GenerateVaryingType(GLint vectorSize)
+    {
+        char varyingType[10];
+
+        if (vectorSize == 1)
+        {
+            sprintf(varyingType, "float");
+        }
+        else
+        {
+            sprintf(varyingType, "vec%d", vectorSize);
+        }
+
+        return std::string(varyingType);
+    }
+
+    std::string GenerateVectorVaryingDeclaration(GLint vectorSize, GLint arraySize, GLint id)
+    {
+        char buff[100];
+
+        if (arraySize == 1)
+        {
+            sprintf(buff, "varying %s v%d;\n", GenerateVaryingType(vectorSize).c_str(), id);
+        }
+        else
+        {
+            sprintf(buff, "varying %s v%d[%d];\n", GenerateVaryingType(vectorSize).c_str(), id, arraySize);
+        }
+
+        return std::string(buff);
+    }
+
+    std::string GenerateVectorVaryingSettingCode(GLint vectorSize, GLint arraySize, GLint id)
+    {
+        std::string returnString;
+        char buff[100];
+
+        if (arraySize == 1)
+        {
+            sprintf(buff, "\t v%d = %s(1.0);\n", id, GenerateVaryingType(vectorSize).c_str());
+            returnString += buff;
+        }
+        else
+        {
+            for (int i = 0; i < arraySize; i++)
+            {
+                sprintf(buff, "\t v%d[%d] = %s(1.0);\n", id, i, GenerateVaryingType(vectorSize).c_str());
+                returnString += buff;
+            }
+        }
+
+        return returnString;
+    }
+
+    std::string GenerateVectorVaryingUseCode(GLint arraySize, GLint id)
+    {
+        if (arraySize == 1)
+        {
+            char buff[100];
+            sprintf(buff, "v%d + ", id);
+            return std::string(buff);
+        }
+        else
+        {
+            std::string returnString;
+            for (int i = 0; i < arraySize; i++)
+            {
+                char buff[100];
+                sprintf(buff, "v%d[%d] + ", id, i);
+                returnString += buff;
+            }
+            return returnString;
+        }
+    }
+
+    void GenerateGLSLWithVaryings(GLint floatCount, GLint floatArrayCount, GLint vec2Count, GLint vec2ArrayCount, GLint vec3Count, GLint vec3ArrayCount,
+                                  GLint vec4Count, GLint vec4ArrayCount, bool useFragCoord, bool usePointCoord, bool usePointSize,
+                                  std::string* fragmentShader, std::string* vertexShader)
+    {
+        // Generate a string declaring the varyings, to share between the fragment shader and the vertex shader.
+        std::string varyingDeclaration;
+
+        unsigned int varyingCount = 0;
+
+        for (GLint i = 0; i < floatCount; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(1, 1, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < floatArrayCount; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(1, 2, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < vec2Count; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(2, 1, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < vec2ArrayCount; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(2, 2, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < vec3Count; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(3, 1, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < vec3ArrayCount; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(3, 2, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < vec4Count; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(4, 1, varyingCount);
+            varyingCount += 1;
+        }
+
+        for (GLint i = 0; i < vec4ArrayCount; i++)
+        {
+            varyingDeclaration += GenerateVectorVaryingDeclaration(4, 2, varyingCount);
+            varyingCount += 1;
+        }
+
+        // Generate the vertex shader
+        vertexShader->clear();
+        vertexShader->append(varyingDeclaration);
+        vertexShader->append("\nvoid main()\n{\n");
+
+        unsigned int currentVSVarying = 0;
+
+        for (GLint i = 0; i < floatCount; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(1, 1, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < floatArrayCount; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(1, 2, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec2Count; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(2, 1, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec2ArrayCount; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(2, 2, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec3Count; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(3, 1, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec3ArrayCount; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(3, 2, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec4Count; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(4, 1, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec4ArrayCount; i++)
+        {
+            vertexShader->append(GenerateVectorVaryingSettingCode(4, 2, currentVSVarying));
+            currentVSVarying += 1;
+        }
+
+        if (usePointSize)
+        {
+            vertexShader->append("gl_PointSize = 1.0;\n");
+        }
+
+        vertexShader->append("}\n");
+
+        // Generate the fragment shader
+        fragmentShader->clear();
+        fragmentShader->append("precision highp float;\n");
+        fragmentShader->append(varyingDeclaration);
+        fragmentShader->append("\nvoid main() \n{ \n\tvec4 retColor = vec4(0,0,0,0);\n");
+
+        unsigned int currentFSVarying = 0;
+
+        // Make use of the float varyings
+        fragmentShader->append("\tretColor += vec4(");
+
+        for (GLint i = 0; i < floatCount; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        for (GLint i = 0; i < floatArrayCount; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        fragmentShader->append("0.0, 0.0, 0.0, 0.0);\n");
+
+        // Make use of the vec2 varyings
+        fragmentShader->append("\tretColor += vec4(");
+
+        for (GLint i = 0; i < vec2Count; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec2ArrayCount; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        fragmentShader->append("vec2(0.0, 0.0), 0.0, 0.0);\n");
+
+        // Make use of the vec3 varyings
+        fragmentShader->append("\tretColor += vec4(");
+
+        for (GLint i = 0; i < vec3Count; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec3ArrayCount; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        fragmentShader->append("vec3(0.0, 0.0, 0.0), 0.0);\n");
+
+        // Make use of the vec4 varyings
+        fragmentShader->append("\tretColor += ");
+
+        for (GLint i = 0; i < vec4Count; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        for (GLint i = 0; i < vec4ArrayCount; i++)
+        {
+            fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+            currentFSVarying += 1;
+        }
+
+        fragmentShader->append("vec4(0.0, 0.0, 0.0, 0.0);\n");
+
+        // Set gl_FragColor, and use special variables if requested
+        fragmentShader->append("\tgl_FragColor = retColor");
+        
+        if (useFragCoord)
+        {
+            fragmentShader->append(" + gl_FragCoord");
+        }
+
+        if (usePointCoord)
+        {
+            fragmentShader->append(" + vec4(gl_PointCoord, 0.0, 0.0)");
+        }
+
+        fragmentShader->append(";\n}");
+    }
+
+    void VaryingTestBase(GLint floatCount, GLint floatArrayCount, GLint vec2Count, GLint vec2ArrayCount, GLint vec3Count, GLint vec3ArrayCount,
+                         GLint vec4Count, GLint vec4ArrayCount, bool useFragCoord, bool usePointCoord, bool usePointSize, bool expectSuccess)
+    {
+        std::string fragmentShaderSource;
+        std::string vertexShaderSource;
+
+        GenerateGLSLWithVaryings(floatCount, floatArrayCount, vec2Count, vec2ArrayCount, vec3Count, vec3ArrayCount,
+                                 vec4Count, vec4ArrayCount, useFragCoord, usePointCoord, usePointSize,
+                                 &fragmentShaderSource, &vertexShaderSource);
+
+        GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+
+        if (expectSuccess)
+        {
+            EXPECT_NE(0u, program);
+        }
+        else
+        {
+            EXPECT_EQ(0u, program);
+        }
+    }
+
+    std::string mSimpleVSSource;
+};
+
+class GLSLTest_ES3 : public GLSLTest
+{
+};
+
+TEST_P(GLSLTest, NamelessScopedStructs)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+
+        void main()
+        {
+            struct
+            {
+                float q;
+            } b;
+
+            gl_FragColor = vec4(1, 0, 0, 1);
+            gl_FragColor.a += b.q;
+        }
+    );
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, ScopedStructsOrderBug)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+
+        struct T
+        {
+            float f;
+        };
+
+        void main()
+        {
+            T a;
+
+            struct T
+            {
+                float q;
+            };
+
+            T b;
+
+            gl_FragColor = vec4(1, 0, 0, 1);
+            gl_FragColor.a += a.f;
+            gl_FragColor.a += b.q;
+        }
+    );
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, ScopedStructsBug)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+
+        struct T_0
+        {
+            float f;
+        };
+
+        void main()
+        {
+            gl_FragColor = vec4(1, 0, 0, 1);
+
+            struct T
+            {
+                vec2 v;
+            };
+
+            T_0 a;
+            T b;
+
+            gl_FragColor.a += a.f;
+            gl_FragColor.a += b.v.x;
+        }
+    );
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, DxPositionBug)
+{
+    const std::string &vertexShaderSource = SHADER_SOURCE
+    (
+        attribute vec4 inputAttribute;
+        varying float dx_Position;
+        void main()
+        {
+            gl_Position = vec4(inputAttribute);
+            dx_Position = 0.0;
+        }
+    );
+
+    const std::string &fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+
+        varying float dx_Position;
+
+        void main()
+        {
+            gl_FragColor = vec4(dx_Position, 0, 0, 1);
+        }
+    );
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, ElseIfRewriting)
+{
+    const std::string &vertexShaderSource =
+        "attribute vec4 a_position;\n"
+        "varying float v;\n"
+        "void main() {\n"
+        "  gl_Position = a_position;\n"
+        "  v = 1.0;\n"
+        "  if (a_position.x <= 0.5) {\n"
+        "    v = 0.0;\n"
+        "  } else if (a_position.x >= 0.5) {\n"
+        "    v = 2.0;\n"
+        "  }\n"
+        "}\n";
+
+    const std::string &fragmentShaderSource =
+        "precision highp float;\n"
+        "varying float v;\n"
+        "void main() {\n"
+        "  vec4 color = vec4(1.0, 0.0, 0.0, 1.0);\n"
+        "  if (v >= 1.0) color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+        "  if (v >= 2.0) color = vec4(0.0, 0.0, 1.0, 1.0);\n"
+        "  gl_FragColor = color;\n"
+        "}\n";
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    ASSERT_NE(0u, program);
+
+    drawQuad(program, "a_position", 0.5f);
+    swapBuffers();
+
+    EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+    EXPECT_PIXEL_EQ(getWindowWidth()-1, 0, 0, 255, 0, 255);
+}
+
+TEST_P(GLSLTest, TwoElseIfRewriting)
+{
+    const std::string &vertexShaderSource =
+        "attribute vec4 a_position;\n"
+        "varying float v;\n"
+        "void main() {\n"
+        "  gl_Position = a_position;\n"
+        "  if (a_position.x == 0.0) {\n"
+        "    v = 1.0;\n"
+        "  } else if (a_position.x > 0.5) {\n"
+        "    v = 0.0;\n"
+        "  } else if (a_position.x > 0.75) {\n"
+        "    v = 0.5;\n"
+        "  }\n"
+        "}\n";
+
+    const std::string &fragmentShaderSource =
+        "precision highp float;\n"
+        "varying float v;\n"
+        "void main() {\n"
+        "  gl_FragColor = vec4(v, 0.0, 0.0, 1.0);\n"
+        "}\n";
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, InvariantVaryingOut)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+        varying float v_varying;
+        void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }
+    );
+
+    const std::string vertexShaderSource = SHADER_SOURCE
+    (
+        attribute vec4 a_position;
+        invariant varying float v_varying;
+        void main() { v_varying = a_position.x; gl_Position = a_position; }
+    );
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, FrontFacingAndVarying)
+{
+    EGLPlatformParameters platform = GetParam().mEGLPlatformParameters;
+
+    // Disable this test on D3D11 feature level 9_3, since gl_FrontFacing isn't supported.
+    if (platform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+    {
+        if (platform.majorVersion == 9 && platform.minorVersion == 3)
+        {
+            return;
+        }
+    }
+
+    const std::string vertexShaderSource = SHADER_SOURCE
+    (
+        attribute vec4 a_position;
+        varying float v_varying;
+        void main()
+        {
+            v_varying = a_position.x;
+            gl_Position = a_position;
+        }
+    );
+
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+        varying float v_varying;
+        void main()
+        {
+            vec4 c;
+
+            if (gl_FrontFacing)
+            {
+                c = vec4(v_varying, 0, 0, 1.0);
+            }
+            else
+            {
+                c = vec4(0, v_varying, 0, 1.0);
+            }
+            gl_FragColor = c;
+        }
+    );
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, InvariantVaryingIn)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+        invariant varying float v_varying;
+        void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }
+    );
+
+    const std::string vertexShaderSource = SHADER_SOURCE
+    (
+        attribute vec4 a_position;
+        varying float v_varying;
+        void main() { v_varying = a_position.x; gl_Position = a_position; }
+    );
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, InvariantVaryingBoth)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+        invariant varying float v_varying;
+        void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }
+    );
+
+    const std::string vertexShaderSource = SHADER_SOURCE
+    (
+        attribute vec4 a_position;
+        invariant varying float v_varying;
+        void main() { v_varying = a_position.x; gl_Position = a_position; }
+    );
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, InvariantGLPosition)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+        varying float v_varying;
+        void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }
+    );
+
+    const std::string vertexShaderSource = SHADER_SOURCE
+    (
+        attribute vec4 a_position;
+        invariant gl_Position;
+        varying float v_varying;
+        void main() { v_varying = a_position.x; gl_Position = a_position; }
+    );
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, InvariantAll)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+        varying float v_varying;
+        void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }
+    );
+
+    const std::string vertexShaderSource =
+        "#pragma STDGL invariant(all)\n"
+        "attribute vec4 a_position;\n"
+        "varying float v_varying;\n"
+        "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec4)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, false, false, true);
+}
+
+TEST_P(GLSLTest, MaxMinusTwoVaryingVec4PlusTwoSpecialVariables)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    // Generate shader code that uses gl_FragCoord and gl_PointCoord, two special fragment shader variables.
+    VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, false, true);
+}
+
+TEST_P(GLSLTest, MaxMinusTwoVaryingVec4PlusThreeSpecialVariables)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    // Generate shader code that uses gl_FragCoord, gl_PointCoord and gl_PointSize.
+    VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, true, true);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec4PlusFragCoord)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    // Generate shader code that uses gl_FragCoord, a special fragment shader variables.
+    // This test should fail, since we are really using (maxVaryings + 1) varyings.
+    VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, true, false, false, false);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec4PlusPointCoord)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    // Generate shader code that uses gl_FragCoord, a special fragment shader variables.
+    // This test should fail, since we are really using (maxVaryings + 1) varyings.
+    VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, true, false, false);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec3)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 0, 0, maxVaryings, 0, 0, 0, false, false, false, true);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec3Array)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec3AndOneFloat)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(1, 0, 0, 0, maxVaryings, 0, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec3ArrayAndOneFloatArray)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 1, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, DISABLED_TwiceMaxVaryingVec2)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 2 * maxVaryings, 0, 0, 0, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec2Arrays)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 0, maxVaryings, 0, 0, 0, 0, false, false, false, true);
+}
+
+TEST_P(GLSLTest, MaxPlusOneVaryingVec3)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 0, 0, maxVaryings + 1, 0, 0, 0, false, false, false, false);
+}
+
+TEST_P(GLSLTest, MaxPlusOneVaryingVec3Array)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2 + 1, 0, 0, false, false, false, false);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec3AndOneVec2)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 1, 0, maxVaryings, 0, 0, 0, false, false, false, false);
+}
+
+TEST_P(GLSLTest, MaxPlusOneVaryingVec2)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, 0, 2 * maxVaryings + 1, 0, 0, 0, 0, 0, false, false, false, false);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
+{
+    GLint maxVaryings = 0;
+    glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+    VaryingTestBase(0, maxVaryings / 2 + 1, 0, 0, 0, 0, 0, maxVaryings / 2, false, false, false, false);
+}
+
+// Verify shader source with a fixed length that is less than the null-terminated length will compile.
+TEST_P(GLSLTest, FixedShaderLength)
+{
+    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+    const std::string appendGarbage = "abcasdfasdfasdfasdfasdf";
+    const std::string source = "void main() { gl_FragColor = vec4(0, 0, 0, 0); }" + appendGarbage;
+    const char *sourceArray[1] = { source.c_str() };
+    GLint lengths[1] = { source.length() - appendGarbage.length() };
+    glShaderSource(shader, ArraySize(sourceArray), sourceArray, lengths);
+    glCompileShader(shader);
+
+    GLint compileResult;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+    EXPECT_NE(compileResult, 0);
+}
+
+// Verify that a negative shader source length is treated as a null-terminated length.
+TEST_P(GLSLTest, NegativeShaderLength)
+{
+    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+    const char *sourceArray[1] = { "void main() { gl_FragColor = vec4(0, 0, 0, 0); }" };
+    GLint lengths[1] = { -10 };
+    glShaderSource(shader, ArraySize(sourceArray), sourceArray, lengths);
+    glCompileShader(shader);
+
+    GLint compileResult;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+    EXPECT_NE(compileResult, 0);
+}
+
+// Verify that a length array with mixed positive and negative values compiles.
+TEST_P(GLSLTest, MixedShaderLengths)
+{
+    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+    const char *sourceArray[] =
+    {
+        "void main()",
+        "{",
+        "    gl_FragColor = vec4(0, 0, 0, 0);",
+        "}",
+    };
+    GLint lengths[] =
+    {
+        -10,
+        1,
+        std::strlen(sourceArray[2]),
+        -1,
+    };
+    ASSERT_EQ(ArraySize(sourceArray), ArraySize(lengths));
+
+    glShaderSource(shader, ArraySize(sourceArray), sourceArray, lengths);
+    glCompileShader(shader);
+
+    GLint compileResult;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+    EXPECT_NE(compileResult, 0);
+}
+
+// Verify that zero-length shader source does not affect shader compilation.
+TEST_P(GLSLTest, ZeroShaderLength)
+{
+    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+    const char *sourceArray[] =
+    {
+        "adfasdf",
+        "34534",
+        "void main() { gl_FragColor = vec4(0, 0, 0, 0); }",
+        "",
+        "asdfasdfsdsdf",
+    };
+    GLint lengths[] =
+    {
+        0,
+        0,
+        -1,
+        0,
+        0,
+    };
+    ASSERT_EQ(ArraySize(sourceArray), ArraySize(lengths));
+
+    glShaderSource(shader, ArraySize(sourceArray), sourceArray, lengths);
+    glCompileShader(shader);
+
+    GLint compileResult;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+    EXPECT_NE(compileResult, 0);
+}
+
+// Tests that bad index expressions don't crash ANGLE's translator.
+// https://code.google.com/p/angleproject/issues/detail?id=857
+TEST_P(GLSLTest, BadIndexBug)
+{
+    const std::string &fragmentShaderSourceVec =
+        "precision mediump float;\n"
+        "uniform vec4 uniformVec;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_FragColor = vec4(uniformVec[int()]);\n"
+        "}";
+
+    GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSourceVec);
+    EXPECT_EQ(0u, shader);
+
+    if (shader != 0)
+    {
+        glDeleteShader(shader);
+    }
+
+    const std::string &fragmentShaderSourceMat =
+        "precision mediump float;\n"
+        "uniform mat4 uniformMat;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_FragColor = vec4(uniformMat[int()]);\n"
+        "}";
+
+    shader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSourceMat);
+    EXPECT_EQ(0u, shader);
+
+    if (shader != 0)
+    {
+        glDeleteShader(shader);
+    }
+
+    const std::string &fragmentShaderSourceArray =
+        "precision mediump float;\n"
+        "uniform vec4 uniformArray;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_FragColor = vec4(uniformArray[int()]);\n"
+        "}";
+
+    shader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSourceArray);
+    EXPECT_EQ(0u, shader);
+
+    if (shader != 0)
+    {
+        glDeleteShader(shader);
+    }
+}
+
+// Tests that using a global static initialized from a varying works as expected.
+// See: https://code.google.com/p/angleproject/issues/detail?id=878
+TEST_P(GLSLTest, GlobalStaticAndVarying)
+{
+    const std::string &vertexShaderSource =
+        "attribute vec4 a_position;\n"
+        "varying float v;\n"
+        "void main() {\n"
+        "  gl_Position = a_position;\n"
+        "  v = 1.0;\n"
+        "}\n";
+
+    const std::string &fragmentShaderSource =
+        "precision highp float;\n"
+        "varying float v;\n"
+        "float x = v;"
+        "float global_v = x;"
+        "void main() {\n"
+        "  gl_FragColor = vec4(global_v, 0.0, 0.0, 1.0);\n"
+        "}\n";
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    ASSERT_NE(0u, program);
+
+    drawQuad(program, "a_position", 0.5f);
+    swapBuffers();
+
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+}
+
+// Tests that using a global static initialized from gl_InstanceID works as expected.
+TEST_P(GLSLTest_ES3, GlobalStaticAndInstanceID)
+{
+    const std::string &vertexShaderSource =
+        "#version 300 es\n"
+        "precision highp float;\n"
+        "in vec4 a_position;\n"
+        "out vec4 vColour;"
+        "int x = gl_InstanceID;"
+        "int global_v = x;"
+        "void main() {\n"
+        "  gl_Position = a_position;\n"
+        "  vColour = vec4(float(global_v)/255., 0.0, 0.0, 1.0);\n"
+        "}\n";
+
+    const std::string &fragmentShaderSource =
+        "#version 300 es\n"
+        "precision highp float;\n"
+        "in vec4 vColour;"
+        "out vec4 colour;"
+        "void main() {\n"
+        "  colour = vColour;\n"
+        "}\n";
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    ASSERT_NE(0u, program);
+
+    GLint positionLocation = glGetAttribLocation(program, "a_position");
+
+    glUseProgram(program);
+
+    const GLfloat vertices[] =
+    {
+        -1.0f,  1.0f, 0.5f,
+        -1.0f, -1.0f, 0.5f,
+         1.0f, -1.0f, 0.5f,
+
+        -1.0f,  1.0f, 0.5f,
+         1.0f, -1.0f, 0.5f,
+         1.0f,  1.0f, 0.5f,
+    };
+
+    glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
+    glEnableVertexAttribArray(positionLocation);
+
+    glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 7);
+
+    glDisableVertexAttribArray(positionLocation);
+    glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
+
+    glUseProgram(0);
+
+    swapBuffers();
+
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(0, 0, 6, 0, 0, 255);
+}
+
+// Test that structs defined in uniforms are translated correctly.
+TEST_P(GLSLTest, StructSpecifiersUniforms)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+
+        uniform struct S { float field;} s;
+
+        void main()
+        {
+            gl_FragColor = vec4(1, 0, 0, 1);
+            gl_FragColor.a += s.field;
+        }
+    );
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+}
+
+// Test that gl_DepthRange is not stored as a uniform location. Since uniforms
+// beginning with "gl_" are filtered out by our validation logic, we must
+// bypass the validation to test the behaviour of the implementation.
+// (note this test is still Impl-independent)
+TEST_P(GLSLTest, DepthRangeUniforms)
+{
+    const std::string fragmentShaderSource = SHADER_SOURCE
+    (
+        precision mediump float;
+
+        void main()
+        {
+            gl_FragColor = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff, 1);
+        }
+    );
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+
+    // dive into the ANGLE internals, so we can bypass validation.
+    gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
+    gl::Program *glProgram = context->getProgram(program);
+    GLint nearIndex = glProgram->getUniformLocation("gl_DepthRange.near");
+    EXPECT_EQ(-1, nearIndex);
+
+    // Test drawing does not throw an exception.
+    drawQuad(program, "inputAttribute", 0.5f);
+
+    EXPECT_GL_NO_ERROR();
+
+    glDeleteProgram(program);
+}
+
+// Covers the WebGL test 'glsl/bugs/pow-of-small-constant-in-user-defined-function'
+// See https://code.google.com/p/angleproject/issues/detail?id=851
+// TODO(jmadill): ANGLE constant folding can fix this
+TEST_P(GLSLTest, DISABLED_PowOfSmallConstant)
+{
+    const std::string &fragmentShaderSource = SHADER_SOURCE
+    (
+        precision highp float;
+
+        float fun(float arg)
+        {
+            // These values are still easily within the highp range.
+            // The minimum range in terms of 10's exponent is around -19 to 19, and IEEE-754 single precision range is higher than that.
+            return pow(arg, 2.0);
+        }
+
+        void main()
+        {
+            // Note that the bug did not reproduce if an uniform was passed to the function instead of a constant,
+            // or if the expression was moved outside the user-defined function.
+            const float a = 1.0e-6;
+            float b = 1.0e12 * fun(a);
+            if (abs(b - 1.0) < 0.01)
+            {
+                gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); // green
+            }
+            else
+            {
+                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // red
+            }
+        }
+    );
+
+    GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+    EXPECT_NE(0u, program);
+
+    drawQuad(program, "inputAttribute", 0.5f);
+    EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+    EXPECT_GL_NO_ERROR();
+}
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
+ANGLE_INSTANTIATE_TEST(GLSLTest, ES2_D3D9(), ES2_D3D11());
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
+ANGLE_INSTANTIATE_TEST(GLSLTest_ES3, ES3_D3D11());