298 lines
12 KiB
Python
Executable File
298 lines
12 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Unittest for the generate_stubs.py.
|
|
|
|
Since generate_stubs.py is a code generator, it is hard to do a very good
|
|
test. Instead of creating a golden-file test, which might be flakey, this
|
|
test elects instead to verify that various components "exist" within the
|
|
generated file as a sanity check. In particular, there is a simple hit
|
|
test to make sure that umbrella functions, etc., do try and include every
|
|
function they are responsible for invoking. Missing an invocation is quite
|
|
easily missed.
|
|
|
|
There is no attempt to verify ordering of different components, or whether
|
|
or not those components are going to parse incorrectly because of prior
|
|
errors or positioning. Most of that should be caught really fast anyways
|
|
during any attempt to use a badly behaving script.
|
|
"""
|
|
|
|
import generate_stubs as gs
|
|
import re
|
|
import StringIO
|
|
import sys
|
|
import unittest
|
|
|
|
|
|
def _MakeSignature(return_type, name, params):
|
|
return {'return_type': return_type,
|
|
'name': name,
|
|
'params': params}
|
|
|
|
|
|
SIMPLE_SIGNATURES = [
|
|
('int foo(int a)', _MakeSignature('int', 'foo', ['int a'])),
|
|
('int bar(int a, double b)', _MakeSignature('int', 'bar',
|
|
['int a', 'double b'])),
|
|
('int baz(void)', _MakeSignature('int', 'baz', ['void'])),
|
|
('void quux(void)', _MakeSignature('void', 'quux', ['void'])),
|
|
('void waldo(void);', _MakeSignature('void', 'waldo', ['void'])),
|
|
('int corge(void);', _MakeSignature('int', 'corge', ['void'])),
|
|
]
|
|
|
|
TRICKY_SIGNATURES = [
|
|
('const struct name *foo(int a, struct Test* b); ',
|
|
_MakeSignature('const struct name *',
|
|
'foo',
|
|
['int a', 'struct Test* b'])),
|
|
('const struct name &foo(int a, struct Test* b);',
|
|
_MakeSignature('const struct name &',
|
|
'foo',
|
|
['int a', 'struct Test* b'])),
|
|
('const struct name &_foo(int a, struct Test* b);',
|
|
_MakeSignature('const struct name &',
|
|
'_foo',
|
|
['int a', 'struct Test* b'])),
|
|
('struct name const * const _foo(int a, struct Test* b) '
|
|
'__attribute__((inline));',
|
|
_MakeSignature('struct name const * const',
|
|
'_foo',
|
|
['int a', 'struct Test* b']))
|
|
]
|
|
|
|
INVALID_SIGNATURES = ['I am bad', 'Seriously bad(', ';;;']
|
|
|
|
|
|
class GenerateStubModuleFunctionsUnittest(unittest.TestCase):
|
|
def testExtractModuleName(self):
|
|
self.assertEqual('somefile-2', gs.ExtractModuleName('somefile-2.ext'))
|
|
|
|
def testParseSignatures_EmptyFile(self):
|
|
# Empty file just generates empty signatures.
|
|
infile = StringIO.StringIO()
|
|
signatures = gs.ParseSignatures(infile)
|
|
self.assertEqual(0, len(signatures))
|
|
|
|
def testParseSignatures_SimpleSignatures(self):
|
|
file_contents = '\n'.join([x[0] for x in SIMPLE_SIGNATURES])
|
|
infile = StringIO.StringIO(file_contents)
|
|
signatures = gs.ParseSignatures(infile)
|
|
self.assertEqual(len(SIMPLE_SIGNATURES), len(signatures))
|
|
|
|
# We assume signatures are in order.
|
|
for i in xrange(len(SIMPLE_SIGNATURES)):
|
|
self.assertEqual(SIMPLE_SIGNATURES[i][1], signatures[i],
|
|
msg='Expected %s\nActual %s\nFor %s' %
|
|
(SIMPLE_SIGNATURES[i][1],
|
|
signatures[i],
|
|
SIMPLE_SIGNATURES[i][0]))
|
|
|
|
def testParseSignatures_TrickySignatures(self):
|
|
file_contents = '\n'.join([x[0] for x in TRICKY_SIGNATURES])
|
|
infile = StringIO.StringIO(file_contents)
|
|
signatures = gs.ParseSignatures(infile)
|
|
self.assertEqual(len(TRICKY_SIGNATURES), len(signatures))
|
|
|
|
# We assume signatures are in order.
|
|
for i in xrange(len(TRICKY_SIGNATURES)):
|
|
self.assertEqual(TRICKY_SIGNATURES[i][1], signatures[i],
|
|
msg='Expected %s\nActual %s\nFor %s' %
|
|
(TRICKY_SIGNATURES[i][1],
|
|
signatures[i],
|
|
TRICKY_SIGNATURES[i][0]))
|
|
|
|
def testParseSignatures_InvalidSignatures(self):
|
|
for i in INVALID_SIGNATURES:
|
|
infile = StringIO.StringIO(i)
|
|
self.assertRaises(gs.BadSignatureError, gs.ParseSignatures, infile)
|
|
|
|
def testParseSignatures_CommentsIgnored(self):
|
|
my_sigs = []
|
|
my_sigs.append('# a comment')
|
|
my_sigs.append(SIMPLE_SIGNATURES[0][0])
|
|
my_sigs.append('# another comment')
|
|
my_sigs.append(SIMPLE_SIGNATURES[0][0])
|
|
my_sigs.append('# a third comment')
|
|
my_sigs.append(SIMPLE_SIGNATURES[0][0])
|
|
|
|
file_contents = '\n'.join(my_sigs)
|
|
infile = StringIO.StringIO(file_contents)
|
|
signatures = gs.ParseSignatures(infile)
|
|
self.assertEqual(3, len(signatures))
|
|
|
|
|
|
class WindowsLibUnittest(unittest.TestCase):
|
|
def testWriteWindowsDefFile(self):
|
|
module_name = 'my_module-1'
|
|
signatures = [sig[1] for sig in SIMPLE_SIGNATURES]
|
|
outfile = StringIO.StringIO()
|
|
gs.WriteWindowsDefFile(module_name, signatures, outfile)
|
|
contents = outfile.getvalue()
|
|
|
|
# Check that the file header is correct.
|
|
self.assertTrue(contents.startswith("""LIBRARY %s
|
|
EXPORTS
|
|
""" % module_name))
|
|
|
|
# Check that the signatures were exported.
|
|
for sig in signatures:
|
|
pattern = '\n %s\n' % sig['name']
|
|
self.assertTrue(re.search(pattern, contents),
|
|
msg='Expected match of "%s" in %s' % (pattern, contents))
|
|
|
|
def testQuietRun(self):
|
|
output = StringIO.StringIO()
|
|
gs.QuietRun([sys.executable,
|
|
'-c', 'print "line 1 and suffix\\nline 2"'],
|
|
write_to=output)
|
|
self.assertEqual('line 1 and suffix\nline 2\n', output.getvalue())
|
|
|
|
output = StringIO.StringIO()
|
|
gs.QuietRun([sys.executable,
|
|
'-c', 'print "line 1 and suffix\\nline 2"'],
|
|
filter='line 1', write_to=output)
|
|
self.assertEqual('line 2\n', output.getvalue())
|
|
|
|
|
|
class PosixStubWriterUnittest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.module_name = 'my_module-1'
|
|
self.signatures = [sig[1] for sig in SIMPLE_SIGNATURES]
|
|
self.out_dir = 'out_dir'
|
|
self.writer = gs.PosixStubWriter(self.module_name, self.signatures)
|
|
|
|
def testEnumName(self):
|
|
self.assertEqual('kModuleMy_module1',
|
|
gs.PosixStubWriter.EnumName(self.module_name))
|
|
|
|
def testIsInitializedName(self):
|
|
self.assertEqual('IsMy_module1Initialized',
|
|
gs.PosixStubWriter.IsInitializedName(self.module_name))
|
|
|
|
def testInitializeModuleName(self):
|
|
self.assertEqual(
|
|
'InitializeMy_module1',
|
|
gs.PosixStubWriter.InitializeModuleName(self.module_name))
|
|
|
|
def testUninitializeModuleName(self):
|
|
self.assertEqual(
|
|
'UninitializeMy_module1',
|
|
gs.PosixStubWriter.UninitializeModuleName(self.module_name))
|
|
|
|
def testStubFunctionPointer(self):
|
|
self.assertEqual(
|
|
'static int (*foo_ptr)(int a) = NULL;',
|
|
gs.PosixStubWriter.StubFunctionPointer(SIMPLE_SIGNATURES[0][1]))
|
|
|
|
def testStubFunction(self):
|
|
# Test for a signature with a return value and a parameter.
|
|
self.assertEqual("""extern int foo(int a) __attribute__((weak));
|
|
int foo(int a) {
|
|
return foo_ptr(a);
|
|
}""", gs.PosixStubWriter.StubFunction(SIMPLE_SIGNATURES[0][1]))
|
|
|
|
# Test for a signature with a void return value and no parameters.
|
|
self.assertEqual("""extern void waldo(void) __attribute__((weak));
|
|
void waldo(void) {
|
|
waldo_ptr();
|
|
}""", gs.PosixStubWriter.StubFunction(SIMPLE_SIGNATURES[4][1]))
|
|
|
|
def testWriteImplemenationContents(self):
|
|
outfile = StringIO.StringIO()
|
|
self.writer.WriteImplementationContents('my_namespace', outfile)
|
|
contents = outfile.getvalue()
|
|
|
|
# Verify namespace exists somewhere.
|
|
self.assertTrue(contents.find('namespace my_namespace {') != -1)
|
|
|
|
# Verify that each signature has an _ptr and a function call in the file.
|
|
# Check that the signatures were exported.
|
|
for sig in self.signatures:
|
|
decl = gs.PosixStubWriter.StubFunctionPointer(sig)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
|
|
# Verify that each signature has an stub function generated for it.
|
|
for sig in self.signatures:
|
|
decl = gs.PosixStubWriter.StubFunction(sig)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
|
|
# Find module initializer functions. Make sure all 3 exist.
|
|
decl = gs.PosixStubWriter.InitializeModuleName(self.module_name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
decl = gs.PosixStubWriter.UninitializeModuleName(self.module_name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
decl = gs.PosixStubWriter.IsInitializedName(self.module_name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
|
|
def testWriteHeaderContents(self):
|
|
# Data for header generation.
|
|
module_names = ['oneModule', 'twoModule']
|
|
|
|
# Make the header.
|
|
outfile = StringIO.StringIO()
|
|
self.writer.WriteHeaderContents(module_names, 'my_namespace', 'GUARD_',
|
|
outfile)
|
|
contents = outfile.getvalue()
|
|
|
|
# Check for namespace and header guard.
|
|
self.assertTrue(contents.find('namespace my_namespace {') != -1)
|
|
self.assertTrue(contents.find('#ifndef GUARD_') != -1)
|
|
|
|
# Check for umbrella initializer.
|
|
self.assertTrue(contents.find('InitializeStubs(') != -1)
|
|
|
|
# Check per-module declarations.
|
|
for name in module_names:
|
|
# Check for enums.
|
|
decl = gs.PosixStubWriter.EnumName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
|
|
# Check for module initializer functions.
|
|
decl = gs.PosixStubWriter.IsInitializedName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
decl = gs.PosixStubWriter.InitializeModuleName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
decl = gs.PosixStubWriter.UninitializeModuleName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
|
|
def testWriteUmbrellaInitializer(self):
|
|
# Data for header generation.
|
|
module_names = ['oneModule', 'twoModule']
|
|
|
|
# Make the header.
|
|
outfile = StringIO.StringIO()
|
|
self.writer.WriteUmbrellaInitializer(module_names, 'my_namespace', outfile)
|
|
contents = outfile.getvalue()
|
|
|
|
# Check for umbrella initializer declaration.
|
|
self.assertTrue(contents.find('bool InitializeStubs(') != -1)
|
|
|
|
# If the umbrella initializer is correctly written, each module will have
|
|
# its initializer called, checked, and uninitialized on failure. Sanity
|
|
# check that here.
|
|
for name in module_names:
|
|
# Check for module initializer functions.
|
|
decl = gs.PosixStubWriter.IsInitializedName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
decl = gs.PosixStubWriter.InitializeModuleName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
decl = gs.PosixStubWriter.UninitializeModuleName(name)
|
|
self.assertTrue(contents.find(decl) != -1,
|
|
msg='Expected "%s" in %s' % (decl, contents))
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|