From c725e4ddc69aa89f2d9debbffddd88c5e9c20d4b Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 12 Sep 2017 12:50:09 -0400 Subject: [PATCH 1/3] Handle pointer-to-constant types more consistently. 725bfd93a070 fixed handling of pointer-to-constant types in function arguments but did not apply the same fix to function return types. Unify the logic in a parse_type_and_name() function that is used for both arguments and return types. Update tests. --- lib/cmock_header_parser.rb | 92 ++++++++++++++++----------- test/unit/cmock_header_parser_test.rb | 61 ++++++++++++------ 2 files changed, 97 insertions(+), 56 deletions(-) diff --git a/lib/cmock_header_parser.rb b/lib/cmock_header_parser.rb index 85154c7..ee0fe6a 100644 --- a/lib/cmock_header_parser.rb +++ b/lib/cmock_header_parser.rb @@ -140,24 +140,51 @@ class CMockHeaderParser return funcs end + def parse_type_and_name(arg) + # Split up words and remove known attributes. For pointer types, make sure + # to remove 'const' only when it applies to the pointer itself, not when it + # applies to the type pointed to. For non-pointer types, remove any + # occurrence of 'const'. + arg.gsub!(/(\w)\*/,'\1 *') # pull asterisks away from preceding word + arg.gsub!(/\*(\w)/,'* \1') # pull asterisks away from following word + arg_array = arg.split + arg_info = divine_ptr_and_const(arg) + arg_info[:name] = arg_array[-1] + + attributes = arg.include?('*') ? @c_attr_noconst : @c_attributes + attr_array = [] + type_array = [] + + arg_array[0..-2].each do |word| + if attributes.include?(word) + attr_array << word + elsif @c_calling_conventions.include?(word) + arg_info[:c_calling_convention] = word + else + type_array << word + end + end + + if arg_info[:const_ptr?] + attr_array << 'const' + type_array.delete_at(type_array.rindex('const')) + end + + arg_info[:modifier] = attr_array.join(' ') + arg_info[:type] = type_array.join(' ').gsub(/\s+\*/,'*') # remove space before asterisks + return arg_info + 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 ... - # Split up words and remove known attributes, but in case of pointer args, don't remove any - # 'const' from the type that it points to, since that may change the underlying assembly-code - # pointer type on some embedded platforms, making it point to RAM instead of ROM. (I.e. For - # pointer args, remove 'const' only when it applies to the pointer itself. For non-pointer - # args, remove 'const' regardless.) - # - arg_array = arg.split - ptr_const_info = divine_ptr_and_const(arg) - arg_elements = arg_array - (arg.include?('*') ? @c_attr_noconst : @c_attributes) - args << { :type => arg_elements[0..(ptr_const_info[:const_ptr?] ? -3 : -2)].join(' '), - :name => arg_elements[-1] - }.merge(ptr_const_info) + arg_info = parse_type_and_name(arg) + arg_info.delete(:modifier) # don't care about this + arg_info.delete(:c_calling_convention) # don't care about this + args << arg_info end return args end @@ -236,35 +263,24 @@ class CMockHeaderParser args = regex_match[2].strip #process function attributes, return type, and name - descriptors = regex_match[1] - descriptors.gsub!(/(\w)\*/,'\1 *') #pull asterisks away from preceding word - descriptors.gsub!(/\*(\w)/,'* \1') #pull asterisks away from following word - descriptors = descriptors.split #array of all descriptor strings + parsed = parse_type_and_name(regex_match[1]) - #grab name - decl[:name] = descriptors[-1] #snag name as last array item - - #build attribute and return type strings - decl[:modifier] = [] - rettype = [] - full_retval = descriptors[0..-2].join(' ') - 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 + decl[:name] = parsed[:name] + decl[:modifier] = parsed[:modifier] + unless parsed[:c_calling_convention].nil? + decl[:c_calling_convention] = parsed[:c_calling_convention] end - decl[:modifier] = decl[:modifier].join(' ') - rettype = rettype.join(' ').gsub(/\s+\*/,'*') #remove space before asterisks + + rettype = parsed[:type] rettype = 'void' if (@local_as_void.include?(rettype.strip)) - decl[:return] = { :type => rettype, - :name => 'cmock_to_return', - :str => "#{rettype} cmock_to_return", - :void? => (rettype == 'void') - }.merge(divine_ptr_and_const(full_retval)) + decl[:return] = { :type => rettype, + :name => 'cmock_to_return', + :str => "#{rettype} cmock_to_return", + :void? => (rettype == 'void'), + :ptr? => parsed[:ptr?], + :const? => parsed[:const?], + :const_ptr? => parsed[:const_ptr?] + } #remove default argument statements from mock definitions args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ') diff --git a/test/unit/cmock_header_parser_test.rb b/test/unit/cmock_header_parser_test.rb index c6cecc0..add920f 100644 --- a/test/unit/cmock_header_parser_test.rb +++ b/test/unit/cmock_header_parser_test.rb @@ -805,32 +805,57 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do assert_equal(expected, @parser.parse("module", source)[:functions]) end - it "should properly handle const before or after return type" do - + it "should properly handle const before return type" do sources = [ "const int * PorkRoast(void);\n", - "int const * PorkRoast(void);\n", "const int* PorkRoast(void);\n", + "const int *PorkRoast(void);\n" + ] + + expected = [{ :var_arg => nil, + :name => "PorkRoast", + :return => { :type => "const int*", + :name => 'cmock_to_return', + :ptr? => true, + :const? => true, + :const_ptr? => false, + :str => "const int* cmock_to_return", + :void? => false + }, + :modifier => "", + :contains_ptr? => false, + :args => [], + :args_string => "void", + :args_call => "" + }] + + sources.each do |source| + assert_equal(expected, @parser.parse("module", source)[:functions]) + end + end + + it "should properly handle const before return type" do + sources = [ + "int const * PorkRoast(void);\n", "int const* PorkRoast(void);\n", - "const int *PorkRoast(void);\n", "int const *PorkRoast(void);\n" ] - expected = [{ :var_arg=>nil, - :name=>"PorkRoast", - :return=> { :type => "int*", - :name => 'cmock_to_return', - :ptr? => true, - :const? => true, - :const_ptr? => false, - :str => "int* cmock_to_return", - :void? => false - }, - :modifier=>"const", + expected = [{ :var_arg => nil, + :name => "PorkRoast", + :return => { :type => "int const*", + :name => 'cmock_to_return', + :ptr? => true, + :const? => true, + :const_ptr? => false, + :str => "int const* cmock_to_return", + :void? => false + }, + :modifier => "", :contains_ptr? => false, - :args=>[], - :args_string=>"void", - :args_call=>"" + :args => [], + :args_string => "void", + :args_call => "" }] sources.each do |source| From 3b123fb5335789635cdb54037f1dfd6c445f1bbb Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 12 Sep 2017 15:54:47 -0400 Subject: [PATCH 2/3] Don't assume that pointer-to-constant types have "const" removed. 1. Update treat_as table to include pointer-to-constant types. 2. Remove unnecessary casts in assignments and return statements. 3. Improve logic for adding "const" to types of function arguments. 4. It's no longer necessary to prepend "const" to function return type. --- lib/cmock_config.rb | 4 +++ lib/cmock_generator.rb | 3 +- lib/cmock_generator_plugin_array.rb | 8 +++--- lib/cmock_generator_plugin_callback.rb | 20 ++++++------- lib/cmock_generator_plugin_ignore.rb | 5 ++-- lib/cmock_generator_utils.rb | 19 +++++++++++-- test/test_helper.rb | 18 ++++++------ .../unit/cmock_generator_plugin_array_test.rb | 28 ++++++++++++------- .../cmock_generator_plugin_ignore_arg_test.rb | 6 ++-- ...k_generator_plugin_return_thru_ptr_test.rb | 8 +++--- test/unit/cmock_generator_utils_test.rb | 20 ++++++------- 11 files changed, 80 insertions(+), 59 deletions(-) diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index 4eebab1..398c582 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -120,6 +120,8 @@ class CMockConfig 'UINT32' => 'HEX32', 'UINT32_T' => 'HEX32', 'void*' => 'HEX8_ARRAY', + 'void const*' => 'HEX8_ARRAY', + 'const void*' => 'HEX8_ARRAY', 'unsigned short' => 'HEX16', 'uint16' => 'HEX16', 'uint16_t' => 'HEX16', @@ -131,6 +133,8 @@ class CMockConfig 'UINT8' => 'HEX8', 'UINT8_T' => 'HEX8', 'char*' => 'STRING', + 'char const*' => 'STRING', + 'const char*' => 'STRING', 'pCHAR' => 'STRING', 'cstring' => 'STRING', 'CSTRING' => 'STRING', diff --git a/lib/cmock_generator.rb b/lib/cmock_generator.rb index 592e979..5cbafcd 100644 --- a/lib/cmock_generator.rb +++ b/lib/cmock_generator.rb @@ -247,10 +247,9 @@ class CMockGenerator file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n" file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledLate);\n" end - return_type = function[:return][:const?] ? "(const #{function[:return][:type]})" : ((function[:return][:type] =~ /cmock/) ? "(#{function[:return][:type]})" : '') file << @plugins.run(:mock_implementation, function) file << " UNITY_CLR_DETAILS();\n" - file << " return #{return_type}cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?]) + file << " return cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?]) file << "}\n\n" end diff --git a/lib/cmock_generator_plugin_array.rb b/lib/cmock_generator_plugin_array.rb index 480c1df..3b73708 100644 --- a/lib/cmock_generator_plugin_array.rb +++ b/lib/cmock_generator_plugin_array.rb @@ -27,8 +27,8 @@ class CMockGeneratorPluginArray 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 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]}" + type = @utils.arg_type_with_const(m) + m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" end.join(', ') if (function[:return][:void?]) return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" + @@ -44,8 +44,8 @@ class CMockGeneratorPluginArray lines = [] func_name = function[:name] 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]}" + type = @utils.arg_type_with_const(m) + m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" end.join(', ') call_string = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name]}.join(', ') if (function[:return][:void?]) diff --git a/lib/cmock_generator_plugin_callback.rb b/lib/cmock_generator_plugin_callback.rb index 0731c13..da55085 100644 --- a/lib/cmock_generator_plugin_callback.rb +++ b/lib/cmock_generator_plugin_callback.rb @@ -33,7 +33,7 @@ class CMockGeneratorPluginCallback def mock_function_declarations(function) func_name = function[:name] - return_type = function[:return][:const?] ? "const #{function[:return][:type]}" : function[:return][:type] + 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" @@ -41,7 +41,6 @@ class CMockGeneratorPluginCallback def mock_implementation_for_callbacks_after_arg_check(function) func_name = function[:name] - return_cast = function[:return][:const?] ? "(#{function[:return][:type]})" : "" 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) @@ -49,16 +48,15 @@ class CMockGeneratorPluginCallback when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" - when 4 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer();\n }\n" - when 5 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" - when 6 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" - when 7 then " cmock_call_instance->ReturnVal = #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" + when 4 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer();\n }\n" + when 5 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" + when 6 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" + when 7 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" end end def mock_implementation_for_callbacks_without_arg_check(function) func_name = function[:name] - return_cast = function[:return][:const?] ? "(#{function[:return][:type]})" : "" 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) @@ -66,10 +64,10 @@ class CMockGeneratorPluginCallback 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 #{return_cast}Mock.#{func_name}_CallbackFunctionPointer();\n }\n" - when 5 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" - when 6 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" - when 7 then " return #{return_cast}Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\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 diff --git a/lib/cmock_generator_plugin_ignore.rb b/lib/cmock_generator_plugin_ignore.rb index c971830..a291dd4 100644 --- a/lib/cmock_generator_plugin_ignore.rb +++ b/lib/cmock_generator_plugin_ignore.rb @@ -40,10 +40,9 @@ class CMockGeneratorPluginIgnore lines << " return;\n }\n" else retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} ) - return_type = function[:return][:const?] ? "(const #{function[:return][:type]})" : ((function[:return][:type] =~ /cmock/) ? "(#{function[:return][:type]})" : '') - lines << " if (cmock_call_instance == NULL)\n return #{return_type}Mock.#{function[:name]}_FinalReturn;\n" + 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 #{return_type}cmock_call_instance->ReturnVal;\n }\n" + lines << " return cmock_call_instance->ReturnVal;\n }\n" end lines end diff --git a/lib/cmock_generator_utils.rb b/lib/cmock_generator_utils.rb index fde3338..eb12e23 100644 --- a/lib/cmock_generator_utils.rb +++ b/lib/cmock_generator_utils.rb @@ -22,6 +22,19 @@ class CMockGeneratorUtils @helpers = helpers end + def self.arg_type_with_const(arg) + # Restore any "const" that was removed in header parsing + if arg[:type].include?('*') + arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type] + else + arg[:const?] ? "const #{arg[:type]}" : arg[:type] + end + end + + def arg_type_with_const(arg) + self.class.arg_type_with_const(arg) + end + def code_verify_an_arg_expectation(function, arg) if (@arrays) case(@ptr_handling) @@ -58,7 +71,7 @@ class CMockGeneratorUtils def code_assign_argument_quickly(dest, arg) if (arg[:ptr?] or @treat_as.include?(arg[:type])) - " #{dest} = #{arg[:const?] ? "(#{arg[:type]})" : ''}#{arg[:name]};\n" + " #{dest} = #{arg[:name]};\n" else " memcpy(&#{dest}, &#{arg[:name]}, sizeof(#{arg[:type]}));\n" end @@ -68,8 +81,8 @@ class CMockGeneratorUtils 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]}" + type = arg_type_with_const(m) + m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{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) ) } + diff --git a/test/test_helper.rb b/test/test_helper.rb index 9bbe3b0..f369895 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -24,20 +24,20 @@ end def test_return { - :int => {:type => "int", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => false, :str => 'int cmock_to_return'}, - :int_ptr => {:type => "int*", :name => 'cmock_to_return', :ptr? => true, :const? => false, :void? => false, :str => 'int* cmock_to_return'}, - :void => {:type => "void", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => true, :str => 'void cmock_to_return'}, - :string => {:type => "char*", :name => 'cmock_to_return', :ptr? => false, :const? => true, :void? => false, :str => 'const char* cmock_to_return'}, + :int => {:type => "int", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => false, :str => 'int cmock_to_return'}, + :int_ptr => {:type => "int*", :name => 'cmock_to_return', :ptr? => true, :const? => false, :void? => false, :str => 'int* cmock_to_return'}, + :void => {:type => "void", :name => 'cmock_to_return', :ptr? => false, :const? => false, :void? => true, :str => 'void cmock_to_return'}, + :string => {:type => "const char*", :name => 'cmock_to_return', :ptr? => false, :const? => true, :void? => false, :str => 'const char* cmock_to_return'}, } end def test_arg { - :int => {:type => "int", :name => 'MyInt', :ptr? => false, :const? => false}, - :int_ptr => {:type => "int*", :name => 'MyIntPtr', :ptr? => true, :const? => false}, - :mytype => {:type => "MY_TYPE", :name => 'MyMyType', :ptr? => false, :const? => true}, - :mytype_ptr => {:type => "MY_TYPE*", :name => 'MyMyTypePtr', :ptr? => true, :const? => false}, - :string => {:type => "char*", :name => 'MyStr', :ptr? => false, :const? => true}, + :int => {:type => "int", :name => 'MyInt', :ptr? => false, :const? => false}, + :int_ptr => {:type => "int*", :name => 'MyIntPtr', :ptr? => true, :const? => false}, + :mytype => {:type => "MY_TYPE", :name => 'MyMyType', :ptr? => false, :const? => true}, + :mytype_ptr => {:type => "MY_TYPE*", :name => 'MyMyTypePtr', :ptr? => true, :const? => false}, + :string => {:type => "const char*", :name => 'MyStr', :ptr? => false, :const? => true}, } end diff --git a/test/unit/cmock_generator_plugin_array_test.rb b/test/unit/cmock_generator_plugin_array_test.rb index 3b0b4f8..8449616 100644 --- a/test/unit/cmock_generator_plugin_array_test.rb +++ b/test/unit/cmock_generator_plugin_array_test.rb @@ -6,21 +6,29 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_plugin_array' +require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_utils' + +class UtilsStub + def helpers + {} + end + def arg_type_with_const(arg) + CMockGeneratorUtils.arg_type_with_const(arg) + end + def code_add_base_expectation(func) + "mock_retval_0" + end +end describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do before do - create_mocks :utils - #no strict ordering @config = create_stub( :when_ptr => :compare_data, :enforce_strict_ordering => false, :respond_to? => true ) - @utils = create_stub( - :helpers => {}, - :code_add_base_expectation => "mock_retval_0" - ) + @utils = UtilsStub.new @cmock_generator_plugin_array = CMockGeneratorPluginArray.new(@config, @utils) end @@ -88,10 +96,10 @@ describe CMockGeneratorPluginArray, "Verify CMockPGeneratorluginArray Module" do it "add another mock function declaration for functions of style 'const char* func(const int* tofu)'" do function = {:name => "Pine", - :args => [{ :type => "int*", - :name => "tofu", - :ptr? => true, - :const? => true, + :args => [{ :type => "const int*", + :name => "tofu", + :ptr? => true, + :const? => true, }], :return => test_return[:string], :contains_ptr? => true } diff --git a/test/unit/cmock_generator_plugin_ignore_arg_test.rb b/test/unit/cmock_generator_plugin_ignore_arg_test.rb index ed556ea..8ac4648 100644 --- a/test/unit/cmock_generator_plugin_ignore_arg_test.rb +++ b/test/unit/cmock_generator_plugin_ignore_arg_test.rb @@ -21,9 +21,9 @@ describe CMockGeneratorPluginIgnoreArg, "Verify CMockGeneratorPluginIgnoreArg Mo :name => "chicken", :ptr? => false, }, - { :type => "int*", - :name => "beef", - :ptr? => true, + { :type => "const int*", + :name => "beef", + :ptr? => true, :const? => true, }, { :type => "int*", 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 68d0fb8..f715880 100644 --- a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb +++ b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb @@ -27,9 +27,9 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh :name => "chicken", :ptr? => false, }, - { :type => "int*", - :name => "beef", - :ptr? => true, + { :type => "const int*", + :name => "beef", + :ptr? => true, :const? => true, }, { :type => "int*", @@ -52,7 +52,7 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh def complex_func_expect @utils.expect :ptr_or_str?, false, ['int'] - @utils.expect :ptr_or_str?, true, ['int*'] + @utils.expect :ptr_or_str?, true, ['const int*'] @utils.expect :ptr_or_str?, true, ['int*'] end diff --git a/test/unit/cmock_generator_utils_test.rb b/test/unit/cmock_generator_utils_test.rb index aad99ab..f2066f8 100644 --- a/test/unit/cmock_generator_utils_test.rb +++ b/test/unit/cmock_generator_utils_test.rb @@ -20,7 +20,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do @config.expect :plugins, [] @config.expect :plugins, [] @config.expect :plugins, [] - @config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','char*' => 'STRING'} + @config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','const char*' => 'STRING'} @cmock_generator_utils_simple = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper}) @config.expect :when_ptr, :smart @@ -31,7 +31,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] - @config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','uint32_t' => 'HEX32','char*' => 'STRING'} + @config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','uint32_t' => 'HEX32','const char*' => 'STRING'} @cmock_generator_utils_complex = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper, :A=>1, :B=>2}) end @@ -99,8 +99,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do arg1 = { :name => "Orange", :const? => false, :type => 'int', :ptr? => false } expected1 = " cmock_call_instance->Expected_Orange = Orange;\n" - arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => true } - expected2 = " cmock_call_instance->Expected_Lemon = (const char*)Lemon;\n" + arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => false } + expected2 = " cmock_call_instance->Expected_Lemon = Lemon;\n" arg3 = { :name => "Kiwi", :const? => false, :type => 'KIWI_T*', :ptr? => true } expected3 = " cmock_call_instance->Expected_Kiwi = Kiwi;\n" @@ -119,8 +119,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do expected1 = " cmock_call_instance->Expected_Orange = Orange;\n" + " cmock_call_instance->IgnoreArg_Orange = 0;\n" - arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => true } - expected2 = " cmock_call_instance->Expected_Lemon = (const char*)Lemon;\n" + + arg2 = { :name => "Lemon", :const? => true, :type => 'const char*', :ptr? => false } + expected2 = " cmock_call_instance->Expected_Lemon = Lemon;\n" + " cmock_call_instance->Expected_Lemon_Depth = Lemon_Depth;\n" + " cmock_call_instance->IgnoreArg_Lemon = 0;\n" @@ -154,7 +154,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" + " cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" + " memcpy(&cmock_call_instance->Expected_MyMyType, &MyMyType, sizeof(MY_TYPE));\n" + - " cmock_call_instance->Expected_MyStr = (char*)MyStr;\n" + + " cmock_call_instance->Expected_MyStr = MyStr;\n" + "}\n\n" assert_equal(expected, @cmock_generator_utils_simple.code_add_argument_loader(function)) end @@ -171,7 +171,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do " cmock_call_instance->ReturnThruPtr_MyIntPtr_Used = 0;\n" + " memcpy(&cmock_call_instance->Expected_MyMyType, &MyMyType, sizeof(MY_TYPE));\n" + " cmock_call_instance->IgnoreArg_MyMyType = 0;\n" + - " cmock_call_instance->Expected_MyStr = (char*)MyStr;\n" + + " cmock_call_instance->Expected_MyStr = MyStr;\n" + " cmock_call_instance->IgnoreArg_MyStr = 0;\n" + "}\n\n" assert_equal(expected, @cmock_generator_utils_complex.code_add_argument_loader(function)) @@ -231,7 +231,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do " UNITY_TEST_ASSERT_EQUAL_STRING(cmock_call_instance->Expected_MyStr, MyStr, cmock_line, CMockStringMismatch);\n" + " }\n" @unity_helper.expect :nil?, false - @unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['char*'] + @unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['const char*'] assert_equal(expected, @cmock_generator_utils_simple.code_verify_an_arg_expectation(function, arg)) end @@ -311,7 +311,7 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do " UNITY_TEST_ASSERT_EQUAL_STRING(cmock_call_instance->Expected_MyStr, MyStr, cmock_line, CMockStringMismatch);\n" + " }\n" @unity_helper.expect :nil?, false - @unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['char*'] + @unity_helper.expect :get_helper, ['UNITY_TEST_ASSERT_EQUAL_STRING',''], ['const char*'] assert_equal(expected, @cmock_generator_utils_complex.code_verify_an_arg_expectation(function, arg)) end From 526668961afcda97594c32c63ac242cf36cd8583 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 12 Sep 2017 17:24:35 -0400 Subject: [PATCH 3/3] Add an additional test for handling of pointer arguments. --- test/test_helper.rb | 13 +++++++------ test/unit/cmock_generator_utils_test.rb | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index f369895..486196c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -33,11 +33,12 @@ end def test_arg { - :int => {:type => "int", :name => 'MyInt', :ptr? => false, :const? => false}, - :int_ptr => {:type => "int*", :name => 'MyIntPtr', :ptr? => true, :const? => false}, - :mytype => {:type => "MY_TYPE", :name => 'MyMyType', :ptr? => false, :const? => true}, - :mytype_ptr => {:type => "MY_TYPE*", :name => 'MyMyTypePtr', :ptr? => true, :const? => false}, - :string => {:type => "const char*", :name => 'MyStr', :ptr? => false, :const? => true}, + :int => {:type => "int", :name => 'MyInt', :ptr? => false, :const? => false, :const_ptr? => false}, + :int_ptr => {:type => "int*", :name => 'MyIntPtr', :ptr? => true, :const? => false, :const_ptr? => false}, + :const_ptr => {:type => "int*", :name => 'MyConstPtr', :ptr? => true, :const? => false, :const_ptr? => true}, + :double_ptr => {:type => "int const**", :name => 'MyDoublePtr', :ptr? => true, :const? => true, :const_ptr? => false}, + :mytype => {:type => "MY_TYPE", :name => 'MyMyType', :ptr? => false, :const? => true, :const_ptr? => false}, + :mytype_ptr => {:type => "MY_TYPE*", :name => 'MyMyTypePtr', :ptr? => true, :const? => false, :const_ptr? => false}, + :string => {:type => "const char*", :name => 'MyStr', :ptr? => false, :const? => true, :const_ptr? => false}, } end - diff --git a/test/unit/cmock_generator_utils_test.rb b/test/unit/cmock_generator_utils_test.rb index f2066f8..bd59749 100644 --- a/test/unit/cmock_generator_utils_test.rb +++ b/test/unit/cmock_generator_utils_test.rb @@ -177,6 +177,23 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do assert_equal(expected, @cmock_generator_utils_complex.code_add_argument_loader(function)) end + it 'create an argument loader when the function has pointer arguments supporting arrays' do + function = { :name => "Melon", + :args_string => "stuff", + :args => [test_arg[:const_ptr], test_arg[:double_ptr]] + } + expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* const MyConstPtr, int MyConstPtr_Depth, int const** MyDoublePtr, int MyDoublePtr_Depth)\n{\n" + + " cmock_call_instance->Expected_MyConstPtr = MyConstPtr;\n" + + " cmock_call_instance->Expected_MyConstPtr_Depth = MyConstPtr_Depth;\n" + + " cmock_call_instance->IgnoreArg_MyConstPtr = 0;\n" + + " cmock_call_instance->ReturnThruPtr_MyConstPtr_Used = 0;\n" + + " cmock_call_instance->Expected_MyDoublePtr = MyDoublePtr;\n" + + " cmock_call_instance->Expected_MyDoublePtr_Depth = MyDoublePtr_Depth;\n" + + " cmock_call_instance->IgnoreArg_MyDoublePtr = 0;\n" + + "}\n\n" + assert_equal(expected, @cmock_generator_utils_complex.code_add_argument_loader(function)) + end + it "not call argument loader if there are no arguments to actually use for this function" do function = { :name => "Pineapple", :args_string => "void" }