File indexing completed on 2025-08-09 08:19:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 """Generate Google Mock classes from base classes.
0018
0019 This program will read in a C++ source file and output the Google Mock
0020 classes for the specified classes. If no class is specified, all
0021 classes in the source file are emitted.
0022
0023 Usage:
0024 gmock_class.py header-file.h [ClassName]...
0025
0026 Output is sent to stdout.
0027 """
0028
0029 __author__ = 'nnorwitz@google.com (Neal Norwitz)'
0030
0031
0032 import os
0033 import re
0034 import sys
0035
0036 from cpp import ast
0037 from cpp import utils
0038
0039
0040 try:
0041 _dummy = set
0042 except NameError:
0043 import sets
0044 set = sets.Set
0045
0046 _VERSION = (1, 0, 1)
0047
0048 _INDENT = 2
0049
0050
0051 def _GenerateMethods(output_lines, source, class_node):
0052 function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL |
0053 ast.FUNCTION_OVERRIDE)
0054 ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
0055 indent = ' ' * _INDENT
0056
0057 for node in class_node.body:
0058
0059 if (isinstance(node, ast.Function) and
0060 node.modifiers & function_type and
0061 not node.modifiers & ctor_or_dtor):
0062
0063 const = ''
0064 if node.modifiers & ast.FUNCTION_CONST:
0065 const = 'CONST_'
0066 return_type = 'void'
0067 if node.return_type:
0068
0069 modifiers = ''
0070 if node.return_type.modifiers:
0071 modifiers = ' '.join(node.return_type.modifiers) + ' '
0072 return_type = modifiers + node.return_type.name
0073 template_args = [arg.name for arg in node.return_type.templated_types]
0074 if template_args:
0075 return_type += '<' + ', '.join(template_args) + '>'
0076 if len(template_args) > 1:
0077 for line in [
0078 '// The following line won\'t really compile, as the return',
0079 '// type has multiple template arguments. To fix it, use a',
0080 '// typedef for the return type.']:
0081 output_lines.append(indent + line)
0082 if node.return_type.pointer:
0083 return_type += '*'
0084 if node.return_type.reference:
0085 return_type += '&'
0086 num_parameters = len(node.parameters)
0087 if len(node.parameters) == 1:
0088 first_param = node.parameters[0]
0089 if source[first_param.start:first_param.end].strip() == 'void':
0090
0091 num_parameters = 0
0092 tmpl = ''
0093 if class_node.templated_types:
0094 tmpl = '_T'
0095 mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
0096
0097 args = ''
0098 if node.parameters:
0099
0100
0101
0102
0103
0104
0105
0106 if len([param for param in node.parameters if param.default]) > 0:
0107 args = ', '.join(param.type.name for param in node.parameters)
0108 else:
0109
0110
0111 start = node.parameters[0].start
0112 end = node.parameters[-1].end
0113
0114 args_strings = re.sub(r'//.*', '', source[start:end])
0115
0116
0117
0118
0119 args = re.sub(' +', ' ', args_strings.replace('\n', ' '))
0120
0121
0122 output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name),
0123 '%s%s(%s));' % (indent*3, return_type, args)])
0124
0125
0126 def _GenerateMocks(filename, source, ast_list, desired_class_names):
0127 processed_class_names = set()
0128 lines = []
0129 for node in ast_list:
0130 if (isinstance(node, ast.Class) and node.body and
0131
0132 (not desired_class_names or node.name in desired_class_names)):
0133 class_name = node.name
0134 parent_name = class_name
0135 processed_class_names.add(class_name)
0136 class_node = node
0137
0138 if class_node.namespace:
0139 lines.extend(['namespace %s {' % n for n in class_node.namespace])
0140 lines.append('')
0141
0142
0143 if class_node.templated_types:
0144
0145
0146
0147
0148 template_arg_count = len(class_node.templated_types.keys())
0149 template_args = ['T%d' % n for n in range(template_arg_count)]
0150 template_decls = ['typename ' + arg for arg in template_args]
0151 lines.append('template <' + ', '.join(template_decls) + '>')
0152 parent_name += '<' + ', '.join(template_args) + '>'
0153
0154
0155 lines.append('class Mock%s : public %s {'
0156 % (class_name, parent_name))
0157 lines.append('%spublic:' % (' ' * (_INDENT // 2)))
0158
0159
0160 _GenerateMethods(lines, source, class_node)
0161
0162
0163 if lines:
0164
0165 if len(lines) == 2:
0166 del lines[-1]
0167
0168
0169 lines.append('};')
0170 lines.append('')
0171
0172
0173 if class_node.namespace:
0174 for i in range(len(class_node.namespace)-1, -1, -1):
0175 lines.append('} // namespace %s' % class_node.namespace[i])
0176 lines.append('')
0177
0178 if desired_class_names:
0179 missing_class_name_list = list(desired_class_names - processed_class_names)
0180 if missing_class_name_list:
0181 missing_class_name_list.sort()
0182 sys.stderr.write('Class(es) not found in %s: %s\n' %
0183 (filename, ', '.join(missing_class_name_list)))
0184 elif not processed_class_names:
0185 sys.stderr.write('No class found in %s\n' % filename)
0186
0187 return lines
0188
0189
0190 def main(argv=sys.argv):
0191 if len(argv) < 2:
0192 sys.stderr.write('Google Mock Class Generator v%s\n\n' %
0193 '.'.join(map(str, _VERSION)))
0194 sys.stderr.write(__doc__)
0195 return 1
0196
0197 global _INDENT
0198 try:
0199 _INDENT = int(os.environ['INDENT'])
0200 except KeyError:
0201 pass
0202 except:
0203 sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT'))
0204
0205 filename = argv[1]
0206 desired_class_names = None
0207 if len(argv) >= 3:
0208 desired_class_names = set(argv[2:])
0209 source = utils.ReadFile(filename)
0210 if source is None:
0211 return 1
0212
0213 builder = ast.BuilderFromSource(source, filename)
0214 try:
0215 entire_ast = filter(None, builder.Generate())
0216 except KeyboardInterrupt:
0217 return
0218 except:
0219
0220 sys.exit(1)
0221 else:
0222 lines = _GenerateMocks(filename, source, entire_ast, desired_class_names)
0223 sys.stdout.write('\n'.join(lines))
0224
0225
0226 if __name__ == '__main__':
0227 main(sys.argv)