1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Unittest for the generate_stubs.py. 7 8Since generate_stubs.py is a code generator, it is hard to do a very good 9test. Instead of creating a golden-file test, which might be flakey, this 10test elects instead to verify that various components "exist" within the 11generated file as a sanity check. In particular, there is a simple hit 12test to make sure that umbrella functions, etc., do try and include every 13function they are responsible for invoking. Missing an invocation is quite 14easily missed. 15 16There is no attempt to verify ordering of different components, or whether 17or not those components are going to parse incorrectly because of prior 18errors or positioning. Most of that should be caught really fast anyways 19during any attempt to use a badly behaving script. 20""" 21 22import generate_stubs as gs 23import re 24import StringIO 25import sys 26import unittest 27 28 29def _MakeSignature(return_type, name, params): 30 return {'return_type': return_type, 31 'name': name, 32 'params': params} 33 34 35SIMPLE_SIGNATURES = [ 36 ('int foo(int a)', _MakeSignature('int', 'foo', ['int a'])), 37 ('int bar(int a, double b)', _MakeSignature('int', 'bar', 38 ['int a', 'double b'])), 39 ('int baz(void)', _MakeSignature('int', 'baz', ['void'])), 40 ('void quux(void)', _MakeSignature('void', 'quux', ['void'])), 41 ('void waldo(void);', _MakeSignature('void', 'waldo', ['void'])), 42 ('int corge(void);', _MakeSignature('int', 'corge', ['void'])), 43 ] 44 45TRICKY_SIGNATURES = [ 46 ('const struct name *foo(int a, struct Test* b); ', 47 _MakeSignature('const struct name *', 48 'foo', 49 ['int a', 'struct Test* b'])), 50 ('const struct name &foo(int a, struct Test* b);', 51 _MakeSignature('const struct name &', 52 'foo', 53 ['int a', 'struct Test* b'])), 54 ('const struct name &_foo(int a, struct Test* b);', 55 _MakeSignature('const struct name &', 56 '_foo', 57 ['int a', 'struct Test* b'])), 58 ('struct name const * const _foo(int a, struct Test* b) ' 59 '__attribute__((inline));', 60 _MakeSignature('struct name const * const', 61 '_foo', 62 ['int a', 'struct Test* b'])) 63 ] 64 65INVALID_SIGNATURES = ['I am bad', 'Seriously bad(', ';;;'] 66 67 68class GenerateStubModuleFunctionsUnittest(unittest.TestCase): 69 def testExtractModuleName(self): 70 self.assertEqual('somefile-2', gs.ExtractModuleName('somefile-2.ext')) 71 72 def testParseSignatures_EmptyFile(self): 73 # Empty file just generates empty signatures. 74 infile = StringIO.StringIO() 75 signatures = gs.ParseSignatures(infile) 76 self.assertEqual(0, len(signatures)) 77 78 def testParseSignatures_SimpleSignatures(self): 79 file_contents = '\n'.join([x[0] for x in SIMPLE_SIGNATURES]) 80 infile = StringIO.StringIO(file_contents) 81 signatures = gs.ParseSignatures(infile) 82 self.assertEqual(len(SIMPLE_SIGNATURES), len(signatures)) 83 84 # We assume signatures are in order. 85 for i in xrange(len(SIMPLE_SIGNATURES)): 86 self.assertEqual(SIMPLE_SIGNATURES[i][1], signatures[i], 87 msg='Expected %s\nActual %s\nFor %s' % 88 (SIMPLE_SIGNATURES[i][1], 89 signatures[i], 90 SIMPLE_SIGNATURES[i][0])) 91 92 def testParseSignatures_TrickySignatures(self): 93 file_contents = '\n'.join([x[0] for x in TRICKY_SIGNATURES]) 94 infile = StringIO.StringIO(file_contents) 95 signatures = gs.ParseSignatures(infile) 96 self.assertEqual(len(TRICKY_SIGNATURES), len(signatures)) 97 98 # We assume signatures are in order. 99 for i in xrange(len(TRICKY_SIGNATURES)): 100 self.assertEqual(TRICKY_SIGNATURES[i][1], signatures[i], 101 msg='Expected %s\nActual %s\nFor %s' % 102 (TRICKY_SIGNATURES[i][1], 103 signatures[i], 104 TRICKY_SIGNATURES[i][0])) 105 106 def testParseSignatures_InvalidSignatures(self): 107 for i in INVALID_SIGNATURES: 108 infile = StringIO.StringIO(i) 109 self.assertRaises(gs.BadSignatureError, gs.ParseSignatures, infile) 110 111 def testParseSignatures_CommentsIgnored(self): 112 my_sigs = [] 113 my_sigs.append('# a comment') 114 my_sigs.append(SIMPLE_SIGNATURES[0][0]) 115 my_sigs.append('# another comment') 116 my_sigs.append(SIMPLE_SIGNATURES[0][0]) 117 my_sigs.append('# a third comment') 118 my_sigs.append(SIMPLE_SIGNATURES[0][0]) 119 120 file_contents = '\n'.join(my_sigs) 121 infile = StringIO.StringIO(file_contents) 122 signatures = gs.ParseSignatures(infile) 123 self.assertEqual(3, len(signatures)) 124 125 126class WindowsLibUnittest(unittest.TestCase): 127 def testWriteWindowsDefFile(self): 128 module_name = 'my_module-1' 129 signatures = [sig[1] for sig in SIMPLE_SIGNATURES] 130 outfile = StringIO.StringIO() 131 gs.WriteWindowsDefFile(module_name, signatures, outfile) 132 contents = outfile.getvalue() 133 134 # Check that the file header is correct. 135 self.assertTrue(contents.startswith("""LIBRARY %s 136EXPORTS 137""" % module_name)) 138 139 # Check that the signatures were exported. 140 for sig in signatures: 141 pattern = '\n %s\n' % sig['name'] 142 self.assertTrue(re.search(pattern, contents), 143 msg='Expected match of "%s" in %s' % (pattern, contents)) 144 145 def testQuietRun(self): 146 output = StringIO.StringIO() 147 gs.QuietRun([sys.executable, 148 '-c', 'print "line 1 and suffix\\nline 2"'], 149 write_to=output) 150 self.assertEqual('line 1 and suffix\nline 2\n', output.getvalue()) 151 152 output = StringIO.StringIO() 153 gs.QuietRun([sys.executable, 154 '-c', 'print "line 1 and suffix\\nline 2"'], 155 filter='line 1', write_to=output) 156 self.assertEqual('line 2\n', output.getvalue()) 157 158 159class PosixStubWriterUnittest(unittest.TestCase): 160 def setUp(self): 161 self.module_name = 'my_module-1' 162 self.signatures = [sig[1] for sig in SIMPLE_SIGNATURES] 163 self.out_dir = 'out_dir' 164 self.writer = gs.PosixStubWriter(self.module_name, self.signatures) 165 166 def testEnumName(self): 167 self.assertEqual('kModuleMy_module1', 168 gs.PosixStubWriter.EnumName(self.module_name)) 169 170 def testIsInitializedName(self): 171 self.assertEqual('IsMy_module1Initialized', 172 gs.PosixStubWriter.IsInitializedName(self.module_name)) 173 174 def testInitializeModuleName(self): 175 self.assertEqual( 176 'InitializeMy_module1', 177 gs.PosixStubWriter.InitializeModuleName(self.module_name)) 178 179 def testUninitializeModuleName(self): 180 self.assertEqual( 181 'UninitializeMy_module1', 182 gs.PosixStubWriter.UninitializeModuleName(self.module_name)) 183 184 def testStubFunctionPointer(self): 185 self.assertEqual( 186 'static int (*foo_ptr)(int a) = NULL;', 187 gs.PosixStubWriter.StubFunctionPointer(SIMPLE_SIGNATURES[0][1])) 188 189 def testStubFunction(self): 190 # Test for a signature with a return value and a parameter. 191 self.assertEqual("""extern int foo(int a) __attribute__((weak)); 192int foo(int a) { 193 return foo_ptr(a); 194}""", gs.PosixStubWriter.StubFunction(SIMPLE_SIGNATURES[0][1])) 195 196 # Test for a signature with a void return value and no parameters. 197 self.assertEqual("""extern void waldo(void) __attribute__((weak)); 198void waldo(void) { 199 waldo_ptr(); 200}""", gs.PosixStubWriter.StubFunction(SIMPLE_SIGNATURES[4][1])) 201 202 def testWriteImplemenationContents(self): 203 outfile = StringIO.StringIO() 204 self.writer.WriteImplementationContents('my_namespace', outfile) 205 contents = outfile.getvalue() 206 207 # Verify namespace exists somewhere. 208 self.assertTrue(contents.find('namespace my_namespace {') != -1) 209 210 # Verify that each signature has an _ptr and a function call in the file. 211 # Check that the signatures were exported. 212 for sig in self.signatures: 213 decl = gs.PosixStubWriter.StubFunctionPointer(sig) 214 self.assertTrue(contents.find(decl) != -1, 215 msg='Expected "%s" in %s' % (decl, contents)) 216 217 # Verify that each signature has an stub function generated for it. 218 for sig in self.signatures: 219 decl = gs.PosixStubWriter.StubFunction(sig) 220 self.assertTrue(contents.find(decl) != -1, 221 msg='Expected "%s" in %s' % (decl, contents)) 222 223 # Find module initializer functions. Make sure all 3 exist. 224 decl = gs.PosixStubWriter.InitializeModuleName(self.module_name) 225 self.assertTrue(contents.find(decl) != -1, 226 msg='Expected "%s" in %s' % (decl, contents)) 227 decl = gs.PosixStubWriter.UninitializeModuleName(self.module_name) 228 self.assertTrue(contents.find(decl) != -1, 229 msg='Expected "%s" in %s' % (decl, contents)) 230 decl = gs.PosixStubWriter.IsInitializedName(self.module_name) 231 self.assertTrue(contents.find(decl) != -1, 232 msg='Expected "%s" in %s' % (decl, contents)) 233 234 def testWriteHeaderContents(self): 235 # Data for header generation. 236 module_names = ['oneModule', 'twoModule'] 237 238 # Make the header. 239 outfile = StringIO.StringIO() 240 self.writer.WriteHeaderContents(module_names, 'my_namespace', 'GUARD_', 241 outfile) 242 contents = outfile.getvalue() 243 244 # Check for namespace and header guard. 245 self.assertTrue(contents.find('namespace my_namespace {') != -1) 246 self.assertTrue(contents.find('#ifndef GUARD_') != -1) 247 248 # Check for umbrella initializer. 249 self.assertTrue(contents.find('InitializeStubs(') != -1) 250 251 # Check per-module declarations. 252 for name in module_names: 253 # Check for enums. 254 decl = gs.PosixStubWriter.EnumName(name) 255 self.assertTrue(contents.find(decl) != -1, 256 msg='Expected "%s" in %s' % (decl, contents)) 257 258 # Check for module initializer functions. 259 decl = gs.PosixStubWriter.IsInitializedName(name) 260 self.assertTrue(contents.find(decl) != -1, 261 msg='Expected "%s" in %s' % (decl, contents)) 262 decl = gs.PosixStubWriter.InitializeModuleName(name) 263 self.assertTrue(contents.find(decl) != -1, 264 msg='Expected "%s" in %s' % (decl, contents)) 265 decl = gs.PosixStubWriter.UninitializeModuleName(name) 266 self.assertTrue(contents.find(decl) != -1, 267 msg='Expected "%s" in %s' % (decl, contents)) 268 269 def testWriteUmbrellaInitializer(self): 270 # Data for header generation. 271 module_names = ['oneModule', 'twoModule'] 272 273 # Make the header. 274 outfile = StringIO.StringIO() 275 self.writer.WriteUmbrellaInitializer(module_names, 'my_namespace', outfile) 276 contents = outfile.getvalue() 277 278 # Check for umbrella initializer declaration. 279 self.assertTrue(contents.find('bool InitializeStubs(') != -1) 280 281 # If the umbrella initializer is correctly written, each module will have 282 # its initializer called, checked, and uninitialized on failure. Sanity 283 # check that here. 284 for name in module_names: 285 # Check for module initializer functions. 286 decl = gs.PosixStubWriter.IsInitializedName(name) 287 self.assertTrue(contents.find(decl) != -1, 288 msg='Expected "%s" in %s' % (decl, contents)) 289 decl = gs.PosixStubWriter.InitializeModuleName(name) 290 self.assertTrue(contents.find(decl) != -1, 291 msg='Expected "%s" in %s' % (decl, contents)) 292 decl = gs.PosixStubWriter.UninitializeModuleName(name) 293 self.assertTrue(contents.find(decl) != -1, 294 msg='Expected "%s" in %s' % (decl, contents)) 295 296if __name__ == '__main__': 297 unittest.main() 298