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.
6 """Unittest for the generate_stubs.py.
8 Since generate_stubs.py is a code generator, it is hard to do a very good
9 test. Instead of creating a golden-file test, which might be flakey, this
10 test elects instead to verify that various components "exist" within the
11 generated file as a sanity check. In particular, there is a simple hit
12 test to make sure that umbrella functions, etc., do try and include every
13 function they are responsible for invoking. Missing an invocation is quite
16 There is no attempt to verify ordering of different components, or whether
17 or not those components are going to parse incorrectly because of prior
18 errors or positioning. Most of that should be caught really fast anyways
19 during any attempt to use a badly behaving script.
22 import generate_stubs
as gs
29 def _MakeSignature(return_type
, name
, params
):
30 return {'return_type': return_type
,
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'])),
46 ('const struct name *foo(int a, struct Test* b); ',
47 _MakeSignature('const struct name *',
49 ['int a', 'struct Test* b'])),
50 ('const struct name &foo(int a, struct Test* b);',
51 _MakeSignature('const struct name &',
53 ['int a', 'struct Test* b'])),
54 ('const struct name &_foo(int a, struct Test* b);',
55 _MakeSignature('const struct name &',
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',
62 ['int a', 'struct Test* b']))
65 INVALID_SIGNATURES
= ['I am bad', 'Seriously bad(', ';;;']
68 class GenerateStubModuleFunctionsUnittest(unittest
.TestCase
):
69 def testExtractModuleName(self
):
70 self
.assertEqual('somefile-2', gs
.ExtractModuleName('somefile-2.ext'))
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
))
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
))
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],
90 SIMPLE_SIGNATURES
[i
][0]))
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
))
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],
104 TRICKY_SIGNATURES
[i
][0]))
106 def testParseSignatures_InvalidSignatures(self
):
107 for i
in INVALID_SIGNATURES
:
108 infile
= StringIO
.StringIO(i
)
109 self
.assertRaises(gs
.BadSignatureError
, gs
.ParseSignatures
, infile
)
111 def testParseSignatures_CommentsIgnored(self
):
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 my_sigs
.append('// a fourth comment')
120 my_sigs
.append(SIMPLE_SIGNATURES
[0][0])
122 my_sigs
.append(SIMPLE_SIGNATURES
[0][0])
124 file_contents
= '\n'.join(my_sigs
)
125 infile
= StringIO
.StringIO(file_contents
)
126 signatures
= gs
.ParseSignatures(infile
)
127 self
.assertEqual(5, len(signatures
))
130 class WindowsLibUnittest(unittest
.TestCase
):
131 def testWriteWindowsDefFile(self
):
132 module_name
= 'my_module-1'
133 signatures
= [sig
[1] for sig
in SIMPLE_SIGNATURES
]
134 outfile
= StringIO
.StringIO()
135 gs
.WriteWindowsDefFile(module_name
, signatures
, outfile
)
136 contents
= outfile
.getvalue()
138 # Check that the file header is correct.
139 self
.assertTrue(contents
.startswith("""LIBRARY %s
143 # Check that the signatures were exported.
144 for sig
in signatures
:
145 pattern
= '\n %s\n' % sig
['name']
146 self
.assertTrue(re
.search(pattern
, contents
),
147 msg
='Expected match of "%s" in %s' % (pattern
, contents
))
149 def testQuietRun(self
):
150 output
= StringIO
.StringIO()
151 gs
.QuietRun([sys
.executable
,
152 '-c', 'print "line 1 and suffix\\nline 2"'],
154 self
.assertEqual('line 1 and suffix\nline 2\n', output
.getvalue())
156 output
= StringIO
.StringIO()
157 gs
.QuietRun([sys
.executable
,
158 '-c', 'print "line 1 and suffix\\nline 2"'],
159 filter='line 1', write_to
=output
)
160 self
.assertEqual('line 2\n', output
.getvalue())
163 class PosixStubWriterUnittest(unittest
.TestCase
):
165 self
.module_name
= 'my_module-1'
166 self
.signatures
= [sig
[1] for sig
in SIMPLE_SIGNATURES
]
167 self
.out_dir
= 'out_dir'
168 self
.writer
= gs
.PosixStubWriter(self
.module_name
, self
.signatures
)
170 def testEnumName(self
):
171 self
.assertEqual('kModuleMy_module1',
172 gs
.PosixStubWriter
.EnumName(self
.module_name
))
174 def testIsInitializedName(self
):
175 self
.assertEqual('IsMy_module1Initialized',
176 gs
.PosixStubWriter
.IsInitializedName(self
.module_name
))
178 def testInitializeModuleName(self
):
180 'InitializeMy_module1',
181 gs
.PosixStubWriter
.InitializeModuleName(self
.module_name
))
183 def testUninitializeModuleName(self
):
185 'UninitializeMy_module1',
186 gs
.PosixStubWriter
.UninitializeModuleName(self
.module_name
))
188 def testStubFunctionPointer(self
):
190 'static int (*foo_ptr)(int a) = NULL;',
191 gs
.PosixStubWriter
.StubFunctionPointer(SIMPLE_SIGNATURES
[0][1]))
193 def testStubFunction(self
):
194 # Test for a signature with a return value and a parameter.
195 self
.assertEqual("""extern int foo(int a) __attribute__((weak));
198 }""", gs
.PosixStubWriter
.StubFunction(SIMPLE_SIGNATURES
[0][1]))
200 # Test for a signature with a void return value and no parameters.
201 self
.assertEqual("""extern void waldo(void) __attribute__((weak));
204 }""", gs
.PosixStubWriter
.StubFunction(SIMPLE_SIGNATURES
[4][1]))
206 def testWriteImplemenationContents(self
):
207 outfile
= StringIO
.StringIO()
208 self
.writer
.WriteImplementationContents('my_namespace', outfile
)
209 contents
= outfile
.getvalue()
211 # Verify namespace exists somewhere.
212 self
.assertTrue(contents
.find('namespace my_namespace {') != -1)
214 # Verify that each signature has an _ptr and a function call in the file.
215 # Check that the signatures were exported.
216 for sig
in self
.signatures
:
217 decl
= gs
.PosixStubWriter
.StubFunctionPointer(sig
)
218 self
.assertTrue(contents
.find(decl
) != -1,
219 msg
='Expected "%s" in %s' % (decl
, contents
))
221 # Verify that each signature has an stub function generated for it.
222 for sig
in self
.signatures
:
223 decl
= gs
.PosixStubWriter
.StubFunction(sig
)
224 self
.assertTrue(contents
.find(decl
) != -1,
225 msg
='Expected "%s" in %s' % (decl
, contents
))
227 # Find module initializer functions. Make sure all 3 exist.
228 decl
= gs
.PosixStubWriter
.InitializeModuleName(self
.module_name
)
229 self
.assertTrue(contents
.find(decl
) != -1,
230 msg
='Expected "%s" in %s' % (decl
, contents
))
231 decl
= gs
.PosixStubWriter
.UninitializeModuleName(self
.module_name
)
232 self
.assertTrue(contents
.find(decl
) != -1,
233 msg
='Expected "%s" in %s' % (decl
, contents
))
234 decl
= gs
.PosixStubWriter
.IsInitializedName(self
.module_name
)
235 self
.assertTrue(contents
.find(decl
) != -1,
236 msg
='Expected "%s" in %s' % (decl
, contents
))
238 def testWriteHeaderContents(self
):
239 # Data for header generation.
240 module_names
= ['oneModule', 'twoModule']
243 outfile
= StringIO
.StringIO()
244 self
.writer
.WriteHeaderContents(module_names
, 'my_namespace', 'GUARD_',
246 contents
= outfile
.getvalue()
248 # Check for namespace and header guard.
249 self
.assertTrue(contents
.find('namespace my_namespace {') != -1)
250 self
.assertTrue(contents
.find('#ifndef GUARD_') != -1)
252 # Check for umbrella initializer.
253 self
.assertTrue(contents
.find('InitializeStubs(') != -1)
255 # Check per-module declarations.
256 for name
in module_names
:
258 decl
= gs
.PosixStubWriter
.EnumName(name
)
259 self
.assertTrue(contents
.find(decl
) != -1,
260 msg
='Expected "%s" in %s' % (decl
, contents
))
262 # Check for module initializer functions.
263 decl
= gs
.PosixStubWriter
.IsInitializedName(name
)
264 self
.assertTrue(contents
.find(decl
) != -1,
265 msg
='Expected "%s" in %s' % (decl
, contents
))
266 decl
= gs
.PosixStubWriter
.InitializeModuleName(name
)
267 self
.assertTrue(contents
.find(decl
) != -1,
268 msg
='Expected "%s" in %s' % (decl
, contents
))
269 decl
= gs
.PosixStubWriter
.UninitializeModuleName(name
)
270 self
.assertTrue(contents
.find(decl
) != -1,
271 msg
='Expected "%s" in %s' % (decl
, contents
))
273 def testWriteUmbrellaInitializer(self
):
274 # Data for header generation.
275 module_names
= ['oneModule', 'twoModule']
278 outfile
= StringIO
.StringIO()
279 self
.writer
.WriteUmbrellaInitializer(module_names
, 'my_namespace', outfile
)
280 contents
= outfile
.getvalue()
282 # Check for umbrella initializer declaration.
283 self
.assertTrue(contents
.find('bool InitializeStubs(') != -1)
285 # If the umbrella initializer is correctly written, each module will have
286 # its initializer called, checked, and uninitialized on failure. Sanity
288 for name
in module_names
:
289 # Check for module initializer functions.
290 decl
= gs
.PosixStubWriter
.IsInitializedName(name
)
291 self
.assertTrue(contents
.find(decl
) != -1,
292 msg
='Expected "%s" in %s' % (decl
, contents
))
293 decl
= gs
.PosixStubWriter
.InitializeModuleName(name
)
294 self
.assertTrue(contents
.find(decl
) != -1,
295 msg
='Expected "%s" in %s' % (decl
, contents
))
296 decl
= gs
.PosixStubWriter
.UninitializeModuleName(name
)
297 self
.assertTrue(contents
.find(decl
) != -1,
298 msg
='Expected "%s" in %s' % (decl
, contents
))
300 if __name__
== '__main__':