mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-09-18 08:09:58 +00:00
Merge pull request #263 from laurensmiers/master
Inline function mocking refactor
This commit is contained in:
+66
-15
@@ -73,28 +73,79 @@ class CMockHeaderParser
|
|||||||
return source
|
return source
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Return the number of pairs of braces/square brackets in the function provided by the user
|
||||||
|
# +source+:: String containing the function to be processed
|
||||||
|
def count_number_of_pairs_of_braces_in_function(source)
|
||||||
|
is_function_start_found = false
|
||||||
|
curr_level = 0
|
||||||
|
total_pairs = 0
|
||||||
|
|
||||||
|
source.each_char do |c|
|
||||||
|
if ("{" == c)
|
||||||
|
curr_level += 1
|
||||||
|
total_pairs +=1
|
||||||
|
is_function_start_found = true
|
||||||
|
elsif ("}" == c)
|
||||||
|
curr_level -=1
|
||||||
|
end
|
||||||
|
|
||||||
|
break if is_function_start_found && curr_level == 0 # We reached the end of the inline function body
|
||||||
|
end
|
||||||
|
|
||||||
|
if 0 != curr_level
|
||||||
|
total_pairs = 0 # Something is fishy about this source, not enough closing braces?
|
||||||
|
end
|
||||||
|
|
||||||
|
return total_pairs
|
||||||
|
end
|
||||||
|
|
||||||
|
# Transform inline functions to regular functions in the source by the user
|
||||||
|
# +source+:: String containing the source to be processed
|
||||||
def transform_inline_functions(source)
|
def transform_inline_functions(source)
|
||||||
|
# Format to look for inline functions.
|
||||||
|
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
|
||||||
|
# There are several possibilities:
|
||||||
|
# - sometimes they appear together, sometimes individually,
|
||||||
|
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
|
||||||
|
# so we check for word boundaries when searching for them
|
||||||
|
# - We first remove "static inline" combinations and boil down to single inline or static statements
|
||||||
|
inline_function_regex_formats = [
|
||||||
|
/(static\s+inline|inline\s+static)\s*/, # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
||||||
|
/(\bstatic\b|\binline\b)\s*/, # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
||||||
|
]
|
||||||
|
square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets
|
||||||
|
|
||||||
# let's clean up the encoding in case they've done anything weird with the characters we might find
|
# let's clean up the encoding in case they've done anything weird with the characters we might find
|
||||||
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil)
|
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil)
|
||||||
|
|
||||||
source.gsub!(/(static|inline)+.*\{.*\w*\}/m) do |m|
|
# - Just looking for static|inline in the gsub is a bit too aggressive (functions that are named like this, ...), so we try to be a bit smarter
|
||||||
m.gsub!(/(static|inline)/, '') # remove static and inline keywords
|
# Instead, look for "static inline" and parse it:
|
||||||
m = remove_nested_pairs_of_braces(m)
|
# - Everything before the match should just be copied, we don't want
|
||||||
|
# to touch anything but the inline functions.
|
||||||
|
# - Remove the implementation of the inline function (this is enclosed
|
||||||
|
# in square brackets) and replace it with ";" to complete the
|
||||||
|
# transformation to normal/non-inline function.
|
||||||
|
# To ensure proper removal of the function body, we count the number of square-bracket pairs
|
||||||
|
# and remove the pairs one-by-one.
|
||||||
|
# - Copy everything after the inline function implementation and start the parsing of the next inline function
|
||||||
|
|
||||||
# Functions having "{ }" at this point are/were inline functions,
|
inline_function_regex_formats.each do |format|
|
||||||
# Disguise them as normal functions with the ";"
|
loop do
|
||||||
m.gsub!(/\s*\{\s\}/, ";")
|
inline_function_match = source.match(/#{format}/) # Search for inline function declaration
|
||||||
|
break if nil == inline_function_match # No inline functions so nothing to do
|
||||||
|
|
||||||
# Cleanup the function declarations
|
total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match)
|
||||||
# Not strictly necessary, it will compile just fine, but it can help during debugging
|
|
||||||
m_lines = m.split(/\s*;\s*/).uniq
|
break if 0 == total_pairs_to_remove # Bad source?
|
||||||
m_lines.each do |m_line|
|
|
||||||
m_line.gsub!(/^\s+/, '') # remove extra white space from beginning of line
|
inline_function_stripped = inline_function_match.post_match
|
||||||
m_line.gsub!(/\s+/, ' ') # remove remaining extra white space
|
|
||||||
m_line.gsub!(/\n/, '') # remove newlines
|
total_pairs_to_remove.times do
|
||||||
|
inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ";") # Remove inline implementation (+ some whitespace because it's prettier)
|
||||||
|
end
|
||||||
|
|
||||||
|
source = inline_function_match.pre_match + inline_function_stripped # Make new source with the inline function removed and move on to the next
|
||||||
end
|
end
|
||||||
|
|
||||||
m_lines.join(";\n") + ";" # Join the lines and add the last semicolon manually
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return source
|
return source
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
|
|
||||||
static inline void dummy_func_0(void) {
|
static inline int dummy_func_0(void) {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void dummy_func_1(int a) {
|
inline static int dummy_func_1(int a) {
|
||||||
int a = dummy_func_0();
|
int a = dummy_func_0();
|
||||||
int b = 10;
|
int b = 10;
|
||||||
|
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline static dummy_func_2(int a, char b, float c) {
|
int inline static dummy_func_2(int a, char b, float c) {
|
||||||
c += 3.14;
|
c += 3.14;
|
||||||
b -= 32;
|
b -= 32;
|
||||||
return a + (int)(b) + c;
|
return a + (int)(b) + (int)c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dummy_normal_func(int a);
|
void dummy_normal_func(int a);
|
||||||
|
|||||||
@@ -1842,18 +1842,59 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
"};\n" +
|
"};\n" +
|
||||||
"int my_function(int a);\n" +
|
"int my_function(int a);\n" +
|
||||||
"int my_better_function(struct my_struct *s);\n" +
|
"int my_better_function(struct my_struct *s);\n" +
|
||||||
"static inline int get_member_a(struct my_struct *s)\n" +
|
"static inline int staticinlinebar(struct my_struct *s)\n" + # This is a function with a lot of indentation levels, we should be able to handle it
|
||||||
|
"{\n" +
|
||||||
|
"\t{\n" +
|
||||||
|
"\t\t{\n" +
|
||||||
|
"\t\t\treturn s->a;\n" +
|
||||||
|
"\t\t}\n" +
|
||||||
|
"\t}\n" +
|
||||||
|
"}\n" +
|
||||||
|
"static inline int staticinlinefunc(struct my_struct *s)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
" return s->a;\n" +
|
" return s->a;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"inline static int my_func_0(int a)\n" +
|
"int bar(struct my_struct *s);\n" + # A normal function to screw with our parser
|
||||||
"{\n" +
|
"inline static int inlinestaticfunc(int a) {\n" +
|
||||||
" return a + 42;\n" +
|
" return a + 42;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"inline int my_func_1(struct my_struct *s)\n" +
|
"inline int StaticInlineFunc(struct my_struct *s)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
" return get_member_a(s) + 42;\n" +
|
" return get_member_a(s) + 42;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
|
"int inline StaticInlineBar(struct my_struct *s)\n" +
|
||||||
|
"{\n" +
|
||||||
|
" return get_member_a(s) + 42;\n" +
|
||||||
|
"}\n" +
|
||||||
|
"struct staticinlinestruct {\n" + # Add a structure declaration between the inline functions, just to make sure we don't touch it!
|
||||||
|
"int a;\n" +
|
||||||
|
"};\n" +
|
||||||
|
"\n" +
|
||||||
|
"struct staticinlinestruct fubarstruct(struct my_struct *s);\n" + # Another normal function to screw with our parser
|
||||||
|
"static inline struct staticinlinestruct inlinefubarfunction(struct my_struct *s)\n" +
|
||||||
|
"{\n" +
|
||||||
|
" return (struct staticinlinestruct)*s;\n" +
|
||||||
|
"}\n" +
|
||||||
|
"int fubar(struct my_struct *s);\n" + # Another normal function to screw with our parser
|
||||||
|
"inline int stuff(int num)" +
|
||||||
|
"{" +
|
||||||
|
" int reg = 0x12;" +
|
||||||
|
" if (num > 0)" +
|
||||||
|
" {" +
|
||||||
|
" reg |= (0x0Eu);" +
|
||||||
|
" }" +
|
||||||
|
" else" +
|
||||||
|
" {" +
|
||||||
|
" reg |= (0x07u);" +
|
||||||
|
" }" +
|
||||||
|
" return reg;" +
|
||||||
|
"}" +
|
||||||
|
"\n" +
|
||||||
|
"int inline static dummy_func_2(int a, char b, float c) {" + # This is a sneaky one, inline static is placed AFTER the return value
|
||||||
|
" c += 3.14;" +
|
||||||
|
" b -= 32;" +
|
||||||
|
" return a + (int)(b) + (int)c;" +
|
||||||
|
"}" +
|
||||||
"#endif _NOINCLUDES\n"
|
"#endif _NOINCLUDES\n"
|
||||||
|
|
||||||
expected =
|
expected =
|
||||||
@@ -1883,12 +1924,77 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
"};\n" +
|
"};\n" +
|
||||||
"int my_function(int a);\n" +
|
"int my_function(int a);\n" +
|
||||||
"int my_better_function(struct my_struct *s);\n" +
|
"int my_better_function(struct my_struct *s);\n" +
|
||||||
"int get_member_a(struct my_struct *s);\n" +
|
"int staticinlinebar(struct my_struct *s);\n" +
|
||||||
"int my_func_0(int a);\n" +
|
"int staticinlinefunc(struct my_struct *s);\n" +
|
||||||
"int my_func_1(struct my_struct *s);\n" +
|
"int bar(struct my_struct *s);\n" +
|
||||||
|
"int inlinestaticfunc(int a);\n" +
|
||||||
|
"int StaticInlineFunc(struct my_struct *s);\n" +
|
||||||
|
"int StaticInlineBar(struct my_struct *s);\n" +
|
||||||
|
"struct staticinlinestruct {\n" +
|
||||||
|
"int a;\n" +
|
||||||
|
"};\n" +
|
||||||
|
"\n" +
|
||||||
|
"struct staticinlinestruct fubarstruct(struct my_struct *s);\n" +
|
||||||
|
"struct staticinlinestruct inlinefubarfunction(struct my_struct *s);\n" +
|
||||||
|
"int fubar(struct my_struct *s);\n" +
|
||||||
|
"int stuff(int num);\n" +
|
||||||
|
"int dummy_func_2(int a, char b, float c);" +
|
||||||
"#endif _NOINCLUDES\n"
|
"#endif _NOINCLUDES\n"
|
||||||
|
|
||||||
assert_equal(expected, @parser.transform_inline_functions(source))
|
assert_equal(expected, @parser.transform_inline_functions(source))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "Count number of pairs of braces in function succesfully" do
|
||||||
|
source =
|
||||||
|
"int foo(struct my_struct *s)\n" +
|
||||||
|
"{\n" +
|
||||||
|
" return get_member_a(s) + 42;\n" +
|
||||||
|
"}\n"
|
||||||
|
complex_source =
|
||||||
|
"int bar(struct my_struct *s)\n" +
|
||||||
|
"{\n" +
|
||||||
|
"\tint a = 6;\n" +
|
||||||
|
"\tint res = foo(&(struct my_struct){.nr = a});\n" +
|
||||||
|
"\t{\n" +
|
||||||
|
"\t\tint a = 5;\n" +
|
||||||
|
"\t\tint res = foo(&(struct my_struct){.nr = a});\n" +
|
||||||
|
"\t\t{\n" +
|
||||||
|
"\t\t\tstruct my_struct a = {.nr = 1};\n" +
|
||||||
|
"\t\t}\n" +
|
||||||
|
"\t}\n" +
|
||||||
|
"\treturn 42;\n" +
|
||||||
|
"}\n"
|
||||||
|
|
||||||
|
assert_equal(1, @parser.count_number_of_pairs_of_braces_in_function(source))
|
||||||
|
assert_equal(6, @parser.count_number_of_pairs_of_braces_in_function(complex_source))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Count number of pairs of braces returns 0 if bad source is supplied" do
|
||||||
|
bad_source_0 =
|
||||||
|
"int foo(struct my_struct *s)\n" +
|
||||||
|
"{\n" +
|
||||||
|
" return get_member_a(s) + 42;\n" +
|
||||||
|
"\n" # Missing closing brace
|
||||||
|
bad_source_1 =
|
||||||
|
"int bar(struct my_struct *s)\n" +
|
||||||
|
"{\n" +
|
||||||
|
"\tint a = 6;\n" +
|
||||||
|
"\tint res = foo(&(struct my_struct){.nr = a});\n" +
|
||||||
|
"\t{\n" +
|
||||||
|
"\t\tint a = 5;\n" +
|
||||||
|
"\t\tint res = foo(&(struct my_struct){.nr = a});\n" +
|
||||||
|
"\t\t{\n" +
|
||||||
|
"\t\t\n" + # Missing closing brace
|
||||||
|
"\t}\n" +
|
||||||
|
"\treturn 42;\n" +
|
||||||
|
"}\n"
|
||||||
|
bad_source_2 =
|
||||||
|
"int foo(struct my_struct *s)\n" +
|
||||||
|
"\n" # No braces in source
|
||||||
|
|
||||||
|
assert_equal(0, @parser.count_number_of_pairs_of_braces_in_function(bad_source_0))
|
||||||
|
assert_equal(0, @parser.count_number_of_pairs_of_braces_in_function(bad_source_1))
|
||||||
|
assert_equal(0, @parser.count_number_of_pairs_of_braces_in_function(bad_source_2))
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user