From 693c65878028ab9e1ed66d354885e717a33cddec Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Thu, 31 Aug 2017 16:25:11 -0400 Subject: [PATCH] Fix const determination for pointer-to-pointer types. For example, consider: void function(const int **ret_ptr). This function stores a (const int *) at the address passed in. We'd want to test it with function_ReturnThruPtr_ret_ptr, but CMock was incorrectly considering the (const int **) a constant argument, and thus did not generate the ReturnThruPtr function. Add a test to ensure that all permutations of constants and pointers work as expected. --- lib/cmock_header_parser.rb | 28 +++++++--------------- test/unit/cmock_header_parser_test.rb | 34 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/lib/cmock_header_parser.rb b/lib/cmock_header_parser.rb index 53377b9..a44cc20 100644 --- a/lib/cmock_header_parser.rb +++ b/lib/cmock_header_parser.rb @@ -160,30 +160,20 @@ class CMockHeaderParser end def divine_const(arg) - return false if !(/(?:^|\s|\*)const(?:\*|\s|$)/ =~ arg) # check for const as part of a larger word - return true if (/const(?:\w|\s)*\*/ =~ arg) # check const comes before * indicating const data - return false if (/\*\s*const/ =~ arg) # check const comes after * indicating const ptr - return true + # a non-pointer arg containing "const" is a constant + # an arg containing "const" before the last * is a pointer to a constant + return ( arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg) + : (/(^|\s)const(\s|$)/ =~ arg) ) ? true : false end def divine_ptr_and_const(arg) - divination = { :ptr? => false, :const? => false, :const_ptr? => false } + divination = {} - #first check if there is a pointer present and that it's not part of a C string or function definition - #divination[:ptr?] = (arg.split[0..-2].join.include?('*') && !arg.gsub(/(const|char|\*|\s)+/,'').empty?) - divination[:ptr?] = (arg.include?('*') && !arg.gsub(/(const|char|\*|\s)+/,'').empty?) + divination[:ptr?] = divine_ptr(arg) + divination[:const?] = divine_const(arg) - #if there isn't a const that isn't part of a larger word, we're done - return divination if !(/(?:^|\s|\*)const(?:\*|\s|$)/ =~ arg) - divination[:const?] = true - - # check const comes after * indicating const ptr - if (/\*\s*const/ =~ arg) - divination[:const_ptr?] = true - - #check const comes before * indicating also const data - divination[:const?] = (/const(?:\w|\s)*\*/ =~ arg) ? true : false - end + # an arg containing "const" after the last * is a constant pointer + divination[:const_ptr?] = (/\*(?!.*\*)\s*const(\s|$)/ =~ arg) ? true : false return divination end diff --git a/test/unit/cmock_header_parser_test.rb b/test/unit/cmock_header_parser_test.rb index a3d4a45..591cb57 100644 --- a/test/unit/cmock_header_parser_test.rb +++ b/test/unit/cmock_header_parser_test.rb @@ -1510,4 +1510,38 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do assert_equal(expected, @parser.parse("module", source)[:functions]) end + it "divines all permutations of ptr, const, and const_ptr correctly" do + truth_table = [ + # argument ptr const const_ptr + [ "constNOTconst constNOTconst", false, false, false ], + [ "const constNOTconst constNOTconst", false, true, false ], + [ "constNOTconst const constNOTconst", false, true, false ], + [ "constNOTconst *constNOTconst", true, false, false ], + [ "const constNOTconst *constNOTconst", true, true, false ], + [ "constNOTconst const *constNOTconst", true, true, false ], + [ "constNOTconst *const constNOTconst", true, false, true ], + [ "const constNOTconst *const constNOTconst", true, true, true ], + [ "constNOTconst const *const constNOTconst", true, true, true ], + [ "constNOTconst **constNOTconst", true, false, false ], + [ "const constNOTconst **constNOTconst", true, false, false ], + [ "constNOTconst const **constNOTconst", true, false, false ], + [ "constNOTconst *const *constNOTconst", true, true, false ], + [ "const constNOTconst *const *constNOTconst", true, true, false ], + [ "constNOTconst const *const *constNOTconst", true, true, false ], + [ "constNOTconst **const constNOTconst", true, false, true ], + [ "const constNOTconst **const constNOTconst", true, false, true ], + [ "constNOTconst const **const constNOTconst", true, false, true ], + [ "constNOTconst *const *const constNOTconst", true, true, true ], + [ "const constNOTconst *const *const constNOTconst", true, true, true ], + [ "constNOTconst const *const *const constNOTconst", true, true, true ] + ] + + truth_table.each do |entry| + assert_equal(@parser.divine_ptr(entry[0]), entry[1]) + assert_equal(@parser.divine_const(entry[0]), entry[2]) + assert_equal(@parser.divine_ptr_and_const(entry[0]), + { ptr?: entry[1], const?: entry[2], const_ptr?: entry[3] }) + end + end + end