Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright 2014 the V8 project authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 import os | |
| 7 import re | |
| 8 import shutil | |
| 9 import sys | |
| 10 | |
| 11 # TODO(jkummerow): Support DATA_VIEW_{G,S}ETTER in runtime.cc | |
| 12 | |
| 13 FILENAME = "src/runtime.cc" | |
| 14 HEADERFILENAME = "src/runtime.h" | |
| 15 FUNCTION = re.compile("^RUNTIME_FUNCTION\(Runtime_(\w+)") | |
| 16 ARGSLENGTH = re.compile(".*ASSERT\(.*args\.length\(\) == (\d+)\);") | |
| 17 FUNCTIONEND = "}\n" | |
| 18 | |
| 19 WORKSPACE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "..")) | |
| 20 BASEPATH = os.path.join(WORKSPACE, "test", "mjsunit", "runtime-gen") | |
|
Michael Achenbach
2014/05/08 08:03:12
Wouldn't this fit better into the fuzz-natives tes
Jakob Kummerow
2014/05/08 09:45:38
Semantically yes, but the distinction between mjsu
| |
| 21 THIS_SCRIPT = os.path.relpath(sys.argv[0]) | |
| 22 | |
| 23 # Counts of functions in each detection state. These are used to assert | |
| 24 # that the parser doesn't bit-rot. Change the values as needed when you add, | |
| 25 # remove or change runtime functions, but make sure we don't lose our ability | |
| 26 # to parse them! | |
| 27 EXPECTED_FUNCTION_COUNT = 339 | |
| 28 EXPECTED_FUZZABLE_COUNT = 317 | |
| 29 EXPECTED_CCTEST_COUNT = 6 | |
| 30 EXPECTED_UNKNOWN_COUNT = 5 | |
| 31 | |
| 32 | |
| 33 # Don't call these at all. | |
| 34 BLACKLISTED = [ | |
| 35 "Abort", # Kills the process. | |
| 36 "AbortJS", # Kills the process. | |
| 37 "CompileForOnStackReplacement", # Riddled with ASSERTs. | |
| 38 "IS_VAR", # Not implemented in the runtime. | |
| 39 "ListNatives", # Not available in Release mode. | |
| 40 "SetAllocationTimeout", # Too slow for fuzzing. | |
| 41 "SystemBreak", # Kills (int3) the process. | |
| 42 | |
| 43 # These are weird. They violate some invariants when called after | |
| 44 # bootstrapping. | |
| 45 "DisableAccessChecks", | |
| 46 "EnableAccessChecks", | |
| 47 | |
| 48 # Seems to be incompatible with --stress-runs. | |
| 49 "LiveEditReplaceScript", | |
| 50 | |
| 51 # TODO(jkummerow): Fix these and un-blacklist them! | |
| 52 "CreateDateTimeFormat", | |
| 53 "CreateNumberFormat", | |
| 54 ] | |
| 55 | |
| 56 | |
| 57 # These will always throw. | |
| 58 THROWS = [ | |
| 59 "CheckExecutionState", # Needs to hit a break point. | |
| 60 "CheckIsBootstrapping", # Needs to be bootstrapping. | |
| 61 "DebugEvaluate", # Needs to hit a break point. | |
| 62 "DebugEvaluateGlobal", # Needs to hit a break point. | |
| 63 "DebugIndexedInterceptorElementValue", # Needs an indexed interceptor. | |
| 64 "DebugNamedInterceptorPropertyValue", # Needs a named interceptor. | |
| 65 "DebugSetScriptSource", # Checks compilation state of script. | |
| 66 "GetAllScopesDetails", # Needs to hit a break point. | |
| 67 "GetFrameCount", # Needs to hit a break point. | |
| 68 "GetFrameDetails", # Needs to hit a break point. | |
| 69 "GetRootNaN", # Needs to be bootstrapping. | |
| 70 "GetScopeCount", # Needs to hit a break point. | |
| 71 "GetScopeDetails", # Needs to hit a break point. | |
| 72 "GetStepInPositions", # Needs to hit a break point. | |
| 73 "GetTemplateField", # Needs a {Function,Object}TemplateInfo. | |
| 74 "GetThreadCount", # Needs to hit a break point. | |
| 75 "GetThreadDetails", # Needs to hit a break point. | |
| 76 "IsAccessAllowedForObserver", # Needs access-check-required object. | |
| 77 "LiveEditFunctionSourceUpdated", # Needs a SharedFunctionInfo. | |
| 78 "LiveEditPatchFunctionPositions", # Needs a SharedFunctionInfo. | |
| 79 "LiveEditReplaceFunctionCode", # Needs a SharedFunctionInfo. | |
| 80 "LiveEditReplaceRefToNestedFunction", # Needs a SharedFunctionInfo. | |
| 81 "LiveEditRestartFrame", # Needs to hit a break point. | |
| 82 "UnblockConcurrentRecompilation" # Needs --block-concurrent-recompilation. | |
| 83 ] | |
| 84 | |
| 85 | |
| 86 # Definitions used in CUSTOM_KNOWN_GOOD_INPUT below. | |
| 87 _BREAK_ITERATOR = ( | |
| 88 "%GetImplFromInitializedIntlObject(new Intl.v8BreakIterator())") | |
| 89 _COLLATOR = "%GetImplFromInitializedIntlObject(new Intl.Collator('en-US'))" | |
| 90 _DATETIME_FORMAT = ( | |
| 91 "%GetImplFromInitializedIntlObject(new Intl.DateTimeFormat('en-US'))") | |
| 92 _NUMBER_FORMAT = ( | |
| 93 "%GetImplFromInitializedIntlObject(new Intl.NumberFormat('en-US'))") | |
| 94 _SCRIPT = "%DebugGetLoadedScripts()[1]" | |
| 95 | |
| 96 | |
| 97 # Custom definitions for function input that does not throw. | |
| 98 # Format: "FunctionName": ["arg0", "arg1", ..., argslength]. | |
| 99 # None means "fall back to autodetected value". | |
| 100 CUSTOM_KNOWN_GOOD_INPUT = { | |
| 101 "Apply": ["function() {}", None, None, None, None, None], | |
| 102 "ArrayBufferSliceImpl": [None, None, 0, None], | |
| 103 "ArrayConcat": ["[1, 'a']", None], | |
| 104 "BreakIteratorAdoptText": [_BREAK_ITERATOR, None, None], | |
| 105 "BreakIteratorBreakType": [_BREAK_ITERATOR, None], | |
| 106 "BreakIteratorCurrent": [_BREAK_ITERATOR, None], | |
| 107 "BreakIteratorFirst": [_BREAK_ITERATOR, None], | |
| 108 "BreakIteratorNext": [_BREAK_ITERATOR, None], | |
| 109 "CompileString": [None, "false", None], | |
| 110 "CreateBreakIterator": ["'en-US'", "{type: 'string'}", None, None], | |
| 111 "CreateJSFunctionProxy": [None, "function() {}", None, None, None], | |
| 112 "CreatePrivateSymbol": ["\"foo\"", None], | |
| 113 "CreateSymbol": ["\"foo\"", None], | |
| 114 "DateParseString": [None, "new Array(8)", None], | |
| 115 "DebugSetScriptSource": [_SCRIPT, None, None], | |
| 116 "DefineOrRedefineAccessorProperty": [None, None, "function() {}", | |
| 117 "function() {}", 2, None], | |
| 118 "GetBreakLocations": [None, 0, None], | |
| 119 "GetDefaultReceiver": ["function() {}", None], | |
| 120 "GetImplFromInitializedIntlObject": ["new Intl.NumberFormat('en-US')", None], | |
| 121 "InternalCompare": [_COLLATOR, None, None, None], | |
| 122 "InternalDateFormat": [_DATETIME_FORMAT, None, None], | |
| 123 "InternalDateParse": [_DATETIME_FORMAT, None, None], | |
| 124 "InternalNumberFormat": [_NUMBER_FORMAT, None, None], | |
| 125 "InternalNumberParse": [_NUMBER_FORMAT, None, None], | |
| 126 "IsSloppyModeFunction": ["function() {}", None], | |
| 127 "LiveEditFindSharedFunctionInfosForScript": [_SCRIPT, None], | |
| 128 "LiveEditGatherCompileInfo": [_SCRIPT, None, None], | |
| 129 "LoadMutableDouble": ["{foo: 1.2}", None, None], | |
| 130 "NewObjectFromBound": ["(function() {}).bind({})", None], | |
| 131 "NumberToRadixString": [None, "2", None], | |
| 132 "ParseJson": ["\"{}\"", 1], | |
| 133 "SetAccessorProperty": [None, None, "undefined", "undefined", None, None, | |
| 134 None], | |
| 135 "SetCreateIterator": [None, "2", None], | |
| 136 "SetDebugEventListener": ["undefined", None, None], | |
| 137 "SetScriptBreakPoint": [_SCRIPT, None, 0, None, None], | |
| 138 "StringBuilderConcat": ["[1, 2, 3]", 3, None, None], | |
| 139 "StringBuilderJoin": ["['a', 'b']", 4, None, None], | |
| 140 "StringMatch": [None, None, "['a', 'b']", None], | |
| 141 "StringNormalize": [None, 2, None], | |
| 142 "TypedArrayInitialize": [None, None, "new ArrayBuffer(8)", None, None, None], | |
| 143 "TypedArraySetFastCases": [None, None, "0", None], | |
| 144 } | |
| 145 | |
| 146 | |
| 147 # Types of arguments that cannot be generated in a JavaScript testcase. | |
| 148 NON_JS_TYPES = [ | |
| 149 "Code", "Context", "FixedArray", "FunctionTemplateInfo", | |
| 150 "JSFunctionResultCache", "JSMessageObject", "Map", "ScopeInfo", | |
| 151 "SharedFunctionInfo"] | |
| 152 | |
| 153 | |
| 154 # Maps argument types to concrete example inputs of that type. | |
| 155 JS_TYPE_GENERATORS = { | |
| 156 "Boolean": "true", | |
| 157 "HeapObject": "new Object()", | |
| 158 "Int32": "32", | |
| 159 "JSArray": "new Array()", | |
| 160 "JSArrayBuffer": "new ArrayBuffer(8)", | |
| 161 "JSDataView": "new DataView(new ArrayBuffer(8))", | |
| 162 "JSDate": "new Date()", | |
| 163 "JSFunction": "function() {}", | |
| 164 "JSFunctionProxy": "Proxy.createFunction({}, function() {})", | |
| 165 "JSGeneratorObject": "(function*(){ yield 1; })()", | |
| 166 "JSMap": "new Map()", | |
| 167 "JSMapIterator": "%MapCreateIterator(new Map(), 3)", | |
| 168 "JSObject": "new Object()", | |
| 169 "JSProxy": "Proxy.create({})", | |
| 170 "JSReceiver": "new Object()", | |
| 171 "JSRegExp": "/ab/g", | |
| 172 "JSSet": "new Set()", | |
| 173 "JSSetIterator": "%SetCreateIterator(new Set(), 2)", | |
| 174 "JSTypedArray": "new Int32Array(2)", | |
| 175 "JSValue": "new String('foo')", | |
| 176 "JSWeakCollection": "new WeakMap()", | |
| 177 "Name": "\"name\"", | |
| 178 "Number": "1.5", | |
| 179 "Object": "new Object()", | |
| 180 "PropertyDetails": "513", | |
| 181 "SeqString": "\"seqstring\"", | |
| 182 "Smi": 1, | |
| 183 "StrictMode": "1", | |
| 184 "String": "\"foo\"", | |
| 185 "Symbol": "Symbol(\"symbol\")", | |
| 186 "Uint32": "32", | |
| 187 } | |
| 188 | |
| 189 | |
| 190 class ArgParser(object): | |
| 191 def __init__(self, regex, ctor): | |
| 192 self.regex = regex | |
| 193 self.ArgCtor = ctor | |
|
Michael Achenbach
2014/05/08 08:03:12
nit: lower case?
Jakob Kummerow
2014/05/08 09:45:38
Chose upper case since this isn't just a field, it
| |
| 194 | |
| 195 | |
| 196 class Arg(object): | |
| 197 def __init__(self, typename, varname, index): | |
| 198 self.type = typename | |
| 199 self.name = "_%s" % varname | |
| 200 self.index = index | |
| 201 | |
| 202 | |
| 203 class Function(object): | |
| 204 def __init__(self, match): | |
| 205 self.name = match.group(1) | |
| 206 self.argslength = -1 | |
| 207 self.args = {} | |
| 208 self.inline = "" | |
| 209 | |
| 210 handle_arg_parser = ArgParser( | |
| 211 re.compile("^\s*CONVERT_ARG_HANDLE_CHECKED\((\w+), (\w+), (\d+)\)"), | |
| 212 lambda match: Arg(match.group(1), match.group(2), int(match.group(3)))) | |
| 213 | |
| 214 plain_arg_parser = ArgParser( | |
| 215 re.compile("^\s*CONVERT_ARG_CHECKED\((\w+), (\w+), (\d+)\)"), | |
| 216 lambda match: Arg(match.group(1), match.group(2), int(match.group(3)))) | |
| 217 | |
| 218 number_handle_arg_parser = ArgParser( | |
| 219 re.compile("^\s*CONVERT_NUMBER_ARG_HANDLE_CHECKED\((\w+), (\d+)\)"), | |
| 220 lambda match: Arg("Number", match.group(1), int(match.group(2)))) | |
| 221 | |
| 222 smi_arg_parser = ArgParser( | |
| 223 re.compile("^\s*CONVERT_SMI_ARG_CHECKED\((\w+), (\d+)\)"), | |
| 224 lambda match: Arg("Smi", match.group(1), int(match.group(2)))) | |
| 225 | |
| 226 double_arg_parser = ArgParser( | |
| 227 re.compile("^\s*CONVERT_DOUBLE_ARG_CHECKED\((\w+), (\d+)\)"), | |
| 228 lambda match: Arg("Number", match.group(1), int(match.group(2)))) | |
| 229 | |
| 230 number_arg_parser = ArgParser( | |
| 231 re.compile( | |
| 232 "^\s*CONVERT_NUMBER_CHECKED\(\w+, (\w+), (\w+), args\[(\d+)\]\)"), | |
| 233 lambda match: Arg(match.group(2), match.group(1), int(match.group(3)))) | |
| 234 | |
| 235 strict_mode_arg_parser = ArgParser( | |
| 236 re.compile("^\s*CONVERT_STRICT_MODE_ARG_CHECKED\((\w+), (\d+)\)"), | |
| 237 lambda match: Arg("StrictMode", match.group(1), int(match.group(2)))) | |
| 238 | |
| 239 boolean_arg_parser = ArgParser( | |
| 240 re.compile("^\s*CONVERT_BOOLEAN_ARG_CHECKED\((\w+), (\d+)\)"), | |
| 241 lambda match: Arg("Boolean", match.group(1), int(match.group(2)))) | |
| 242 | |
| 243 property_details_parser = ArgParser( | |
| 244 re.compile("^\s*CONVERT_PROPERTY_DETAILS_CHECKED\((\w+), (\d+)\)"), | |
| 245 lambda match: Arg("PropertyDetails", match.group(1), int(match.group(2)))) | |
| 246 | |
| 247 arg_parsers = [handle_arg_parser, plain_arg_parser, number_handle_arg_parser, | |
| 248 smi_arg_parser, | |
| 249 double_arg_parser, number_arg_parser, strict_mode_arg_parser, | |
| 250 boolean_arg_parser, property_details_parser] | |
| 251 | |
| 252 | |
| 253 def SetArgsLength(self, match): | |
| 254 self.argslength = int(match.group(1)) | |
| 255 | |
| 256 def TryParseArg(self, line): | |
| 257 for parser in Function.arg_parsers: | |
| 258 match = parser.regex.match(line) | |
| 259 if match: | |
| 260 arg = parser.ArgCtor(match) | |
| 261 self.args[arg.index] = arg | |
| 262 return True | |
| 263 return False | |
| 264 | |
| 265 def Filename(self): | |
| 266 return "%s.js" % self.name.lower() | |
| 267 | |
| 268 def __str__(self): | |
| 269 s = [self.name, "("] | |
| 270 argcount = self.argslength | |
| 271 if argcount < 0: | |
| 272 print("WARNING: unknown argslength for function %s" % self.name) | |
| 273 if self.args: | |
| 274 argcount = max([self.args[i].index + 1 for i in self.args]) | |
| 275 else: | |
| 276 argcount = 0 | |
| 277 for i in range(argcount): | |
| 278 if i > 0: s.append(", ") | |
| 279 s.append(self.args[i].type if i in self.args else "<unknown>") | |
| 280 s.append(")") | |
| 281 return "".join(s) | |
| 282 | |
| 283 # Parses HEADERFILENAME to find out which runtime functions are "inline". | |
| 284 def FindInlineRuntimeFunctions(): | |
| 285 inline_functions = [] | |
| 286 with open(HEADERFILENAME, "r") as f: | |
| 287 inline_list = "#define INLINE_FUNCTION_LIST(F) \\\n" | |
| 288 inline_opt_list = "#define INLINE_OPTIMIZED_FUNCTION_LIST(F) \\\n" | |
| 289 inline_function = re.compile(r"^\s*F\((\w+), \d+, \d+\)\s*\\?") | |
| 290 mode = "SEARCHING" | |
| 291 for line in f: | |
| 292 if mode == "ACTIVE": | |
| 293 match = inline_function.match(line) | |
| 294 if match: | |
| 295 inline_functions.append(match.group(1)) | |
| 296 if not line.endswith("\\\n"): | |
| 297 mode = "SEARCHING" | |
| 298 elif mode == "SEARCHING": | |
| 299 if line == inline_list or line == inline_opt_list: | |
| 300 mode = "ACTIVE" | |
| 301 return inline_functions | |
| 302 | |
| 303 | |
| 304 # Detects runtime functions by parsing FILENAME. | |
| 305 def FindRuntimeFunctions(): | |
| 306 inline_functions = FindInlineRuntimeFunctions() | |
| 307 functions = [] | |
| 308 with open(FILENAME, "r") as f: | |
| 309 function = None | |
| 310 partial_line = "" | |
| 311 for line in f: | |
| 312 # Multi-line definition support, ignoring macros. | |
| 313 if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"): | |
| 314 if line.endswith("\\\n"): continue | |
| 315 partial_line = line.rstrip() | |
| 316 continue | |
| 317 if partial_line: | |
| 318 partial_line += " " + line.strip() | |
| 319 if partial_line.endswith("{"): | |
| 320 line = partial_line | |
| 321 partial_line = "" | |
| 322 else: | |
| 323 continue | |
| 324 | |
| 325 match = FUNCTION.match(line) | |
| 326 if match: | |
| 327 function = Function(match) | |
| 328 if function.name in inline_functions: | |
| 329 function.inline = "_" | |
| 330 continue | |
| 331 if function is None: continue | |
| 332 | |
| 333 match = ARGSLENGTH.match(line) | |
| 334 if match: | |
| 335 function.SetArgsLength(match) | |
| 336 continue | |
| 337 | |
| 338 if function.TryParseArg(line): | |
| 339 continue | |
| 340 | |
| 341 if line == FUNCTIONEND: | |
| 342 if function is not None: | |
| 343 functions.append(function) | |
| 344 function = None | |
| 345 return functions | |
| 346 | |
| 347 # Classifies runtime functions. | |
| 348 def ClassifyFunctions(functions): | |
| 349 # Can be fuzzed with a JavaScript testcase. | |
| 350 js_fuzzable_functions = [] | |
| 351 # We have enough information to fuzz these, but they need inputs that | |
| 352 # cannot be created or passed around in JavaScript. | |
| 353 cctest_fuzzable_functions = [] | |
| 354 # This script does not have enough information about these. | |
| 355 unknown_functions = [] | |
| 356 | |
| 357 types = {} | |
| 358 for f in functions: | |
| 359 if f.name in BLACKLISTED: | |
| 360 continue | |
| 361 decision = js_fuzzable_functions | |
| 362 custom = CUSTOM_KNOWN_GOOD_INPUT.get(f.name, None) | |
| 363 if f.argslength < 0: | |
| 364 # Unknown length -> give up unless there's a custom definition. | |
| 365 if custom and custom[-1] is not None: | |
| 366 f.argslength = custom[-1] | |
| 367 assert len(custom) == f.argslength + 1, \ | |
| 368 ("%s: last custom definition must be argslength" % f.name) | |
| 369 else: | |
| 370 decision = unknown_functions | |
| 371 else: | |
| 372 if custom: | |
| 373 # Any custom definitions must match the known argslength. | |
| 374 assert len(custom) == f.argslength + 1, \ | |
| 375 ("%s should have %d custom definitions but has %d" % | |
| 376 (f.name, f.argslength + 1, len(custom))) | |
| 377 for i in range(f.argslength): | |
| 378 if custom and custom[i] is not None: | |
| 379 # All good, there's a custom definition. | |
| 380 pass | |
| 381 elif not i in f.args: | |
| 382 # No custom definition and no parse result -> give up. | |
| 383 decision = unknown_functions | |
| 384 else: | |
| 385 t = f.args[i].type | |
| 386 if t in NON_JS_TYPES: | |
| 387 decision = cctest_fuzzable_functions | |
| 388 else: | |
| 389 assert t in JS_TYPE_GENERATORS, \ | |
| 390 ("type generator not found for %s, function: %s" % (t, f)) | |
| 391 decision.append(f) | |
| 392 return (js_fuzzable_functions, cctest_fuzzable_functions, unknown_functions) | |
| 393 | |
| 394 | |
| 395 def GenerateJSTestcaseForFunction(f): | |
| 396 s = ["// Copyright 2014 the V8 project authors. All rights reserved.", | |
| 397 "// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY", | |
| 398 "// Flags: --allow-natives-syntax --harmony"] | |
| 399 call = "%%%s%s(" % (f.inline, f.name) | |
| 400 custom = CUSTOM_KNOWN_GOOD_INPUT.get(f.name, None) | |
| 401 for i in range(f.argslength): | |
| 402 if custom and custom[i] is not None: | |
| 403 (name, value) = ("arg%d" % i, custom[i]) | |
| 404 else: | |
| 405 arg = f.args[i] | |
| 406 (name, value) = (arg.name, JS_TYPE_GENERATORS[arg.type]) | |
| 407 s.append("var %s = %s;" % (name, value)) | |
| 408 if i > 0: call += ", " | |
|
Michael Achenbach
2014/05/08 08:03:12
how about collecting the names in a list and then
Jakob Kummerow
2014/05/08 09:45:38
I've already refactored this in a follow-up CL tha
| |
| 409 call += name | |
| 410 call += ");" | |
| 411 if f.name in THROWS: | |
| 412 s.append("try {") | |
| 413 s.append(call); | |
| 414 s.append("} catch(e) {}") | |
| 415 else: | |
| 416 s.append(call) | |
| 417 testcase = "\n".join(s) | |
| 418 path = os.path.join(BASEPATH, f.Filename()) | |
| 419 with open(path, "w") as f: | |
| 420 f.write("%s\n" % testcase) | |
| 421 | |
| 422 def GenerateTestcases(functions): | |
| 423 shutil.rmtree(BASEPATH) # Re-generate everything. | |
| 424 os.makedirs(BASEPATH) | |
| 425 for f in functions: | |
| 426 GenerateJSTestcaseForFunction(f) | |
| 427 | |
| 428 def PrintUsage(): | |
| 429 print """Usage: %(this_script)s ACTION | |
| 430 | |
| 431 where ACTION can be: | |
| 432 | |
| 433 info Print diagnostic info. | |
| 434 check Check that runtime functions can be parsed as expected, and that | |
| 435 test cases exist. | |
| 436 generate Parse source code for runtime functions, and auto-generate | |
| 437 test cases for them. Warning: this will nuke and re-create | |
| 438 %(path)s. | |
| 439 """ % {"path": os.path.relpath(BASEPATH), "this_script": THIS_SCRIPT} | |
| 440 | |
| 441 if __name__ == "__main__": | |
| 442 if len(sys.argv) != 2: | |
| 443 PrintUsage() | |
| 444 sys.exit(1) | |
| 445 action = sys.argv[1] | |
| 446 if action in ["-h", "--help", "help"]: | |
| 447 PrintUsage() | |
| 448 sys.exit(0) | |
| 449 | |
| 450 functions = FindRuntimeFunctions() | |
|
Michael Achenbach
2014/05/08 08:03:12
Would it be useful if it found also functions defi
Jakob Kummerow
2014/05/08 09:45:38
Potentially. This is just a first step. There is p
| |
| 451 (js_fuzzable_functions, cctest_fuzzable_functions, unknown_functions) = \ | |
| 452 ClassifyFunctions(functions) | |
| 453 | |
| 454 if action == "info": | |
| 455 print("%d functions total; js_fuzzable_functions: %d, " | |
| 456 "cctest_fuzzable_functions: %d, unknown_functions: %d" | |
| 457 % (len(functions), len(js_fuzzable_functions), | |
| 458 len(cctest_fuzzable_functions), len(unknown_functions))) | |
| 459 print("unknown functions:") | |
| 460 for f in unknown_functions: | |
| 461 print(f) | |
| 462 sys.exit(0) | |
| 463 | |
| 464 if action == "check": | |
| 465 error = False | |
| 466 def CheckCount(actual, expected, description): | |
| 467 global error | |
| 468 if len(actual) != expected: | |
| 469 print("Expected to detect %d %s, but found %d." % ( | |
| 470 expected, description, len(actual))) | |
| 471 error = True | |
| 472 CheckCount(functions, EXPECTED_FUNCTION_COUNT, "functions in total") | |
| 473 CheckCount(js_fuzzable_functions, EXPECTED_FUZZABLE_COUNT, | |
| 474 "JavaScript-fuzzable functions") | |
| 475 CheckCount(cctest_fuzzable_functions, EXPECTED_CCTEST_COUNT, | |
| 476 "cctest-fuzzable functions") | |
| 477 CheckCount(unknown_functions, EXPECTED_UNKNOWN_COUNT, | |
| 478 "functions with incomplete type information") | |
| 479 | |
| 480 def CheckTestcasesExisting(functions): | |
| 481 global error | |
| 482 for f in functions: | |
| 483 if not os.path.isfile(os.path.join(BASEPATH, f.Filename())): | |
| 484 print("Missing testcase for %s, please run '%s generate'" % | |
| 485 (f.name, THIS_SCRIPT)) | |
| 486 error = True | |
| 487 files = os.listdir(BASEPATH) | |
|
Michael Achenbach
2014/05/08 08:03:12
Wonder if there appears a .svn folder on the bots
Jakob Kummerow
2014/05/08 09:45:38
Good point. Let's filter out dotfiles.
| |
| 488 if (len(files) != len(functions)): | |
| 489 unexpected_files = set(files) - set([f.Filename() for f in functions]) | |
| 490 for f in unexpected_files: | |
| 491 print("Unexpected testcase: %s" % os.path.join(BASEPATH, f)) | |
| 492 error = True | |
| 493 CheckTestcasesExisting(js_fuzzable_functions) | |
| 494 | |
| 495 if error: | |
| 496 sys.exit(1) | |
| 497 print("All good.") | |
| 498 sys.exit(0) | |
| 499 | |
| 500 if action == "generate": | |
| 501 GenerateTestcases(js_fuzzable_functions) | |
| 502 sys.exit(0) | |
| OLD | NEW |