"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "googlemock/scripts/generator/cpp/gmock_class.py" between
googletest-release-1.10.0.tar.gz and googletest-release-1.11.0.tar.gz

About: GoogleTest is Google's (unit) testing and mocking framework for C++ tests.

gmock_class.py  (googletest-release-1.10.0):gmock_class.py  (googletest-release-1.11.0)
skipping to change at line 29 skipping to change at line 29
This program will read in a C++ source file and output the Google Mock This program will read in a C++ source file and output the Google Mock
classes for the specified classes. If no class is specified, all classes for the specified classes. If no class is specified, all
classes in the source file are emitted. classes in the source file are emitted.
Usage: Usage:
gmock_class.py header-file.h [ClassName]... gmock_class.py header-file.h [ClassName]...
Output is sent to stdout. Output is sent to stdout.
""" """
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
import os import os
import re import re
import sys import sys
from cpp import ast from cpp import ast
from cpp import utils from cpp import utils
# Preserve compatibility with Python 2.3. # Preserve compatibility with Python 2.3.
try: try:
_dummy = set _dummy = set
except NameError: except NameError:
import sets import sets
set = sets.Set set = sets.Set
_VERSION = (1, 0, 1) # The version of this script. _VERSION = (1, 0, 1) # The version of this script.
# How many spaces to indent. Can set me with the INDENT environment variable. # How many spaces to indent. Can set me with the INDENT environment variable.
_INDENT = 2 _INDENT = 2
def _RenderType(ast_type):
"""Renders the potentially recursively templated type into a string.
Args:
ast_type: The AST of the type.
Returns:
Rendered string of the type.
"""
# Add modifiers like 'const'.
modifiers = ''
if ast_type.modifiers:
modifiers = ' '.join(ast_type.modifiers) + ' '
return_type = modifiers + ast_type.name
if ast_type.templated_types:
# Collect template args.
template_args = []
for arg in ast_type.templated_types:
rendered_arg = _RenderType(arg)
template_args.append(rendered_arg)
return_type += '<' + ', '.join(template_args) + '>'
if ast_type.pointer:
return_type += '*'
if ast_type.reference:
return_type += '&'
return return_type
def _GenerateArg(source):
"""Strips out comments, default arguments, and redundant spaces from a single
argument.
Args:
source: A string for a single argument.
Returns:
Rendered string of the argument.
"""
# Remove end of line comments before eliminating newlines.
arg = re.sub(r'//.*', '', source)
# Remove c-style comments.
arg = re.sub(r'/\*.*\*/', '', arg)
# Remove default arguments.
arg = re.sub(r'=.*', '', arg)
# Collapse spaces and newlines into a single space.
arg = re.sub(r'\s+', ' ', arg)
return arg.strip()
def _EscapeForMacro(s):
"""Escapes a string for use as an argument to a C++ macro."""
paren_count = 0
for c in s:
if c == '(':
paren_count += 1
elif c == ')':
paren_count -= 1
elif c == ',' and paren_count == 0:
return '(' + s + ')'
return s
def _GenerateMethods(output_lines, source, class_node): def _GenerateMethods(output_lines, source, class_node):
function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL | function_type = (
ast.FUNCTION_OVERRIDE) ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL | ast.FUNCTION_OVERRIDE)
ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
indent = ' ' * _INDENT indent = ' ' * _INDENT
for node in class_node.body: for node in class_node.body:
# We only care about virtual functions. # We only care about virtual functions.
if (isinstance(node, ast.Function) and if (isinstance(node, ast.Function) and node.modifiers & function_type and
node.modifiers & function_type and
not node.modifiers & ctor_or_dtor): not node.modifiers & ctor_or_dtor):
# Pick out all the elements we need from the original function. # Pick out all the elements we need from the original function.
const = '' modifiers = 'override'
if node.modifiers & ast.FUNCTION_CONST: if node.modifiers & ast.FUNCTION_CONST:
const = 'CONST_' modifiers = 'const, ' + modifiers
return_type = 'void' return_type = 'void'
if node.return_type: if node.return_type:
# Add modifiers like 'const'. return_type = _EscapeForMacro(_RenderType(node.return_type))
modifiers = ''
if node.return_type.modifiers:
modifiers = ' '.join(node.return_type.modifiers) + ' '
return_type = modifiers + node.return_type.name
template_args = [arg.name for arg in node.return_type.templated_types]
if template_args:
return_type += '<' + ', '.join(template_args) + '>'
if len(template_args) > 1:
for line in [
'// The following line won\'t really compile, as the return',
'// type has multiple template arguments. To fix it, use a',
'// typedef for the return type.']:
output_lines.append(indent + line)
if node.return_type.pointer:
return_type += '*'
if node.return_type.reference:
return_type += '&'
num_parameters = len(node.parameters)
if len(node.parameters) == 1:
first_param = node.parameters[0]
if source[first_param.start:first_param.end].strip() == 'void':
# We must treat T(void) as a function with no parameters.
num_parameters = 0
tmpl = ''
if class_node.templated_types:
tmpl = '_T'
mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
args = '' args = []
if node.parameters: for p in node.parameters:
# Due to the parser limitations, it is impossible to keep comments arg = _GenerateArg(source[p.start:p.end])
# while stripping the default parameters. When defaults are if arg != 'void':
# present, we choose to strip them and comments (and produce args.append(_EscapeForMacro(arg))
# compilable code).
# TODO(nnorwitz@google.com): Investigate whether it is possible to
# preserve parameter name when reconstructing parameter text from
# the AST.
if len([param for param in node.parameters if param.default]) > 0:
args = ', '.join(param.type.name for param in node.parameters)
else:
# Get the full text of the parameters from the start
# of the first parameter to the end of the last parameter.
start = node.parameters[0].start
end = node.parameters[-1].end
# Remove // comments.
args_strings = re.sub(r'//.*', '', source[start:end])
# Condense multiple spaces and eliminate newlines putting the
# parameters together on a single line. Ensure there is a
# space in an argument which is split by a newline without
# intervening whitespace, e.g.: int\nBar
args = re.sub(' +', ' ', args_strings.replace('\n', ' '))
# Create the mock method definition. # Create the mock method definition.
output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name), output_lines.extend([
'%s%s(%s));' % (indent*3, return_type, args)]) '%sMOCK_METHOD(%s, %s, (%s), (%s));' %
(indent, return_type, node.name, ', '.join(args), modifiers)
])
def _GenerateMocks(filename, source, ast_list, desired_class_names): def _GenerateMocks(filename, source, ast_list, desired_class_names):
processed_class_names = set() processed_class_names = set()
lines = [] lines = []
for node in ast_list: for node in ast_list:
if (isinstance(node, ast.Class) and node.body and if (isinstance(node, ast.Class) and node.body and
# desired_class_names being None means that all classes are selected. # desired_class_names being None means that all classes are selected.
(not desired_class_names or node.name in desired_class_names)): (not desired_class_names or node.name in desired_class_names)):
class_name = node.name class_name = node.name
parent_name = class_name parent_name = class_name
processed_class_names.add(class_name) processed_class_names.add(class_name)
class_node = node class_node = node
# Add namespace before the class. # Add namespace before the class.
if class_node.namespace: if class_node.namespace:
lines.extend(['namespace %s {' % n for n in class_node.namespace]) # } lines.extend(['namespace %s {' % n for n in class_node.namespace]) # }
lines.append('') lines.append('')
# Add template args for templated classes. # Add template args for templated classes.
if class_node.templated_types: if class_node.templated_types:
# TODO(paulchang): The AST doesn't preserve template argument order,
# so we have to make up names here.
# TODO(paulchang): Handle non-type template arguments (e.g. # TODO(paulchang): Handle non-type template arguments (e.g.
# template<typename T, int N>). # template<typename T, int N>).
template_arg_count = len(class_node.templated_types.keys())
template_args = ['T%d' % n for n in range(template_arg_count)] # class_node.templated_types is an OrderedDict from strings to a tuples.
# The key is the name of the template, and the value is
# (type_name, default). Both type_name and default could be None.
template_args = class_node.templated_types.keys()
template_decls = ['typename ' + arg for arg in template_args] template_decls = ['typename ' + arg for arg in template_args]
lines.append('template <' + ', '.join(template_decls) + '>') lines.append('template <' + ', '.join(template_decls) + '>')
parent_name += '<' + ', '.join(template_args) + '>' parent_name += '<' + ', '.join(template_args) + '>'
# Add the class prolog. # Add the class prolog.
lines.append('class Mock%s : public %s {' # } lines.append('class Mock%s : public %s {' # }
% (class_name, parent_name)) % (class_name, parent_name))
lines.append('%spublic:' % (' ' * (_INDENT // 2))) lines.append('%spublic:' % (' ' * (_INDENT // 2)))
# Add all the methods. # Add all the methods.
skipping to change at line 171 skipping to change at line 189
# If there are no virtual methods, no need for a public label. # If there are no virtual methods, no need for a public label.
if len(lines) == 2: if len(lines) == 2:
del lines[-1] del lines[-1]
# Only close the class if there really is a class. # Only close the class if there really is a class.
lines.append('};') lines.append('};')
lines.append('') # Add an extra newline. lines.append('') # Add an extra newline.
# Close the namespace. # Close the namespace.
if class_node.namespace: if class_node.namespace:
for i in range(len(class_node.namespace)-1, -1, -1): for i in range(len(class_node.namespace) - 1, -1, -1):
lines.append('} // namespace %s' % class_node.namespace[i]) lines.append('} // namespace %s' % class_node.namespace[i])
lines.append('') # Add an extra newline. lines.append('') # Add an extra newline.
if desired_class_names: if desired_class_names:
missing_class_name_list = list(desired_class_names - processed_class_names) missing_class_name_list = list(desired_class_names - processed_class_names)
if missing_class_name_list: if missing_class_name_list:
missing_class_name_list.sort() missing_class_name_list.sort()
sys.stderr.write('Class(es) not found in %s: %s\n' % sys.stderr.write('Class(es) not found in %s: %s\n' %
(filename, ', '.join(missing_class_name_list))) (filename, ', '.join(missing_class_name_list)))
elif not processed_class_names: elif not processed_class_names:
 End of changes. 13 change blocks. 
66 lines changed or deleted 85 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)