Synopsis - Cross-Reference

File: /tests/old_cxx_regressions/test.py
  1#!/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: