Synopsis - Cross-Reference
File: /tests/QMTest/synopsis_test.py1#!/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.executable import RedirectedExecutable 11from qm.test.test import Test 12from qm.test.resource import Resource 13from qm.test.result import Result 14 15import os, sys, string, re 16import difflib 17 18class APITest(Test): 19 """Compile and run a test to validate the C++ API.""" 20 21 arguments = [TextField(name="src", description="The source file."), 22 TextField(name="exe", description="The executable file."), 23 TextField(name="expected", description="The expected output file.")] 24 25 def compile(self, context, result): 26 if not os.path.isdir(os.path.dirname(self.exe)): 27 os.makedirs(os.path.dirname(self.exe)) 28 29 CXX = context.get('CXX', 'c++') 30 CPPFLAGS = context.get('CPPFLAGS', '') 31 CXXFLAGS = context.get('CXXFLAGS', '') 32 LDFLAGS = context.get('LDFLAGS', '') 33 LIBS = context.get('LIBS', '') 34 command = '%s %s %s %s -o %s %s %s'%(CXX, CPPFLAGS, CXXFLAGS, LDFLAGS, 35 self.exe, self.src, LIBS) 36 compiler = RedirectedExecutable() 37 status = compiler.Run(string.split(command)) 38 if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0: 39 return self.exe 40 else: 41 result.Fail('compilation failed', 42 {'synopsis_test.error': compiler.stderr, 43 'synopsis_test.command': command}) 44 return None 45 46 def Run(self, context, result): 47 exe = self.compile(context, result) 48 if not exe: return 49 test = RedirectedExecutable() 50 status = test.Run([exe]) 51 if not os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0: 52 result.Fail('program exit value : %i'%os.WEXITSTATUS(status)) 53 if test.stderr: result['synopsis_test.error'] = test.stderr 54 55 try: 56 expected = open(self.expected, 'r').readlines() 57 output = test.stdout.split('\n') 58 except IOError, error: 59 result.Fail('error reading expected output', 60 {'synopsis_test.error': error.strerror}) 61 return 62 if expected and not output: 63 result.Fail('program did not generate output') 64 elif expected and expected != output: 65 diff = ''.join(difflib.unified_diff(expected, output)) 66 expected = ''.join(expected) 67 result.Fail('incorrect output', 68 {'synopsis_test.expected': result.Quote(expected), 69 'synopsis_test.output': result.Quote(test.stdout), 70 'synopsis_test.diff': result.Quote(diff)}) 71 72 73class ProcessorTest(Test): 74 """Process an input file with a synopsis script and 75 compare the output.""" 76 77 arguments = [TextField(name="srcdir", description="The source directory."), 78 TextField(name="synopsis", description="The synopsis script."), 79 TextField(name="input", description="The input files."), 80 TextField(name="output", description="The output file."), 81 TextField(name="expected", description="The output file.")] 82 83 def run_processor(self, context, result): 84 85 input = map(lambda x:os.path.join(self.srcdir, x), self.input) 86 if not os.path.isdir(os.path.dirname(self.output)): 87 os.makedirs(os.path.dirname(self.output)) 88 89 command = 'python %s parse --output=%s %s'%(self.synopsis, 90 self.output, 91 string.join(self.input, ' ')) 92 # Make sure the modules from the current working dir are used. 93 #os.environ['PYTHONPATH'] = os.path.join(self.srcdir, os.pardir) 94 script = RedirectedExecutable(60) # 1 minute ought to be enough... 95 status = script.Run(string.split(command)) 96 if status != 0: 97 result.Fail('unable to run', 98 {'synopsis_test.command': result.Quote(command), 99 'synopsis_test.error': result.Quote(script.stderr)}) 100 return status == 0 101 102 def Run(self, context, result): 103 104 if self.run_processor(context, result): 105 try: 106 expected = open(self.expected, 'r').readlines() 107 except IOError, error: 108 result.Fail('error reading expected output', 109 {'synopsis_test.error': error.strerror}) 110 return 111 output = open(self.output, 'r').readlines() 112 if expected != output: 113 diff = ''.join(difflib.unified_diff(expected, output)) 114 expected = ''.join(expected) 115 output = ''.join(output) 116 result.Fail('incorrect output', 117 {'synopsis_test.expected': result.Quote(expected), 118 'synopsis_test.output': result.Quote(output), 119 'synopsis_test.diff': result.Quote(diff)}) 120 121class CxxResource(Resource): 122 """build the executables the CxxTests all depend on.""" 123 124 arguments = [TextField(name="MAKE", description="The make tool."), 125 TextField(name="exe", description="The executable file.")] 126 127 def compile(self, context, result): 128 129 make = os.environ.get('MAKE', 'make') 130 command = '%s -C Cxx %s '%(make, self.exe) 131 compiler = RedirectedExecutable() 132 status = compiler.Run(string.split(command)) 133 if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0: 134 return self.exe 135 else: 136 result.Fail('compilation failed', 137 {'synopsis_test.error': compiler.stderr, 138 'synopsis_test.command': command}) 139 return None 140 141 def SetUp(self, context, result): 142 143 self.compile(context, result) 144 145class CxxTest(Test): 146 """Process an input file with a processor and compare the output. 147 If the processor doesn't exist yet, attempt to build it.""" 148 149 arguments = [TextField(name="applet", description="The applet."), 150 TextField(name="srcdir", description="The source directory."), 151 TextField(name="input", description="The input files."), 152 TextField(name="output", description="The output files."), 153 TextField(name="expected", description="The expected output file.")] 154 155 _ld_paths = re.compile(r'-L\s*\S+') 156 157 def run_applet(self, context, result): 158 159 input = map(lambda x:os.path.join(self.srcdir, x), self.input) 160 if not os.path.isdir(os.path.dirname(self.output)): 161 os.makedirs(os.path.dirname(self.output)) 162 163 # Make sure we see the right libraries during program loading. 164 LIBS=context.get('LIBS', '') 165 LD_PATHS=[p[2:].strip() for p in CxxTest._ld_paths.findall(LIBS)] 166 LD_LIBRARY_PATH = ':'.join(LD_PATHS) 167 LD_LIBRARY_PATH += ':' + os.environ.get('LD_LIBRARY_PATH', '') 168 os.environ['LD_LIBRARY_PATH'] = LD_LIBRARY_PATH 169 170 test = RedirectedExecutable() 171 command = '%s %s %s'%(self.applet, self.output, self.input) 172 status = test.Run(command.split()) 173 if os.WIFSIGNALED(status): 174 result.Fail('program killed with signal %i'%os.WTERMSIG(status), 175 {'synopsis_test.command': command}) 176 177 elif os.WIFEXITED(status) and os.WEXITSTATUS(status) != 0: 178 result.Fail('program exit value : %i'%os.WEXITSTATUS(status), 179 {'synopsis_test.command': command}) 180 if test.stderr: result['synopsis_test.error'] = test.stderr 181 182 else: 183 try: 184 expected = open(self.expected, 'r').readlines() 185 except IOError, error: 186 result.Fail('error reading expected output', 187 {'synopsis_test.error': error.strerror}) 188 return 189 try: 190 output = open(self.output, 'r').readlines() 191 except IOError, error: 192 result.Fail('error reading actual output', 193 {'synopsis_test.error': error.strerror}) 194 return 195 196 if expected != output: 197 diff = ''.join(difflib.unified_diff(expected, output)) 198 expected = ''.join(expected) 199 output = ''.join(output) 200 result.Fail('incorrect output', 201 {'synopsis_test.expected': result.Quote(expected), 202 'synopsis_test.output': result.Quote(output), 203 'synopsis_test.diff': result.Quote(diff)}) 204 205 def Run(self, context, result): 206 207 self.run_applet(context, result)