Home | History | Annotate | Download | only in tools
      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 json
      7 import optparse
      8 import os
      9 import random
     10 import shutil
     11 import subprocess
     12 import sys
     13 
     14 
     15 BLACKLIST = [
     16   # Skip special d8 functions.
     17   "load", "os", "print", "read", "readline", "quit"
     18 ]
     19 
     20 
     21 def GetRandomObject():
     22   return random.choice([
     23     "0", "1", "2.5", "0x1000", "\"string\"", "{foo: \"bar\"}", "[1, 2, 3]",
     24     "function() { return 0; }"
     25   ])
     26 
     27 
     28 g_var_index = 0
     29 
     30 
     31 def GetVars(result, num, first = []):
     32   global g_var_index
     33   variables = []
     34   for i in range(num):
     35     variables.append("__v_%d" % g_var_index)
     36     g_var_index += 1
     37   for var in variables:
     38     result.append("var %s = %s;" % (var, GetRandomObject()))
     39   return ", ".join(first + variables)
     40 
     41 
     42 # Wraps |string| in try..catch.
     43 def TryCatch(result, string, exception_behavior = ""):
     44   result.append("try { %s } catch(e) { %s }" % (string, exception_behavior))
     45 
     46 
     47 def BuildTests(function, full_name, options):
     48   assert function["type"] == "function"
     49   global g_var_index
     50   g_var_index = 0
     51   result = ["// AUTO-GENERATED BY tools/generate-builtins-tests.py.\n"]
     52   result.append("// Function call test:")
     53   length = function["length"]
     54   TryCatch(result, "%s(%s);" % (full_name, GetVars(result, length)))
     55 
     56   if "prototype" in function:
     57     proto = function["prototype"]
     58     result.append("\n// Constructor test:")
     59     TryCatch(result,
     60              "var recv = new %s(%s);" % (full_name, GetVars(result, length)),
     61              "var recv = new Object();")
     62 
     63     getters = []
     64     methods = []
     65     for prop in proto:
     66       proto_property = proto[prop]
     67       proto_property_type = proto_property["type"]
     68       if proto_property_type == "getter":
     69         getters.append(proto_property)
     70         result.append("recv.__defineGetter__(\"%s\", "
     71                       "function() { return %s; });" %
     72                       (proto_property["name"], GetVars(result, 1)))
     73       if proto_property_type == "number":
     74         result.append("recv.__defineGetter__(\"%s\", "
     75                       "function() { return %s; });" %
     76                       (proto_property["name"], GetVars(result, 1)))
     77       if proto_property_type == "function":
     78         methods.append(proto_property)
     79     if getters:
     80       result.append("\n// Getter tests:")
     81       for getter in getters:
     82         result.append("print(recv.%s);" % getter["name"])
     83     if methods:
     84       result.append("\n// Method tests:")
     85       for method in methods:
     86         args = GetVars(result, method["length"], ["recv"])
     87         call = "%s.prototype.%s.call(%s)" % (full_name, method["name"], args)
     88         TryCatch(result, call)
     89 
     90   filename = os.path.join(options.outdir, "%s.js" % (full_name))
     91   with open(filename, "w") as f:
     92     f.write("\n".join(result))
     93     f.write("\n")
     94 
     95 
     96 def VisitObject(obj, path, options):
     97   obj_type = obj["type"]
     98   obj_name = "%s%s" % (path, obj["name"])
     99   if obj_type == "function":
    100     BuildTests(obj, obj_name, options)
    101   if "properties" in obj:
    102     for prop_name in obj["properties"]:
    103       prop = obj["properties"][prop_name]
    104       VisitObject(prop, "%s." % (obj_name), options)
    105 
    106 
    107 def ClearGeneratedFiles(options):
    108   if os.path.exists(options.outdir):
    109     shutil.rmtree(options.outdir)
    110 
    111 
    112 def GenerateTests(options):
    113   ClearGeneratedFiles(options)  # Re-generate everything.
    114   output = subprocess.check_output(
    115       "%s %s" % (options.d8, options.script), shell=True).strip()
    116   objects = json.loads(output)
    117 
    118   os.makedirs(options.outdir)
    119   for obj_name in objects:
    120     if obj_name in BLACKLIST: continue
    121     obj = objects[obj_name]
    122     VisitObject(obj, "", options)
    123 
    124 
    125 def BuildOptions():
    126   result = optparse.OptionParser()
    127   result.add_option("--d8", help="d8 binary to use",
    128                     default="out/ia32.release/d8")
    129   result.add_option("--outdir", help="directory where to place generated tests",
    130                     default="test/mjsunit/builtins-gen")
    131   result.add_option("--script", help="builtins detector script to run in d8",
    132                     default="tools/detect-builtins.js")
    133   return result
    134 
    135 
    136 def Main():
    137   parser = BuildOptions()
    138   (options, args) = parser.parse_args()
    139   if len(args) != 1 or args[0] == "help":
    140     parser.print_help()
    141     return 1
    142   action = args[0]
    143 
    144   if action == "generate":
    145     GenerateTests(options)
    146     return 0
    147 
    148   if action == "clear":
    149     ClearGeneratedFiles(options)
    150     return 0
    151 
    152   print("Unknown action: %s" % action)
    153   parser.print_help()
    154   return 1
    155 
    156 
    157 if __name__ == "__main__":
    158   sys.exit(Main())
    159