From 932785fd713c88dfcd307ce79bf3d3c3b14295aa Mon Sep 17 00:00:00 2001 From: Dennis Lambe Jr Date: Wed, 19 Dec 2012 19:06:10 -0500 Subject: [PATCH] Added the return_thru_ptr and ignore_arg plugins --- lib/cmock_generator_plugin_ignore_arg.rb | 47 ++++++++ lib/cmock_generator_plugin_return_thru_ptr.rb | 77 +++++++++++++ lib/cmock_generator_utils.rb | 109 +++++++++++------- src/cmock.c | 18 +++ src/cmock.h | 1 + 5 files changed, 210 insertions(+), 42 deletions(-) create mode 100644 lib/cmock_generator_plugin_ignore_arg.rb create mode 100644 lib/cmock_generator_plugin_return_thru_ptr.rb diff --git a/lib/cmock_generator_plugin_ignore_arg.rb b/lib/cmock_generator_plugin_ignore_arg.rb new file mode 100644 index 0000000..e71b707 --- /dev/null +++ b/lib/cmock_generator_plugin_ignore_arg.rb @@ -0,0 +1,47 @@ +class CMockGeneratorPluginIgnoreArg + attr_reader :priority + attr_accessor :config, :utils, :unity_helper, :ordered + + def initialize(config, utils) + @config = config + @ordered = @config.enforce_strict_ordering + @utils = utils + @unity_helper = @utils.helpers[:unity_helper] + @priority = 10 + end + + def instance_typedefs(function) + lines = "" + function[:args].each do |arg| + lines << " int IgnoreArg_#{arg[:name]};\n" + end + lines + end + + def mock_function_declarations(function) + lines = "" + function[:args].each do |arg| + lines << "#define #{function[:name]}_IgnoreArg_#{arg[:name]}()" + lines << " #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(__LINE__)\n" + lines << "void #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line);\n" + end + lines + end + + def mock_interfaces(function) + lines = [] + func_name = function[:name] + function[:args].each do |arg| + arg_name = arg[:name] + arg_type = arg[:type] + lines << "void #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n" + lines << "{\n" + lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " + + "cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n" + lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, \"#{arg_name} IgnoreArg called before Expect on '#{func_name}'.\");\n" + lines << " cmock_call_instance->IgnoreArg_#{arg_name} = 1;\n" + lines << "}\n\n" + end + lines + end +end diff --git a/lib/cmock_generator_plugin_return_thru_ptr.rb b/lib/cmock_generator_plugin_return_thru_ptr.rb new file mode 100644 index 0000000..8ba4fdb --- /dev/null +++ b/lib/cmock_generator_plugin_return_thru_ptr.rb @@ -0,0 +1,77 @@ +class CMockGeneratorPluginReturnThruPtr + attr_reader :priority + attr_accessor :config, :utils, :unity_helper, :ordered + + def initialize(config, utils) + @config = config + @ordered = @config.enforce_strict_ordering + @utils = utils + @unity_helper = @utils.helpers[:unity_helper] + @priority = 9 + end + + def instance_typedefs(function) + lines = "" + function[:args].each do |arg| + if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?]) + lines << " int ReturnThruPtr_#{arg[:name]}_Used;\n" + lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n" + lines << " int ReturnThruPtr_#{arg[:name]}_Size;\n" + end + end + lines + end + + def mock_function_declarations(function) + lines = "" + function[:args].each do |arg| + if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?]) + lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})" + lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n" + lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)" + lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_len * sizeof(*#{arg[:name]}))\n" + lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)" + lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n" + lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, int cmock_size);\n" + end + end + lines + end + + def mock_interfaces(function) + lines = [] + func_name = function[:name] + function[:args].each do |arg| + arg_name = arg[:name] + arg_type = arg[:type] + if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?]) + lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, int cmock_size)\n" + lines << "{\n" + lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " + + "cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n" + lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, \"#{arg_name} ReturnThruPtr called before Expect on '#{func_name}'.\");\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n" + lines << "}\n\n" + end + end + lines + end + + def mock_implementation(function) + lines = [] + function[:args].each do |arg| + arg_name = arg[:name] + arg_type = arg[:type] + if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?]) + lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n" + lines << " {\n" + lines << " memcpy(#{arg_name}, cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n" + lines << " }\n" + end + end + lines + end +end diff --git a/lib/cmock_generator_utils.rb b/lib/cmock_generator_utils.rb index 043ff2d..a4d2f69 100644 --- a/lib/cmock_generator_utils.rb +++ b/lib/cmock_generator_utils.rb @@ -14,6 +14,8 @@ class CMockGeneratorUtils @ordered = @config.enforce_strict_ordering @arrays = @config.plugins.include? :array @cexception = @config.plugins.include? :cexception + @return_thru_ptr = @config.plugins.include? :return_thru_ptr + @ignore_arg = @config.plugins.include? :ignore_arg @treat_as = @config.treat_as @helpers = helpers @@ -28,7 +30,7 @@ class CMockGeneratorUtils end end - def code_add_base_expectation(func_name, global_ordering_supported=true) + 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" @@ -42,6 +44,8 @@ class CMockGeneratorUtils 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 << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if (@ignore_arg) + lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if (@return_thru_ptr and ptr_or_str?(arg[:type]) and not arg[:const?]) lines end @@ -84,94 +88,115 @@ class CMockGeneratorUtils end end + def ptr_or_str?(arg_type) + return (arg_type.include? '*' or + @treat_as.fetch(arg_type, "").include? '*') + end + #private ###################### def lookup_expect_type(function, arg) c_type = arg[:type] arg_name = arg[:name] - expected = "cmock_call_instance->Expected_#{arg_name}" + expected = "cmock_call_instance->Expected_#{arg_name}" + ignore = "cmock_call_instance->IgnoreArg_#{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 + return c_type, arg_name, expected, ignore, 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) + c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg) + lines = "" + lines << " if (!#{ignore})\n" if @ignore_arg + lines << " {\n" 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" + lines << " 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") + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }\n" + lines << " else\n" + lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, \"#{unity_msg}\"); }\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") + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }\n" + lines << " else\n" + lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, \"#{unity_msg}\"); }\n" else - return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" - end + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" + end + lines << " }\n" + lines 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) + c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg) depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 + lines = "" + lines << " if (!#{ignore})\n" if @ignore_arg + lines << " {\n" 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" + lines << " 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") + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }\n" + lines << " else\n" + lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n" when /_ARRAY/ if (pre == '&') - " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\");\n" + lines << " #{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") + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }\n" + lines << " else\n" + lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n" end else - return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" end + lines << " }\n" + lines 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) + c_type, arg_name, expected, ignore, unity_func, pre, unity_msg = lookup_expect_type(function, arg) depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 + lines = "" + lines << " if (!#{ignore})\n" if @ignore_arg + lines << " {\n" 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" + lines << " 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") + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }\n" + lines << ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\"); }\n" : "") + lines << " else\n" + lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n" when /_ARRAY/ if (pre == '&') - " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\");\n" + lines << " #{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") + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }\n" + lines << ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\"); }\n" : "") + lines << " else\n" + lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n" end else - return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" end + lines << " }\n" + lines end -end \ No newline at end of file +end diff --git a/src/cmock.c b/src/cmock.c index e26243a..40a4ef6 100644 --- a/src/cmock.c +++ b/src/cmock.c @@ -146,6 +146,24 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index return CMOCK_GUTS_NONE; } +//------------------------------------------------------- +// CMock_Guts_MemEndOfChain +//------------------------------------------------------- +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) +{ + CMOCK_MEM_INDEX_TYPE index = root_index; + CMOCK_MEM_INDEX_TYPE next_index; + + for (next_index = root_index; + next_index != CMOCK_GUTS_NONE; + next_index = CMock_Guts_MemNext(index)) + { + index = next_index; + } + + return index; +} + //------------------------------------------------------- // CMock_GetAddressFor //------------------------------------------------------- diff --git a/src/cmock.h b/src/cmock.h index 084a828..4dcfc1f 100644 --- a/src/cmock.h +++ b/src/cmock.h @@ -20,6 +20,7 @@ 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); +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index); void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index);