mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-10-13 12:27:26 +00:00
Merge pull request #187 from jlindgren90/array-typedefs
Add treat_as_array configuration option.
This commit is contained in:
@@ -479,6 +479,18 @@ from the defaults. We've tried to specify what the defaults are below.
|
|||||||
* 'float': 'FLOAT'
|
* 'float': 'FLOAT'
|
||||||
* 'double': 'FLOAT'
|
* 'double': 'FLOAT'
|
||||||
|
|
||||||
|
* `:treat_as_array`:
|
||||||
|
A specialized sort of `:treat_as` to be used when you've created a
|
||||||
|
typedef of an array type, such as `typedef int TenIntegers[10];`. This
|
||||||
|
is a hash of typedef name to element type. For example:
|
||||||
|
|
||||||
|
{ "TenIntegers" => "int",
|
||||||
|
"ArrayOfFloat" => "float" }
|
||||||
|
|
||||||
|
Telling CMock about these typedefs allows it to be more intelligent
|
||||||
|
about parameters of such types, so that you can use features like
|
||||||
|
ExpectWithArray and ReturnArrayThruPtr with them.
|
||||||
|
|
||||||
* `:treat_as_void`:
|
* `:treat_as_void`:
|
||||||
We've seen "fun" legacy systems typedef 'void' with a custom type,
|
We've seen "fun" legacy systems typedef 'void' with a custom type,
|
||||||
like MY_VOID. Add any instances of those to this list to help CMock
|
like MY_VOID. Add any instances of those to this list to help CMock
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class CMockConfig
|
|||||||
:fail_on_unexpected_calls => true,
|
:fail_on_unexpected_calls => true,
|
||||||
:unity_helper_path => false,
|
:unity_helper_path => false,
|
||||||
:treat_as => {},
|
:treat_as => {},
|
||||||
|
:treat_as_array => {},
|
||||||
:treat_as_void => [],
|
:treat_as_void => [],
|
||||||
:memcmp_if_unknown => true,
|
:memcmp_if_unknown => true,
|
||||||
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
|
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
|
||||||
|
|||||||
@@ -73,7 +73,10 @@ class CMockGeneratorUtils
|
|||||||
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
|
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
|
||||||
" #{dest} = #{arg[:name]};\n"
|
" #{dest} = #{arg[:name]};\n"
|
||||||
else
|
else
|
||||||
" memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}), sizeof(#{arg[:type]}));\n"
|
assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1"
|
||||||
|
comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */"
|
||||||
|
" memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}),\n" +
|
||||||
|
" sizeof(#{arg[:type]}[#{assert_expr}])); #{comment}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class CMockHeaderParser
|
|||||||
@c_attr_noconst = cfg.attributes.uniq - ['const']
|
@c_attr_noconst = cfg.attributes.uniq - ['const']
|
||||||
@c_attributes = ['const'] + c_attr_noconst
|
@c_attributes = ['const'] + c_attr_noconst
|
||||||
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
||||||
|
@treat_as_array = cfg.treat_as_array
|
||||||
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
||||||
@declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m
|
@declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m
|
||||||
@standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq
|
@standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq
|
||||||
@@ -186,6 +187,15 @@ class CMockHeaderParser
|
|||||||
arg_info = parse_type_and_name(arg)
|
arg_info = parse_type_and_name(arg)
|
||||||
arg_info.delete(:modifier) # don't care about this
|
arg_info.delete(:modifier) # don't care about this
|
||||||
arg_info.delete(:c_calling_convention) # don't care about this
|
arg_info.delete(:c_calling_convention) # don't care about this
|
||||||
|
|
||||||
|
# in C, array arguments implicitly degrade to pointers
|
||||||
|
# make the translation explicit here to simplify later logic
|
||||||
|
if @treat_as_array[arg_info[:type]] and not arg_info[:ptr?] then
|
||||||
|
arg_info[:type] = "#{@treat_as_array[arg_info[:type]]}*"
|
||||||
|
arg_info[:type] = "const #{arg_info[:type]}" if arg_info[:const?]
|
||||||
|
arg_info[:ptr?] = true
|
||||||
|
end
|
||||||
|
|
||||||
args << arg_info
|
args << arg_info
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
|
|||||||
expected3 = " cmock_call_instance->Expected_Kiwi = Kiwi;\n"
|
expected3 = " cmock_call_instance->Expected_Kiwi = Kiwi;\n"
|
||||||
|
|
||||||
arg4 = { :name => "Lime", :const? => false, :type => 'LIME_T', :ptr? => false }
|
arg4 = { :name => "Lime", :const? => false, :type => 'LIME_T', :ptr? => false }
|
||||||
expected4 = " memcpy((void*)(&cmock_call_instance->Expected_Lime), (void*)(&Lime), sizeof(LIME_T));\n"
|
expected4 = " memcpy((void*)(&cmock_call_instance->Expected_Lime), (void*)(&Lime),\n" +
|
||||||
|
" sizeof(LIME_T[sizeof(Lime) == sizeof(LIME_T) ? 1 : -1])); /* add LIME_T to :treat_as_array if this causes an error */\n"
|
||||||
|
|
||||||
assert_equal(expected1, @cmock_generator_utils_simple.code_add_an_arg_expectation(arg1))
|
assert_equal(expected1, @cmock_generator_utils_simple.code_add_an_arg_expectation(arg1))
|
||||||
assert_equal(expected2, @cmock_generator_utils_simple.code_add_an_arg_expectation(arg2))
|
assert_equal(expected2, @cmock_generator_utils_simple.code_add_an_arg_expectation(arg2))
|
||||||
@@ -131,7 +132,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
|
|||||||
" cmock_call_instance->ReturnThruPtr_Kiwi_Used = 0;\n"
|
" cmock_call_instance->ReturnThruPtr_Kiwi_Used = 0;\n"
|
||||||
|
|
||||||
arg4 = { :name => "Lime", :const? => false, :type => 'LIME_T', :ptr? => false }
|
arg4 = { :name => "Lime", :const? => false, :type => 'LIME_T', :ptr? => false }
|
||||||
expected4 = " memcpy((void*)(&cmock_call_instance->Expected_Lime), (void*)(&Lime), sizeof(LIME_T));\n" +
|
expected4 = " memcpy((void*)(&cmock_call_instance->Expected_Lime), (void*)(&Lime),\n" +
|
||||||
|
" sizeof(LIME_T[sizeof(Lime) == sizeof(LIME_T) ? 1 : -1])); /* add LIME_T to :treat_as_array if this causes an error */\n" +
|
||||||
" cmock_call_instance->IgnoreArg_Lime = 0;\n"
|
" cmock_call_instance->IgnoreArg_Lime = 0;\n"
|
||||||
|
|
||||||
assert_equal(expected1, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg1))
|
assert_equal(expected1, @cmock_generator_utils_complex.code_add_an_arg_expectation(arg1))
|
||||||
@@ -153,7 +155,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
|
|||||||
}
|
}
|
||||||
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" +
|
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" +
|
||||||
" cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" +
|
" cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" +
|
||||||
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType), sizeof(MY_TYPE));\n" +
|
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType),\n" +
|
||||||
|
" sizeof(MY_TYPE[sizeof(MyMyType) == sizeof(MY_TYPE) ? 1 : -1])); /* add MY_TYPE to :treat_as_array if this causes an error */\n" +
|
||||||
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
|
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
|
||||||
"}\n\n"
|
"}\n\n"
|
||||||
assert_equal(expected, @cmock_generator_utils_simple.code_add_argument_loader(function))
|
assert_equal(expected, @cmock_generator_utils_simple.code_add_argument_loader(function))
|
||||||
@@ -169,7 +172,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
|
|||||||
" cmock_call_instance->Expected_MyIntPtr_Depth = MyIntPtr_Depth;\n" +
|
" cmock_call_instance->Expected_MyIntPtr_Depth = MyIntPtr_Depth;\n" +
|
||||||
" cmock_call_instance->IgnoreArg_MyIntPtr = 0;\n" +
|
" cmock_call_instance->IgnoreArg_MyIntPtr = 0;\n" +
|
||||||
" cmock_call_instance->ReturnThruPtr_MyIntPtr_Used = 0;\n" +
|
" cmock_call_instance->ReturnThruPtr_MyIntPtr_Used = 0;\n" +
|
||||||
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType), sizeof(MY_TYPE));\n" +
|
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType),\n" +
|
||||||
|
" sizeof(MY_TYPE[sizeof(MyMyType) == sizeof(MY_TYPE) ? 1 : -1])); /* add MY_TYPE to :treat_as_array if this causes an error */\n" +
|
||||||
" cmock_call_instance->IgnoreArg_MyMyType = 0;\n" +
|
" cmock_call_instance->IgnoreArg_MyMyType = 0;\n" +
|
||||||
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
|
" cmock_call_instance->Expected_MyStr = MyStr;\n" +
|
||||||
" cmock_call_instance->IgnoreArg_MyStr = 0;\n" +
|
" cmock_call_instance->IgnoreArg_MyStr = 0;\n" +
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
@config.expect :c_calling_conventions, ['__stdcall']
|
@config.expect :c_calling_conventions, ['__stdcall']
|
||||||
@config.expect :treat_as_void, ['MY_FUNKY_VOID']
|
@config.expect :treat_as_void, ['MY_FUNKY_VOID']
|
||||||
@config.expect :treat_as, { "BANJOS" => "INT", "TUBAS" => "HEX16"}
|
@config.expect :treat_as, { "BANJOS" => "INT", "TUBAS" => "HEX16"}
|
||||||
|
@config.expect :treat_as_array, {"IntArray" => "int", "Book" => "Page"}
|
||||||
@config.expect :when_no_prototypes, :error
|
@config.expect :when_no_prototypes, :error
|
||||||
@config.expect :verbosity, 1
|
@config.expect :verbosity, 1
|
||||||
@config.expect :treat_externs, :exclude
|
@config.expect :treat_externs, :exclude
|
||||||
@@ -951,6 +952,32 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "converts typedef'd array arguments to pointers" do
|
||||||
|
|
||||||
|
source = "Book AddToBook(Book book, const IntArray values);\n"
|
||||||
|
|
||||||
|
expected = [{ :name => "AddToBook",
|
||||||
|
:modifier=>"",
|
||||||
|
:return => { :type => "Book",
|
||||||
|
:name => "cmock_to_return",
|
||||||
|
:str => "Book cmock_to_return",
|
||||||
|
:void? => false,
|
||||||
|
:ptr? => false,
|
||||||
|
:const? => false,
|
||||||
|
:const_ptr? => false
|
||||||
|
},
|
||||||
|
:var_arg => nil,
|
||||||
|
:args => [{ :type => "Page*", :name => "book", :ptr? => true, :const? => false, :const_ptr? => false },
|
||||||
|
{ :type => "const int*", :name => "values", :ptr? => true, :const? => true, :const_ptr? => false }],
|
||||||
|
:args_string => "Book book, const IntArray values",
|
||||||
|
:args_call => "book, values",
|
||||||
|
:contains_ptr? => true
|
||||||
|
}]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
it "properly detect typedef'd variants of void and use those" do
|
it "properly detect typedef'd variants of void and use those" do
|
||||||
|
|
||||||
source = "typedef (void) FUNKY_VOID_T;\n" +
|
source = "typedef (void) FUNKY_VOID_T;\n" +
|
||||||
|
|||||||
Reference in New Issue
Block a user