• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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