You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
10 KiB
256 lines
10 KiB
#!/usr/bin/python |
|
|
|
# |
|
# Copyright (C) 2014 The Android Open Source Project |
|
# |
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
# you may not use this file except in compliance with the License. |
|
# You may obtain a copy of the License at |
|
# |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
|
# |
|
# Unless required by applicable law or agreed to in writing, software |
|
# distributed under the License is distributed on an "AS IS" BASIS, |
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
# See the License for the specific language governing permissions and |
|
# limitations under the License. |
|
# |
|
|
|
"""Unit tests for the TPM 2.0 code generator.""" |
|
|
|
from __future__ import print_function |
|
|
|
import StringIO |
|
import unittest |
|
|
|
import generator |
|
|
|
|
|
class TestGenerators(unittest.TestCase): |
|
"""Test generator classes.""" |
|
|
|
def testTypedef(self): |
|
"""Test generation of typedefs and dependencies.""" |
|
typedef = generator.Typedef('int', 'INT') |
|
defined_types = set(['int']) |
|
typemap = {} |
|
out_file = StringIO.StringIO() |
|
# Expect this to just write the typedef. |
|
typedef.OutputForward(out_file, defined_types, typemap) |
|
# Expect this to know it has already been written. |
|
typedef.Output(out_file, defined_types, typemap) |
|
self.assertEqual(out_file.getvalue(), 'typedef int INT;\n') |
|
self.assertIn('INT', defined_types) |
|
typedef2 = generator.Typedef('TYPE1', 'TYPE2') |
|
typemap = {'TYPE1': generator.Structure('TYPE1', False)} |
|
defined_types = set([]) |
|
out_file2 = StringIO.StringIO() |
|
# Expect this to write first TYPE1 forward then TYPE2 typedef. |
|
typedef2.Output(out_file2, defined_types, typemap) |
|
output_re = r'struct TYPE1;\s+typedef TYPE1 TYPE2;\s+' |
|
self.assertRegexpMatches(out_file2.getvalue(), output_re) |
|
self.assertIn('TYPE2', defined_types) |
|
out_file.close() |
|
out_file2.close() |
|
|
|
def testTypedefSerialize(self): |
|
"""Test generation of serialization code for typedefs.""" |
|
serialized_types = set(['int']) |
|
typedef = generator.Typedef('int', 'INT') |
|
typedef2 = generator.Typedef('INT', 'INT2') |
|
typemap = {'INT': typedef} |
|
out_file = StringIO.StringIO() |
|
typedef2.OutputSerialize(out_file, serialized_types, typemap) |
|
self.assertIn('INT', serialized_types) |
|
self.assertIn('INT2', serialized_types) |
|
out_file.close() |
|
|
|
def testConstant(self): |
|
"""Test generation of constant definitions and type dependencies.""" |
|
constant = generator.Constant('INT', 'test', '1') |
|
typemap = {'INT': generator.Structure('INT', False)} |
|
defined_types = set([]) |
|
out_file = StringIO.StringIO() |
|
constant.Output(out_file, defined_types, typemap) |
|
output_re = r'struct INT;\s+const INT test = 1;\s+' |
|
self.assertRegexpMatches(out_file.getvalue(), output_re) |
|
out_file.close() |
|
|
|
def testStructure(self): |
|
"""Test generation of structure declarations and field dependencies.""" |
|
struct = generator.Structure('STRUCT', False) |
|
struct.AddField('int', 'i') |
|
struct.AddDependency('DEPEND') |
|
union = generator.Structure('UNION', True) |
|
union.AddField('STRUCT', 'inner') |
|
depend = generator.Structure('DEPEND', False) |
|
defined_types = set(['int']) |
|
out_file = StringIO.StringIO() |
|
typemap = {'STRUCT': struct, 'DEPEND': depend} |
|
# Only output |union|, this will test the dependency logic. |
|
union.OutputForward(out_file, defined_types, typemap) |
|
union.OutputForward(out_file, defined_types, typemap) |
|
union.Output(out_file, defined_types, typemap) |
|
output_re = r'union UNION;\s+struct DEPEND {\s+};\s+' |
|
output_re += r'struct STRUCT {\s+int i;\s+};\s+' |
|
output_re += r'union UNION {\s+STRUCT inner;\s+};\s+' |
|
self.assertRegexpMatches(out_file.getvalue(), output_re) |
|
for t in ('STRUCT', 'DEPEND', 'UNION'): |
|
self.assertIn(t, defined_types) |
|
# Test serialize / parse code generation. |
|
out_file.close() |
|
|
|
def testStructSerialize(self): |
|
"""Test generation of serialization code for typedefs.""" |
|
serialized_types = set(['int', 'FOO', 'BAR', 'TPMI_ALG_SYM_OBJECT']) |
|
struct = generator.Structure('TEST_STRUCT', False) |
|
struct.fields = [('TPMI_ALG_SYM_OBJECT', 'selector'), |
|
('TPMU_SYM_MODE', 'mode'), |
|
('int', 'sizeOfFoo'), |
|
('int', 'foo[FOO_MAX]')] |
|
# Choose TPMU_SYM_MODE because it exists in the selectors definition and it |
|
# has few fields. |
|
union = generator.Structure('TPMU_SYM_MODE', True) |
|
union.fields = [('FOO', 'aes'), ('BAR', 'sm4')] |
|
typemap = {'TPMU_SYM_MODE': union} |
|
out_file = StringIO.StringIO() |
|
struct.OutputSerialize(out_file, serialized_types, typemap) |
|
self.assertIn('TPMU_SYM_MODE', serialized_types) |
|
self.assertIn('TEST_STRUCT', serialized_types) |
|
out_file.close() |
|
|
|
def testDefine(self): |
|
"""Test generation of preprocessor defines.""" |
|
define = generator.Define('name', 'value') |
|
out_file = StringIO.StringIO() |
|
define.Output(out_file) |
|
output_re = r'#if !defined\(name\)\s+#define name value\s+#endif\s+' |
|
self.assertRegexpMatches(out_file.getvalue(), output_re) |
|
out_file.close() |
|
|
|
def _MakeArg(self, arg_type, arg_name): |
|
return {'type': arg_type, |
|
'name': arg_name, |
|
'command_code': None, |
|
'description': None} |
|
|
|
def testCommand(self): |
|
"""Test generation of command methods and callbacks.""" |
|
command = generator.Command('TPM2_Test') |
|
command.request_args = [self._MakeArg('int', 'input')] |
|
command.response_args = [self._MakeArg('char', 'output')] |
|
out_file = StringIO.StringIO() |
|
command.OutputDeclarations(out_file) |
|
expected_callback = """typedef base::Callback<void( |
|
TPM_RC response_code, |
|
const char& output)> TestResponse;""" |
|
self.assertIn(expected_callback, out_file.getvalue()) |
|
expected_serialize = """static TPM_RC SerializeCommand_Test( |
|
const int& input, |
|
std::string* serialized_command, |
|
AuthorizationDelegate* authorization_delegate);""" |
|
self.assertIn(expected_serialize, out_file.getvalue()) |
|
expected_parse = """static TPM_RC ParseResponse_Test( |
|
const std::string& response, |
|
char* output, |
|
AuthorizationDelegate* authorization_delegate);""" |
|
self.assertIn(expected_parse, out_file.getvalue()) |
|
expected_async = """virtual void Test( |
|
const int& input, |
|
AuthorizationDelegate* authorization_delegate, |
|
const TestResponse& callback);""" |
|
self.assertIn(expected_async, out_file.getvalue()) |
|
expected_sync = """virtual TPM_RC TestSync( |
|
const int& input, |
|
char* output, |
|
AuthorizationDelegate* authorization_delegate);""" |
|
self.assertIn(expected_sync, out_file.getvalue()) |
|
out_file.close() |
|
|
|
|
|
class TestParsers(unittest.TestCase): |
|
"""Test parser classes.""" |
|
|
|
FAKE_TYPEDEF = '_BEGIN_TYPES\n_OLD_TYPE type1\n_NEW_TYPE type2\n_END\n' |
|
FAKE_CONSTANT = ('_BEGIN_CONSTANTS\n_CONSTANTS (base_type) const_type\n' |
|
'_TYPE base_type\n_NAME const_name\n_VALUE const_value\n' |
|
'_END\n') |
|
FAKE_STRUCTURE = ('_BEGIN_STRUCTURES\n_STRUCTURE struct_type\n' |
|
'_TYPE field_type\n' |
|
'_NAME field_name[sizeof(depend_type)]\n_END\n') |
|
FAKE_DEFINE = '_BEGIN_DEFINES\n_NAME define_name\n_VALUE define_value\n_END' |
|
FAKE_COMMAND = ('_BEGIN\n_INPUT_START TPM2_Test\n' |
|
'_TYPE UINT32\n_NAME commandSize\n' |
|
'_TYPE TPM_CC\n_NAME commandCode\n_COMMENT TPM_CC_Test\n' |
|
'_TYPE UINT16\n_NAME input\n' |
|
'_OUTPUT_START TPM2_Test\n_END\n') |
|
|
|
def testStructureParserWithBadData(self): |
|
"""Test the structure parser with invalid data.""" |
|
input_data = 'bad_data' |
|
in_file = StringIO.StringIO(input_data) |
|
parser = generator.StructureParser(in_file) |
|
types, constants, structs, defines, typemap = parser.Parse() |
|
self.assertIsNotNone(types) |
|
self.assertIsNotNone(constants) |
|
self.assertIsNotNone(structs) |
|
self.assertIsNotNone(defines) |
|
self.assertIsNotNone(typemap) |
|
|
|
def testStructureParser(self): |
|
"""Test the structure parser with valid data.""" |
|
input_data = (self.FAKE_TYPEDEF + self.FAKE_CONSTANT + self.FAKE_STRUCTURE + |
|
self.FAKE_DEFINE) |
|
in_file = StringIO.StringIO(input_data) |
|
parser = generator.StructureParser(in_file) |
|
types, constants, structs, defines, typemap = parser.Parse() |
|
# Be flexible on these counts because the parser may add special cases. |
|
self.assertGreaterEqual(len(types), 2) |
|
self.assertGreaterEqual(len(constants), 1) |
|
self.assertGreaterEqual(len(structs), 1) |
|
self.assertGreaterEqual(len(defines), 1) |
|
self.assertGreaterEqual(len(typemap), 3) |
|
self.assertEqual(types[0].old_type, 'type1') |
|
self.assertEqual(types[0].new_type, 'type2') |
|
self.assertEqual(types[1].old_type, 'base_type') |
|
self.assertEqual(types[1].new_type, 'const_type') |
|
self.assertEqual(constants[0].const_type, 'const_type') |
|
self.assertEqual(constants[0].name, 'const_name') |
|
self.assertEqual(constants[0].value, 'const_value') |
|
self.assertEqual(structs[0].name, 'struct_type') |
|
self.assertEqual(structs[0].is_union, False) |
|
self.assertEqual(len(structs[0].fields), 1) |
|
self.assertEqual(structs[0].fields[0][0], 'field_type') |
|
self.assertEqual(structs[0].fields[0][1], 'field_name[sizeof(depend_type)]') |
|
self.assertEqual(len(structs[0].depends_on), 1) |
|
self.assertEqual(structs[0].depends_on[0], 'depend_type') |
|
self.assertEqual(defines[0].name, 'define_name') |
|
self.assertEqual(defines[0].value, 'define_value') |
|
|
|
def testCommandParserWithBadData(self): |
|
"""Test the command parser with invalid data.""" |
|
input_data = 'bad_data' |
|
in_file = StringIO.StringIO(input_data) |
|
parser = generator.CommandParser(in_file) |
|
commands = parser.Parse() |
|
self.assertIsNotNone(commands) |
|
|
|
def testCommandParser(self): |
|
"""Test the command parser with valid data.""" |
|
input_data = self.FAKE_COMMAND |
|
in_file = StringIO.StringIO(input_data) |
|
parser = generator.CommandParser(in_file) |
|
commands = parser.Parse() |
|
self.assertEqual(len(commands), 1) |
|
self.assertEqual(commands[0].name, 'TPM2_Test') |
|
self.assertEqual(commands[0].command_code, 'TPM_CC_Test') |
|
# We expect the 'commandSize' and 'commandCode' args to be filtered out. |
|
self.assertEqual(len(commands[0].request_args), 1) |
|
self.assertEqual(commands[0].request_args[0]['type'], 'UINT16') |
|
self.assertEqual(commands[0].request_args[0]['name'], 'input') |
|
self.assertIsNotNone(commands[0].response_args) |
|
self.assertFalse(commands[0].response_args) |
|
|
|
|
|
if __name__ == '__main__': |
|
unittest.main()
|
|
|