Synopsis - Cross-Reference

File: /tests/QMTest/synopsis_database.py
  1#!/usr/bin/env python
  2#
  3# Copyright (C) 2003 Stefan Seefeld
  4# All rights reserved.
  5# Licensed to the public under the terms of the GNU LGPL (>= 2),
  6# see the file COPYING for details.
  7#
  8
  9from qm.fields import TextField
 10from qm.test import database
 11from qm.test.database import TestDescriptor, ResourceDescriptor
 12from qm.test.database import NoSuchTestError, NoSuchSuiteError, NoSuchResourceError
 13from explicit_suite import ExplicitSuite
 14from qm.test.suite import Suite
 15
 16import os, string, dircache
 17
 18class Database(database.Database):
 19   """The Database stores the synopsis tests."""
 20
 21   arguments = [TextField(name="srcdir")]
 22
 23   def __init__(self, path, arguments):
 24
 25      arguments["modifiable"] = "false"
 26      database.Database.__init__(self, path, arguments)
 27      if os.name == 'nt':
 28         self.srcdir = os.popen('cygpath -w "%s"'%self.srcdir).read()[:-1]
 29
 30   def get_src_path(self, id):
 31      return self.srcdir + os.sep + id.replace('.', os.sep)
 32
 33   def get_build_path(self, id):
 34      return id.replace('.', os.sep)
 35
 36   def get_file_tests(self, path, ext = ''):
 37      """tests are file names without extension"""
 38      return [t[0]
 39              for t in [os.path.splitext(x) for x in dircache.listdir(path)] 
 40              if t[0] != '' and (not ext or t[1] == ext)]
 41
 42   def get_dir_tests(self, id, script):
 43      """tests are directories if <script> exists"""
 44      return [t for t in dircache.listdir(self.get_src_path(id))
 45              if os.path.isfile(os.path.join(self.get_build_path(id), t, script))]
 46
 47   def get_dir_suites(self, id):
 48      """by default all directories are suites"""
 49      path = self.get_src_path(id)
 50      return filter(lambda x: os.path.isdir(os.path.join(path, x)),
 51                    dircache.listdir(path))
 52
 53   def GetSubdirectories(self, dir):
 54
 55      if not os.path.isdir(self.get_src_path(dir)):
 56         raise NoSuchSuiteError, dir
 57
 58      suites = []
 59
 60      if not dir:
 61
 62         return ['Cxx', 'Parsers', 'Processors']
 63
 64      elif dir.startswith('Processors.Linker'):
 65
 66         # just make sure this isn't a test itself...
 67         if os.path.exists(os.path.join(self.get_build_path(dir), 'synopsis.py')):
 68            raise NoSuchSuiteError, dir
 69
 70         tests = self.get_dir_tests(dir, 'synopsis.py')
 71         suites = [s for s in self.get_dir_suites(dir) if s not in tests]
 72
 73      elif dir.startswith('Cxx-API'):
 74         # if 'src' exists, it contains the tests
 75         path = os.path.join(self.get_src_path(dir), 'src')
 76         if not os.path.isdir(path):
 77            suites = self.get_dir_suites(dir)
 78
 79      elif dir.startswith('Cxx'):
 80         if not os.path.isdir(os.path.join(self.get_src_path(dir), 'input')):
 81            suites = self.get_dir_suites(dir)
 82            suites.remove('src')
 83
 84      else:
 85         if not os.path.isdir(os.path.join(self.get_src_path(dir), 'input')):
 86            suites = self.get_dir_suites(dir)
 87
 88      # ignore accidental inclusion of false tests / suites
 89      if '.svn' in suites: suites.remove('.svn')
 90      if 'autom4te.cache' in suites: suites.remove('autom4te.cache')
 91
 92      return suites
 93
 94
 95   def GetTestIds(self, dir = "", scan_subdirs = 1):
 96      """Return all test IDs that are part of the given suite."""
 97
 98      if not os.path.isdir(self.get_src_path(dir)):
 99         raise NoSuchSuiteError, dir
100
101      tests = []
102
103      if dir.startswith('Processors.Linker'):
104
105         # just make sure this isn't a test itself...
106         if os.path.exists(os.path.join(self.get_build_path(dir), 'synopsis.py')):
107            raise NoSuchSuiteError, dir
108
109         tests = self.get_dir_tests(dir, 'synopsis.py')
110
111      elif dir.startswith('Cxx-API'):
112         # if 'src' exists, it contains the tests
113         path = os.path.join(self.get_src_path(dir), 'src')
114         if os.path.isdir(path):
115            tests = self.get_file_tests(path, '.cc')
116
117      elif dir.startswith('Cxx'):
118         if os.path.isdir(os.path.join(self.get_src_path(dir), 'input')):
119            tests = self.get_file_tests(os.path.join(self.get_src_path(dir),
120                                                     'input'),
121                                   '.cc')
122
123      else:
124         if os.path.isdir(os.path.join(self.get_src_path(dir), 'input')):
125            tests = self.get_file_tests(os.path.join(self.get_src_path(dir),
126                                                     'input'))
127      # ignore accidental inclusion of false tests / suites
128      if '.svn' in tests: tests.remove('.svn')
129
130      if dir:
131         tests = ['%s.%s'%(dir, t) for t in tests]
132
133      if scan_subdirs:
134         for d in self.GetSubdirectories(dir):
135            d = self.JoinLabels(dir, d)
136            tests.extend(self.GetTestIds(d, scan_subdirs))
137
138      return tests
139   
140   
141   def GetResourceIds(self, directory="", scan_subdirs=1):
142
143      if directory == '' and scan_subdirs or directory == 'Cxx':
144         return ['Cxx.Lexer',
145                 'Cxx.Parser',
146                 'Cxx.Encoding',
147                 'Cxx.ConstEvaluator',
148                 'Cxx.SymbolLookup',
149                 'Cxx.TypeAnalysis']
150      else:
151         return []
152
153   def GetResource(self, id):
154      """Construct a resource for the given id.
155      For now the only resources provided are Cxx test applets."""
156
157      if not id.startswith('Cxx'): raise NoSuchResourceError(id)
158
159      parameters = {}
160
161      suite = id.split('.', 1)[1]
162      if suite not in ['Lexer', 'Parser', 'Encoding',
163                       'ConstEvaluator', 'SymbolLookup', 'TypeAnalysis']:
164         raise NoSuchResourceError(id)
165      
166      parameters['exe'] = os.path.normpath('bin/%s'%suite)
167
168      return ResourceDescriptor(self, id, 'synopsis_test.CxxResource', parameters)
169      
170   def GetSuite(self, id):
171      """Construct a suite for the given id.
172      For suites there is a general mapping from ids to paths:
173      replace the period by os.sep to get the path in the build tree,
174      and prefix that with self.srcdir to get the path in the source tree."""
175
176      test_ids = self.GetTestIds(id)
177      suite_ids = self.GetSuiteIds(id)
178
179      arguments = {'test_ids' : test_ids, 'suite_ids' : suite_ids}
180
181      return ExplicitSuite(arguments,
182                           qmtest_database = self,
183                           qmtest_id = id)
184        
185   def GetTest(self, id):
186      """Create a test for the given id. Tests are grouped by type,
187      i.e. specific suites contain specific test classes."""
188
189      if not id: raise NoSuchTestError, id
190         
191      if id.startswith('Processors.Linker'): return self.make_linker_test(id)
192      elif id.startswith('Cxx-API'): return self.make_api_test(id)
193      elif id.startswith('Cxx'): return self.make_opencxx_test(id)
194      else: return self.make_processor_test(id)
195
196   def make_processor_test(self, id):
197      """A test id 'a.b.c' corresponds to an input file
198      'a/b/input/c.<ext>. Create a ProcessorTest if that
199      input file exists, and throw NoSuchTestError otherwise."""
200
201      components = id.split('.')
202      dirname = os.path.join(*[self.srcdir] + components[:-1])
203
204      input = os.path.join(dirname, 'input', components[-1])
205         
206      if components[:-1] == ['Parsers', 'IDL']: input += '.idl'
207      elif components[:-1] == ['Parsers', 'Python']: input += '.py'
208      elif components[:-1] == ['Parsers', 'C']: input += '.c'
209      else: input += '.cc'
210      if not os.path.isfile(input): raise NoSuchTestError, id
211
212      output = os.path.join(*components[:-1] + ['output', components[-1] + '.xml'])
213      expected = os.path.join(dirname, 'expected', components[-1] + '.xml')
214      if components[0] == 'Processors' and components[1] != 'Linker':
215         synopsis = os.path.join('Processors', 'synopsis.py')
216      else:
217         synopsis = os.path.join(*components[:-1] + ['synopsis.py'])
218
219      parameters = {}
220      parameters['srcdir'] = self.srcdir
221      parameters['input'] = [input]
222      parameters['output'] = output
223      parameters['expected'] = expected
224      parameters['synopsis'] = synopsis
225      
226      return TestDescriptor(self, id, 'synopsis_test.ProcessorTest', parameters)
227
228   def make_linker_test(self, id):
229      """A test id 'a.b.c' corresponds to an input directory
230      'a/b/c/input containing files to be linked together.
231      Create a ProcessorTest if that directory exists,
232      and throw NoSuchTestError otherwise."""
233
234      path = self.get_src_path(id)
235      if not os.path.isdir(path): raise NoSuchTestError, id
236
237      dirname = os.path.join(path, 'input')
238
239      parameters = {}
240      parameters['srcdir'] = self.srcdir
241      parameters['input'] = [os.path.join(dirname, x) for x in dircache.listdir(dirname) if x != '.svn']
242      parameters['output'] = os.path.join(*id.split('.') + ['output.xml'])
243      parameters['expected'] = os.path.join(path, 'expected.xml')
244      parameters['synopsis'] = os.path.join(*id.split('.') + ['synopsis.py'])
245      
246      return TestDescriptor(self, id, 'synopsis_test.ProcessorTest', parameters)
247
248   def make_api_test(self, id):
249      """A test id 'a.b.c' corresponds to an input file
250      'a/b/src/c.cc. Create an APITest if that
251      input file exists, and throw NoSuchTestError otherwise."""
252
253      components = id.split('.')
254      dirname = os.path.join(*[self.srcdir] + components[:-1])
255
256      if not os.path.exists(os.path.join(dirname, 'src', components[-1]) + '.cc'):
257         raise NoSuchTestError, id
258
259      parameters = {}
260      parameters['CXX'] = self.CXX
261      parameters['CPPFLAGS'] = self.CPPFLAGS
262      parameters['CXXFLAGS'] = self.CXXFLAGS
263      parameters['LDFLAGS'] = self.LDFLAGS
264      parameters['LIBS'] = self.LIBS
265      parameters['src'] = os.path.join(dirname, 'src', components[-1]) + '.cc'
266      parameters['exe'] = os.path.join(*components[:-1] + ['bin', components[-1]])
267      parameters['expected'] = os.path.join(dirname, 'expected',
268                                            components[-1] + '.out')
269      
270      return TestDescriptor(self, id, 'synopsis_test.APITest', parameters)
271
272   def make_opencxx_test(self, id):
273      """A test id 'a.b.c' corresponds to an input file
274      'a/b/input/c.<ext>. Create an CxxTest if that
275      input file exists, and throw NoSuchTestError otherwise."""
276
277      base, suite, test = id.split('.')
278      dirname = os.path.join(*[self.srcdir] + [base, suite])
279
280      input = os.path.join(dirname, 'input', test) + '.cc'
281      output = os.path.join(*[base, suite, 'output', test + '.out'])
282         
283      if not os.path.isfile(input): raise NoSuchTestError, id
284
285      expected = os.path.join(dirname, 'expected', test + '.out')
286
287      parameters = {}
288      parameters['input'] = input
289      parameters['output'] = output
290      parameters['expected'] = expected
291
292      parameters['resources'] = ['Cxx.%s'%suite]
293      parameters['applet'] = 'Cxx/bin/%s'%suite
294         
295      return TestDescriptor(self, id, 'synopsis_test.CxxTest', parameters)
296