<filename>cpp/CppStubGenerator.py
#!/usr/bin/env python
#
# This is a modified version of the stub generator (gmock_gen.py) provided with 
# Google Test. This version is intended to generate c++ mock files of the
# functions/classes/methods defined in a given header file. This script will 
# generate a mock version of each function/method defined in a header file, 
# with global data to allow the user to set the return value, output parameters, 
# and to check the perform analysis on the data passed to all of the given 
# functions/methods.
#
# Copyright 2008 Google Inc.  All Rights Reserved.
#
# 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.

"""
Usage:
  CppStubGenerator.py header-file.h ...

Output is sent to stdout.
"""

import os
import re
import sys
import re

from cpp import ast
from cpp import utils

# Preserve compatibility with Python 2.3.
try:
  _dummy = set
except NameError:
  import sets
  set = sets.Set

gStubGenHeader = []
gStubGenHeader.append('//********************************************************************************')
gStubGenHeader.append('// Automatically generated by CppStubGenerator')
gStubGenHeader.append('//********************************************************************************\n')

# How many spaces to indent.  Can set me with the INDENT environment variable.
_INDENT = 4

class FunctionParam:
    def __init__(self, typeName='',paramName='', inputParam=0, refParam=0, ptrParam=0, sizeVarName=''):
      self.typeName = typeName
      self.paramName = paramName
      self.inputParam = inputParam
      self.refParam = refParam
      self.ptrParam = ptrParam
      self.sizeVarName = sizeVarName

def CamelToSnake(name):
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).upper()

def AppendClassIfMemberType(typeStr, memberTypes, className):
  isMemberType = False
  for memberType in memberTypes:
    if typeStr == memberType:
      isMemberType = True;
  if isMemberType:
    typeStr = '%s::%s' % (className, typeStr)
  return typeStr

def GetReturnType(node):
  return_type = 'void'
  if node.return_type:
    # Add modifiers like 'const'.
    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 node.return_type.pointer:
      return_type += '*'
    if node.return_type.reference:
      return_type += '&'
    if return_type.find('operator') != -1:
      return_type = return_type.replace('operator','').strip()
      node.name = ('operator%s' %(node.name))
  return_type = return_type.replace('static', '').replace('  ', ' ').strip()

  return return_type

def GetArgs(parameters, source):
  args = ''
  if parameters:
    # Due to the parser limitations, it is impossible to keep comments
    # while stripping the default parameters.  When defaults are
    # present, we choose to strip them and comments (and produce
    # compilable code).
    args = ', '.join(param.type.FullName() + ' ' + param.name for param in parameters)

  # If the parameter list is void, just remove it
  if args == 'void':
    args = ''
  return args

def GetParamList(args, memberTypes, className):
  paramList = []
  for param in args.split(','):
    paramParts = []
    for paramPart in param.split(' '):
      paramPart = AppendClassIfMemberType(paramPart.strip(), memberTypes, className)
      paramParts.append(paramPart.strip())
    paramList.append(' '.join(paramParts).strip())
  return paramList

def ParseParamList(paramList):
  functionParams = []
  paramCount = 0
  for param in paramList:
    refParam = param.find('&') != -1
    ptrParam = param.find('*') != -1
    param = param.replace('&','').strip()
    if len(param) == 0: continue
    typename = ''
    paramname = ''
    inputParam = False
    paramParts = param.split(' ')
    if paramParts[0] == 'const':
      inputParam = True
    elif len(paramParts) > 1:
      if paramParts[1].find('const') != -1:
        inputParam = True
    param = param.replace('const','').replace('  ',' ').strip()
    if refParam == False and ptrParam == False:
      inputParam = True
    paramname = paramParts[len(paramParts)-1]
    typename = param[:len(param)-len(paramname)].strip()
    sizeVarName = ''
    if ptrParam:
      sizeVarName = ('%sSize' % paramname)
    functionParams.append(FunctionParam(typename, paramname, inputParam, refParam, ptrParam, sizeVarName))
    paramCount += 1
    if ptrParam:
      functionParams.append(FunctionParam('int', ('%sSize' % paramname), False, False, False, ''))
      paramCount += 1

  return functionParams, paramCount

def GetNamespaceName(name):
  methodNsName = name
  methodNsName = methodNsName.replace('==', 'EqualTo')
  methodNsName = methodNsName.replace('!=', 'NotEqualTo')
  methodNsName = methodNsName.replace('<', 'LessThan')
  methodNsName = methodNsName.replace('<=', 'LessThanOrEqualTo')
  methodNsName = methodNsName.replace('>', 'GreaterThan')
  methodNsName = methodNsName.replace('>=', 'GreaterThanOrEqualTo')
  methodNsName = methodNsName.replace('+=', 'PlusEquals')
  methodNsName = methodNsName.replace('-=', 'MinusEquals')
  methodNsName = methodNsName.replace('=', 'Assignment')
  methodNsName = methodNsName.replace('+', 'Add')
  methodNsName = methodNsName.replace('-', 'Subtract')
  methodNsName = methodNsName.replace('*', 'Multiply')
  methodNsName = methodNsName.replace('/', 'Divide')
  methodNsName = methodNsName.replace('[]', 'ArrayIndex')
  return methodNsName

def GetInitCommand(typeName):
  if typeName.find(' ') != -1:
    initCmd = ('(%s)(0)' % typeName)
  elif typeName.find('*') != -1:
    initCmd = ('(%s)(0)' % typeName)
  elif typeName == 'bool':
    initCmd = ('false')
  else:
    initCmd = ('%s(0)' % typeName)
  return initCmd

def _GenerateFunction(cpp_output, h_output_ns, h_output_init, source, node, stubName, className = '', memberTypes = []):
  ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
  indent = ' ' * _INDENT
  # List of known virual methods that will always have stubs generated regardless of their visibility
  knownVirtuals = ['Update', 'Encode', 'Decode', 'Size']

  if (isinstance(node, ast.Function) and
      not node.modifiers & ctor_or_dtor and
      ((node.visibility != ast.VISIBILITY_PRIVATE) or 
       (node.modifiers & ast.FUNCTION_VIRTUAL) or
       (node.name in knownVirtuals))):
    # Pick out all the elements we need from the original function.
    # return_type is the return_type for the function definition
    # retValType is the type to use for the retVal object
    node.return_type.name = AppendClassIfMemberType(node.return_type.name, memberTypes, className)
    return_type = GetReturnType(node)
    retValType = return_type.replace('&','').replace('const','').strip()
       
    # Get the argument string and the list of parameters
    args = GetArgs(node.parameters, source)
    paramList = GetParamList(args, memberTypes, className)
    functionParams, paramCount = ParseParamList(paramList)
    
    methodNsName = GetNamespaceName(node.name)

    # Create the mock method definition.
    cpp_method_impl = []
    classStr = ''
    if className != '':
      classStr = className + '::'
    constStr = ''
    if node.modifiers & ast.FUNCTION_CONST:
      constStr = ' const'
    cpp_method_impl.append('%s %s%s(%s)%s' % (return_type, classStr, node.name, ', '.join(paramList), constStr))
    cpp_method_impl.append('{')

    # Create method namespace
    h_output_ns.append('%snamespace %s' % (indent, methodNsName))
    h_output_ns.append('%s{' % (indent))

    # called tracks whether the given function/method has been called
    h_output_ns.append('%sextern bool called;' % (indent*2))
    h_output_init.append('%s%s::%s::called = false; \\' % (indent, stubName, methodNsName))
    cpp_output.append('bool %s::%s::called = false;' % (stubName, methodNsName))
    cpp_method_impl.append('%s%s::%s::called = true;' % (indent, stubName, methodNsName))

    # callCount tracks the number of times the given function/method has been called
    h_output_ns.append('%sextern int callCount;' % (indent*2))
    h_output_init.append('%s%s::%s::callCount = 0; \\' % (indent, stubName, methodNsName))
    cpp_output.append('int %s::%s::callCount = 0;' % (stubName, methodNsName))
    cpp_method_impl.append('%s%s::%s::callCount++;' % (indent, stubName, methodNsName))

    # retVal defined the return value for the given function/method
    if retValType != 'void':
      initCmd = GetInitCommand(retValType)
      h_output_ns.append('%sextern %s retVal;' % (indent*2, retValType))
      h_output_init.append('%s%s::%s::retVal = %s; \\' % (indent, stubName, methodNsName, initCmd)) 
      cpp_output.append('%s %s::%s::retVal = %s;' % (retValType, stubName, methodNsName, initCmd)) 

    # Function parameters
    for gParam in functionParams:
      if gParam.paramName != 'void':
        initCmd = GetInitCommand(gParam.typeName)
        h_output_ns.append('%sextern %s %s;' % (indent*2, gParam.typeName, gParam.paramName))
        h_output_init.append('%s%s::%s::%s = %s; \\' % (indent, stubName, methodNsName, gParam.paramName, initCmd)) 
        cpp_output.append('%s %s::%s::%s = %s;' % (gParam.typeName, stubName, methodNsName, gParam.paramName, initCmd))

        if gParam.inputParam:
          if gParam.ptrParam:
            cpp_method_impl.append('%smemcpy(%s::%s::%s, %s, %s::%s::%s);' % (indent, stubName, methodNsName, gParam.paramName, gParam.paramName, stubName, methodNsName, gParam.sizeVarName))
          else:
            cpp_method_impl.append('%s%s::%s::%s = %s;' % (indent, stubName, methodNsName, gParam.paramName, gParam.paramName))
        else:
          if gParam.ptrParam:
            cpp_method_impl.append('%smemcpy(%s, %s::%s::%s, %s::%s::%s);' % (indent, gParam.paramName, stubName, methodNsName, gParam.paramName, stubName, methodNsName, gParam.sizeVarName))
          elif gParam.refParam:
            cpp_method_impl.append('%s%s = %s::%s::%s;' % (indent, gParam.paramName, stubName, methodNsName, gParam.paramName))

    if retValType != 'void':
      cpp_method_impl.append('%sreturn %s::%s::retVal;' % (indent, stubName, methodNsName))

    cpp_output.extend(cpp_method_impl)
    cpp_output.append('}\n')   
    h_output_ns.append('%s}' % (indent)) 

def _GenerateClassMethods(cpp_output, h_output_ns, h_output_init, source, class_node, stubName):
  memberTypes = []
  for node in class_node.body:
    if isinstance(node, ast.Enum) or isinstance(node, ast.Struct) or isinstance(node, ast.Class) or isinstance(node, ast.Typedef):
      if node.name != None:
        memberTypes.append(node.name)
    else:
      _GenerateFunction(cpp_output, h_output_ns, h_output_init, source, node, stubName, class_node.name, memberTypes)

def _GenerateMocks(filename, source, ast_list, desired_class_names):
  processed_class_names = set()
  cpp_output = []
  h_output_ns = []
  h_output_init = []

  #generate the header for the cpp file
  filePath = os.path.dirname(filename)
  file = os.path.basename(filename)
  stubName = '%s_Stub' % file.split('.')[0]
  cppFileName = stubName + '.cpp'
  hFileName = stubName + '.h'
  
  cpp_header = []
  cpp_header.extend(gStubGenHeader)
  cpp_header.append('#include \"%s\"' % hFileName)
  cpp_header.append('\n');

  #generate the header and footer for the h file
  includeGuard = CamelToSnake(file).replace('.','_STUB_')
  h_header = []
  h_header.extend(gStubGenHeader)
  h_header.append('#ifndef %s' % includeGuard)
  h_header.append('#define %s' % includeGuard)
  h_header.append('')
  h_header.append('#include \"%s\"' % file)
  h_header.append('#include <string.h>')
  h_header.append('\n')

  h_footer = []
  h_footer.append('\n#endif//%s' % includeGuard)
  h_footer.append('\n')

  h_output_init.append('#define INITIALIZE_%s() \\' % (includeGuard.replace('_H', '').strip()))

  h_output_ns.append('namespace %s' % stubName)
  h_output_ns.append('{')

  for node in ast_list:
    if ((isinstance(node, ast.Class) and node.body and
        # desired_class_names being None means that all classes are selected.
        (not desired_class_names or node.name in desired_class_names))):
      class_name = node.name
      parent_name = class_name
      processed_class_names.add(class_name)
      # Add all the methods.
      _GenerateClassMethods(cpp_output, h_output_ns, h_output_init, source, node, stubName)

      # Close the namespace.
      if node.namespace:
        for i in range(len(node.namespace)-1, -1, -1):
          cpp_output.append('}  // namespace %s' % node.namespace[i])
        cpp_output.append('')  # Add an extra newline.
    elif isinstance(node, ast.Function):
      _GenerateFunction(cpp_output, h_output_ns, h_output_init, source, node, stubName)

  h_output_ns.append('}\n\n')
  h_output_init.append('')

  if desired_class_names:
    missing_class_name_list = list(desired_class_names - processed_class_names)
    if missing_class_name_list:
      missing_class_name_list.sort()
      sys.stderr.write('Class(es) not found in %s: %s\n' %
                       (filename, ', '.join(missing_class_name_list)))
  elif not processed_class_names:
    sys.stderr.write('No class found in %s\n' % filename)

  # Write the files
  cppFileContent = '\n'.join(cpp_header) + '\n'.join(cpp_output)

  f = open(cppFileName, 'w')
  f.write(cppFileContent)
  f.close()
  print('%s created' % (cppFileName))

  hFileContent = '\n'.join(h_header) + '\n'.join(h_output_ns) + '\n'.join(h_output_init) + '\n'.join(h_footer)

  f = open(hFileName, 'w')
  f.write(hFileContent)
  f.close()
  print('%s created' % (hFileName))

def main(argv=sys.argv):
  if len(argv) < 2:
    sys.stderr.write('Google Mock Class Generator v%s\n\n' %
                     '.'.join(map(str, _VERSION)))
    sys.stderr.write(__doc__)
    return 1

  global _INDENT
  try:
    _INDENT = int(os.environ['INDENT'])
  except KeyError:
    pass
  except:
    sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT'))

  filename = argv[1]
  desired_class_names = None  # None means all classes in the source file.
  if len(argv) >= 3:
    desired_class_names = set(argv[2:])
  source = utils.ReadFile(filename)
  if source is None:
    return 1

  builder = ast.BuilderFromSource(source, filename)
  try:
    entire_ast = filter(None, builder.Generate())
  except KeyboardInterrupt:
    return
  except:
    # An error message was already printed since we couldn't parse.
    sys.exit(1)
  else:
    _GenerateMocks(filename, source, entire_ast, desired_class_names)
    

if __name__ == '__main__':
  main(sys.argv)

<filename>cpp/CppStubGenerator.py
#!/usr/bin/env python
#
# This is a modified version of the stub generator (gmock_gen.py) provided with 
# Google Test. This version is intended to generate c++ mock files of the
# functions/classes/methods defined in a given header file. This script will 
# generate a mock version of each function/method defined in a header file, 
# with global data to allow the user to set the return value, output parameters, 
# and to check the perform analysis on the data passed to all of the given 
# functions/methods.
#
# Copyright 2008 Google Inc.  All Rights Reserved.
#
# 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.

"""
Usage:
  CppStubGenerator.py header-file.h ...

Output is sent to stdout.
"""

import os
import re
import sys
import re

from cpp import ast
from cpp import utils

# Preserve compatibility with Python 2.3.
try:
  _dummy = set
except NameError:
  import sets
  set = sets.Set

gStubGenHeader = []
gStubGenHeader.append('//********************************************************************************')
gStubGenHeader.append('// Automatically generated by CppStubGenerator')
gStubGenHeader.append('//********************************************************************************\n')

# How many spaces to indent.  Can set me with the INDENT environment variable.
_INDENT = 4

class FunctionParam:
    def __init__(self, typeName='',paramName='', inputParam=0, refParam=0, ptrParam=0, sizeVarName=''):
      self.typeName = typeName
      self.paramName = paramName
      self.inputParam = inputParam
      self.refParam = refParam
      self.ptrParam = ptrParam
      self.sizeVarName = sizeVarName

def CamelToSnake(name):
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).upper()

def AppendClassIfMemberType(typeStr, memberTypes, className):
  isMemberType = False
  for memberType in memberTypes:
    if typeStr == memberType:
      isMemberType = True;
  if isMemberType:
    typeStr = '%s::%s' % (className, typeStr)
  return typeStr

def GetReturnType(node):
  return_type = 'void'
  if node.return_type:
    # Add modifiers like 'const'.
    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 node.return_type.pointer:
      return_type += '*'
    if node.return_type.reference:
      return_type += '&'
    if return_type.find('operator') != -1:
      return_type = return_type.replace('operator','').strip()
      node.name = ('operator%s' %(node.name))
  return_type = return_type.replace('static', '').replace('  ', ' ').strip()

  return return_type

def GetArgs(parameters, source):
  args = ''
  if parameters:
    # Due to the parser limitations, it is impossible to keep comments
    # while stripping the default parameters.  When defaults are
    # present, we choose to strip them and comments (and produce
    # compilable code).
    args = ', '.join(param.type.FullName() + ' ' + param.name for param in parameters)

  # If the parameter list is void, just remove it
  if args == 'void':
    args = ''
  return args

def GetParamList(args, memberTypes, className):
  paramList = []
  for param in args.split(','):
    paramParts = []
    for paramPart in param.split(' '):
      paramPart = AppendClassIfMemberType(paramPart.strip(), memberTypes, className)
      paramParts.append(paramPart.strip())
    paramList.append(' '.join(paramParts).strip())
  return paramList

def ParseParamList(paramList):
  functionParams = []
  paramCount = 0
  for param in paramList:
    refParam = param.find('&') != -1
    ptrParam = param.find('*') != -1
    param = param.replace('&','').strip()
    if len(param) == 0: continue
    typename = ''
    paramname = ''
    inputParam = False
    paramParts = param.split(' ')
    if paramParts[0] == 'const':
      inputParam = True
    elif len(paramParts) > 1:
      if paramParts[1].find('const') != -1:
        inputParam = True
    param = param.replace('const','').replace('  ',' ').strip()
    if refParam == False and ptrParam == False:
      inputParam = True
    paramname = paramParts[len(paramParts)-1]
    typename = param[:len(param)-len(paramname)].strip()
    sizeVarName = ''
    if ptrParam:
      sizeVarName = ('%sSize' % paramname)
    functionParams.append(FunctionParam(typename, paramname, inputParam, refParam, ptrParam, sizeVarName))
    paramCount += 1
    if ptrParam:
      functionParams.append(FunctionParam('int', ('%sSize' % paramname), False, False, False, ''))
      paramCount += 1

  return functionParams, paramCount

def GetNamespaceName(name):
  methodNsName = name
  methodNsName = methodNsName.replace('==', 'EqualTo')
  methodNsName = methodNsName.replace('!=', 'NotEqualTo')
  methodNsName = methodNsName.replace('<', 'LessThan')
  methodNsName = methodNsName.replace('<=', 'LessThanOrEqualTo')
  methodNsName = methodNsName.replace('>', 'GreaterThan')
  methodNsName = methodNsName.replace('>=', 'GreaterThanOrEqualTo')
  methodNsName = methodNsName.replace('+=', 'PlusEquals')
  methodNsName = methodNsName.replace('-=', 'MinusEquals')
  methodNsName = methodNsName.replace('=', 'Assignment')
  methodNsName = methodNsName.replace('+', 'Add')
  methodNsName = methodNsName.replace('-', 'Subtract')
  methodNsName = methodNsName.replace('*', 'Multiply')
  methodNsName = methodNsName.replace('/', 'Divide')
  methodNsName = methodNsName.replace('[]', 'ArrayIndex')
  return methodNsName

def GetInitCommand(typeName):
  if typeName.find(' ') != -1:
    initCmd = ('(%s)(0)' % typeName)
  elif typeName.find('*') != -1:
    initCmd = ('(%s)(0)' % typeName)
  elif typeName == 'bool':
    initCmd = ('false')
  else:
    initCmd = ('%s(0)' % typeName)
  return initCmd

def _GenerateFunction(cpp_output, h_output_ns, h_output_init, source, node, stubName, className = '', memberTypes = []):
  ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
  indent = ' ' * _INDENT
  # List of known virual methods that will always have stubs generated regardless of their visibility
  knownVirtuals = ['Update', 'Encode', 'Decode', 'Size']

  if (isinstance(node, ast.Function) and
      not node.modifiers & ctor_or_dtor and
      ((node.visibility != ast.VISIBILITY_PRIVATE) or 
       (node.modifiers & ast.FUNCTION_VIRTUAL) or
       (node.name in knownVirtuals))):
    # Pick out all the elements we need from the original function.
    # return_type is the return_type for the function definition
    # retValType is the type to use for the retVal object
    node.return_type.name = AppendClassIfMemberType(node.return_type.name, memberTypes, className)
    return_type = GetReturnType(node)
    retValType = return_type.replace('&','').replace('const','').strip()
       
    # Get the argument string and the list of parameters
    args = GetArgs(node.parameters, source)
    paramList = GetParamList(args, memberTypes, className)
    functionParams, paramCount = ParseParamList(paramList)
    
    methodNsName = GetNamespaceName(node.name)

    # Create the mock method definition.
    cpp_method_impl = []
    classStr = ''
    if className != '':
      classStr = className + '::'
    constStr = ''
    if node.modifiers & ast.FUNCTION_CONST:
      constStr = ' const'
    cpp_method_impl.append('%s %s%s(%s)%s' % (return_type, classStr, node.name, ', '.join(paramList), constStr))
    cpp_method_impl.append('{')

    # Create method namespace
    h_output_ns.append('%snamespace %s' % (indent, methodNsName))
    h_output_ns.append('%s{' % (indent))

    # called tracks whether the given function/method has been called
    h_output_ns.append('%sextern bool called;' % (indent*2))
    h_output_init.append('%s%s::%s::called = false; \\' % (indent, stubName, methodNsName))
    cpp_output.append('bool %s::%s::called = false;' % (stubName, methodNsName))
    cpp_method_impl.append('%s%s::%s::called = true;' % (indent, stubName, methodNsName))

    # callCount tracks the number of times the given function/method has been called
    h_output_ns.append('%sextern int callCount;' % (indent*2))
    h_output_init.append('%s%s::%s::callCount = 0; \\' % (indent, stubName, methodNsName))
    cpp_output.append('int %s::%s::callCount = 0;' % (stubName, methodNsName))
    cpp_method_impl.append('%s%s::%s::callCount++;' % (indent, stubName, methodNsName))

    # retVal defined the return value for the given function/method
    if retValType != 'void':
      initCmd = GetInitCommand(retValType)
      h_output_ns.append('%sextern %s retVal;' % (indent*2, retValType))
      h_output_init.append('%s%s::%s::retVal = %s; \\' % (indent, stubName, methodNsName, initCmd)) 
      cpp_output.append('%s %s::%s::retVal = %s;' % (retValType, stubName, methodNsName, initCmd)) 

    # Function parameters
    for gParam in functionParams:
      if gParam.paramName != 'void':
        initCmd = GetInitCommand(gParam.typeName)
        h_output_ns.append('%sextern %s %s;' % (indent*2, gParam.typeName, gParam.paramName))
        h_output_init.append('%s%s::%s::%s = %s; \\' % (indent, stubName, methodNsName, gParam.paramName, initCmd)) 
        cpp_output.append('%s %s::%s::%s = %s;' % (gParam.typeName, stubName, methodNsName, gParam.paramName, initCmd))

        if gParam.inputParam:
          if gParam.ptrParam:
            cpp_method_impl.append('%smemcpy(%s::%s::%s, %s, %s::%s::%s);' % (indent, stubName, methodNsName, gParam.paramName, gParam.paramName, stubName, methodNsName, gParam.sizeVarName))
          else:
            cpp_method_impl.append('%s%s::%s::%s = %s;' % (indent, stubName, methodNsName, gParam.paramName, gParam.paramName))
        else:
          if gParam.ptrParam:
            cpp_method_impl.append('%smemcpy(%s, %s::%s::%s, %s::%s::%s);' % (indent, gParam.paramName, stubName, methodNsName, gParam.paramName, stubName, methodNsName, gParam.sizeVarName))
          elif gParam.refParam:
            cpp_method_impl.append('%s%s = %s::%s::%s;' % (indent, gParam.paramName, stubName, methodNsName, gParam.paramName))

    if retValType != 'void':
      cpp_method_impl.append('%sreturn %s::%s::retVal;' % (indent, stubName, methodNsName))

    cpp_output.extend(cpp_method_impl)
    cpp_output.append('}\n')   
    h_output_ns.append('%s}' % (indent)) 

def _GenerateClassMethods(cpp_output, h_output_ns, h_output_init, source, class_node, stubName):
  memberTypes = []
  for node in class_node.body:
    if isinstance(node, ast.Enum) or isinstance(node, ast.Struct) or isinstance(node, ast.Class) or isinstance(node, ast.Typedef):
      if node.name != None:
        memberTypes.append(node.name)
    else:
      _GenerateFunction(cpp_output, h_output_ns, h_output_init, source, node, stubName, class_node.name, memberTypes)

def _GenerateMocks(filename, source, ast_list, desired_class_names):
  processed_class_names = set()
  cpp_output = []
  h_output_ns = []
  h_output_init = []

  #generate the header for the cpp file
  filePath = os.path.dirname(filename)
  file = os.path.basename(filename)
  stubName = '%s_Stub' % file.split('.')[0]
  cppFileName = stubName + '.cpp'
  hFileName = stubName + '.h'
  
  cpp_header = []
  cpp_header.extend(gStubGenHeader)
  cpp_header.append('#include \"%s\"' % hFileName)
  cpp_header.append('\n');

  #generate the header and footer for the h file
  includeGuard = CamelToSnake(file).replace('.','_STUB_')
  h_header = []
  h_header.extend(gStubGenHeader)
  h_header.append('#ifndef %s' % includeGuard)
  h_header.append('#define %s' % includeGuard)
  h_header.append('')
  h_header.append('#include \"%s\"' % file)
  h_header.append('#include <string.h>')
  h_header.append('\n')

  h_footer = []
  h_footer.append('\n#endif//%s' % includeGuard)
  h_footer.append('\n')

  h_output_init.append('#define INITIALIZE_%s() \\' % (includeGuard.replace('_H', '').strip()))

  h_output_ns.append('namespace %s' % stubName)
  h_output_ns.append('{')

  for node in ast_list:
    if ((isinstance(node, ast.Class) and node.body and
        # desired_class_names being None means that all classes are selected.
        (not desired_class_names or node.name in desired_class_names))):
      class_name = node.name
      parent_name = class_name
      processed_class_names.add(class_name)
      # Add all the methods.
      _GenerateClassMethods(cpp_output, h_output_ns, h_output_init, source, node, stubName)

      # Close the namespace.
      if node.namespace:
        for i in range(len(node.namespace)-1, -1, -1):
          cpp_output.append('}  // namespace %s' % node.namespace[i])
        cpp_output.append('')  # Add an extra newline.
    elif isinstance(node, ast.Function):
      _GenerateFunction(cpp_output, h_output_ns, h_output_init, source, node, stubName)

  h_output_ns.append('}\n\n')
  h_output_init.append('')

  if desired_class_names:
    missing_class_name_list = list(desired_class_names - processed_class_names)
    if missing_class_name_list:
      missing_class_name_list.sort()
      sys.stderr.write('Class(es) not found in %s: %s\n' %
                       (filename, ', '.join(missing_class_name_list)))
  elif not processed_class_names:
    sys.stderr.write('No class found in %s\n' % filename)

  # Write the files
  cppFileContent = '\n'.join(cpp_header) + '\n'.join(cpp_output)

  f = open(cppFileName, 'w')
  f.write(cppFileContent)
  f.close()
  print('%s created' % (cppFileName))

  hFileContent = '\n'.join(h_header) + '\n'.join(h_output_ns) + '\n'.join(h_output_init) + '\n'.join(h_footer)

  f = open(hFileName, 'w')
  f.write(hFileContent)
  f.close()
  print('%s created' % (hFileName))

def main(argv=sys.argv):
  if len(argv) < 2:
    sys.stderr.write('Google Mock Class Generator v%s\n\n' %
                     '.'.join(map(str, _VERSION)))
    sys.stderr.write(__doc__)
    return 1

  global _INDENT
  try:
    _INDENT = int(os.environ['INDENT'])
  except KeyError:
    pass
  except:
    sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT'))

  filename = argv[1]
  desired_class_names = None  # None means all classes in the source file.
  if len(argv) >= 3:
    desired_class_names = set(argv[2:])
  source = utils.ReadFile(filename)
  if source is None:
    return 1

  builder = ast.BuilderFromSource(source, filename)
  try:
    entire_ast = filter(None, builder.Generate())
  except KeyboardInterrupt:
    return
  except:
    # An error message was already printed since we couldn't parse.
    sys.exit(1)
  else:
    _GenerateMocks(filename, source, entire_ast, desired_class_names)
    

if __name__ == '__main__':
  main(sys.argv)

#!/usr/bin/env python # # This is a modified version of the stub generator (gmock_gen.py) provided with # Google Test. This version is intended to generate c++ mock files of the # functions/classes/methods defined in a given header file. This script will # generate a mock version of each function/method defined in a header file, # with global data to allow the user to set the return value, output parameters, # and to check the perform analysis on the data passed to all of the given # functions/methods. # # Copyright 2008 Google Inc.  All Rights Reserved. # # 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. Usage:   CppStubGenerator.py header-file.h ...  Output is sent to stdout. # Preserve compatibility with Python 2.3. # How many spaces to indent.  Can set me with the INDENT environment variable. # Add modifiers like 'const'. # Due to the parser limitations, it is impossible to keep comments # while stripping the default parameters.  When defaults are # present, we choose to strip them and comments (and produce # compilable code). # If the parameter list is void, just remove it # List of known virual methods that will always have stubs generated regardless of their visibility # Pick out all the elements we need from the original function. # return_type is the return_type for the function definition # retValType is the type to use for the retVal object # Get the argument string and the list of parameters # Create the mock method definition. # Create method namespace # called tracks whether the given function/method has been called # callCount tracks the number of times the given function/method has been called # retVal defined the return value for the given function/method # Function parameters #generate the header for the cpp file #generate the header and footer for the h file #endif//%s' % includeGuard) # desired_class_names being None means that all classes are selected. # Add all the methods. # Close the namespace. # Add an extra newline. # Write the files # None means all classes in the source file. # An error message was already printed since we couldn't parse.