- add ceedling/cmock/unity as testing framework and support
- unified makefile project for the whole repos - new separate project for tests
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
# Setup our load path:
|
||||
[
|
||||
'lib',
|
||||
].each do |dir|
|
||||
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__)) + '/../', dir) )
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
# Setup our load path:
|
||||
[
|
||||
'lib',
|
||||
'vendor/behaviors/lib',
|
||||
'vendor/hardmock/lib',
|
||||
'vendor/unity/auto/',
|
||||
'test/system/'
|
||||
].each do |dir|
|
||||
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) )
|
||||
end
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
[ "../config/production_environment",
|
||||
"cmock_header_parser",
|
||||
"cmock_generator",
|
||||
"cmock_file_writer",
|
||||
"cmock_config",
|
||||
"cmock_plugin_manager",
|
||||
"cmock_generator_utils",
|
||||
"cmock_unityhelper_parser"].each {|req| require "#{File.expand_path(File.dirname(__FILE__))}/#{req}"}
|
||||
|
||||
class CMock
|
||||
|
||||
def initialize(options=nil)
|
||||
cm_config = CMockConfig.new(options)
|
||||
cm_unityhelper = CMockUnityHelperParser.new(cm_config)
|
||||
cm_writer = CMockFileWriter.new(cm_config)
|
||||
cm_gen_utils = CMockGeneratorUtils.new(cm_config, {:unity_helper => cm_unityhelper})
|
||||
cm_gen_plugins = CMockPluginManager.new(cm_config, cm_gen_utils)
|
||||
@cm_parser = CMockHeaderParser.new(cm_config)
|
||||
@cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils, cm_gen_plugins)
|
||||
@silent = (cm_config.verbosity < 2)
|
||||
end
|
||||
|
||||
def setup_mocks(files)
|
||||
[files].flatten.each do |src|
|
||||
generate_mock src
|
||||
end
|
||||
end
|
||||
|
||||
private ###############################
|
||||
|
||||
def generate_mock(src)
|
||||
name = File.basename(src, '.h')
|
||||
puts "Creating mock for #{name}..." unless @silent
|
||||
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)))
|
||||
end
|
||||
end
|
||||
|
||||
# Command Line Support ###############################
|
||||
|
||||
if ($0 == __FILE__)
|
||||
usage = "usage: ruby #{__FILE__} (-oOptionsFile) File(s)ToMock"
|
||||
|
||||
if (!ARGV[0])
|
||||
puts usage
|
||||
exit 1
|
||||
end
|
||||
|
||||
options = nil
|
||||
filelist = []
|
||||
ARGV.each do |arg|
|
||||
if (arg =~ /^-o(\w*)/)
|
||||
options = arg.gsub(/^-o/,'')
|
||||
else
|
||||
filelist << arg
|
||||
end
|
||||
end
|
||||
|
||||
CMock.new(options).setup_mocks(filelist)
|
||||
end
|
||||
@@ -0,0 +1,129 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockConfig
|
||||
|
||||
CMockDefaultOptions =
|
||||
{
|
||||
:framework => :unity,
|
||||
:mock_path => 'mocks',
|
||||
:mock_prefix => 'Mock',
|
||||
:plugins => [],
|
||||
:strippables => ['(?:__attribute__\s*\(+.*?\)+)'],
|
||||
:attributes => ['__ramfunc', '__irq', '__fiq', 'register', 'extern'],
|
||||
:c_calling_conventions => ['__stdcall', '__cdecl', '__fastcall'],
|
||||
:enforce_strict_ordering => false,
|
||||
:unity_helper_path => false,
|
||||
:treat_as => {},
|
||||
:treat_as_void => [],
|
||||
:memcmp_if_unknown => true,
|
||||
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
|
||||
:when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart
|
||||
:verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
|
||||
:treat_externs => :exclude, #the options being :include or :exclude
|
||||
:ignore => :args_and_calls, #the options being :args_and_calls or :args_only
|
||||
:callback_include_count => true,
|
||||
:callback_after_arg_check => false,
|
||||
:includes => nil,
|
||||
:includes_h_pre_orig_header => nil,
|
||||
:includes_h_post_orig_header => nil,
|
||||
:includes_c_pre_header => nil,
|
||||
:includes_c_post_header => nil
|
||||
}
|
||||
|
||||
def initialize(options=nil)
|
||||
case(options)
|
||||
when NilClass then options = CMockDefaultOptions.clone
|
||||
when String then options = CMockDefaultOptions.clone.merge(load_config_file_from_yaml(options))
|
||||
when Hash then options = CMockDefaultOptions.clone.merge(options)
|
||||
else raise "If you specify arguments, it should be a filename or a hash of options"
|
||||
end
|
||||
|
||||
#do some quick type verification
|
||||
[:plugins, :attributes, :treat_as_void].each do |opt|
|
||||
unless (options[opt].class == Array)
|
||||
options[opt] = []
|
||||
puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1)
|
||||
end
|
||||
end
|
||||
[:includes, :includes_h_pre_orig_header, :includes_h_post_orig_header, :includes_c_pre_header, :includes_c_post_header].each do |opt|
|
||||
unless (options[opt].nil? or (options[opt].class == Array))
|
||||
options[opt] = []
|
||||
puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1)
|
||||
end
|
||||
end
|
||||
options[:unity_helper_path] ||= options[:unity_helper]
|
||||
options[:plugins].compact!
|
||||
options[:plugins].map! {|p| p.to_sym}
|
||||
@options = options
|
||||
|
||||
treat_as_map = standard_treat_as_map()#.clone
|
||||
treat_as_map.merge!(@options[:treat_as])
|
||||
@options[:treat_as] = treat_as_map
|
||||
|
||||
@options.each_key { |key| eval("def #{key.to_s}() return @options[:#{key.to_s}] end") }
|
||||
end
|
||||
|
||||
def load_config_file_from_yaml yaml_filename
|
||||
require 'yaml'
|
||||
require 'fileutils'
|
||||
YAML.load_file(yaml_filename)[:cmock]
|
||||
end
|
||||
|
||||
def set_path(path)
|
||||
@src_path = path
|
||||
end
|
||||
|
||||
def load_unity_helper
|
||||
return File.new(@options[:unity_helper_path]).read if (@options[:unity_helper_path])
|
||||
return nil
|
||||
end
|
||||
|
||||
def standard_treat_as_map
|
||||
{
|
||||
'int' => 'INT',
|
||||
'char' => 'INT8',
|
||||
'short' => 'INT16',
|
||||
'long' => 'INT',
|
||||
'int8' => 'INT8',
|
||||
'int16' => 'INT16',
|
||||
'int32' => 'INT',
|
||||
'int8_t' => 'INT8',
|
||||
'int16_t' => 'INT16',
|
||||
'int32_t' => 'INT',
|
||||
'INT8_T' => 'INT8',
|
||||
'INT16_T' => 'INT16',
|
||||
'INT32_T' => 'INT',
|
||||
'bool' => 'INT',
|
||||
'bool_t' => 'INT',
|
||||
'BOOL' => 'INT',
|
||||
'BOOL_T' => 'INT',
|
||||
'unsigned int' => 'HEX32',
|
||||
'unsigned long' => 'HEX32',
|
||||
'uint32' => 'HEX32',
|
||||
'uint32_t' => 'HEX32',
|
||||
'UINT32' => 'HEX32',
|
||||
'UINT32_T' => 'HEX32',
|
||||
'void*' => 'PTR',
|
||||
'unsigned short' => 'HEX16',
|
||||
'uint16' => 'HEX16',
|
||||
'uint16_t' => 'HEX16',
|
||||
'UINT16' => 'HEX16',
|
||||
'UINT16_T' => 'HEX16',
|
||||
'unsigned char' => 'HEX8',
|
||||
'uint8' => 'HEX8',
|
||||
'uint8_t' => 'HEX8',
|
||||
'UINT8' => 'HEX8',
|
||||
'UINT8_T' => 'HEX8',
|
||||
'char*' => 'STRING',
|
||||
'pCHAR' => 'STRING',
|
||||
'cstring' => 'STRING',
|
||||
'CSTRING' => 'STRING',
|
||||
'float' => 'FLOAT',
|
||||
'double' => 'FLOAT'
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockFileWriter
|
||||
|
||||
attr_reader :config
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def create_file(filename)
|
||||
raise "Where's the block of data to create?" unless block_given?
|
||||
full_file_name_temp = "#{@config.mock_path}/#{filename}.new"
|
||||
full_file_name_done = "#{@config.mock_path}/#{filename}"
|
||||
File.open(full_file_name_temp, 'w') do |file|
|
||||
yield(file, filename)
|
||||
end
|
||||
update_file(full_file_name_done, full_file_name_temp)
|
||||
end
|
||||
|
||||
private ###################################
|
||||
|
||||
def update_file(dest, src)
|
||||
require 'fileutils'
|
||||
FileUtils.rm(dest) if (File.exist?(dest))
|
||||
FileUtils.cp(src, dest)
|
||||
FileUtils.rm(src)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,194 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
$here = File.dirname __FILE__
|
||||
|
||||
class CMockGenerator
|
||||
|
||||
attr_accessor :config, :file_writer, :module_name, :mock_name, :utils, :plugins, :ordered
|
||||
|
||||
def initialize(config, file_writer, utils, plugins)
|
||||
@file_writer = file_writer
|
||||
@utils = utils
|
||||
@plugins = plugins
|
||||
@config = config
|
||||
@prefix = @config.mock_prefix
|
||||
@ordered = @config.enforce_strict_ordering
|
||||
@framework = @config.framework.to_s
|
||||
|
||||
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
@includes_c_pre_header = (@config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
@includes_c_post_header = (@config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
end
|
||||
|
||||
def create_mock(module_name, parsed_stuff)
|
||||
@module_name = module_name
|
||||
@mock_name = @prefix + @module_name
|
||||
create_mock_header_file(parsed_stuff)
|
||||
create_mock_source_file(parsed_stuff)
|
||||
end
|
||||
|
||||
private if $ThisIsOnlyATest.nil? ##############################
|
||||
|
||||
def create_mock_header_file(parsed_stuff)
|
||||
@file_writer.create_file(@mock_name + ".h") do |file, filename|
|
||||
create_mock_header_header(file, filename)
|
||||
create_mock_header_service_call_declarations(file)
|
||||
create_typedefs(file, parsed_stuff[:typedefs])
|
||||
parsed_stuff[:functions].each do |function|
|
||||
file << @plugins.run(:mock_function_declarations, function)
|
||||
end
|
||||
create_mock_header_footer(file)
|
||||
end
|
||||
end
|
||||
|
||||
def create_mock_source_file(parsed_stuff)
|
||||
@file_writer.create_file(@mock_name + ".c") do |file, filename|
|
||||
create_source_header_section(file, filename)
|
||||
create_instance_structure(file, parsed_stuff[:functions])
|
||||
create_extern_declarations(file)
|
||||
create_mock_verify_function(file, parsed_stuff[:functions])
|
||||
create_mock_init_function(file)
|
||||
create_mock_destroy_function(file, parsed_stuff[:functions])
|
||||
parsed_stuff[:functions].each do |function|
|
||||
create_mock_implementation(file, function)
|
||||
create_mock_interfaces(file, function)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_mock_header_header(file, filename)
|
||||
define_name = filename.gsub(/\.h/, "_h").upcase
|
||||
orig_filename = filename.gsub(@config.mock_prefix, "")
|
||||
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
file << "#ifndef _#{define_name}\n"
|
||||
file << "#define _#{define_name}\n\n"
|
||||
@includes_h_pre_orig_header.each {|inc| file << "#include #{inc}\n"}
|
||||
file << "#include \"#{orig_filename}\"\n"
|
||||
@includes_h_post_orig_header.each {|inc| file << "#include #{inc}\n"}
|
||||
plugin_includes = @plugins.run(:include_files)
|
||||
file << plugin_includes if (!plugin_includes.empty?)
|
||||
file << "\n"
|
||||
end
|
||||
|
||||
def create_typedefs(file, typedefs)
|
||||
file << "\n"
|
||||
typedefs.each {|typedef| file << "#{typedef}\n" }
|
||||
file << "\n\n"
|
||||
end
|
||||
|
||||
def create_mock_header_service_call_declarations(file)
|
||||
file << "void #{@mock_name}_Init(void);\n"
|
||||
file << "void #{@mock_name}_Destroy(void);\n"
|
||||
file << "void #{@mock_name}_Verify(void);\n\n"
|
||||
end
|
||||
|
||||
def create_mock_header_footer(header)
|
||||
header << "\n#endif\n"
|
||||
end
|
||||
|
||||
def create_source_header_section(file, filename)
|
||||
header_file = filename.gsub(".c",".h")
|
||||
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
file << "#include <string.h>\n"
|
||||
file << "#include <stdlib.h>\n"
|
||||
file << "#include <setjmp.h>\n"
|
||||
file << "#include \"#{@framework}.h\"\n"
|
||||
file << "#include \"cmock.h\"\n"
|
||||
@includes_c_pre_header.each {|inc| file << "#include #{inc}\n"}
|
||||
file << "#include \"#{header_file}\"\n"
|
||||
@includes_c_post_header.each {|inc| file << "#include #{inc}\n"}
|
||||
file << "\n"
|
||||
end
|
||||
|
||||
def create_instance_structure(file, functions)
|
||||
functions.each do |function|
|
||||
file << "typedef struct _CMOCK_#{function[:name]}_CALL_INSTANCE\n{\n"
|
||||
file << " UNITY_LINE_TYPE LineNumber;\n"
|
||||
file << @plugins.run(:instance_typedefs, function)
|
||||
file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n"
|
||||
end
|
||||
file << "static struct #{@mock_name}Instance\n{\n"
|
||||
if (functions.size == 0)
|
||||
file << " unsigned char placeHolder;\n"
|
||||
end
|
||||
functions.each do |function|
|
||||
file << @plugins.run(:instance_structure, function)
|
||||
file << " CMOCK_MEM_INDEX_TYPE #{function[:name]}_CallInstance;\n"
|
||||
end
|
||||
file << "} Mock;\n\n"
|
||||
end
|
||||
|
||||
def create_extern_declarations(file)
|
||||
file << "extern jmp_buf AbortFrame;\n"
|
||||
if (@ordered)
|
||||
file << "extern int GlobalExpectCount;\n"
|
||||
file << "extern int GlobalVerifyOrder;\n"
|
||||
end
|
||||
file << "\n"
|
||||
end
|
||||
|
||||
def create_mock_verify_function(file, functions)
|
||||
file << "void #{@mock_name}_Verify(void)\n{\n"
|
||||
verifications = functions.collect {|function| @plugins.run(:mock_verify, function)}.join
|
||||
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" unless verifications.empty?
|
||||
file << verifications
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_init_function(file)
|
||||
file << "void #{@mock_name}_Init(void)\n{\n"
|
||||
file << " #{@mock_name}_Destroy();\n"
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_destroy_function(file, functions)
|
||||
file << "void #{@mock_name}_Destroy(void)\n{\n"
|
||||
file << " CMock_Guts_MemFreeAll();\n"
|
||||
file << " memset(&Mock, 0, sizeof(Mock));\n"
|
||||
file << functions.collect {|function| @plugins.run(:mock_destroy, function)}.join
|
||||
if (@ordered)
|
||||
file << " GlobalExpectCount = 0;\n"
|
||||
file << " GlobalVerifyOrder = 0;\n"
|
||||
end
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_implementation(file, function)
|
||||
# prepare return value and arguments
|
||||
function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") +
|
||||
(function[:return][:type]) +
|
||||
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
|
||||
args_string = function[:args_string]
|
||||
args_string += (", " + function[:var_arg]) unless (function[:var_arg].nil?)
|
||||
|
||||
# Create mock function
|
||||
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string})\n"
|
||||
file << "{\n"
|
||||
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
|
||||
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n"
|
||||
file << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
|
||||
file << @plugins.run(:mock_implementation_precheck, function)
|
||||
file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, \"Function '#{function[:name]}' called more times than expected.\");\n"
|
||||
file << " cmock_line = cmock_call_instance->LineNumber;\n"
|
||||
if (@ordered)
|
||||
file << " if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)\n"
|
||||
file << " UNITY_TEST_FAIL(cmock_line, \"Function '#{function[:name]}' called earlier than expected.\");\n"
|
||||
file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n"
|
||||
file << " UNITY_TEST_FAIL(cmock_line, \"Function '#{function[:name]}' called later than expected.\");\n"
|
||||
# file << " UNITY_TEST_ASSERT((cmock_call_instance->CallOrder == ++GlobalVerifyOrder), cmock_line, \"Out of order function calls. Function '#{function[:name]}'\");\n"
|
||||
end
|
||||
file << @plugins.run(:mock_implementation, function)
|
||||
file << " return cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?])
|
||||
file << "}\n\n"
|
||||
end
|
||||
|
||||
def create_mock_interfaces(file, function)
|
||||
file << @utils.code_add_argument_loader(function)
|
||||
file << @plugins.run(:mock_interfaces, function)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,57 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockGeneratorPluginArray
|
||||
|
||||
attr_reader :priority
|
||||
attr_accessor :config, :utils, :unity_helper, :ordered
|
||||
def initialize(config, utils)
|
||||
@config = config
|
||||
@ptr_handling = @config.when_ptr
|
||||
@ordered = @config.enforce_strict_ordering
|
||||
@utils = utils
|
||||
@unity_helper = @utils.helpers[:unity_helper]
|
||||
@priority = 8
|
||||
end
|
||||
|
||||
def instance_typedefs(function)
|
||||
function[:args].inject("") do |all, arg|
|
||||
(arg[:ptr?]) ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
|
||||
end
|
||||
end
|
||||
|
||||
def mock_function_declarations(function)
|
||||
return nil unless function[:contains_ptr?]
|
||||
args_call = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : "#{m[:name]}"}.join(', ')
|
||||
args_string = function[:args].map{|m| m[:ptr?] ? "#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{m[:type]} #{m[:name]}"}.join(', ')
|
||||
if (function[:return][:void?])
|
||||
return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" +
|
||||
"void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
|
||||
else
|
||||
return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" +
|
||||
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
|
||||
end
|
||||
end
|
||||
|
||||
def mock_interfaces(function)
|
||||
return nil unless function[:contains_ptr?]
|
||||
lines = []
|
||||
func_name = function[:name]
|
||||
args_string = function[:args].map{|m| m[:ptr?] ? "#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{m[:type]} #{m[:name]}"}.join(', ')
|
||||
call_string = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name]}.join(', ')
|
||||
if (function[:return][:void?])
|
||||
lines << "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n"
|
||||
else
|
||||
lines << "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n"
|
||||
end
|
||||
lines << "{\n"
|
||||
lines << @utils.code_add_base_expectation(func_name)
|
||||
lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n"
|
||||
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless (function[:return][:void?])
|
||||
lines << "}\n\n"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,78 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockGeneratorPluginCallback
|
||||
|
||||
attr_accessor :include_count
|
||||
attr_reader :priority
|
||||
attr_reader :config, :utils
|
||||
|
||||
def initialize(config, utils)
|
||||
@config = config
|
||||
@utils = utils
|
||||
@priority = 6
|
||||
|
||||
@include_count = @config.callback_include_count
|
||||
if (@config.callback_after_arg_check)
|
||||
alias :mock_implementation :mock_implementation_for_callbacks
|
||||
alias :mock_implementation_precheck :nothing
|
||||
else
|
||||
alias :mock_implementation_precheck :mock_implementation_for_callbacks
|
||||
alias :mock_implementation :nothing
|
||||
end
|
||||
end
|
||||
|
||||
def instance_structure(function)
|
||||
func_name = function[:name]
|
||||
" CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" +
|
||||
" int #{func_name}_CallbackCalls;\n"
|
||||
end
|
||||
|
||||
def mock_function_declarations(function)
|
||||
func_name = function[:name]
|
||||
return_type = function[:return][:const?] ? "const #{function[:return][:type]}" : function[:return][:type]
|
||||
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2)
|
||||
styles = [ "void", "int cmock_num_calls", function[:args_string], "#{function[:args_string]}, int cmock_num_calls" ]
|
||||
"typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\nvoid #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback);\n"
|
||||
end
|
||||
|
||||
def mock_implementation_for_callbacks(function)
|
||||
func_name = function[:name]
|
||||
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) | (function[:return][:void?] ? 0 : 4)
|
||||
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" +
|
||||
case(style)
|
||||
when 0 then " Mock.#{func_name}_CallbackFunctionPointer();\n return;\n }\n"
|
||||
when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n return;\n }\n"
|
||||
when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n return;\n }\n"
|
||||
when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n return;\n }\n"
|
||||
when 4 then " return Mock.#{func_name}_CallbackFunctionPointer();\n }\n"
|
||||
when 5 then " return Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n"
|
||||
when 6 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n"
|
||||
when 7 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n"
|
||||
end
|
||||
end
|
||||
|
||||
def nothing(function)
|
||||
return ""
|
||||
end
|
||||
|
||||
def mock_interfaces(function)
|
||||
func_name = function[:name]
|
||||
"void #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" +
|
||||
" Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
||||
end
|
||||
|
||||
def mock_destroy(function)
|
||||
" Mock.#{function[:name]}_CallbackFunctionPointer = NULL;\n" +
|
||||
" Mock.#{function[:name]}_CallbackCalls = 0;\n"
|
||||
end
|
||||
|
||||
def mock_verify(function)
|
||||
func_name = function[:name]
|
||||
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,51 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockGeneratorPluginCexception
|
||||
|
||||
attr_reader :priority
|
||||
attr_reader :config, :utils
|
||||
|
||||
def initialize(config, utils)
|
||||
@config = config
|
||||
@utils = utils
|
||||
@priority = 7
|
||||
end
|
||||
|
||||
def include_files
|
||||
return "#include \"CException.h\"\n"
|
||||
end
|
||||
|
||||
def instance_typedefs(function)
|
||||
" CEXCEPTION_T ExceptionToThrow;\n"
|
||||
end
|
||||
|
||||
def mock_function_declarations(function)
|
||||
if (function[:args_string] == "void")
|
||||
return "#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" +
|
||||
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, CEXCEPTION_T cmock_to_throw);\n"
|
||||
else
|
||||
return "#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" +
|
||||
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, CEXCEPTION_T cmock_to_throw);\n"
|
||||
end
|
||||
end
|
||||
|
||||
def mock_implementation(function)
|
||||
" if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" +
|
||||
" Throw(cmock_call_instance->ExceptionToThrow);\n }\n"
|
||||
end
|
||||
|
||||
def mock_interfaces(function)
|
||||
arg_insert = (function[:args_string] == "void") ? "" : "#{function[:args_string]}, "
|
||||
call_string = function[:args].map{|m| m[:name]}.join(', ')
|
||||
[ "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n",
|
||||
@utils.code_add_base_expectation(function[:name]),
|
||||
@utils.code_call_argument_loader(function),
|
||||
" cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n",
|
||||
"}\n\n" ].join
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,86 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockGeneratorPluginExpect
|
||||
|
||||
attr_reader :priority
|
||||
attr_accessor :config, :utils, :unity_helper, :ordered
|
||||
|
||||
def initialize(config, utils)
|
||||
@config = config
|
||||
@ptr_handling = @config.when_ptr
|
||||
@ordered = @config.enforce_strict_ordering
|
||||
@utils = utils
|
||||
@unity_helper = @utils.helpers[:unity_helper]
|
||||
@priority = 5
|
||||
end
|
||||
|
||||
def instance_typedefs(function)
|
||||
lines = ""
|
||||
lines << " #{function[:return][:type]} ReturnVal;\n" unless (function[:return][:void?])
|
||||
lines << " int CallOrder;\n" if (@ordered)
|
||||
function[:args].each do |arg|
|
||||
lines << " #{arg[:type]} Expected_#{arg[:name]};\n"
|
||||
end
|
||||
lines
|
||||
end
|
||||
|
||||
def mock_function_declarations(function)
|
||||
if (function[:args].empty?)
|
||||
if (function[:return][:void?])
|
||||
return "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" +
|
||||
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n"
|
||||
else
|
||||
return "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" +
|
||||
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
||||
end
|
||||
else
|
||||
if (function[:return][:void?])
|
||||
return "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" +
|
||||
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
|
||||
else
|
||||
return "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" +
|
||||
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mock_implementation(function)
|
||||
lines = ""
|
||||
function[:args].each do |arg|
|
||||
lines << @utils.code_verify_an_arg_expectation(function, arg)
|
||||
end
|
||||
lines
|
||||
end
|
||||
|
||||
def mock_interfaces(function)
|
||||
lines = ""
|
||||
func_name = function[:name]
|
||||
if (function[:return][:void?])
|
||||
if (function[:args_string] == "void")
|
||||
lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n"
|
||||
else
|
||||
lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n"
|
||||
end
|
||||
else
|
||||
if (function[:args_string] == "void")
|
||||
lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||
else
|
||||
lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
|
||||
end
|
||||
end
|
||||
lines << @utils.code_add_base_expectation(func_name)
|
||||
lines << @utils.code_call_argument_loader(function)
|
||||
lines << @utils.code_assign_argument_quickly("cmock_call_instance->ReturnVal", function[:return]) unless (function[:return][:void?])
|
||||
lines << "}\n\n"
|
||||
end
|
||||
|
||||
def mock_verify(function)
|
||||
func_name = function[:name]
|
||||
" UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.#{func_name}_CallInstance, cmock_line, \"Function '#{func_name}' called less times than expected.\");\n"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,95 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockGeneratorPluginIgnore
|
||||
|
||||
attr_reader :priority
|
||||
attr_reader :config, :utils
|
||||
|
||||
def initialize(config, utils)
|
||||
@config = config
|
||||
if (@config.ignore == :args_and_calls)
|
||||
alias :mock_implementation_precheck :mock_implementation_for_ignores
|
||||
alias :mock_implementation :nothing
|
||||
alias :mock_verify :mock_conditionally_verify_counts
|
||||
else
|
||||
alias :mock_implementation :mock_implementation_for_ignores
|
||||
alias :mock_implementation_precheck :nothing
|
||||
alias :mock_verify :nothing
|
||||
end
|
||||
@utils = utils
|
||||
@priority = 2
|
||||
end
|
||||
|
||||
def instance_structure(function)
|
||||
if (function[:return][:void?])
|
||||
" int #{function[:name]}_IgnoreBool;\n"
|
||||
else
|
||||
" int #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
|
||||
end
|
||||
end
|
||||
|
||||
def mock_function_declarations(function)
|
||||
if (function[:return][:void?])
|
||||
if (@config.ignore == :args_only)
|
||||
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore(__LINE__)\n" +
|
||||
"void #{function[:name]}_CMockIgnore(UNITY_LINE_TYPE cmock_line);\n"
|
||||
else
|
||||
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" +
|
||||
"void #{function[:name]}_CMockIgnore(void);\n"
|
||||
end
|
||||
else
|
||||
return "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" +
|
||||
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
||||
end
|
||||
end
|
||||
|
||||
def mock_implementation_for_ignores(function)
|
||||
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
|
||||
if (function[:return][:void?])
|
||||
lines << " return;\n }\n"
|
||||
else
|
||||
retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} )
|
||||
lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n"
|
||||
lines << " " + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless (retval[:void?])
|
||||
lines << " return cmock_call_instance->ReturnVal;\n }\n"
|
||||
end
|
||||
lines
|
||||
end
|
||||
|
||||
def mock_interfaces(function)
|
||||
lines = ""
|
||||
args_only = (@config.ignore == :args_only)
|
||||
if (function[:return][:void?])
|
||||
if (args_only)
|
||||
lines << "void #{function[:name]}_CMockIgnore(UNITY_LINE_TYPE cmock_line)\n{\n"
|
||||
else
|
||||
lines << "void #{function[:name]}_CMockIgnore(void)\n{\n"
|
||||
end
|
||||
else
|
||||
lines << "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||
end
|
||||
if (args_only)
|
||||
lines << @utils.code_add_base_expectation(function[:name], true)
|
||||
elsif (!function[:return][:void?])
|
||||
lines << @utils.code_add_base_expectation(function[:name], false)
|
||||
end
|
||||
unless (function[:return][:void?])
|
||||
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
||||
end
|
||||
lines << " Mock.#{function[:name]}_IgnoreBool = (int)1;\n"
|
||||
lines << "}\n\n"
|
||||
end
|
||||
|
||||
def mock_conditionally_verify_counts(function)
|
||||
func_name = function[:name]
|
||||
" if (Mock.#{func_name}_IgnoreBool)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n"
|
||||
end
|
||||
|
||||
def nothing(function)
|
||||
return ""
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,177 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockGeneratorUtils
|
||||
|
||||
attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays, :cexception
|
||||
|
||||
def initialize(config, helpers={})
|
||||
@config = config
|
||||
@ptr_handling = @config.when_ptr
|
||||
@ordered = @config.enforce_strict_ordering
|
||||
@arrays = @config.plugins.include? :array
|
||||
@cexception = @config.plugins.include? :cexception
|
||||
@treat_as = @config.treat_as
|
||||
@helpers = helpers
|
||||
|
||||
if (@arrays)
|
||||
case(@ptr_handling)
|
||||
when :smart then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_smart_arrays
|
||||
when :compare_data then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_normal_arrays
|
||||
when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option."
|
||||
end
|
||||
else
|
||||
alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_no_arrays
|
||||
end
|
||||
end
|
||||
|
||||
def code_add_base_expectation(func_name, global_ordering_supported=true)
|
||||
lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n"
|
||||
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n"
|
||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, \"CMock has run out of memory. Please allocate more.\");\n"
|
||||
lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n"
|
||||
lines << " cmock_call_instance->LineNumber = cmock_line;\n"
|
||||
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if (@ordered and global_ordering_supported)
|
||||
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if (@cexception)
|
||||
lines
|
||||
end
|
||||
|
||||
def code_add_an_arg_expectation(arg, depth=1)
|
||||
lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg)
|
||||
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if (@arrays and (depth.class == String))
|
||||
lines
|
||||
end
|
||||
|
||||
def code_assign_argument_quickly(dest, arg)
|
||||
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
|
||||
" #{dest} = #{arg[:const?] ? "(#{arg[:type]})" : ''}#{arg[:name]};\n"
|
||||
else
|
||||
" memcpy(&#{dest}, &#{arg[:name]}, sizeof(#{arg[:type]}));\n"
|
||||
end
|
||||
end
|
||||
|
||||
def code_add_argument_loader(function)
|
||||
if (function[:args_string] != "void")
|
||||
if (@arrays)
|
||||
args_string = function[:args].map do |m|
|
||||
const_str = m[ :const? ] ? 'const ' : ''
|
||||
m[:ptr?] ? "#{const_str}#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{const_str}#{m[:type]} #{m[:name]}"
|
||||
end.join(', ')
|
||||
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" +
|
||||
function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1) ) } +
|
||||
"}\n\n"
|
||||
else
|
||||
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
|
||||
function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg) } +
|
||||
"}\n\n"
|
||||
end
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def code_call_argument_loader(function)
|
||||
if (function[:args_string] != "void")
|
||||
args = function[:args].map do |m|
|
||||
(@arrays and m[:ptr?]) ? "#{m[:name]}, 1" : m[:name]
|
||||
end
|
||||
" CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
#private ######################
|
||||
|
||||
def lookup_expect_type(function, arg)
|
||||
c_type = arg[:type]
|
||||
arg_name = arg[:name]
|
||||
expected = "cmock_call_instance->Expected_#{arg_name}"
|
||||
unity_func = if ((arg[:ptr?]) and ((c_type =~ /\*\*/) or (@ptr_handling == :compare_ptr)))
|
||||
['UNITY_TEST_ASSERT_EQUAL_PTR', '']
|
||||
else
|
||||
(@helpers.nil? or @helpers[:unity_helper].nil?) ? ["UNITY_TEST_ASSERT_EQUAL",''] : @helpers[:unity_helper].get_helper(c_type)
|
||||
end
|
||||
unity_msg = "Function '#{function[:name]}' called with unexpected value for argument '#{arg_name}'."
|
||||
return c_type, arg_name, expected, unity_func[0], unity_func[1], unity_msg
|
||||
end
|
||||
|
||||
def code_verify_an_arg_expectation_with_no_arrays(function, arg)
|
||||
c_type, arg_name, expected, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
|
||||
case(unity_func)
|
||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
||||
c_type_local = c_type.gsub(/\*$/,'')
|
||||
return " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, \"#{unity_msg}\");\n"
|
||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
||||
[ " if (#{pre}#{expected} == NULL)",
|
||||
" { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }",
|
||||
" else",
|
||||
" { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, \"#{unity_msg}\"); }\n"].join("\n")
|
||||
when /_ARRAY/
|
||||
[ " if (#{pre}#{expected} == NULL)",
|
||||
" { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }",
|
||||
" else",
|
||||
" { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, \"#{unity_msg}\"); }\n"].join("\n")
|
||||
else
|
||||
return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
|
||||
end
|
||||
end
|
||||
|
||||
def code_verify_an_arg_expectation_with_normal_arrays(function, arg)
|
||||
c_type, arg_name, expected, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
|
||||
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
|
||||
case(unity_func)
|
||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
||||
c_type_local = c_type.gsub(/\*$/,'')
|
||||
return " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, \"#{unity_msg}\");\n"
|
||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
|
||||
[ " if (#{pre}#{expected} == NULL)",
|
||||
" { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }",
|
||||
" else",
|
||||
" { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n")
|
||||
when /_ARRAY/
|
||||
if (pre == '&')
|
||||
" #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\");\n"
|
||||
else
|
||||
[ " if (#{pre}#{expected} == NULL)",
|
||||
" { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }",
|
||||
" else",
|
||||
" { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n")
|
||||
end
|
||||
else
|
||||
return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
|
||||
end
|
||||
end
|
||||
|
||||
def code_verify_an_arg_expectation_with_smart_arrays(function, arg)
|
||||
c_type, arg_name, expected, unity_func, pre, unity_msg = lookup_expect_type(function, arg)
|
||||
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
|
||||
case(unity_func)
|
||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
||||
c_type_local = c_type.gsub(/\*$/,'')
|
||||
return " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, \"#{unity_msg}\");\n"
|
||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
|
||||
[ " if (#{pre}#{expected} == NULL)",
|
||||
" { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }",
|
||||
((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\"); }" : nil),
|
||||
" else",
|
||||
" { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n")
|
||||
when /_ARRAY/
|
||||
if (pre == '&')
|
||||
" #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\");\n"
|
||||
else
|
||||
[ " if (#{pre}#{expected} == NULL)",
|
||||
" { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }",
|
||||
((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\"); }" : nil),
|
||||
" else",
|
||||
" { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n")
|
||||
end
|
||||
else
|
||||
return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,277 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockHeaderParser
|
||||
|
||||
attr_accessor :funcs, :c_attributes, :treat_as_void, :treat_externs
|
||||
|
||||
def initialize(cfg)
|
||||
@funcs = []
|
||||
@c_strippables = cfg.strippables
|
||||
@c_attributes = (['const'] + cfg.attributes).uniq
|
||||
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
||||
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
||||
@declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m
|
||||
@standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq
|
||||
@when_no_prototypes = cfg.when_no_prototypes
|
||||
@local_as_void = @treat_as_void
|
||||
@verbosity = cfg.verbosity
|
||||
@treat_externs = cfg.treat_externs
|
||||
@c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs
|
||||
end
|
||||
|
||||
def parse(name, source)
|
||||
@module_name = name.gsub(/\W/,'')
|
||||
@typedefs = []
|
||||
@funcs = []
|
||||
function_names = []
|
||||
|
||||
parse_functions( import_source(source) ).map do |decl|
|
||||
func = parse_declaration(decl)
|
||||
unless (function_names.include? func[:name])
|
||||
@funcs << func
|
||||
function_names << func[:name]
|
||||
end
|
||||
end
|
||||
|
||||
{ :includes => nil,
|
||||
:functions => @funcs,
|
||||
:typedefs => @typedefs
|
||||
}
|
||||
end
|
||||
|
||||
private if $ThisIsOnlyATest.nil? ################
|
||||
|
||||
def import_source(source)
|
||||
|
||||
# void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void
|
||||
# to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void
|
||||
@local_as_void = @treat_as_void
|
||||
void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w\d]+)\s*;/)
|
||||
if void_types
|
||||
@local_as_void += void_types.flatten.uniq.compact
|
||||
end
|
||||
|
||||
# smush multiline macros into single line (checking for continuation character at end of line '\')
|
||||
source.gsub!(/\s*\\\s*/m, ' ')
|
||||
|
||||
#remove comments (block and line, in three steps to ensure correct precedence)
|
||||
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
|
||||
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
|
||||
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
|
||||
|
||||
# remove assembler pragma sections
|
||||
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
|
||||
|
||||
# remove gcc's __attribute__ tags
|
||||
source.gsub(/__attrbute__\s*\(\(\.*\)\)/, '')
|
||||
|
||||
# remove preprocessor statements and extern "C"
|
||||
source.gsub!(/^\s*#.*/, '')
|
||||
source.gsub!(/extern\s+\"C\"\s+\{/, '')
|
||||
|
||||
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
|
||||
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
|
||||
source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs
|
||||
source.gsub!(/^[\w\s]*(enum|union|struct|typepdef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
|
||||
source.gsub!(/(\W)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords
|
||||
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
|
||||
source.gsub!(/^(?:[\w\s]*\W)?typedef\W.*/, '') # remove typedef statements
|
||||
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/,'\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
|
||||
|
||||
#scan for functions which return function pointers, because they are a pain
|
||||
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |m|
|
||||
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
|
||||
@typedefs << "typedef #{$1.strip}(*#{functype})(#{$4});"
|
||||
"#{functype} #{$2.strip}(#{$3});"
|
||||
end
|
||||
|
||||
#drop extra white space to make the rest go faster
|
||||
source.gsub!(/^\s+/, '') # remove extra white space from beginning of line
|
||||
source.gsub!(/\s+$/, '') # remove extra white space from end of line
|
||||
source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens
|
||||
source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens
|
||||
source.gsub!(/\s+/, ' ') # remove remaining extra white space
|
||||
|
||||
#split lines on semicolons and remove things that are obviously not what we are looking for
|
||||
src_lines = source.split(/\s*;\s*/)
|
||||
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
|
||||
src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays
|
||||
if (@treat_externs == :include)
|
||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
|
||||
else
|
||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern|inline)\s+/).nil?} # remove inline and extern functions
|
||||
end
|
||||
end
|
||||
|
||||
def parse_functions(source)
|
||||
funcs = []
|
||||
source.each {|line| funcs << line.strip.gsub(/\s+/, ' ') if (line =~ @declaration_parse_matcher)}
|
||||
if funcs.empty?
|
||||
case @when_no_prototypes
|
||||
when :error
|
||||
raise "ERROR: No function prototypes found!"
|
||||
when :warn
|
||||
puts "WARNING: No function prototypes found!" unless (@verbosity < 1)
|
||||
end
|
||||
end
|
||||
return funcs
|
||||
end
|
||||
|
||||
def parse_args(arg_list)
|
||||
args = []
|
||||
arg_list.split(',').each do |arg|
|
||||
arg.strip!
|
||||
return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ...
|
||||
arg_array = arg.split
|
||||
arg_elements = arg_array - @c_attributes # split up words and remove known attributes
|
||||
args << { :type => (arg_type =arg_elements[0..-2].join(' ')),
|
||||
:name => arg_elements[-1],
|
||||
:ptr? => divine_ptr(arg_type),
|
||||
:const? => arg_array.include?('const')
|
||||
}
|
||||
end
|
||||
return args
|
||||
end
|
||||
|
||||
def divine_ptr(arg_type)
|
||||
return false unless arg_type.include? '*'
|
||||
return false if arg_type.gsub(/(const|char|\*|\s)+/,'').empty?
|
||||
return true
|
||||
end
|
||||
|
||||
def clean_args(arg_list)
|
||||
if ((@local_as_void.include?(arg_list.strip)) or (arg_list.empty?))
|
||||
return 'void'
|
||||
else
|
||||
c=0
|
||||
arg_list.gsub!(/(\w+)(?:\s*\[[\s\d\w+-]*\])+/,'*\1') # magically turn brackets into asterisks
|
||||
arg_list.gsub!(/\s+\*/,'*') # remove space to place asterisks with type (where they belong)
|
||||
arg_list.gsub!(/\*(\w)/,'* \1') # pull asterisks away from arg to place asterisks with type (where they belong)
|
||||
|
||||
#scan argument list for function pointers and replace them with custom types
|
||||
arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |m|
|
||||
|
||||
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
|
||||
funcret = $1.strip
|
||||
funcname = $2.strip
|
||||
funcargs = $3.strip
|
||||
funconst = ''
|
||||
if (funcname.include? 'const')
|
||||
funcname.gsub!('const','').strip!
|
||||
funconst = 'const '
|
||||
end
|
||||
@typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});"
|
||||
funcname = "cmock_arg#{c+=1}" if (funcname.empty?)
|
||||
"#{functype} #{funconst}#{funcname}"
|
||||
end
|
||||
|
||||
#automatically name unnamed arguments (those that only had a type)
|
||||
arg_list.split(/\s*,\s*/).map { |arg|
|
||||
parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*'])
|
||||
if ((parts.size < 2) or (parts[-1][-1].chr == '*') or (@standards.include?(parts[-1])))
|
||||
"#{arg} cmock_arg#{c+=1}"
|
||||
else
|
||||
arg
|
||||
end
|
||||
}.join(', ')
|
||||
end
|
||||
end
|
||||
|
||||
def parse_declaration(declaration)
|
||||
decl = {}
|
||||
|
||||
regex_match = @declaration_parse_matcher.match(declaration)
|
||||
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
|
||||
|
||||
#grab argument list
|
||||
args = regex_match[2].strip
|
||||
|
||||
#process function attributes, return type, and name
|
||||
descriptors = regex_match[1]
|
||||
descriptors.gsub!(/\s+\*/,'*') #remove space to place asterisks with return type (where they belong)
|
||||
descriptors.gsub!(/\*(\w)/,'* \1') #pull asterisks away from function name to place asterisks with return type (where they belong)
|
||||
descriptors = descriptors.split #array of all descriptor strings
|
||||
|
||||
#grab name
|
||||
decl[:name] = descriptors[-1] #snag name as last array item
|
||||
|
||||
#build attribute and return type strings
|
||||
decl[:modifier] = []
|
||||
rettype = []
|
||||
descriptors[0..-2].each do |word|
|
||||
if @c_attributes.include?(word)
|
||||
decl[:modifier] << word
|
||||
elsif @c_calling_conventions.include?(word)
|
||||
decl[:c_calling_convention] = word
|
||||
else
|
||||
rettype << word
|
||||
end
|
||||
end
|
||||
decl[:modifier] = decl[:modifier].join(' ')
|
||||
rettype = rettype.join(' ')
|
||||
rettype = 'void' if (@local_as_void.include?(rettype.strip))
|
||||
decl[:return] = { :type => rettype,
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => divine_ptr(rettype),
|
||||
:const? => rettype.split(/\s/).include?('const'),
|
||||
:str => "#{rettype} cmock_to_return",
|
||||
:void? => (rettype == 'void')
|
||||
}
|
||||
|
||||
#remove default argument statements from mock definitions
|
||||
args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ')
|
||||
|
||||
#check for var args
|
||||
if (args =~ /\.\.\./)
|
||||
decl[:var_arg] = args.match( /[\w\s]*\.\.\./ ).to_s.strip
|
||||
if (args =~ /\,[\w\s]*\.\.\./)
|
||||
args = args.gsub!(/\,[\w\s]*\.\.\./,'')
|
||||
else
|
||||
args = 'void'
|
||||
end
|
||||
else
|
||||
decl[:var_arg] = nil
|
||||
end
|
||||
args = clean_args(args)
|
||||
decl[:args_string] = args
|
||||
decl[:args] = parse_args(args)
|
||||
decl[:args_call] = decl[:args].map{|a| a[:name]}.join(', ')
|
||||
decl[:contains_ptr?] = decl[:args].inject(false) {|ptr, arg| arg[:ptr?] ? true : ptr }
|
||||
|
||||
if (decl[:return][:type].nil? or decl[:name].nil? or decl[:args].nil? or
|
||||
decl[:return][:type].empty? or decl[:name].empty?)
|
||||
raise "Failed Parsing Declaration Prototype!\n" +
|
||||
" declaration: '#{declaration}'\n" +
|
||||
" modifier: '#{decl[:modifier]}'\n" +
|
||||
" return: #{prototype_inspect_hash(decl[:return])}\n" +
|
||||
" function: '#{decl[:name]}'\n" +
|
||||
" args: #{prototype_inspect_array_of_hashes(decl[:args])}\n"
|
||||
end
|
||||
|
||||
return decl
|
||||
end
|
||||
|
||||
def prototype_inspect_hash(hash)
|
||||
pairs = []
|
||||
hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if (value.class == String)}#{value}#{"'" if (value.class == String)}" }
|
||||
return "{#{pairs.join(', ')}}"
|
||||
end
|
||||
|
||||
def prototype_inspect_array_of_hashes(array)
|
||||
hashes = []
|
||||
array.each { |hash| hashes << prototype_inspect_hash(hash) }
|
||||
case (array.size)
|
||||
when 0
|
||||
return "[]"
|
||||
when 1
|
||||
return "[#{hashes[0]}]"
|
||||
else
|
||||
return "[\n #{hashes.join("\n ")}\n ]\n"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,40 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockPluginManager
|
||||
|
||||
attr_accessor :plugins
|
||||
|
||||
def initialize(config, utils)
|
||||
@plugins = []
|
||||
plugins_to_load = [:expect, config.plugins].flatten.uniq.compact
|
||||
plugins_to_load.each do |plugin|
|
||||
plugin_name = plugin.to_s
|
||||
object_name = "CMockGeneratorPlugin" + camelize(plugin_name)
|
||||
begin
|
||||
unless (Object.const_defined? object_name)
|
||||
require "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
|
||||
end
|
||||
@plugins << eval("#{object_name}.new(config, utils)")
|
||||
rescue
|
||||
raise "ERROR: CMock unable to load plugin '#{plugin_name}'"
|
||||
end
|
||||
end
|
||||
@plugins.sort! {|a,b| a.priority <=> b.priority }
|
||||
end
|
||||
|
||||
def run(method, args=nil)
|
||||
if args.nil?
|
||||
return @plugins.collect{ |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join
|
||||
else
|
||||
return @plugins.collect{ |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join
|
||||
end
|
||||
end
|
||||
|
||||
def camelize(lower_case_and_underscored_word)
|
||||
lower_case_and_underscored_word.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,75 @@
|
||||
# ==========================================
|
||||
# CMock Project - Automatic Mock Generation for C
|
||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
# [Released under MIT License. Please refer to license.txt for details]
|
||||
# ==========================================
|
||||
|
||||
class CMockUnityHelperParser
|
||||
|
||||
attr_accessor :c_types
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
@fallback = @config.plugins.include?(:array) ? 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' : 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
|
||||
@c_types = map_C_types.merge(import_source)
|
||||
end
|
||||
|
||||
def get_helper(ctype)
|
||||
lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/,'\1\3\5\6').strip.gsub(/\s+/,'_')
|
||||
return [@c_types[lookup], ''] if (@c_types[lookup])
|
||||
if (lookup =~ /\*$/)
|
||||
lookup = lookup.gsub(/\*$/,'')
|
||||
return [@c_types[lookup], '*'] if (@c_types[lookup])
|
||||
else
|
||||
lookup = lookup + '*'
|
||||
return [@c_types[lookup], '&'] if (@c_types[lookup])
|
||||
end
|
||||
return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if (ctype =~ /cmock_\w+_ptr\d+/)
|
||||
raise("Don't know how to test #{ctype} and memory tests are disabled!") unless @config.memcmp_if_unknown
|
||||
return (lookup =~ /\*$/) ? [@fallback, '&'] : [@fallback, '']
|
||||
end
|
||||
|
||||
private ###########################
|
||||
|
||||
def map_C_types
|
||||
c_types = {}
|
||||
@config.treat_as.each_pair do |ctype, expecttype|
|
||||
c_type = ctype.gsub(/\s+/,'_')
|
||||
if (expecttype =~ /\*/)
|
||||
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.gsub(/\*/,'')}_ARRAY"
|
||||
else
|
||||
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype}"
|
||||
c_types[c_type+'*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY"
|
||||
end
|
||||
end
|
||||
c_types
|
||||
end
|
||||
|
||||
def import_source
|
||||
source = @config.load_unity_helper
|
||||
return {} if source.nil?
|
||||
c_types = {}
|
||||
source = source.gsub(/\/\/.*$/, '') #remove line comments
|
||||
source = source.gsub(/\/\*.*?\*\//m, '') #remove block comments
|
||||
|
||||
#scan for comparison helpers
|
||||
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4,'\s*\w+\s*').join(',') + '\)')
|
||||
pairs = source.scan(match_regex).flatten.compact
|
||||
(pairs.size/2).times do |i|
|
||||
expect = pairs[i*2]
|
||||
ctype = pairs[(i*2)+1]
|
||||
c_types[ctype] = expect unless expect.include?("_ARRAY")
|
||||
end
|
||||
|
||||
#scan for array variants of those helpers
|
||||
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5,'\s*\w+\s*').join(',') + '\)')
|
||||
pairs = source.scan(match_regex).flatten.compact
|
||||
(pairs.size/2).times do |i|
|
||||
expect = pairs[i*2]
|
||||
ctype = pairs[(i*2)+1]
|
||||
c_types[ctype.gsub('_ARRAY','*')] = expect
|
||||
end
|
||||
|
||||
c_types
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
212
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
2.0
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/* ==========================================
|
||||
CMock Project - Automatic Mock Generation for C
|
||||
Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
[Released under MIT License. Please refer to license.txt for details]
|
||||
========================================== */
|
||||
|
||||
#include "unity.h"
|
||||
#include "cmock.h"
|
||||
|
||||
//define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc
|
||||
//when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total
|
||||
#ifdef CMOCK_MEM_STATIC
|
||||
#undef CMOCK_MEM_DYNAMIC
|
||||
#endif
|
||||
|
||||
#ifdef CMOCK_MEM_DYNAMIC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
//this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type
|
||||
#ifndef CMOCK_MEM_PTR_AS_INT
|
||||
#define CMOCK_MEM_PTR_AS_INT unsigned long
|
||||
#endif
|
||||
|
||||
//0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit
|
||||
#ifndef CMOCK_MEM_ALIGN
|
||||
#define CMOCK_MEM_ALIGN (2)
|
||||
#endif
|
||||
|
||||
//amount of memory to allow cmock to use in its internal heap
|
||||
#ifndef CMOCK_MEM_SIZE
|
||||
#define CMOCK_MEM_SIZE (32768)
|
||||
#endif
|
||||
|
||||
//automatically calculated defs for easier reading
|
||||
#define CMOCK_MEM_ALIGN_SIZE (1u << CMOCK_MEM_ALIGN)
|
||||
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_ALIGN_SIZE - 1)
|
||||
#define CMOCK_MEM_INDEX_SIZE ((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE)
|
||||
|
||||
//private variables
|
||||
#ifdef CMOCK_MEM_DYNAMIC
|
||||
static unsigned char* CMock_Guts_Buffer = NULL;
|
||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
|
||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr;
|
||||
#else
|
||||
static unsigned char CMock_Guts_Buffer[CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE];
|
||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE;
|
||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr;
|
||||
#endif
|
||||
//-------------------------------------------------------
|
||||
// CMock_Guts_MemNew
|
||||
//-------------------------------------------------------
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
|
||||
{
|
||||
CMOCK_MEM_INDEX_TYPE index;
|
||||
|
||||
//verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere)
|
||||
if (size < 1)
|
||||
return CMOCK_GUTS_NONE;
|
||||
|
||||
//verify we have enough room
|
||||
size = size + CMOCK_MEM_INDEX_SIZE;
|
||||
if (size & CMOCK_MEM_ALIGN_MASK)
|
||||
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
|
||||
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
|
||||
{
|
||||
#ifdef CMOCK_MEM_DYNAMIC
|
||||
CMock_Guts_BufferSize += CMOCK_MEM_SIZE + size;
|
||||
CMock_Guts_Buffer = realloc(CMock_Guts_Buffer, CMock_Guts_BufferSize);
|
||||
if (CMock_Guts_Buffer == NULL)
|
||||
#endif //yes that if will continue to the return below if TRUE
|
||||
return CMOCK_GUTS_NONE;
|
||||
}
|
||||
|
||||
//determine where we're putting this new block, and init its pointer to be the end of the line
|
||||
index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE;
|
||||
*(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE;
|
||||
CMock_Guts_FreePtr += size;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// CMock_Guts_MemChain
|
||||
//-------------------------------------------------------
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index)
|
||||
{
|
||||
CMOCK_MEM_INDEX_TYPE index;
|
||||
void* root;
|
||||
void* obj;
|
||||
void* next;
|
||||
|
||||
if (root_index == CMOCK_GUTS_NONE)
|
||||
{
|
||||
//if there is no root currently, we return this object as the root of the chain
|
||||
return obj_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
//reject illegal nodes
|
||||
if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr))
|
||||
{
|
||||
return CMOCK_GUTS_NONE;
|
||||
}
|
||||
if ((obj_index < CMOCK_MEM_ALIGN_SIZE) || (obj_index >= CMock_Guts_FreePtr))
|
||||
{
|
||||
return CMOCK_GUTS_NONE;
|
||||
}
|
||||
|
||||
root = (void*)(&CMock_Guts_Buffer[root_index]);
|
||||
obj = (void*)(&CMock_Guts_Buffer[obj_index]);
|
||||
|
||||
//find the end of the existing chain and add us
|
||||
next = root;
|
||||
do {
|
||||
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
|
||||
if (index >= CMock_Guts_FreePtr)
|
||||
return CMOCK_GUTS_NONE;
|
||||
if (index > 0)
|
||||
next = (void*)(&CMock_Guts_Buffer[index]);
|
||||
} while (index > 0);
|
||||
*(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE) = ((CMOCK_MEM_PTR_AS_INT)obj - (CMOCK_MEM_PTR_AS_INT)CMock_Guts_Buffer);
|
||||
return root_index;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// CMock_Guts_MemNext
|
||||
//-------------------------------------------------------
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
|
||||
{
|
||||
CMOCK_MEM_INDEX_TYPE index;
|
||||
void* previous_item;
|
||||
|
||||
//There is nothing "next" if the pointer isn't from our buffer
|
||||
if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr))
|
||||
return CMOCK_GUTS_NONE;
|
||||
previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]);
|
||||
|
||||
//if the pointer is good, then use it to look up the next index
|
||||
//(we know the first element always goes in zero, so NEXT must always be > 1)
|
||||
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE);
|
||||
if ((index > 1) && (index < CMock_Guts_FreePtr))
|
||||
return index;
|
||||
else
|
||||
return CMOCK_GUTS_NONE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// CMock_GetAddressFor
|
||||
//-------------------------------------------------------
|
||||
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
|
||||
{
|
||||
if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr))
|
||||
{
|
||||
return (void*)(&CMock_Guts_Buffer[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// CMock_Guts_MemBytesFree
|
||||
//-------------------------------------------------------
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
|
||||
{
|
||||
return CMock_Guts_BufferSize - CMock_Guts_FreePtr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// CMock_Guts_MemBytesUsed
|
||||
//-------------------------------------------------------
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
|
||||
{
|
||||
return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// CMock_Guts_MemFreeAll
|
||||
//-------------------------------------------------------
|
||||
void CMock_Guts_MemFreeAll(void)
|
||||
{
|
||||
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; //skip the very beginning
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/* ==========================================
|
||||
CMock Project - Automatic Mock Generation for C
|
||||
Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||
[Released under MIT License. Please refer to license.txt for details]
|
||||
========================================== */
|
||||
|
||||
#ifndef CMOCK_FRAMEWORK_H
|
||||
#define CMOCK_FRAMEWORK_H
|
||||
|
||||
//should be big enough to index full range of CMOCK_MEM_MAX
|
||||
#ifndef CMOCK_MEM_INDEX_TYPE
|
||||
#define CMOCK_MEM_INDEX_TYPE unsigned int
|
||||
#endif
|
||||
|
||||
#define CMOCK_GUTS_NONE (0)
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Memory API
|
||||
//-------------------------------------------------------
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size);
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index);
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index);
|
||||
|
||||
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index);
|
||||
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void);
|
||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void);
|
||||
void CMock_Guts_MemFreeAll(void);
|
||||
|
||||
#endif //CMOCK_FRAMEWORK
|
||||
Reference in New Issue
Block a user