[Piglit] [PATCH 02/12] framework/shader_test.py: Replace ShaderTest class with function

Dylan Baker baker.dylan.c at gmail.com
Tue Feb 11 18:11:07 PST 2014


This replaces the ShaderTest class with a shader_test function that
returns a PlainExecTest instance. The reason to make this transition is
simple, ShaderTest never actually modified any of the methods in
PlainExecTest, it never needed to be a class, making it a function
reduces the amount of code required, vastly reduces the complexity of
the code, and makes testing much simpler.

This also removes the dmesg_test for ShaderTest, since shader_test just
returns a PlainExecTest, there isn't any reason for dmesg to test it
specially.

Signed-off-by: Dylan Baker <baker.dylan.c at gmail.com>
---
 framework/shader_test.py       | 233 +++++++++++------------------------------
 framework/tests/dmesg_tests.py |   4 -
 2 files changed, 59 insertions(+), 178 deletions(-)

diff --git a/framework/shader_test.py b/framework/shader_test.py
index 81fef09..ee0dd05 100644
--- a/framework/shader_test.py
+++ b/framework/shader_test.py
@@ -27,12 +27,69 @@ import os
 import os.path as path
 import re
 
-from .core import testBinDir, Group, Test, TestResult
+from .core import testBinDir, Group
 from .exectest import PlainExecTest
 
 
+__all__ = ['add_shader_test', 'add_shader_test_dir']
+
+
+def shader_test(arguments):
+    """ Parse a shader test file and return a PlainExecTest instance
+
+    This function parses a shader test to determine if it's a GL, GLES2 or
+    GLES3 test, and then returns a PlainExecTest setup properly.
+
+    """
+
+    # Compile a bunch of regexes that are used to find the configuration block
+    # in a shader_test
+    re_require_header = re.compile(r'\s*\[require\]')
+    re_end_require_block = re.compile(r'\s*\[')
+    re_gl = re.compile(r'\s*GL\s*(<|<=|=|>=|>)\s*(\d.\d)')
+    re_gles2 = re.compile(r'\s*GL ES\s*(<|<=|=|>=|>)\s*(2.\d)')
+    re_gles3 = re.compile(r'\s*GL ES\s*(<|<=|=|>=|>)\s*(3.\d)')
+
+    # Iterate over each line of the shader_test file, looking for the
+    # configuration block. When it's found, look for a GL version setting and
+    # apply that
+    with open(arguments, 'r') as shader_file:
+        config_block_found = False
+        gl_api = None
+
+        for line in shader_file:
+            # We need to find the first line of the configuration file, as soon
+            # as we do then we can move on to geting the configuration. The
+            # first line needs to be parsed by the next block.
+            if not config_block_found:
+                if re_require_header.match(line):
+                    config_block_found = True
+                continue
+
+            # Find the OpenGL API to use
+            if re_gles2.match(line):
+                gl_api = "GLES2"
+                break
+            elif re_gles3.match(line):
+                gl_api = "GLES3"
+                break
+            elif (re_gl.match(line) or re_end_require_block.match(line)):
+                # In the event that we reach the end of the config black and
+                # an API hasn't been found, it's an old test and uses "GL"
+                gl_api = "GL"
+                break
+
+    # Create the PlainExecTest instance, if no API was selected then gl_api
+    # will be none, which will except here.
+    get_gl = {"GL": path.join(testBinDir, 'shader_runner'),
+              "GLES2": path.join(testBinDir, 'shader_runner_gles2'),
+              "GLES3": path.join(testBinDir, 'shader_runner_gles3')}
+
+    return PlainExecTest([get_gl[gl_api], arguments, '-auto'])
+
+
 def add_shader_test(group, testname, filepath):
-    group[testname] = ShaderTest([filepath, '-auto'])
+    group[testname] = shader_test(filepath)
 
 
 def add_shader_test_dir(group, dirpath, recursive=False):
@@ -51,175 +108,3 @@ def add_shader_test_dir(group, dirpath, recursive=False):
                 continue
             testname = filename[0:-(len(ext) + 1)]  # +1 for '.'
             add_shader_test(group, testname, filepath)
-
-
-class ShaderTest(PlainExecTest):
-    API_ERROR = 0
-    API_GL = 1
-    API_GLES2 = 2
-    API_GLES3 = 3
-
-    __has_compiled_regexes = False
-    __re_require_header = None
-    __re_gl = None
-    __re_gles2 = None
-    __re_gles3 = None
-    __re_gl_unknown = None
-
-    @classmethod
-    def __compile_regexes(cls):
-        """Compile the regular expressions needed to parse shader tests.
-
-        Hundreds, maybe thousands, of ShaderTests may be instantiated.  This
-        function compiles the regular expressions only once, at class scope,
-        and uses them for all instances.
-
-        This function is idempotent."""
-
-        if cls.__has_compiled_regexes:
-            return
-
-        common = {
-            'cmp': r'(<|<=|=|>=|>)',
-            'gl_version': r'(\d.\d)',
-            'gles2_version': r'(2.\d\s)',
-            'gles3_version': r'(3.\d\s)',
-            'comment': r'(#.*)'
-        }
-
-        cls.__re_require_header = re.compile(r'^\s*\[require\]'
-                                             '\s*{comment}?$'.format(**common))
-        cls.__re_end_require_block = re.compile(r'^\s*\['.format(*common))
-        cls.__re_gl = re.compile(r'^\s*GL\s*{cmp}\s*{gl_version}\s*{comment}'
-                                 '?$'.format(**common))
-        cls.__re_gles2 = re.compile(r'^\s*GL ES\s*{cmp}\s*{gles2_version}'
-                                    '\s*{comment}?$'.format(**common))
-        cls.__re_gles3 = re.compile(r'^\s*GL ES\s*{cmp}\s*{gles3_version}'
-                                    '\s*{comment}?$'.format(**common))
-        cls.__re_gl_unknown = re.compile(r'^\s*GL\s*{cmp}'.format(**common))
-
-    def __init__(self, shader_runner_args):
-        Test.__init__(self, runConcurrent=True)
-
-        assert(isinstance(shader_runner_args, list))
-        assert(isinstance(shader_runner_args[0], str) or
-               isinstance(shader_runner_args[0], unicode))
-
-        self.__shader_runner_args = shader_runner_args
-        self.__test_filepath = shader_runner_args[0]
-        self.__result = None
-        self.__command = None
-        self.__gl_api = None
-
-        self.env = {}
-
-    def __report_failure(self, message):
-        assert(self.__result is None)
-        self.__result = TestResult()
-        self.__result["result"] = "fail"
-        self.__result["errors"] = [message]
-
-    def __parse_test_file(self):
-        self.__set_gl_api()
-
-    def __set_gl_api(self):
-        """Set self.__gl_api by parsing the test's requirement block.
-
-        This function is idempotent."""
-
-        if self.__gl_api is not None:
-            return
-
-        cls = self.__class__
-        cls.__compile_regexes()
-
-        PARSE_FIND_REQUIRE_HEADER = 0
-        PARSE_FIND_GL_REQUIREMENT = 1
-
-        parse_state = PARSE_FIND_REQUIRE_HEADER
-
-        try:
-            with open(self.__test_filepath) as f:
-                for line in f:
-                    if parse_state == PARSE_FIND_REQUIRE_HEADER:
-                        if cls.__re_require_header.match(line) is not None:
-                            parse_state = PARSE_FIND_GL_REQUIREMENT
-                        else:
-                            continue
-                    elif parse_state == PARSE_FIND_GL_REQUIREMENT:
-                        if cls.__re_gl.match(line) is not None:
-                            self.__gl_api = ShaderTest.API_GL
-                            return
-                        elif cls.__re_gles2.match(line) is not None:
-                            self.__gl_api = ShaderTest.API_GLES2
-                            return
-                        elif cls.__re_gles3.match(line) is not None:
-                            self.__gl_api = ShaderTest.API_GLES3
-                            return
-                        elif cls.__re_gl_unknown.match(line) is not None:
-                            self.__report_failure("Failed to parse GL "
-                                                  "requirement: " + line)
-                            self.__gl_api = ShaderTest.API_ERROR
-                            return
-                        elif cls.__re_end_require_block.match(line):
-                            # Default to GL if no API is given.
-                            self.__gl_api = ShaderTest.API_GL
-                            return
-                        else:
-                            continue
-                    else:
-                        assert(False)
-
-                if parse_state == PARSE_FIND_REQUIRE_HEADER or \
-                   parse_state == PARSE_FIND_GL_REQUIREMENT:
-                    # If no requirements are found, then assume the required
-                    # API is GL. This matches the behavior of the
-                    # shader_runner executable, whose default requirements are
-                    # GL >= 1.0 and GLSL >= 1.10.
-                    self.__gl_api = ShaderTest.API_GL
-                else:
-                    assert(False)
-
-        except IOError:
-            self.__report_failure("Failed to read test file "
-                                  "{0!r}".format(self.__test_filepath))
-            return
-
-    @property
-    def command(self):
-        if self.__command is not None:
-            return self.__command
-
-        self.__set_gl_api()
-
-        if self.__result is not None:
-            assert(self.__result["result"] == "fail")
-            return ["/bin/false"]
-
-        if self.__gl_api == ShaderTest.API_GL:
-            runner = "shader_runner"
-        elif self.__gl_api == ShaderTest.API_GLES2:
-            runner = "shader_runner_gles2"
-        elif self.__gl_api == ShaderTest.API_GLES3:
-            runner = "shader_runner_gles3"
-        else:
-            assert(False)
-
-        runner = os.path.join(testBinDir, runner)
-        self.__command = [runner] + self.__shader_runner_args
-        return self.__command
-
-    def run(self, env):
-        """ Parse the test file's [require] block to determine which
-        executable is needed to run the test. Then run the executable on the
-        test file."""
-
-        # Parse the test file to discover any errors.
-        self.__parse_test_file()
-
-        if self.__result is not None:
-            # We've already decided the test result, most likely because
-            # parsing the test file discovered an error.
-            return self.__result
-
-        return PlainExecTest.run(self, env)
diff --git a/framework/tests/dmesg_tests.py b/framework/tests/dmesg_tests.py
index 287cf74..b96c067 100644
--- a/framework/tests/dmesg_tests.py
+++ b/framework/tests/dmesg_tests.py
@@ -29,7 +29,6 @@ from framework.dmesg import DummyDmesg, LinuxDmesg, get_dmesg, DmesgError
 from framework.core import TestResult, PiglitJSONEncoder, Environment
 from framework.exectest import PlainExecTest
 from framework.gleantest import GleanTest
-from framework.shader_test import ShaderTest
 from framework.glsl_parser_test import GLSLParserTest
 
 
@@ -221,9 +220,6 @@ def test_testclasses_dmesg():
 
     lists = [(PlainExecTest, ['attribs', '-auto', '-fbo'], 'PlainExecTest'),
              (GleanTest, 'basic', "GleanTest"),
-             (ShaderTest,
-              ['tests/shaders/loopfunc.shader_test', '-auto', '-fbo'],
-              'ShaderTest'),
              (GLSLParserTest, 'tests/glslparsertest/shaders/main1.vert',
               'GLSLParserTest')]
 
-- 
1.8.5.4



More information about the Piglit mailing list