diff --git a/lib/cmock_generator_plugin_return_thru_ptr.rb b/lib/cmock_generator_plugin_return_thru_ptr.rb index 96b20035..ca895c5e 100644 --- a/lib/cmock_generator_plugin_return_thru_ptr.rb +++ b/lib/cmock_generator_plugin_return_thru_ptr.rb @@ -2,9 +2,10 @@ class CMockGeneratorPluginReturnThruPtr attr_reader :priority attr_accessor :utils - def initialize(_config, utils) + def initialize(config, utils) @utils = utils @priority = 9 + @config = config end def instance_typedefs(function) @@ -19,6 +20,15 @@ def instance_typedefs(function) lines end + def void_pointer?(type) + # returns true if the provided type is a void, or is supposed to be treated as void + if type.casecmp?('void') + true + else + @config.respond_to?(:treat_as_void) ? @config.treat_as_void.include?(type) : false + end + end + def mock_function_declarations(function) lines = '' function[:args].each do |arg| @@ -27,7 +37,8 @@ def mock_function_declarations(function) lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})" # If the pointer type actually contains an asterisk, we can do sizeof the type (super safe), otherwise # we need to do a sizeof the dereferenced pointer (which could be a problem if give the wrong size - lines << if arg[:type][-1] == '*' + # however if its a void pointer we are given then we have to use the provided parameter name because sizeof(void) is UB. + lines << if (arg[:type][-1] == '*') && (void_pointer?(arg[:type][0..-2]) == false) " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(#{arg[:type][0..-2]}))\n" else " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n" diff --git a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb index 03fc5e4e..90afd913 100644 --- a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb +++ b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb @@ -39,6 +39,18 @@ :return => test_return[:void], :contains_ptr? => true } + @void_ptr_func = {:name => "Spruce", + :args => [{ :type => "void*", + :name => "pork", + :ptr? => true, + }, + { :type => "MY_FANCY_VOID*", + :name => "salad", + :ptr? => true, + }], + :return => test_return[:void], + :contains_ptr? => true } + #no strict ordering @cmock_generator_plugin_return_thru_ptr = CMockGeneratorPluginReturnThruPtr.new(@config, @utils) end @@ -56,6 +68,13 @@ def complex_func_expect @utils.expect :ptr_or_str?, true, ['int*'] end + def void_ptr_func_expect + @utils.expect :ptr_or_str?, true, ['void*'] + @utils.expect :ptr_or_str?, true, ['MY_FANCY_VOID*'] + + @config.expect :treat_as_void, ['MY_FANCY_VOID'] + end + it "have set up internal priority correctly on init" do assert_equal(9, @cmock_generator_plugin_return_thru_ptr.priority) end @@ -100,6 +119,29 @@ def complex_func_expect assert_equal(expected, returned) end + it "add a mock function declaration with sizeof() for void pointer arguments" do + void_ptr_func_expect(); + + expected = + "#define Spruce_ReturnThruPtr_pork(pork)" + + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, sizeof(*pork))\n" + + "#define Spruce_ReturnArrayThruPtr_pork(pork, cmock_len)" + + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, cmock_len * sizeof(*pork))\n" + + "#define Spruce_ReturnMemThruPtr_pork(pork, cmock_size)" + + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, cmock_size)\n" + + "void Spruce_CMockReturnMemThruPtr_pork(UNITY_LINE_TYPE cmock_line, void* pork, size_t cmock_size);\n" + + "#define Spruce_ReturnThruPtr_salad(salad)" + + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, sizeof(*salad))\n" + + "#define Spruce_ReturnArrayThruPtr_salad(salad, cmock_len)" + + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, cmock_len * sizeof(*salad))\n" + + "#define Spruce_ReturnMemThruPtr_salad(salad, cmock_size)" + + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, cmock_size)\n" + + "void Spruce_CMockReturnMemThruPtr_salad(UNITY_LINE_TYPE cmock_line, MY_FANCY_VOID* salad, size_t cmock_size);\n" + + returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@void_ptr_func) + assert_equal(expected, returned) + end + it "add mock interfaces only for non-const pointer arguments" do complex_func_expect();