mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-07-27 14:27:50 +00:00
- break out config
- parsing happens before generator - generator now uses hashed results git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@9 bf332499-1b4d-0410-844d-d2d48d5cc64c
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
|
||||
class CMockConfig
|
||||
|
||||
attr_accessor :src_path, :mock_path, :tab, :includes, :use_cexception, :allow_ignore_mock, :call_count_type, :ignore_bool_type
|
||||
|
||||
def initialize(src_path='src', mock_path='mocks', includes=[], use_cexception=true, allow_ignore_mock=false, tab=' ')
|
||||
@src_path = src_path
|
||||
@mock_path = mock_path
|
||||
@tab = tab
|
||||
@throw_type = 'int'
|
||||
@call_count_type = 'unsigned short'
|
||||
@ignore_bool_type = 'unsigned char'
|
||||
@includes = includes
|
||||
@use_cexception = use_cexception
|
||||
@allow_ignore_mock = allow_ignore_mock
|
||||
end
|
||||
end
|
||||
+255
-289
@@ -1,34 +1,34 @@
|
||||
$here = File.dirname __FILE__
|
||||
require "#{$here}/c_file_parser"
|
||||
|
||||
class CMockGenerator
|
||||
|
||||
attr_accessor :module_name, :src_path, :mock_path, :tab, :includes
|
||||
attr_accessor :module_name, :module_name, parsed_stuff
|
||||
|
||||
require 'ftools'
|
||||
|
||||
def initialize(module_name=nil, src_path='src', mock_path='mocks', includes=[], use_cexception=true, allow_ignore_mock=false, tab=' ')
|
||||
raise "Must at least specify a code module" if module_name.nil?
|
||||
def initialize(config, module_name)
|
||||
@config = config
|
||||
@module_name = module_name
|
||||
@src_path = src_path
|
||||
@mock_path = mock_path
|
||||
@tab = tab
|
||||
@throw_type = 'int'
|
||||
@call_count_type = 'unsigned short'
|
||||
@ignore_bool = 'unsigned char'
|
||||
@includes = includes
|
||||
@use_cexception = use_cexception
|
||||
@allow_ignore_mock = allow_ignore_mock
|
||||
|
||||
###Most likely going to move again
|
||||
@src_path = @config.src_path
|
||||
@mock_path = @config.mock_path
|
||||
@tab = @config.tab
|
||||
@throw_type = @config.throw_type
|
||||
@call_count_type = @config.call_count_type
|
||||
@ignore_bool = @config.ignore_bool_type
|
||||
@includes = @config.includes
|
||||
@use_cexception = @config.use_cexception
|
||||
@allow_ignore_mock = @config.allow_ignore_mock
|
||||
end
|
||||
|
||||
def create_mock
|
||||
def create_mock(parsed_stuff)
|
||||
update_vars
|
||||
create_mock_header_file
|
||||
create_mock_source_file
|
||||
create_mock_header_file(parsed_stuff)
|
||||
create_mock_source_file(parsed_stuff)
|
||||
end
|
||||
|
||||
def update_vars
|
||||
@parser = CFileParser.new(File.read("#{@src_path}/#{@module_name}.h"))
|
||||
@mock_name = "Mock" + @module_name
|
||||
@mock_header_name_dest = @mock_name + ".h"
|
||||
@mock_imp_name_dest = @mock_name + ".c"
|
||||
@@ -44,399 +44,365 @@ class CMockGenerator
|
||||
File.delete(src)
|
||||
end
|
||||
|
||||
def create_mock_header_file
|
||||
File.open @mock_header_temp, 'w' do |header|
|
||||
@header = header
|
||||
create_mock_header_header(@mock_header_name_dest.gsub(/\.h/, "_h").upcase)
|
||||
create_mock_header_externs
|
||||
@parser.nondefine_functions.each do |function|
|
||||
create_mock_header_function_declaration(function)
|
||||
def create_mock_header_file(parsed_stuff)
|
||||
File.open(@mock_header_temp, 'w') do |header|
|
||||
create_mock_header_header(header, @mock_header_name_dest.gsub(/\.h/, "_h").upcase)
|
||||
create_mock_header_externs(header, parsed_stuff)
|
||||
parsed_stuff[:functions].each do |function|
|
||||
|
||||
function[:args_string_without_varargs] = function[:args_string].gsub(/\,\s*.../,'')
|
||||
create_mock_header_function_declaration(header, function)
|
||||
end
|
||||
create_mock_header_footer
|
||||
create_mock_header_footer(header)
|
||||
end
|
||||
update_file @mock_header_file_path, @mock_header_temp
|
||||
update_file(@mock_header_file_path, @mock_header_temp)
|
||||
end
|
||||
|
||||
def create_mock_source_file
|
||||
File.open @mock_imp_temp, 'w' do |implementation|
|
||||
@source = implementation
|
||||
create_source_header_section
|
||||
create_instance_structure
|
||||
create_extern_declarations
|
||||
create_mock_verify_function
|
||||
create_mock_init_function
|
||||
create_mock_destroy_function
|
||||
def create_mock_source_file(parsed_stuff)
|
||||
File.open(@mock_imp_temp, 'w') do |file|
|
||||
create_source_header_section(file, parsed_stuff[:includes])
|
||||
create_instance_structure(file, parsed_stuff[:functions])
|
||||
create_extern_declarations(file, parsed_stuff[:externs])
|
||||
create_mock_verify_function(file, parsed_stuff[:functions])
|
||||
create_mock_init_function(file)
|
||||
create_mock_destroy_function(file, parsed_stuff[:functions])
|
||||
@parser.nondefine_functions.each do |function|
|
||||
create_mock_implementation(function)
|
||||
create_mock_function_expectation(function)
|
||||
create_mock_function_expectation_with_throw(function) if (@use_cexception)
|
||||
create_mock_function_ignore(function) if (@allow_ignore_mock)
|
||||
create_mock_implementation(file, function)
|
||||
create_mock_function_expectation(file, function)
|
||||
create_mock_function_expectation_with_throw(file, function) if (@use_cexception)
|
||||
create_mock_function_ignore(file, function) if (@allow_ignore_mock)
|
||||
end
|
||||
end
|
||||
update_file @mock_imp_file_path, @mock_imp_temp
|
||||
update_file(@mock_imp_file_path, @mock_imp_temp)
|
||||
end
|
||||
|
||||
private
|
||||
private ##############################
|
||||
|
||||
def create_mock_header_header(define_name)
|
||||
@header << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
@header << "#ifndef _#{define_name}\n"
|
||||
@header << "#define _#{define_name}\n\n"
|
||||
@header << "#include \"#{@mock_header_name_dest.gsub(/^Mock/, "")}\"\n\n"
|
||||
@header << "void #{@mock_name}_Init(void);\n"
|
||||
@header << "void #{@mock_name}_Destroy(void);\n"
|
||||
@header << "void #{@mock_name}_Verify(void);\n\n"
|
||||
def create_mock_header_header(header, define_name)
|
||||
header << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
header << "#ifndef _#{define_name}\n"
|
||||
header << "#define _#{define_name}\n\n"
|
||||
header << "#include \"#{@mock_header_name_dest.gsub(/^Mock/, "")}\"\n\n"
|
||||
header << "void #{@mock_name}_Init(void);\n"
|
||||
header << "void #{@mock_name}_Destroy(void);\n"
|
||||
header << "void #{@mock_name}_Verify(void);\n\n"
|
||||
end
|
||||
|
||||
def create_mock_header_externs
|
||||
@parser.externs.each do |extern|
|
||||
@header << extern << ";\n"
|
||||
def create_mock_header_externs(header, parsed_stuff)
|
||||
unless (parsed_stuff[:externs].empty?)
|
||||
parsed_stuff[:externs].each do |extern|
|
||||
header << extern << ";\n"
|
||||
end
|
||||
header << "\n"
|
||||
end
|
||||
@header << "\n" unless @parser.externs.empty?
|
||||
end
|
||||
|
||||
def create_mock_header_function_declaration(function)
|
||||
decl = parse_declaration(function)
|
||||
def create_mock_header_function_declaration(header, function)
|
||||
|
||||
if decl[:args_no_var_args] == "void"
|
||||
if decl[:return] == "void"
|
||||
@header << "void #{decl[:function]}_Expect(void);\n"
|
||||
if (function[:args].empty?)
|
||||
if (function[:rettype] == 'void')
|
||||
header << "void #{function[:name]}_Expect(void);\n"
|
||||
else
|
||||
@header << "void #{decl[:function]}_ExpectAndReturn(#{decl[:return]} toReturn);\n"
|
||||
header << "void #{function[:name]}_ExpectAndReturn(#{function[:rettype]} toReturn);\n"
|
||||
end
|
||||
else
|
||||
if decl[:return] == "void"
|
||||
@header << "void #{decl[:function]}_Expect(#{decl[:args_no_var_args]});\n"
|
||||
if (function[:rettype] == 'void')
|
||||
header << "void #{function[:name]}_Expect(#{function[:args_string_without_varargs]});\n"
|
||||
else
|
||||
@header << "void #{decl[:function]}_ExpectAndReturn(#{decl[:args_no_var_args]}, #{decl[:return]} toReturn);\n"
|
||||
header << "void #{function[:name]}_ExpectAndReturn(#{function[:args_string_without_varargs]}, #{function[:rettype]} toReturn);\n"
|
||||
end
|
||||
end
|
||||
|
||||
if (@use_cexception)
|
||||
if decl[:args_no_var_args] == "void"
|
||||
@header << "void #{decl[:function]}_ExpectAndThrow(int toThrow);\n"
|
||||
if (function[:args].empty?)
|
||||
header << "void #{function[:name]}_ExpectAndThrow(int toThrow);\n"
|
||||
else
|
||||
@header << "void #{decl[:function]}_ExpectAndThrow(#{decl[:args_no_var_args]}, int toThrow);\n"
|
||||
header << "void #{function[:name]}_ExpectAndThrow(#{function[:args_string_without_varargs]}, int toThrow);\n"
|
||||
end
|
||||
end
|
||||
|
||||
if (@allow_ignore_mock)
|
||||
if decl[:return] == "void"
|
||||
@header << "void #{decl[:function]}_Ignore(void);\n"
|
||||
if (function[:args].empty?)
|
||||
header << "void #{function[:name]}_Ignore(void);\n"
|
||||
else
|
||||
@header << "void #{decl[:function]}_IgnoreAndReturn(#{decl[:return]} toReturn);\n"
|
||||
header << "void #{function[:name]}_IgnoreAndReturn(#{function[:rettype]} toReturn);\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_mock_header_footer
|
||||
@header << "\n#endif\n"
|
||||
def create_mock_header_footer(header)
|
||||
header << "\n#endif\n"
|
||||
end
|
||||
|
||||
def create_source_header_section
|
||||
@source << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
@source << "#include <string.h>\n"
|
||||
@source << "#include <stdlib.h>\n"
|
||||
@source << "#include <setjmp.h>\n"
|
||||
@source << "#include \"unity.h\"\n"
|
||||
@source << "#include \"Exception.h\"\n" if (@use_cexception)
|
||||
@includes.each {|include| @source << "#include \"#{include}\"\n"}
|
||||
@source << "#include \"#{@mock_header_name_dest}\"\n\n"
|
||||
def create_source_header_section(file, include_files)
|
||||
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
file << "#include <string.h>\n"
|
||||
file << "#include <stdlib.h>\n"
|
||||
file << "#include <setjmp.h>\n"
|
||||
file << "#include \"unity.h\"\n"
|
||||
file << "#include \"Exception.h\"\n" if (@use_cexception) ####MSV : REMOVE ME
|
||||
include_files.each {|include| file << "#include \"#{include}\"\n"}
|
||||
file << "#include \"#{@mock_header_name_dest}\"\n\n"
|
||||
end
|
||||
|
||||
def create_instance_structure
|
||||
@source << "static struct #{@mock_name}Instance\n"
|
||||
@source << "{\n"
|
||||
def create_instance_structure(file, functions)
|
||||
file << "static struct #{@mock_name}Instance\n"
|
||||
file << "{\n"
|
||||
|
||||
if @parser.nondefine_functions.length == 0
|
||||
@source << "#{@tab}unsigned char placeHolder;\n"
|
||||
if (functions.size == 0)
|
||||
file << "#{@tab}unsigned char placeHolder;\n"
|
||||
end
|
||||
|
||||
@source << "#{@tab}unsigned char allocFailure;\n"
|
||||
file << "#{@tab}unsigned char allocFailure;\n"
|
||||
|
||||
@parser.nondefine_functions.each do |function|
|
||||
decl = parse_declaration(function)
|
||||
|
||||
@source << "#{@tab}#{@call_count_type} #{decl[:function]}_CallCount;\n"
|
||||
@source << "#{@tab}#{@call_count_type} #{decl[:function]}_CallsExpected;\n"
|
||||
functions.each do |function|
|
||||
|
||||
file << "#{@tab}#{@call_count_type} #{function[:name]}_CallCount;\n"
|
||||
file << "#{@tab}#{@call_count_type} #{function[:name]}_CallsExpected;\n"
|
||||
|
||||
if (@allow_ignore_mock)
|
||||
@source << "#{@tab}#{@ignore_bool} #{decl[:function]}_IgnoreBool;\n"
|
||||
file << "#{@tab}#{@ignore_bool} #{function[:name]}_IgnoreBool;\n"
|
||||
end
|
||||
|
||||
@source << "#{@tab}#{@call_count_type} *#{decl[:function]}_ThrowOnCallCount;\n"
|
||||
@source << "#{@tab}#{@call_count_type} *#{decl[:function]}_ThrowOnCallCount_Head;\n"
|
||||
@source << "#{@tab}#{@call_count_type} *#{decl[:function]}_ThrowOnCallCount_HeadTail;\n"
|
||||
@source << "#{@tab}#{@throw_type} *#{decl[:function]}_ThrowValue;\n"
|
||||
@source << "#{@tab}#{@throw_type} *#{decl[:function]}_ThrowValue_Head;\n"
|
||||
@source << "#{@tab}#{@throw_type} *#{decl[:function]}_ThrowValue_HeadTail;\n"
|
||||
file << "#{@tab}#{@call_count_type} *#{function[:name]}_ThrowOnCallCount;\n"
|
||||
file << "#{@tab}#{@call_count_type} *#{function[:name]}_ThrowOnCallCount_Head;\n"
|
||||
file << "#{@tab}#{@call_count_type} *#{function[:name]}_ThrowOnCallCount_HeadTail;\n"
|
||||
file << "#{@tab}#{@throw_type} *#{function[:name]}_ThrowValue;\n"
|
||||
file << "#{@tab}#{@throw_type} *#{function[:name]}_ThrowValue_Head;\n"
|
||||
file << "#{@tab}#{@throw_type} *#{function[:name]}_ThrowValue_HeadTail;\n"
|
||||
|
||||
if (decl[:return] != "void")
|
||||
@source << "#{@tab}#{decl[:return]} *#{decl[:function]}_Return;\n"
|
||||
@source << "#{@tab}#{decl[:return]} *#{decl[:function]}_Return_Head;\n"
|
||||
@source << "#{@tab}#{decl[:return]} *#{decl[:function]}_Return_HeadTail;\n"
|
||||
if (function[:rettype] != "void")
|
||||
file << "#{@tab}#{function[:rettype]} *#{function[:name]}_Return;\n"
|
||||
file << "#{@tab}#{function[:rettype]} *#{function[:name]}_Return_Head;\n"
|
||||
file << "#{@tab}#{function[:rettype]} *#{function[:name]}_Return_HeadTail;\n"
|
||||
end
|
||||
|
||||
if (decl[:args_no_var_args] != "void")
|
||||
args = parse_args(decl[:args_no_var_args])
|
||||
args.each do |arg|
|
||||
type = arg[:type].sub(/const/, '').strip
|
||||
@source << "#{@tab}#{type} *#{decl[:function]}_Expected_#{arg[:name]};\n"
|
||||
@source << "#{@tab}#{type} *#{decl[:function]}_Expected_#{arg[:name]}_Head;\n"
|
||||
@source << "#{@tab}#{type} *#{decl[:function]}_Expected_#{arg[:name]}_HeadTail;\n"
|
||||
end
|
||||
functions[:args].each do |arg|
|
||||
type = arg[:type].sub(/const/, '').strip
|
||||
file << "#{@tab}#{type} *#{function[:name]}_Expected_#{arg[:name]};\n"
|
||||
file << "#{@tab}#{type} *#{function[:name]}_Expected_#{arg[:name]}_Head;\n"
|
||||
file << "#{@tab}#{type} *#{function[:name]}_Expected_#{arg[:name]}_HeadTail;\n"
|
||||
end
|
||||
end
|
||||
@source << "} Mock;\n\n"
|
||||
file << "} Mock;\n\n"
|
||||
end
|
||||
|
||||
def create_extern_declarations
|
||||
@parser.externs.each do |extern|
|
||||
@source << extern.gsub(/extern/,'') << ";\n"
|
||||
end
|
||||
@source << "extern jmp_buf AbortFrame;\n"
|
||||
@source << "\n"
|
||||
end
|
||||
|
||||
def create_mock_verify_function
|
||||
@source << "void #{@mock_name}_Verify(void)\n{\n"
|
||||
@source << "#{@tab}TEST_ASSERT_EQUAL(0, Mock.allocFailure);\n"
|
||||
@parser.nondefine_functions.each do |function|
|
||||
decl = parse_declaration(function)
|
||||
@source << "#{@tab}TEST_ASSERT_EQUAL_MESSAGE(Mock.#{decl[:function]}_CallsExpected, Mock.#{decl[:function]}_CallCount, \"Function '#{decl[:function]}' called unexpected number of times.\");\n"
|
||||
def create_extern_declarations(file, externs)
|
||||
externs.each do |extern|
|
||||
file << extern.gsub(/extern/,'') << ";\n"
|
||||
end
|
||||
@source << "}\n\n"
|
||||
file << "extern jmp_buf AbortFrame;\n"
|
||||
file << "\n"
|
||||
end
|
||||
|
||||
def create_mock_init_function
|
||||
@source << "void #{@mock_name}_Init(void)\n{\n"
|
||||
@source << "#{@tab}#{@mock_name}_Destroy();\n"
|
||||
@source << "}\n\n"
|
||||
def create_mock_verify_function(file, functions)
|
||||
file << "void #{@mock_name}_Verify(void)\n{\n"
|
||||
file << "#{@tab}TEST_ASSERT_EQUAL(0, Mock.allocFailure);\n"
|
||||
functions.each do |function|
|
||||
file << "#{@tab}TEST_ASSERT_EQUAL_MESSAGE(Mock.#{function[:name]}_CallsExpected, Mock.#{function[:name]}_CallCount, \"Function '#{function[:name]}' called unexpected number of times.\");\n"
|
||||
end
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_destroy_function
|
||||
@source << "void #{@mock_name}_Destroy(void)\n{\n"
|
||||
@parser.nondefine_functions.each do |function|
|
||||
decl = parse_declaration(function)
|
||||
|
||||
if decl[:return] != "void"
|
||||
@source << "#{@tab}if(Mock.#{decl[:function]}_Return_Head)\n"
|
||||
@source << "#{@tab}{\n"
|
||||
@source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_Return_Head);\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Return_Head=NULL;\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Return_HeadTail=NULL;\n"
|
||||
@source << "#{@tab}}\n"
|
||||
def create_mock_init_function(file)
|
||||
file << "void #{@mock_name}_Init(void)\n{\n"
|
||||
file << "#{@tab}#{@mock_name}_Destroy();\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_destroy_function(file, functions)
|
||||
file << "void #{@mock_name}_Destroy(void)\n{\n"
|
||||
functions.each do |function|
|
||||
if function[:rettype] != "void"
|
||||
file << "#{@tab}if(Mock.#{function[:name]}_Return_Head)\n"
|
||||
file << "#{@tab}{\n"
|
||||
file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_Return_Head);\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_Return_Head=NULL;\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_Return_HeadTail=NULL;\n"
|
||||
file << "#{@tab}}\n"
|
||||
end
|
||||
if decl[:args_no_var_args] != "void"
|
||||
args = parse_args(decl[:args_no_var_args])
|
||||
args.each do |arg|
|
||||
@source << "#{@tab}if(Mock.#{decl[:function]}_Expected_#{arg[:name]}_Head)\n"
|
||||
@source << "#{@tab}{\n"
|
||||
@source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_Expected_#{arg[:name]}_Head);\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Expected_#{arg[:name]}_Head=NULL;\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Expected_#{arg[:name]}_HeadTail=NULL;\n"
|
||||
@source << "#{@tab}}\n"
|
||||
end
|
||||
function[:args].each do |arg|
|
||||
file << "#{@tab}if(Mock.#{function[:name]}_Expected_#{arg[:name]}_Head)\n"
|
||||
file << "#{@tab}{\n"
|
||||
file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_Expected_#{arg[:name]}_Head);\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_Expected_#{arg[:name]}_Head=NULL;\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_Expected_#{arg[:name]}_HeadTail=NULL;\n"
|
||||
file << "#{@tab}}\n"
|
||||
end
|
||||
|
||||
@source << "#{@tab}if(Mock.#{decl[:function]}_ThrowOnCallCount_Head)\n"
|
||||
@source << "#{@tab}{\n"
|
||||
@source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_ThrowOnCallCount_Head);\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount_Head=NULL;\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount_HeadTail=NULL;\n"
|
||||
@source << "#{@tab}}\n"
|
||||
file << "#{@tab}if(Mock.#{function[:name]}_ThrowOnCallCount_Head)\n"
|
||||
file << "#{@tab}{\n"
|
||||
file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_ThrowOnCallCount_Head);\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowOnCallCount_Head=NULL;\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowOnCallCount_HeadTail=NULL;\n"
|
||||
file << "#{@tab}}\n"
|
||||
|
||||
@source << "#{@tab}if(Mock.#{decl[:function]}_ThrowValue_Head)\n"
|
||||
@source << "#{@tab}{\n"
|
||||
@source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_ThrowValue_Head);\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowValue_Head=NULL;\n"
|
||||
@source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowValue_HeadTail=NULL;\n"
|
||||
@source << "#{@tab}}\n"
|
||||
file << "#{@tab}if(Mock.#{function[:name]}_ThrowValue_Head)\n"
|
||||
file << "#{@tab}{\n"
|
||||
file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_ThrowValue_Head);\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowValue_Head=NULL;\n"
|
||||
file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowValue_HeadTail=NULL;\n"
|
||||
file << "#{@tab}}\n"
|
||||
end
|
||||
@source << "#{@tab}memset(&Mock, 0, sizeof(Mock));\n"
|
||||
@source << "}\n\n"
|
||||
file << "#{@tab}memset(&Mock, 0, sizeof(Mock));\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_argument_verifier(arguments)
|
||||
@source << "void AssertParameters_#{decl[:function]}(#{decl[:args_no_var_args]})\n{\n"
|
||||
def create_mock_argument_verifier(file, func_name, argument_string, arguments)
|
||||
file << "void AssertParameters_#{func_name}(#{argument_string})\n{\n"
|
||||
arguments.each do |arg|
|
||||
type = arg[:type].sub(/const/, '').strip
|
||||
@source << make_handle_expected(decl[:function], type, arg[:name])
|
||||
file << make_handle_expected(func_name, type, arg[:name])
|
||||
end
|
||||
@source << "}\n\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_call_list(decl)
|
||||
args = parse_args(decl[:args_no_var_args])
|
||||
call_list = ""
|
||||
args.each do |arg|
|
||||
if call_list.empty?
|
||||
call_list = arg[:name]
|
||||
else
|
||||
call_list += ", " + arg[:name]
|
||||
end
|
||||
end
|
||||
return call_list
|
||||
end
|
||||
|
||||
def create_mock_implementation(function)
|
||||
|
||||
decl = parse_declaration(function)
|
||||
def create_mock_implementation(file, function)
|
||||
|
||||
newtab = "#{@tab}"
|
||||
|
||||
# Create mock argument verifier, if necessary
|
||||
if decl[:args] != "void"
|
||||
args = parse_args(decl[:args_no_var_args])
|
||||
create_mock_argument_verifier(args)
|
||||
unless function[:args].empty?
|
||||
create_mock_argument_verifier(file, function[:name], function[:args_string_without_varargs], function[:args])
|
||||
end
|
||||
|
||||
# Create mock function
|
||||
@source << "#{decl[:modifier]} " if (!decl[:modifier].nil? && decl[:modifier].length > 0)
|
||||
@source << "#{decl[:return]} #{decl[:function]}(#{decl[:args]})\n"
|
||||
@source << "{\n"
|
||||
file << "#{function[:attributes]} " if (!function[:attributes].nil? && function[:attributes].length > 0)
|
||||
file << "#{function[:rettype]} #{function[:name]}(#{function[:args_string]})\n"
|
||||
file << "{\n"
|
||||
|
||||
# start ignore block
|
||||
if (@allow_ignore_mock)
|
||||
newtab = "#{@tab}#{@tab}"
|
||||
@source << "#{@tab}if (!Mock.#{decl[:function]}_IgnoreBool)\n"
|
||||
@source << "#{@tab}{\n"
|
||||
file << "#{@tab}if (!Mock.#{function[:name]}_IgnoreBool)\n"
|
||||
file << "#{@tab}{\n"
|
||||
end
|
||||
|
||||
@source << "#{newtab}Mock.#{decl[:function]}_CallCount++;\n"
|
||||
file << "#{newtab}Mock.#{function[:name]}_CallCount++;\n"
|
||||
|
||||
#create overcall protection
|
||||
exp = "Mock.#{decl[:function]}_CallsExpected"
|
||||
@source << "#{newtab}if (Mock.#{decl[:function]}_CallCount > Mock.#{decl[:function]}_CallsExpected)\n"
|
||||
@source << "#{newtab}{\n"
|
||||
@source << "#{newtab}#{@tab}TEST_THROW(\"#{decl[:function]} Called More Times Than Expected\");\n"
|
||||
@source << "#{newtab}}\n"
|
||||
exp = "Mock.#{function[:name]}_CallsExpected"
|
||||
file << "#{newtab}if (Mock.#{function[:name]}_CallCount > Mock.#{function[:name]}_CallsExpected)\n"
|
||||
file << "#{newtab}{\n"
|
||||
file << "#{newtab}#{@tab}TEST_THROW(\"#{function[:name]} Called More Times Than Expected\");\n"
|
||||
file << "#{newtab}}\n"
|
||||
|
||||
# Create call to argument verifier, if necessary
|
||||
if decl[:args_no_var_args] != "void"
|
||||
@source << "#{newtab}AssertParameters_#{decl[:function]}(#{create_call_list(decl)});\n"
|
||||
unless function[:args].empty?
|
||||
file << "#{newtab}AssertParameters_#{function[:name]}(#{function[:args_string]});\n"
|
||||
end
|
||||
|
||||
# Throw exception, if appropriate
|
||||
@source << make_handle_throw(decl[:function], @throw_type) if (@use_cexception)
|
||||
file << make_handle_throw(function[:name], @throw_type) if (@use_cexception)
|
||||
|
||||
# end ignore block
|
||||
if (@allow_ignore_mock)
|
||||
@source << "#{@tab}}\n"
|
||||
file << "#{@tab}}\n"
|
||||
end
|
||||
|
||||
# Return expected value, if necessary
|
||||
if decl[:return] != "void"
|
||||
@source << make_handle_return(decl[:function], decl[:return])
|
||||
if function[:rettype] != "void"
|
||||
file << make_handle_return(function[:name], function[:rettype])
|
||||
end
|
||||
|
||||
# Close out the function
|
||||
@source << "}\n\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_function_expectation(function)
|
||||
decl = parse_declaration(function)
|
||||
if decl[:args_no_var_args] == "void"
|
||||
def create_mock_function_expectation(file, function)
|
||||
|
||||
if (function[:args].empty?)
|
||||
# Function has void return type with no arguments
|
||||
if decl[:return] == "void"
|
||||
@source << "void #{decl[:function]}_Expect(void)\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n"
|
||||
@source << "}\n\n"
|
||||
if (function[:rettype] == "void")
|
||||
file << "void #{function[:name]}_Expect(void)\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n"
|
||||
file << "}\n\n"
|
||||
# Function has non-void return type with no arguments
|
||||
else
|
||||
@source << "void #{decl[:function]}_ExpectAndReturn(#{decl[:return]} toReturn)\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n"
|
||||
@source << make_expand_array(decl[:return], "Mock.#{decl[:function]}_Return_Head", "toReturn")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_Return = Mock.#{decl[:function]}_Return_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_Return += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << "}\n\n"
|
||||
file << "void #{function[:name]}_ExpectAndReturn(#{function[:rettype]} toReturn)\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n"
|
||||
file << make_expand_array(function[:rettype], "Mock.#{function[:name]}_Return_Head", "toReturn")
|
||||
file << "#{@tab}Mock.#{function[:name]}_Return = Mock.#{function[:name]}_Return_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_Return += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
else
|
||||
|
||||
# Parse function arguments
|
||||
args = parse_args(decl[:args_no_var_args])
|
||||
|
||||
# Create parameter expectation function
|
||||
@source << "void ExpectParameters_#{decl[:function]}(#{decl[:args_no_var_args]})\n"
|
||||
@source << "{\n"
|
||||
file << "void ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]})\n"
|
||||
file << "{\n"
|
||||
args.each do |arg|
|
||||
type = arg[:type].sub(/const/, '').strip
|
||||
@source << make_add_new_expected(decl[:function], type, arg[:name])
|
||||
file << make_add_new_expected(function[:name], type, arg[:name])
|
||||
end
|
||||
@source << "}\n\n"
|
||||
file << "}\n\n"
|
||||
|
||||
# Function has void return type with arguments
|
||||
if decl[:return] == "void"
|
||||
@source << "void #{decl[:function]}_Expect(#{decl[:args_no_var_args]})\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n"
|
||||
@source << "#{@tab}ExpectParameters_#{decl[:function]}(#{create_call_list(decl)});\n"
|
||||
@source << "}\n\n"
|
||||
if function[:rettype] == "void"
|
||||
file << "void #{function[:name]}_Expect(#{function[:args_string_without_varargs]})\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n"
|
||||
file << "#{@tab}ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]});\n"
|
||||
file << "}\n\n"
|
||||
# Function has non-void return type with arguments
|
||||
else
|
||||
@source << "void #{decl[:function]}_ExpectAndReturn(#{decl[:args_no_var_args]}, #{decl[:return]} toReturn)\n{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n"
|
||||
@source << "#{@tab}ExpectParameters_#{decl[:function]}(#{create_call_list(decl)});\n"
|
||||
@source << make_expand_array(decl[:return], "Mock.#{decl[:function]}_Return_Head", "toReturn")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_Return = Mock.#{decl[:function]}_Return_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_Return += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << "}\n\n"
|
||||
file << "void #{function[:name]}_ExpectAndReturn(#{function[:args_string_without_varargs]}, #{function[:rettype]} toReturn)\n{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n"
|
||||
file << "#{@tab}ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]});\n"
|
||||
file << make_expand_array(function[:rettype], "Mock.#{function[:name]}_Return_Head", "toReturn")
|
||||
file << "#{@tab}Mock.#{function[:name]}_Return = Mock.#{function[:name]}_Return_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_Return += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_mock_function_expectation_with_throw(function)
|
||||
decl = parse_declaration(function)
|
||||
def create_mock_function_expectation_with_throw(file, function)
|
||||
|
||||
# function takes no arguments
|
||||
if decl[:args_no_var_args] == "void"
|
||||
@source << "void #{decl[:function]}_ExpectAndThrow(#{@throw_type} toThrow)\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n"
|
||||
@source << make_expand_array(@call_count_type, "Mock.#{decl[:function]}_ThrowOnCallCount_Head", "Mock.#{decl[:function]}_CallsExpected")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount = Mock.#{decl[:function]}_ThrowOnCallCount_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << make_expand_array(@throw_type, "Mock.#{decl[:function]}_ThrowValue_Head", "toThrow")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowValue = Mock.#{decl[:function]}_ThrowValue_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowValue += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << "}\n\n"
|
||||
if (function[:args].empty?)
|
||||
file << "void #{function[:name]}_ExpectAndThrow(#{@throw_type} toThrow)\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n"
|
||||
file << make_expand_array(@call_count_type, "Mock.#{function[:name]}_ThrowOnCallCount_Head", "Mock.#{function[:name]}_CallsExpected")
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount = Mock.#{function[:name]}_ThrowOnCallCount_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << make_expand_array(@throw_type, "Mock.#{function[:name]}_ThrowValue_Head", "toThrow")
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowValue = Mock.#{function[:name]}_ThrowValue_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowValue += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << "}\n\n"
|
||||
else
|
||||
# Parse function arguments
|
||||
args = parse_args(decl[:args_no_var_args])
|
||||
|
||||
@source << "void #{decl[:function]}_ExpectAndThrow(#{decl[:args_no_var_args]}, #{@throw_type} toThrow)\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n"
|
||||
@source << make_expand_array(@call_count_type, "Mock.#{decl[:function]}_ThrowOnCallCount_Head", "Mock.#{decl[:function]}_CallsExpected")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount = Mock.#{decl[:function]}_ThrowOnCallCount_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << make_expand_array(@throw_type, "Mock.#{decl[:function]}_ThrowValue_Head", "toThrow")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowValue = Mock.#{decl[:function]}_ThrowValue_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_ThrowValue += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << "#{@tab}ExpectParameters_#{decl[:function]}(#{create_call_list(decl)});\n"
|
||||
@source << "}\n\n"
|
||||
file << "void #{function[:name]}_ExpectAndThrow(#{function[:args_string_without_varargs]}, #{@throw_type} toThrow)\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n"
|
||||
file << make_expand_array(@call_count_type, "Mock.#{function[:name]}_ThrowOnCallCount_Head", "Mock.#{function[:name]}_CallsExpected")
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount = Mock.#{function[:name]}_ThrowOnCallCount_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << make_expand_array(@throw_type, "Mock.#{function[:name]}_ThrowValue_Head", "toThrow")
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowValue = Mock.#{function[:name]}_ThrowValue_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_ThrowValue += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << "#{@tab}ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]});\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
end
|
||||
|
||||
def create_mock_function_ignore(function)
|
||||
decl = parse_declaration(function)
|
||||
def create_mock_function_ignore(file, function)
|
||||
# Function has void return type with no arguments
|
||||
if decl[:return] == "void"
|
||||
@source << "void #{decl[:function]}_Ignore(void)\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_IgnoreBool = (unsigned char)1;\n"
|
||||
@source << "}\n\n"
|
||||
if function[:rettype] == "void"
|
||||
file << "void #{function[:name]}_Ignore(void)\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_IgnoreBool = (unsigned char)1;\n"
|
||||
file << "}\n\n"
|
||||
# Function has non-void return type with no arguments
|
||||
else
|
||||
@source << "void #{decl[:function]}_IgnoreAndReturn(#{decl[:return]} toReturn)\n"
|
||||
@source << "{\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_IgnoreBool = (unsigned char)1;\n"
|
||||
@source << make_expand_array(decl[:return], "Mock.#{decl[:function]}_Return_Head", "toReturn")
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_Return = Mock.#{decl[:function]}_Return_Head;\n"
|
||||
@source << "#{@tab}Mock.#{decl[:function]}_Return += Mock.#{decl[:function]}_CallCount;\n"
|
||||
@source << "}\n\n"
|
||||
file << "void #{function[:name]}_IgnoreAndReturn(#{function[:rettype]} toReturn)\n"
|
||||
file << "{\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_IgnoreBool = (unsigned char)1;\n"
|
||||
file << make_expand_array(function[:rettype], "Mock.#{function[:name]}_Return_Head", "toReturn")
|
||||
file << "#{@tab}Mock.#{function[:name]}_Return = Mock.#{function[:name]}_Return_Head;\n"
|
||||
file << "#{@tab}Mock.#{function[:name]}_Return += Mock.#{function[:name]}_CallCount;\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -480,12 +446,12 @@ EOS
|
||||
#{newtab}if((Mock.#{method}_ThrowOnCallCount != Mock.#{method}_ThrowOnCallCount_HeadTail) &&
|
||||
#{newtab}#{@tab}(Mock.#{method}_ThrowValue != Mock.#{method}_ThrowValue_HeadTail))
|
||||
#{newtab}{
|
||||
#{newtab}#{@tab}if (*Mock.#{decl[:function]}_ThrowOnCallCount &&
|
||||
#{newtab}#{@tab}#{@tab}(Mock.#{decl[:function]}_CallCount == *Mock.#{decl[:function]}_ThrowOnCallCount))
|
||||
#{newtab}#{@tab}if (*Mock.#{function[:name]}_ThrowOnCallCount &&
|
||||
#{newtab}#{@tab}#{@tab}(Mock.#{function[:name]}_CallCount == *Mock.#{function[:name]}_ThrowOnCallCount))
|
||||
#{newtab}#{@tab}{
|
||||
#{newtab}#{@tab}#{@tab}#{throw_type} toThrow = *Mock.#{decl[:function]}_ThrowValue;
|
||||
#{newtab}#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount++;
|
||||
#{newtab}#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowValue++;
|
||||
#{newtab}#{@tab}#{@tab}#{throw_type} toThrow = *Mock.#{function[:name]}_ThrowValue;
|
||||
#{newtab}#{@tab}#{@tab}Mock.#{function[:name]}_ThrowOnCallCount++;
|
||||
#{newtab}#{@tab}#{@tab}Mock.#{function[:name]}_ThrowValue++;
|
||||
#{newtab}#{@tab}#{@tab}Throw(toThrow);
|
||||
#{newtab}#{@tab}}
|
||||
#{newtab}}
|
||||
@@ -513,7 +479,7 @@ EOS
|
||||
def make_add_new_expected(method, type, expected)
|
||||
array = make_expand_array(type, "Mock.#{method}_Expected_#{expected}_Head", expected)
|
||||
array = "#{array}" + "#{@tab}Mock.#{method}_Expected_#{expected} = Mock.#{method}_Expected_#{expected}_Head;\n"
|
||||
return "#{array}" + "#{@tab}Mock.#{method}_Expected_#{expected} += Mock.#{decl[:function]}_CallCount;\n"
|
||||
return "#{array}" + "#{@tab}Mock.#{method}_Expected_#{expected} += Mock.#{function[:name]}_CallCount;\n"
|
||||
end
|
||||
|
||||
def make_handle_expected(method, type, actual)
|
||||
|
||||
+11
-4
@@ -1,5 +1,7 @@
|
||||
$here = File.dirname __FILE__
|
||||
require "#{$here}/cmock_header_parser"
|
||||
require "#{$here}/cmock_generator"
|
||||
require "#{$here}/cmock_config"
|
||||
|
||||
class CMockSetup
|
||||
|
||||
@@ -23,9 +25,14 @@ class CMockSetup
|
||||
def generate_mock(src)
|
||||
name = File.basename(src, '.h')
|
||||
path = File.dirname(src)
|
||||
cmg = CMockGenerator.new(name, path, @mocks_path, @includes, @use_cexception, @allow_ignore_mock)
|
||||
$stderr.puts "Creating mock for #{name}..."
|
||||
$stderr.flush
|
||||
cmg.create_mock
|
||||
|
||||
cmc = CMockConfig.new(path, @mocks_path, @includes, @use_cexception, @allow_ignore_mock)
|
||||
cmp = CMockHeaderParser.new(File.read(src))
|
||||
cmg = CMockGenerator.new(cmc, name)
|
||||
|
||||
puts "Creating mock for #{name}..."
|
||||
flush
|
||||
parsed_stuff = cmp.parse
|
||||
cmg.create_mock(parsed_stuff)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user