kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 1 | # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 | # |
| 3 | # Redistribution and use in source and binary forms, with or without |
| 4 | # modification, are permitted provided that the following conditions are |
| 5 | # met: |
| 6 | # |
| 7 | # * Redistributions of source code must retain the above copyright |
| 8 | # notice, this list of conditions and the following disclaimer. |
| 9 | # * Redistributions in binary form must reproduce the above |
| 10 | # copyright notice, this list of conditions and the following disclaimer |
| 11 | # in the documentation and/or other materials provided with the |
| 12 | # distribution. |
| 13 | # * Neither the name of Google Inc. nor the names of its |
| 14 | # contributors may be used to endorse or promote products derived from |
| 15 | # this software without specific prior written permission. |
| 16 | # |
| 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | |
| 29 | """generates webgl layout tests from the Khronos WebGL Conformance Tests""" |
| 30 | |
| 31 | # To use this, get a copy of the WebGL conformance tests then run this script |
| 32 | # eg. |
| 33 | # |
| 34 | # cd ~/temp |
| 35 | # git clone git://github.com/KhronosGroup/WebGL.git |
| 36 | # cd ~/WebKit/LayoutTests/webgl |
| 37 | # python generate-webgl-tests.py -w ~/temp/WebGL/sdk/tests -e |
| 38 | # |
| 39 | # Now check run the LayoutTests, update TestExpectations and check in the |
| 40 | # result. |
| 41 | |
| 42 | import copy |
| 43 | import os |
| 44 | import os.path |
| 45 | import sys |
| 46 | import re |
| 47 | import json |
| 48 | import shutil |
| 49 | from optparse import OptionParser |
| 50 | |
| 51 | if sys.version < '2.6': |
| 52 | print 'Wrong Python Version !!!: Need >= 2.6' |
| 53 | sys.exit(1) |
| 54 | |
| 55 | |
| 56 | GLOBAL_OPTIONS = { |
| 57 | # version use. Tests at or below this will be included. |
achristensen@apple.com | 4f81411 | 2018-06-13 00:27:15 +0000 | [diff] [blame] | 58 | "version": "2.0.0", |
kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 59 | |
| 60 | # version used for unlabled tests |
achristensen@apple.com | 4f81411 | 2018-06-13 00:27:15 +0000 | [diff] [blame] | 61 | "default-version": "2.0", |
kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 62 | |
| 63 | # If set, the version we require. Tests below this will be ignored. |
roger_fong@apple.com | 6d631f7 | 2014-12-04 02:32:40 +0000 | [diff] [blame] | 64 | "min-version": "1.0.3", |
kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | |
| 68 | def ReadFile(filename): |
| 69 | """Reads a file as a string""" |
| 70 | file = open(filename, "r") |
| 71 | data = file.read() |
| 72 | file.close() |
| 73 | return data |
| 74 | |
| 75 | |
| 76 | def WriteFile(filename, data): |
| 77 | """Writes a string as a file""" |
| 78 | print "Writing: ", filename |
| 79 | dirname = os.path.dirname(filename) |
| 80 | if not os.path.exists(dirname): |
| 81 | os.makedirs(dirname) |
| 82 | file = open(filename, "wb") |
| 83 | file.write(data) |
| 84 | file.close() |
| 85 | |
| 86 | |
| 87 | def CopyTree(src, dst, ignore=None): |
| 88 | """Recursively copy a directory tree""" |
| 89 | names = os.listdir(src) |
| 90 | if ignore is not None: |
| 91 | ignored_names = ignore(src, names) |
| 92 | else: |
| 93 | ignored_names = set() |
| 94 | |
| 95 | if not os.path.exists(dst): |
| 96 | os.makedirs(dst) |
| 97 | errors = [] |
| 98 | for name in names: |
| 99 | if name in ignored_names: |
| 100 | continue |
| 101 | srcname = os.path.join(src, name) |
| 102 | dstname = os.path.join(dst, name) |
| 103 | try: |
| 104 | if os.path.isdir(srcname): |
| 105 | CopyTree(srcname, dstname, ignore) |
| 106 | else: |
| 107 | # Will raise a SpecialFileError for unsupported file types |
| 108 | shutil.copyfile(srcname, dstname) |
| 109 | # catch the Error from the recursive copytree so that we can |
| 110 | # continue with other files |
| 111 | except Error, err: |
| 112 | errors.extend(err.args[0]) |
| 113 | except EnvironmentError, why: |
| 114 | errors.append((srcname, dstname, str(why))) |
| 115 | if errors: |
| 116 | raise Error, errors |
| 117 | |
| 118 | |
| 119 | def FileReader(filename): |
| 120 | """A File generator that returns only non empty, non comment lines""" |
| 121 | file = open(filename, "r") |
| 122 | lines = file.readlines() |
| 123 | file.close() |
| 124 | for line_number, line in enumerate(lines): |
| 125 | line = line.strip() |
| 126 | if (len(line) > 0 and |
| 127 | not line.startswith("#") and |
| 128 | not line.startswith(";") and |
| 129 | not line.startswith("//")): |
| 130 | yield line_number + 1, line |
| 131 | |
| 132 | |
| 133 | def GreaterThanOrEqualToVersion(have, want): |
| 134 | """Compares to version strings""" |
| 135 | have = have.split(" ")[0].split(".") |
| 136 | want = want.split(" ")[0].split(".") |
| 137 | for ndx, want_str in enumerate(want): |
| 138 | want_num = int(want_str) |
| 139 | have_num = 0 |
| 140 | if ndx < len(have): |
| 141 | have_num = int(have[ndx]) |
| 142 | if have_num < want_num: |
| 143 | return False |
achristensen@apple.com | 4f81411 | 2018-06-13 00:27:15 +0000 | [diff] [blame] | 144 | if have_num >= want_num: |
| 145 | return True |
kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 146 | return True |
| 147 | |
| 148 | |
| 149 | def GetTestList(list_filename, dest_dir, hierarchical_options): |
| 150 | global GLOBAL_OPTIONS |
| 151 | tests = [] |
| 152 | prefix = os.path.dirname(list_filename) |
| 153 | for line_number, line in FileReader(list_filename): |
| 154 | args = line.split() |
| 155 | test_options = {} |
| 156 | non_options = [] |
| 157 | use_test = True |
| 158 | while len(args): |
| 159 | arg = args.pop(0) |
| 160 | if arg.startswith("-"): |
| 161 | if not arg.startswith("--"): |
| 162 | raise "%s:%d bad option" % (list_filename, line_number) |
| 163 | option = arg[2:] |
| 164 | if option == 'slow': |
| 165 | pass |
roger_fong@apple.com | 6d631f7 | 2014-12-04 02:32:40 +0000 | [diff] [blame] | 166 | elif option == 'min-version' or option == "max-version": |
kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 167 | test_options[option] = args.pop(0) |
| 168 | else: |
roger_fong@apple.com | 6d631f7 | 2014-12-04 02:32:40 +0000 | [diff] [blame] | 169 | raise Exception("%s:%d unknown option '%s'" % (list_filename, line_number, arg)) |
kbr@google.com | a5e8b2b | 2013-02-22 21:20:57 +0000 | [diff] [blame] | 170 | else: |
| 171 | non_options.append(arg) |
| 172 | url = os.path.join(prefix, " ".join(non_options)) |
| 173 | |
| 174 | if not url.endswith(".txt"): |
| 175 | if "min-version" in test_options: |
| 176 | min_version = test_options["min-version"] |
| 177 | else: |
| 178 | min_version = hierarchical_options["default-version"] |
| 179 | |
| 180 | if "min-version" in GLOBAL_OPTIONS: |
| 181 | use_test = GreaterThanOrEqualToVersion(min_version, GLOBAL_OPTIONS["min-version"]) |
| 182 | else: |
| 183 | use_test = GreaterThanOrEqualToVersion(GLOBAL_OPTIONS["version"], min_version) |
| 184 | |
| 185 | if not use_test: |
| 186 | continue |
| 187 | |
| 188 | if url.endswith(".txt"): |
| 189 | if "min-version" in test_options: |
| 190 | hierarchical_options["default-version"] = test_options["min-version"] |
| 191 | tests = tests + GetTestList( |
| 192 | os.path.join(prefix, url), dest_dir, copy.copy(hierarchical_options)) |
| 193 | else: |
| 194 | tests.append({"url": url}) |
| 195 | return tests |
| 196 | |
| 197 | |
| 198 | def main(argv): |
| 199 | """This is the main function.""" |
| 200 | global GLOBAL_OPTIONS |
| 201 | |
| 202 | parser = OptionParser() |
| 203 | parser.add_option( |
| 204 | "-v", "--verbose", action="store_true", |
| 205 | help="prints more output.") |
| 206 | parser.add_option( |
| 207 | "-w", "--webgl-conformance-test", dest="source_dir", |
| 208 | help="path to webgl conformance tests. REQUIRED") |
| 209 | parser.add_option( |
| 210 | "-n", "--no-copy", action="store_true", |
| 211 | help="do not copy tests") |
| 212 | parser.add_option( |
| 213 | "-e", "--generate-expectations", action="store_true", |
| 214 | help="generatet the test expectations") |
| 215 | |
| 216 | (options, args) = parser.parse_args(args=argv) |
| 217 | |
| 218 | if not options.source_dir: |
| 219 | parser.print_help() |
| 220 | return 1 |
| 221 | |
| 222 | os.chdir(os.path.dirname(__file__) or '.') |
| 223 | |
| 224 | source_dir = options.source_dir; |
| 225 | webgl_tests_dir = "resources/webgl_test_files" |
| 226 | base_path = "." |
| 227 | |
| 228 | # copy all the files from the WebGL conformance tests. |
| 229 | if not options.no_copy: |
| 230 | CopyTree( |
| 231 | source_dir, webgl_tests_dir, shutil.ignore_patterns( |
| 232 | '.git', '*.pyc', 'tmp*')) |
| 233 | |
| 234 | test_template = ReadFile("resources/webgl-wrapper-template.html") |
| 235 | expectation_template = ReadFile("resources/webgl-expectation-template.txt") |
| 236 | |
| 237 | # generate wrappers for all the tests |
| 238 | tests = GetTestList(os.path.join(source_dir, "00_test_list.txt"), ".", |
| 239 | copy.copy(GLOBAL_OPTIONS)) |
| 240 | |
| 241 | for test in tests: |
| 242 | url = os.path.relpath(test["url"], source_dir) |
| 243 | dst = url |
| 244 | dst_dir = os.path.dirname(dst) |
| 245 | src = os.path.relpath(os.path.join(webgl_tests_dir, url), dst_dir).replace("\\", "/") |
| 246 | base_url = os.path.relpath(base_path, dst_dir).replace("\\", "/") |
| 247 | subs = { |
| 248 | "url": src, |
| 249 | "url_name": os.path.basename(url), |
| 250 | "base_url": base_url, |
| 251 | } |
| 252 | WriteFile(dst, test_template % subs) |
| 253 | if options.generate_expectations: |
| 254 | expectation_filename = os.path.splitext(dst)[0] + "-expected.txt" |
| 255 | WriteFile(expectation_filename, expectation_template % subs) |
| 256 | |
| 257 | |
| 258 | |
| 259 | if __name__ == '__main__': |
| 260 | sys.exit(main(sys.argv[1:])) |
| 261 | |
| 262 | |
| 263 | |
| 264 | |
| 265 | |