Synopsis - Cross-Reference
File: /tests/old_cxx_regressions/test.py1#!/usr/bin/python 2# A test-suite for the C++ syntax highlighter 3 4import os, types, sys, string, re, urllib 5 6class config: 7 gdb = 0 8 dump = 0 9 regression = 0 10 11gcc_include2 = "-I/usr/include/g++-3/ -I/usr/lib/gcc-lib/i386-linux/2.95.4/include " 12gcc_include3 = "-I/usr/include/g++-v3/ -I/usr/include/g++-v3/i386-linux/ -I/usr/lib/gcc-lib/i386-linux/3.0.1/include " 13gcc_include = gcc_include2 14python_include = "\"-DPYTHON_INCLUDE=<python2.1/Python.h>\" " 15 16 17html_top = '<html><link rel="stylesheet" href="/home/chalky/src/Synopsis/demo/html.css"><body>' 18class Test: 19 flags = "" 20 str_make_debug = "(cd ../syn; make debug)" 21 str_make = "(cd ../syn; make -s)" 22 23 def run(self): 24 "Return false if test failed" 25 test_text = self.__class__.test 26 test_base = self.__class__.__name__ 27 test_file = "/tmp/%s.cc"%test_base 28 f = open(test_file, "w") 29 f.write(test_text) 30 f.close() 31 return self.do_run(test_file, test_base) 32 33 def do_run(self, test_file, test_base, flags=""): 34 global config 35 flags = flags + self.flags 36 if config.regression: 37 return not self.run_regression(test_file, test_base, flags) 38 elif config.gdb: 39 return not self.gdb_less(test_file, flags) 40 elif config.dump: 41 return not self.dump_less(test_file, flags) 42 else: 43 return not self.view_page(test_file, test_base, flags) 44 45 def system(self, command): 46 """Runs the given command using system(). Returns the error code of the 47 command run, which will be 0 for no error by convention.""" 48 ret = os.system(command) 49 return ret >> 8 50 51 def gdb_less(self, test_file, flags = ""): 52 return self.system(Test.str_make_debug + " && "\ 53 "echo '../syn/occ.gdb %s %s' && "\ 54 "../syn/occ.gdb %s %s 2>&1 | less"%( 55 flags, test_file, flags, test_file)) 56 57 def dump_less(self, test_file, flags = ""): 58 return self.system(Test.str_make + " && "\ 59 "echo synopsis -v -Wc,parser=C++,formatter=DUMP %(flags)s %(test_file)s &&"\ 60 "synopsis -v -Wc,parser=C++,formatter=DUMP -Wf,-d,-t,-f %(flags)s %(test_file)s "\ 61 "2>&1 | less -r"%vars()) 62 63 def _do_synopsis(self, file, base, flags=""): 64 """Runs synopsis on the input file. A Links file (.links) and AST file 65 (.syn) are generated.""" 66 syn_file = "/tmp/"+base+".syn" 67 links_file = "/tmp/"+base+".links" 68 if config.regression: verbose = "" 69 else: verbose = "-v" 70 synopsis_flags = string.join([verbose, # Verbose 71 "-Wc,parser=C++", # Use C++ Parser 72 "-Wp,-t,-s,%(links_file)s", # Tags and links 73 "%(flags)s", # Other flags 74 "-o %(syn_file)s", # Output file 75 "%(file)s"], " ")%vars() # Input file 76 77 commands = [Test.str_make % vars()] 78 if not config.regression: commands.append("echo \"Running Synopsis...\"") 79 commands.append("synopsis %(synopsis_flags)s"%vars()) 80 81 return self.system(string.join(commands, " && ")) 82 83 def _do_cleanup(self, file, base): 84 """Cleans up the files generated by _do_synopsis""" 85 syn_file = "/tmp/"+base+".syn" 86 links_file = "/tmp/"+base+".links" 87 return 0 88 return self.system("rm -f /tmp/%(base)s.{links,syn,html.out,top}"%vars() ) 89 90 91 def _do_html_view(self, file, base): 92 """Launches a web browser to view the html output""" 93 f = open("/tmp/%s.top"%base, "w") 94 f.write(html_top) 95 f.close() 96 syn_file = "/tmp/"+base+".syn" 97 links_file = "/tmp/"+base+".links" 98 return self.system("echo \"Running Linker...\" && "\ 99 "../syn/link-synopsis -i %(file)s -l /tmp/%(base)s.links -o /tmp/%(base)s.html.out && "\ 100 "(cat /tmp/%(base)s.top /tmp/%(base)s.html.out > /tmp/%(base)s.html) && "\ 101 "web /tmp/%(base)s.html"%vars() ) 102 103 def view_page(self, file, base, flags=""): 104 """Runs synopsis on the given page and views the output as HTML""" 105 error = self._do_synopsis(file, base, flags) 106 if not error: error = self._do_html_view(file, base) 107 if not error: error = self._do_cleanup(file, base) 108 else: self._do_cleanup(file, base) # Cleanup anyway 109 return error 110 111 def run_regression(self, file, base, flags=""): 112 """Runs synopsis on the given page and performs tests on the output""" 113 error = self._do_synopsis(file, base, flags) 114 if not error: error = self.test_links(file, base) 115 if not error: error = self._do_cleanup(file, base) 116 return error 117 118 119class Regression: 120 """A regression test identifies a test that takes part in regression 121 testing""" 122 123 re_test = re.compile(r'test ([a-zA-Z_0-9]+) = "([^"]*)"') 124 125 def test_links(self, file, base): 126 """Tests the links in the test to make sure Synopsis is working okay""" 127 128 # Read links file and split into a map 129 links = {} 130 links_file = "/tmp/"+base+".links" 131 flinks = open(links_file, "r") 132 for line in flinks.readlines(): 133 lnum, start, length, ltype, rest = string.split(line, ' ', 4) 134 if ltype not in ("REF", "CALL"): continue 135 ref, comment = string.split(rest) 136 links.setdefault(int(lnum), []).append( (int(start), int(length), ref) ) 137 flinks.close() 138 139 140 # Loop through the lines in the test case, looking for "test = " comments 141 linenum = 0 142 for line in self.test.split('\n'): 143 linenum = linenum + 1 144 145 # Find comment 146 pos = line.find('// ') 147 if pos < 0: continue 148 text = line[pos+3:] 149 150 # Loop to find tests 151 mo = self.re_test.search(text) 152 while mo: 153 # Get name of variable and reference it should point to 154 testname, testref = mo.groups() 155 156 found = 0 157 # Find variable in links map 158 for start, length, ref in links[linenum]: 159 # un-encode ref (note this is done in the less-often case of being 160 # tested, not for every ref at read time!) 161 ref = string.replace(ref, '%09', '::') 162 ref = urllib.unquote_plus(ref) 163 name = line[start-1:start-1+length] 164 #print "Testing",name,"=",testname,"and",ref,"=",testref 165 if name == testname: 166 # Found it! (assumes one variable with this name per line) 167 if ref != testref: 168 print "\nError: reference",testref,"not found on line",linenum 169 print " found '%s' instead."%ref 170 return 1 171 found = 1 172 break 173 174 # Check that a link was found which matched the name 175 if not found: 176 print "\nError: name",testname,"not found on line",linenum 177 print links[linenum] 178 return 1 179 180 # Find next testcase (if any) on this line 181 mo = self.re_test.search(text, mo.end()) 182 183 184# Note: Regression tests are defined in regressions.py 185 186class Link (Test): 187 def run(self): 188 return self.do_run("../syn/link.cc", "link", gcc_include + python_include) 189 190class Builder (Test): 191 def run(self): 192 return self.do_run("../syn/builder.cc", "builder", gcc_include + python_include + "-I../") 193 194class Synopsis (Test): 195 def run(self): 196 return self.do_run("../syn/synopsis.cc", "synopsis", gcc_include + python_include) 197 198class AST (Test): 199 def run(self): 200 return self.do_run("../syn/ast.hh", "ast", gcc_include + python_include) 201 202class TestTemplate (Test): 203 def run(self): 204 return self.do_run("test-template.cc", "test-template", gcc_include) 205 206class IterativeInclude (Test): 207 def run(self): 208 return self.do_run("iterative_include.h", "iterative_include", "") 209 210class RegressionTest (Test): 211 def run(self): 212 # Find tests 213 tests = [] 214 for key, obj in regressions.__dict__.items(): 215 if type(obj) is types.ClassType: 216 if Regression in obj.__bases__: 217 tests.append(obj) 218 219 # Run tests 220 passed = 0 221 for test in tests: 222 print " %-40s .. "%(test.__name__,), 223 result = test().run() 224 if result: 225 print "passed" 226 passed = passed + 1 227 else: 228 print "failed" 229 230 # Print summary 231 print " %d of %d tests passed."%(passed, len(tests)) 232 233 return passed == len(tests) 234 235import regressions 236from regressions import * 237 238if __name__ == "__main__": 239 tests = {} 240 for key in globals().keys(): 241 obj = globals()[key] 242 if type(obj) is types.ClassType: 243 if Test in obj.__bases__: 244 tests[key] = obj 245 test = None 246 for arg in sys.argv[1:]: 247 if arg[0] == '-': 248 if arg[1] == 'g': 249 config.gdb = 1 250 elif arg[1] == 'r': 251 test = "RegressionTest" 252 config.regression = 1 253 elif arg == '--dump': 254 config.dump = 1 255 else: 256 print "Unknown argument:",arg 257 else: 258 test = arg 259 if not tests.has_key(test): test = None 260 if test is None: 261 print "Choose a test from:", string.join(tests.keys()) 262 sys.exit(1) 263 test = tests[test] 264 if not test().run(): print "failed" 265 266# vim: set et sts=2 ts=8 sw=2: