2929r = None
3030
3131
32- TEST_EXCLUSIONS = [
33- # python only tests
34- # 'regression/1133',
35- # 'regression/767',
36- # 'regression/1005',
37- 'regression/' ,
38- 'limits' , # pending fix in issue #4965
39- # double run
40- 'changefeeds/squash' ,
41- 'arity' ,
42- '.rb.yaml' ,
43- ]
32+ # Individual tests can be ignored by specifying their line numbers from the YAML source files.
33+ TEST_EXCLUSIONS = {
34+ 'regression/' : None ,
35+
36+ 'limits.yaml' : [
37+ 36 , # Produces invalid Go code using `list` and `range`
38+ 39 , 41 , 47 , # Rely on above
39+ 75 , 87 , 108 , 120 , # The fetch() calls hang
40+ ],
41+
42+ 'changefeeds/squash' : [
43+ 47 , # double run
44+ ],
45+
46+ 'arity' : [
47+ 51 , 100 , 155 , 272 , 282 , 291 , # Malformed syntax produces malformed Go
48+ ],
49+
50+ 'sindex/truncation.rb.yaml' : None , # The code generator fails when it encounters (0...n).map{}
51+
52+ 'changefeeds/geo.rb.yaml' : None , # The generated code needs to enclose the map keys inside quotation marks
53+
54+ 'aggregation.yaml' : [
55+ 482 , # A nil map key is expected, but Go strings cannot be nil, so actual result is ""
56+ ],
57+
58+ # This file expects a password-less user `test_user` to exist, but even if it does,
59+ # - Lines #18 and #27 try to create a database and fail if it already exists, but the YAML doesn't drop the database
60+ # afterwards, so successive runs always fail. Unfortunately, other test cases depend on these lines being run.
61+ # - Lines #49, #54, #60, and #66 use a global run option `user` which Rethink doesn't recognize.
62+ 'meta/grant.yaml' : None ,
63+
64+ # The lambdas passed to SetWriteHook() must return rethinkdb.Term but the generated code uses interface{} instead.
65+ # These types of queries might be covered by reql_writehook_test.go though.
66+ 'mutation/write_hook.yaml' : None ,
67+
68+ 'changefeeds/idxcopy.yaml' : [
69+ 28 , # The fetch() hangs.
70+ ],
71+
72+ 'changefeeds/now.py_one.yaml' : [
73+ 5 , # Hangs instead of returning an error.
74+ ],
75+
76+ 'times/constructors.yaml' : [
77+ 59 , 61 , # Tries to create year 10000 but Rethink now only allows up to 9999.
78+ 64 , 70 , # The expected error message refers to 10000 but Rethink's error actually says 9999.
79+ ],
80+
81+ 'math_logic/logic.yaml' : [
82+ 143 , 147 , # Expected an error but got nil. Don't know if it's a real problem.
83+ ],
84+
85+ 'control.yaml' : [
86+ # Attempts to add 1 to a integer variable that was set to tbl.Count(). The Go '+' operator must be used instead of the ReQL '.Add()'.
87+ # Deciding which operator to use requires the variable type, which in turn requires knowing what type each ReQL function returns.
88+ # The robust solution is too much work, and checking for '.Count()' in the definition is a hack.
89+ 236 ,
90+ ],
91+
92+ 'meta/dbs.yaml' : [
93+ # For some reason the results include databases created by other tests (eg. 'examples', 'test_cur_all')
94+ 6 , 18 , 31 , 37 ,
95+ ],
96+
97+ # For some reason the results include databases created by other tests (eg. 'examples', 'test_cur_all')
98+ 'meta/composite.py.yaml' : None ,
99+ }
44100
45101GO_KEYWORDS = [
46102 'break' , 'case' , 'chan' , 'const' , 'continue' , 'default' , 'defer' , 'else' ,
51107
52108def main ():
53109 logging .basicConfig (format = "[%(name)s] %(message)s" , level = logging .INFO )
54- start = time .clock ()
110+ start = time .perf_counter ()
55111 args = parse_args ()
56112 if args .debug :
57113 logger .setLevel (logging .DEBUG )
@@ -71,17 +127,25 @@ def main():
71127 __file__ ,
72128 process_polyglot .__file__ ,
73129 ])
130+ full_exclusions = list (file for (file , lines ) in TEST_EXCLUSIONS .items () if not lines )
74131 for testfile in process_polyglot .all_yaml_tests (
75132 args .test_dir ,
76- TEST_EXCLUSIONS ):
133+ full_exclusions ):
77134 logger .info ("Working on %s" , testfile )
135+
136+ excluded_lines = set ()
137+ for exclusion , lines in TEST_EXCLUSIONS .items ():
138+ if exclusion in testfile :
139+ excluded_lines .update (lines )
140+
78141 TestFile (
79142 test_dir = args .test_dir ,
80143 filename = testfile ,
144+ excluded_lines = excluded_lines ,
81145 test_output_dir = args .test_output_dir ,
82146 renderer = renderer ,
83147 ).load ().render ()
84- logger .info ("Finished in %s seconds" , time .clock () - start )
148+ logger .info ("Finished in %s seconds" , time .perf_counter () - start )
85149
86150
87151def parse_args ():
@@ -129,7 +193,7 @@ def import_python_driver(py_driver_dir):
129193 '''Imports the test driver header'''
130194 stashed_path = sys .path
131195 sys .path .insert (0 , os .path .realpath (py_driver_dir ))
132- import rethinkdb as r
196+ from rethinkdb import r
133197 sys .path = stashed_path
134198 return r
135199
@@ -174,9 +238,10 @@ def evaluate_snippet(snippet):
174238class TestFile (object ):
175239 '''Represents a single test file'''
176240
177- def __init__ (self , test_dir , filename , test_output_dir , renderer ):
241+ def __init__ (self , test_dir , filename , excluded_lines , test_output_dir , renderer ):
178242 self .filename = filename
179243 self .full_path = os .path .join (test_dir , filename )
244+ self .excluded_lines = excluded_lines
180245 self .module_name = filename .split ('.' )[0 ].replace ('/' , '_' )
181246 self .test_output_dir = test_output_dir
182247 self .reql_vars = {'r' }
@@ -208,7 +273,7 @@ def get_varnames(self, yaml_file):
208273
209274 def render (self ):
210275 '''Renders the converted tests to a runnable test file'''
211- defs_and_test = ast_to_go (self .test_generator , self .reql_vars )
276+ defs_and_test = ast_to_go (self .test_generator , self .reql_vars , self . excluded_lines )
212277 self .renderer .source_files = [self .full_path ]
213278 self .renderer .render (
214279 'template.go' ,
@@ -268,10 +333,8 @@ def py_to_go_type(py_type):
268333 'uuid' : 'compare.Regex' , # clashes with ast.Uuid
269334 }.get (py_type .__name__ , camel (py_type .__name__ ))
270335 elif py_type .__module__ == 'rethinkdb.query' :
271- # All of the constants like minval maxval etc are defined in
272- # query.py, but no type name is provided to `type`, so we have
273- # to pull it out of a class variable
274- return camel (py_type .st )
336+ # ReQL constants don't have a type; they are just identifiers.
337+ return None
275338 else :
276339 raise Unhandled (
277340 "Don't know how to convert python type {}.{} to Go"
@@ -351,12 +414,14 @@ def query_to_go(item, reql_vars):
351414 )
352415
353416
354- def ast_to_go (sequence , reql_vars ):
417+ def ast_to_go (sequence , reql_vars , excluded_lines ):
355418 '''Converts the the parsed test data to go source lines using the
356419 visitor classes'''
357420 reql_vars = set (reql_vars )
358421 for item in sequence :
359- if type (item ) == process_polyglot .Def :
422+ if hasattr (item , 'line_num' ) and item .line_num in excluded_lines :
423+ logger .info ("Skipped %s line %d due to exclusion" , item .testfile , item .line_num )
424+ elif type (item ) == process_polyglot .Def :
360425 yield def_to_go (item , reql_vars )
361426 elif type (item ) == process_polyglot .CustomDef :
362427 yield GoDef (line = Version (item .line , item .line ),
@@ -532,6 +597,7 @@ def visit_Assign(self, node):
532597 Unhandled ("We only support assigning to one variable" )
533598 var = node .targets [0 ].id
534599 self .write ("var " + var + " " )
600+
535601 if is_reql (self ._type ):
536602 self .write ('r.Term' )
537603 else :
@@ -670,7 +736,7 @@ def visit_Call(self, node):
670736 self .visit (node .func )
671737 elif type (node .func ) == ast .Name and node .func .id == 'fetch' :
672738 if len (node .args ) == 1 :
673- node .args .append (ast .Num (0 ))
739+ node .args .append (ast .Constant (0 ))
674740 elif len (node .args ) > 2 :
675741 node .args = node .args [:2 ]
676742 self .visit (node .func )
@@ -709,14 +775,15 @@ def visit_Lambda(self, node):
709775 self .write ("}" )
710776
711777 def visit_Subscript (self , node ):
712- if node .slice is None or type (node .slice .value ) != ast .Num :
778+ if node .slice is not None and type (node .slice .value ) == ast .Constant and type (node .slice .value .value ) == int :
779+ self .visit (node .value )
780+ self .write ("[" )
781+ self .write (str (node .slice .value .n ))
782+ self .write ("]" )
783+ else :
713784 logger .error ("While doing: %s" , ast .dump (node ))
714785 raise Unhandled ("Only integers subscript can be converted."
715786 " Got %s" % node .slice .value .s )
716- self .visit (node .value )
717- self .write ("[" )
718- self .write (str (node .slice .value .n ))
719- self .write ("]" )
720787
721788 def visit_ListComp (self , node ):
722789 gen = node .generators [0 ]
@@ -782,7 +849,7 @@ def visit_BinOp(self, node):
782849 self .write (opMap [t ])
783850 self .visit (node .right )
784851 elif t == ast .Pow :
785- if type (node .left ) == ast .Num and node .left .n == 2 :
852+ if type (node .left ) == ast .Constant and type ( node . left . value ) == int and node .left .n == 2 :
786853 self .visit (node .left )
787854 self .write (" << " )
788855 self .visit (node .right )
@@ -802,12 +869,12 @@ def is_byte_array_add(self, node):
802869 return False
803870
804871 def is_string_mul (self , node ):
805- if ((type (node .left ) == ast .Str and type (node .right ) == ast .Num ) and type (node .op ) == ast .Mult ):
872+ if ((type (node .left ) == ast .Constant and type (node .left . value ) == str and type ( node . right ) == ast .Constant and type ( node . right . value ) == int ) and type (node .op ) == ast .Mult ):
806873 self .write ("\" " )
807874 self .write (node .left .s * node .right .n )
808875 self .write ("\" " )
809876 return True
810- elif ((type (node .left ) == ast .Num and type (node .right ) == ast .Str ) and type (node .op ) == ast .Mult ):
877+ elif ((type (node .left ) == ast .Constant and type (node .left . value ) == int and type ( node . right ) == ast .Constant and type ( node . right . value ) == str ) and type (node .op ) == ast .Mult ):
811878 self .write ("\" " )
812879 self .write (node .left .n * node .right .s )
813880 self .write ("\" " )
@@ -893,19 +960,15 @@ def infix(self, func_name, left, right):
893960 self .write (")" )
894961
895962 def is_not_reql (self , node ):
896- if type (node ) in (ast .Name , ast .NameConstant ,
897- ast .Num , ast .Str , ast .Dict , ast .List ):
898- return True
899- else :
900- return False
963+ return type (node ) in (ast .Constant , ast .Name , ast .NameConstant , ast .Dict , ast .List )
901964
902965 def visit_Subscript (self , node ):
903966 self .visit (node .value )
904967 if type (node .slice ) == ast .Index :
905968 # Syntax like a[2] or a["b"]
906- if self .smart_bracket and type (node .slice .value ) == ast .Str :
969+ if self .smart_bracket and type (node .slice .value ) == ast .Constant and type ( node . slice . value . value ) == str :
907970 self .write (".Field(" )
908- elif self .smart_bracket and type (node .slice .value ) == ast .Num :
971+ elif self .smart_bracket and type (node .slice .value ) == ast .Constant and type ( node . slice . value . value ) == int :
909972 self .write (".Nth(" )
910973 else :
911974 self .write (".AtIndex(" )
@@ -937,7 +1000,7 @@ def get_bound(bound, default):
9371000 return default
9381001 elif type (bound ) == ast .UnaryOp and type (bound .op ) == ast .USub :
9391002 return - bound .operand .n
940- elif type (bound ) == ast .Num :
1003+ elif type (bound ) == ast .Constant and type ( bound . value ) == int :
9411004 return bound .n
9421005 else :
9431006 raise Unhandled (
0 commit comments