mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-06-23 14:00:33 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 543c230f33 | |||
| 968d3f6ec4 | |||
| 0c45d26a28 | |||
| 811b85e1b1 | |||
| 759d1826c8 | |||
| 60a1829acf | |||
| 8ba3ed99a1 | |||
| 0af0e20d15 | |||
| 2def6c4f21 | |||
| d403eb88c8 | |||
| 18b2deca85 | |||
| bd91eb4cca | |||
| fe829f2d8a | |||
| 5650b79dcd | |||
| 9908930bc5 | |||
| b256013c5e | |||
| 927ca1bec0 | |||
| e1c6851492 | |||
| e0a61d484e | |||
| 431c5c678a | |||
| 3a07201a3f | |||
| 11dfb9c668 | |||
| 27e89dd05e | |||
| 237c02dade | |||
| 5ee470d7e4 | |||
| 79ee5b8419 | |||
| fba3bc22a2 | |||
| 01536c4a67 | |||
| 7a32429bd2 | |||
| dbb2f4964c | |||
| 2817da62db | |||
| ee3ae84e64 | |||
| 0cdc742538 |
@@ -518,6 +518,14 @@ from the defaults. We've tried to specify what the defaults are below.
|
||||
* `:include` will mock externed functions
|
||||
* `:exclude` will ignore externed functions (default).
|
||||
|
||||
* `:treat_inlines`:
|
||||
This specifies how you want CMock to handle functions that have been
|
||||
marked as inline in the header file. Should it mock them?
|
||||
|
||||
* `:include` will mock inlined functions
|
||||
* `:exclude` will ignore inlined functions (default).
|
||||
|
||||
|
||||
* `:unity_helper_path`:
|
||||
If you have created a header with your own extensions to unity to
|
||||
handle your own types, you can set this argument to that path. CMock
|
||||
@@ -686,4 +694,3 @@ you might tool CMock into your build process. You may also want to consider
|
||||
using [Ceedling](https://throwtheswitch.org/ceedling). Please note that
|
||||
these examples are meant to show how the build process works. They have
|
||||
failing tests ON PURPOSE to show what that would look like. Don't be alarmed. ;)
|
||||
|
||||
|
||||
+11
-1
@@ -29,6 +29,7 @@ class CMockConfig
|
||||
:when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart
|
||||
:verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
|
||||
:treat_externs => :exclude, #the options being :include or :exclude
|
||||
:treat_inlines => :exclude, #the options being :include or :exclude
|
||||
:callback_include_count => true,
|
||||
:callback_after_arg_check => false,
|
||||
:includes => nil,
|
||||
@@ -64,7 +65,16 @@ class CMockConfig
|
||||
end
|
||||
options[:unity_helper_path] ||= options[:unity_helper]
|
||||
options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String
|
||||
options[:includes_c_post_header] = ((options[:includes_c_post_header] || []) + (options[:unity_helper_path] || [])).uniq
|
||||
|
||||
if options[:unity_helper_path]
|
||||
require 'pathname'
|
||||
includes1 = options[:includes_c_post_header] || []
|
||||
includes2 = options[:unity_helper_path].map do |path|
|
||||
Pathname(path).relative_path_from(Pathname(options[:mock_path])).to_s
|
||||
end
|
||||
options[:includes_c_post_header] = (includes1 + includes2).uniq
|
||||
end
|
||||
|
||||
options[:plugins].compact!
|
||||
options[:plugins].map! {|p| p.to_sym}
|
||||
@options = options
|
||||
|
||||
@@ -16,6 +16,7 @@ class CMockGenerator
|
||||
@prefix = @config.mock_prefix
|
||||
@suffix = @config.mock_suffix
|
||||
@weak = @config.weak
|
||||
@include_inline = @config.treat_inlines
|
||||
@ordered = @config.enforce_strict_ordering
|
||||
@framework = @config.framework.to_s
|
||||
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
|
||||
@@ -61,6 +62,12 @@ class CMockGenerator
|
||||
end
|
||||
|
||||
def create_mock_header_file(parsed_stuff)
|
||||
if @include_inline == :include
|
||||
@file_writer.create_file(@module_name + ".h", @subdir) do |file, filename|
|
||||
file << parsed_stuff[:normalized_source]
|
||||
end
|
||||
end
|
||||
|
||||
@file_writer.create_file(@mock_name + ".h", @subdir) do |file, filename|
|
||||
create_mock_header_header(file, filename)
|
||||
create_mock_header_service_call_declarations(file)
|
||||
|
||||
@@ -60,9 +60,9 @@ class CMockGeneratorPluginCallback
|
||||
" UNITY_CLR_DETAILS();\n" \
|
||||
" return;\n }\n"
|
||||
else
|
||||
" #{function[:return][:type]} ret = #{generate_call(function)};\n" \
|
||||
" #{function[:return][:type]} cmock_cb_ret = #{generate_call(function)};\n" \
|
||||
" UNITY_CLR_DETAILS();\n" \
|
||||
" return ret;\n }\n"
|
||||
" return cmock_cb_ret;\n }\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+124
-14
@@ -6,7 +6,7 @@
|
||||
|
||||
class CMockHeaderParser
|
||||
|
||||
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs
|
||||
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs, :treat_inlines
|
||||
|
||||
def initialize(cfg)
|
||||
@funcs = []
|
||||
@@ -24,13 +24,16 @@ class CMockHeaderParser
|
||||
@local_as_void = @treat_as_void
|
||||
@verbosity = cfg.verbosity
|
||||
@treat_externs = cfg.treat_externs
|
||||
@treat_inlines = cfg.treat_inlines
|
||||
@c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs
|
||||
@c_strippables += ['inline'] if (@treat_inlines == :include) #we'll need to remove the attribute if we're allowing inlines
|
||||
end
|
||||
|
||||
def parse(name, source)
|
||||
@module_name = name.gsub(/\W/,'')
|
||||
@typedefs = []
|
||||
@funcs = []
|
||||
@normalized_source = nil
|
||||
function_names = []
|
||||
|
||||
parse_functions( import_source(source) ).map do |decl|
|
||||
@@ -41,14 +44,113 @@ class CMockHeaderParser
|
||||
end
|
||||
end
|
||||
|
||||
@normalized_source = if (@treat_inlines == :include)
|
||||
transform_inline_functions(source)
|
||||
else
|
||||
''
|
||||
end
|
||||
|
||||
{ :includes => nil,
|
||||
:functions => @funcs,
|
||||
:typedefs => @typedefs
|
||||
:typedefs => @typedefs,
|
||||
:normalized_source => @normalized_source
|
||||
}
|
||||
end
|
||||
|
||||
private if $ThisIsOnlyATest.nil? ################
|
||||
|
||||
def remove_nested_pairs_of_braces(source)
|
||||
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
|
||||
if (RUBY_VERSION.split('.')[0].to_i > 1)
|
||||
#we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
|
||||
r = "\\{([^\\{\\}]*|\\g<0>)*\\}"
|
||||
source.gsub!(/#{r}/m, '{ }')
|
||||
else
|
||||
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
|
||||
end
|
||||
end
|
||||
|
||||
return source
|
||||
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)
|
||||
# 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
|
||||
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil)
|
||||
|
||||
# - 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
|
||||
# Instead, look for "static inline" and parse it:
|
||||
# - 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
|
||||
|
||||
inline_function_regex_formats.each do |format|
|
||||
loop do
|
||||
inline_function_match = source.match(/#{format}/) # Search for inline function declaration
|
||||
break if nil == inline_function_match # No inline functions so nothing to do
|
||||
|
||||
total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match)
|
||||
|
||||
break if 0 == total_pairs_to_remove # Bad source?
|
||||
|
||||
inline_function_stripped = inline_function_match.post_match
|
||||
|
||||
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
|
||||
|
||||
return source
|
||||
end
|
||||
|
||||
def import_source(source)
|
||||
|
||||
# let's clean up the encoding in case they've done anything weird with the characters we might find
|
||||
@@ -100,16 +202,15 @@ class CMockHeaderParser
|
||||
"#{functype} #{$2.strip}(#{$3});"
|
||||
end
|
||||
|
||||
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
|
||||
if (RUBY_VERSION.split('.')[0].to_i > 1)
|
||||
#we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
|
||||
r = "\\{([^\\{\\}]*|\\g<0>)*\\}"
|
||||
source.gsub!(/#{r}/m, '{ }')
|
||||
else
|
||||
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
|
||||
end
|
||||
source = remove_nested_pairs_of_braces(source)
|
||||
|
||||
if (@treat_inlines == :include)
|
||||
# Functions having "{ }" at this point are/were inline functions,
|
||||
# User wants them in so 'disguise' them as normal functions with the ";"
|
||||
source.gsub!("{ }", ";")
|
||||
end
|
||||
|
||||
|
||||
# remove function definitions by stripping off the arguments right now
|
||||
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ";")
|
||||
|
||||
@@ -124,11 +225,20 @@ class CMockHeaderParser
|
||||
src_lines = source.split(/\s*;\s*/).uniq
|
||||
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
|
||||
src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays
|
||||
if (@treat_externs == :include)
|
||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
|
||||
else
|
||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern|inline)\s+/).nil?} # remove inline and extern functions
|
||||
|
||||
unless (@treat_externs == :include)
|
||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern)\s+/).nil?} # remove extern functions
|
||||
end
|
||||
|
||||
if (@treat_inlines == :include)
|
||||
src_lines.each {
|
||||
|src_line|
|
||||
src_line.gsub!(/^inline/, "") # Remove "inline" so that they are 'normal' functions
|
||||
}
|
||||
else
|
||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
|
||||
end
|
||||
|
||||
src_lines.delete_if {|line| line.empty? } #drop empty lines
|
||||
end
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
#define CMOCK_VERSION_MAJOR 2
|
||||
#define CMOCK_VERSION_MINOR 5
|
||||
#define CMOCK_VERSION_BUILD 0
|
||||
#define CMOCK_VERSION_BUILD 1
|
||||
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
|
||||
|
||||
//should be big enough to index full range of CMOCK_MEM_MAX
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
:includes: []
|
||||
:mock_path: ./system/generated/
|
||||
:mock_prefix: mock_
|
||||
:treat_inlines: :include
|
||||
:treat_as_void:
|
||||
- OSEK_TASK
|
||||
- VOID_TYPE_CRAZINESS
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
static inline int dummy_func_0(void) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
inline static int dummy_func_1(int a) {
|
||||
int a = dummy_func_0();
|
||||
int b = 10;
|
||||
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int inline static dummy_func_2(int a, char b, float c) {
|
||||
c += 3.14;
|
||||
b -= 32;
|
||||
return a + (int)(b) + (int)c;
|
||||
}
|
||||
|
||||
void dummy_normal_func(int a);
|
||||
|
||||
inline void dummy_func_3(void) {
|
||||
//NOP
|
||||
}
|
||||
Executable → Regular
@@ -12,6 +12,7 @@
|
||||
:callback_after_arg_check: true
|
||||
:callback_include_count: false
|
||||
:treat_externs: :include
|
||||
:treat_inlines: :include
|
||||
|
||||
:systest:
|
||||
:types: |
|
||||
|
||||
@@ -19,6 +19,7 @@ describe CMockConfig, "Verify CMockConfig Module" do
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:attributes], config.attributes)
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:plugins], config.plugins)
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:treat_externs], config.treat_externs)
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:treat_inlines], config.treat_inlines)
|
||||
end
|
||||
|
||||
it "replace only options specified in a hash" do
|
||||
@@ -30,6 +31,7 @@ describe CMockConfig, "Verify CMockConfig Module" do
|
||||
assert_equal(test_attributes, config.attributes)
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:plugins], config.plugins)
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:treat_externs], config.treat_externs)
|
||||
assert_equal(CMockConfig::CMockDefaultOptions[:treat_inlines], config.treat_inlines)
|
||||
end
|
||||
|
||||
it "replace only options specified in a yaml file" do
|
||||
@@ -40,6 +42,7 @@ describe CMockConfig, "Verify CMockConfig Module" do
|
||||
assert_nil(config.includes)
|
||||
assert_equal(test_plugins, config.plugins)
|
||||
assert_equal(:include, config.treat_externs)
|
||||
assert_equal(:include, config.treat_inlines)
|
||||
end
|
||||
|
||||
it "populate treat_as map with internal standard_treat_as_map defaults, redefine defaults, and add custom values" do
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
:plugins:
|
||||
- 'soda'
|
||||
- 'pizza'
|
||||
:treat_externs: :include
|
||||
:treat_externs: :include
|
||||
:treat_inlines: :include
|
||||
|
||||
@@ -54,6 +54,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
||||
@config.expect :includes_c_post_header, nil
|
||||
@config.expect :subdir, nil
|
||||
@config.expect :fail_on_unexpected_calls, true
|
||||
@config.expect :treat_inlines, :exclude
|
||||
@cmock_generator = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
||||
@cmock_generator.module_name = @module_name
|
||||
@cmock_generator.mock_name = "Mock#{@module_name}"
|
||||
@@ -72,6 +73,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
||||
@config.expect :includes_c_post_header, nil
|
||||
@config.expect :subdir, nil
|
||||
@config.expect :fail_on_unexpected_calls, true
|
||||
@config.expect :treat_inlines, :exclude
|
||||
@cmock_generator_strict = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
||||
@cmock_generator_strict.module_name = @module_name
|
||||
@cmock_generator_strict.mock_name = "Mock#{@module_name}"
|
||||
@@ -133,6 +135,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
||||
@config.expect :includes_c_post_header, nil
|
||||
@config.expect :subdir, nil
|
||||
@config.expect :fail_on_unexpected_calls, true
|
||||
@config.expect :treat_inlines, :exclude
|
||||
@cmock_generator2 = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
||||
@cmock_generator2.module_name = "Pout-Pout Fish"
|
||||
@cmock_generator2.mock_name = "MockPout-Pout Fish"
|
||||
|
||||
@@ -191,9 +191,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
||||
expected = [" if (!Mock.Apple_CallbackBool &&\n",
|
||||
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
|
||||
" {\n",
|
||||
" int ret = Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n",
|
||||
" int cmock_cb_ret = Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n",
|
||||
" UNITY_CLR_DETAILS();\n",
|
||||
" return ret;\n",
|
||||
" return cmock_cb_ret;\n",
|
||||
" }\n"
|
||||
].join
|
||||
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
|
||||
@@ -246,9 +246,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
||||
expected = [" if (!Mock.Apple_CallbackBool &&\n",
|
||||
" Mock.Apple_CallbackFunctionPointer != NULL)\n",
|
||||
" {\n",
|
||||
" int ret = Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
|
||||
" int cmock_cb_ret = Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n",
|
||||
" UNITY_CLR_DETAILS();\n",
|
||||
" return ret;\n",
|
||||
" return cmock_cb_ret;\n",
|
||||
" }\n"
|
||||
].join
|
||||
returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function)
|
||||
|
||||
@@ -23,6 +23,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
@config.expect :when_no_prototypes, :error
|
||||
@config.expect :verbosity, 1
|
||||
@config.expect :treat_externs, :exclude
|
||||
@config.expect :treat_inlines, :exclude
|
||||
@config.expect :array_size_type, ['int', 'size_t']
|
||||
@config.expect :array_size_name, 'size|len'
|
||||
|
||||
@@ -453,6 +454,60 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
|
||||
end
|
||||
|
||||
it "leave inline functions if inline to be included" do
|
||||
source =
|
||||
"extern uint32 foobar(unsigned int);\n" +
|
||||
"uint32 extern_name_func(unsigned int);\n" +
|
||||
"uint32 funcinline(unsigned int);\n" +
|
||||
"inline void inlineBar(unsigned int);\n" +
|
||||
"extern int extern_bar(void);\n" +
|
||||
"static inline void staticinlineBar(unsigned int);\n" +
|
||||
"static inline void bar(unsigned int);\n" +
|
||||
"static inline void bar(unsigned int)\n" +
|
||||
"{\n" +
|
||||
" // NOP\n" +
|
||||
"}\n"
|
||||
|
||||
expected =
|
||||
[ "uint32 extern_name_func(unsigned int)",
|
||||
"uint32 funcinline(unsigned int)",
|
||||
"void inlineBar(unsigned int)",
|
||||
"void staticinlineBar(unsigned int)",
|
||||
"void bar(unsigned int)"
|
||||
]
|
||||
|
||||
@parser.treat_inlines = :include
|
||||
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
|
||||
end
|
||||
|
||||
it "leave inline and extern functions if inline and extern to be included" do
|
||||
source =
|
||||
"extern uint32 foobar(unsigned int);\n" +
|
||||
"uint32 extern_name_func(unsigned int);\n" +
|
||||
"uint32 funcinline(unsigned int);\n" +
|
||||
"inline void inlineBar(unsigned int);\n" +
|
||||
"extern int extern_bar(void);\n" +
|
||||
"static inline void staticinlineBar(unsigned int);\n" +
|
||||
"static inline void bar(unsigned int);\n" +
|
||||
"static inline void bar(unsigned int)\n" +
|
||||
"{\n" +
|
||||
" // NOP\n" +
|
||||
"}\n"
|
||||
|
||||
expected =
|
||||
[ "extern uint32 foobar(unsigned int)",
|
||||
"uint32 extern_name_func(unsigned int)",
|
||||
"uint32 funcinline(unsigned int)",
|
||||
"void inlineBar(unsigned int)",
|
||||
"extern int extern_bar(void)",
|
||||
"void staticinlineBar(unsigned int)",
|
||||
"void bar(unsigned int)"
|
||||
]
|
||||
|
||||
@parser.treat_externs = :include
|
||||
@parser.treat_inlines = :include
|
||||
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
|
||||
end
|
||||
|
||||
it "remove defines" do
|
||||
source =
|
||||
@@ -1725,4 +1780,221 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
end
|
||||
end
|
||||
|
||||
it "Transform inline functions doesn't change a header with no inlines" do
|
||||
source =
|
||||
"#ifndef _NOINCLUDES\n" +
|
||||
"#define _NOINCLUDES\n" +
|
||||
"#include \"unity.h\"\n" +
|
||||
"#include \"cmock.h\"\n" +
|
||||
"#include \"YetAnotherHeader.h\"\n" +
|
||||
"\n" +
|
||||
"/* Ignore the following warnings since we are copying code */\n" +
|
||||
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
|
||||
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
|
||||
"#pragma GCC diagnostic push\n" +
|
||||
"#endif\n" +
|
||||
"#if !defined(__clang__)\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n" +
|
||||
"#endif\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" +
|
||||
"#endif\n" +
|
||||
"\n" +
|
||||
"struct my_struct {\n" +
|
||||
"int a;\n" +
|
||||
"int b;\n" +
|
||||
"int b;\n" +
|
||||
"char c;\n" +
|
||||
"};\n" +
|
||||
"int my_function(int a);\n" +
|
||||
"int my_better_function(struct my_struct *s);\n" +
|
||||
"\n" +
|
||||
"#endif _NOINCLUDES\n"
|
||||
|
||||
assert_equal(source, @parser.transform_inline_functions(source))
|
||||
end
|
||||
|
||||
it "Transform inline functions changes inline functions to function declarations" do
|
||||
source =
|
||||
"#ifndef _NOINCLUDES\n" +
|
||||
"#define _NOINCLUDES\n" +
|
||||
"#include \"unity.h\"\n" +
|
||||
"#include \"cmock.h\"\n" +
|
||||
"#include \"YetAnotherHeader.h\"\n" +
|
||||
"\n" +
|
||||
"/* Ignore the following warnings since we are copying code */\n" +
|
||||
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
|
||||
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
|
||||
"#pragma GCC diagnostic push\n" +
|
||||
"#endif\n" +
|
||||
"#if !defined(__clang__)\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n" +
|
||||
"#endif\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" +
|
||||
"#endif\n" +
|
||||
"\n" +
|
||||
"struct my_struct {\n" +
|
||||
"int a;\n" +
|
||||
"int b;\n" +
|
||||
"int b;\n" +
|
||||
"char c;\n" +
|
||||
"};\n" +
|
||||
"int my_function(int a);\n" +
|
||||
"int my_better_function(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" +
|
||||
" return s->a;\n" +
|
||||
"}\n" +
|
||||
"int bar(struct my_struct *s);\n" + # A normal function to screw with our parser
|
||||
"inline static int inlinestaticfunc(int a) {\n" +
|
||||
" return a + 42;\n" +
|
||||
"}\n" +
|
||||
"inline int StaticInlineFunc(struct my_struct *s)\n" +
|
||||
"{\n" +
|
||||
" return get_member_a(s) + 42;\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"
|
||||
|
||||
expected =
|
||||
"#ifndef _NOINCLUDES\n" +
|
||||
"#define _NOINCLUDES\n" +
|
||||
"#include \"unity.h\"\n" +
|
||||
"#include \"cmock.h\"\n" +
|
||||
"#include \"YetAnotherHeader.h\"\n" +
|
||||
"\n" +
|
||||
"/* Ignore the following warnings since we are copying code */\n" +
|
||||
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
|
||||
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
|
||||
"#pragma GCC diagnostic push\n" +
|
||||
"#endif\n" +
|
||||
"#if !defined(__clang__)\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n" +
|
||||
"#endif\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" +
|
||||
"#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" +
|
||||
"#endif\n" +
|
||||
"\n" +
|
||||
"struct my_struct {\n" +
|
||||
"int a;\n" +
|
||||
"int b;\n" +
|
||||
"int b;\n" +
|
||||
"char c;\n" +
|
||||
"};\n" +
|
||||
"int my_function(int a);\n" +
|
||||
"int my_better_function(struct my_struct *s);\n" +
|
||||
"int staticinlinebar(struct my_struct *s);\n" +
|
||||
"int staticinlinefunc(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"
|
||||
|
||||
assert_equal(expected, @parser.transform_inline_functions(source))
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user