mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-06-05 21:15:20 +00:00
Merge branch 'master' into master
This commit is contained in:
+23
-7
@@ -282,6 +282,22 @@ You may specify the options explicitly:
|
||||
|
||||
cmock = Cmock.new(:plugins => [:cexception, :ignore], :mock_path => 'my/mocks/')
|
||||
|
||||
Creating Skeletons:
|
||||
-------------------
|
||||
|
||||
Not only is CMock able to generate mock files from a header file, but it is also able
|
||||
to generate (and update) skeleton C files from headers. It does this by creating a
|
||||
(mostly) empty implementation for every function that is declared in the header. If you later
|
||||
add to that header list, just run this feature again and it will add prototypes for the missing
|
||||
functions!
|
||||
|
||||
Like the normal usecase for CMock, this feature can be used from the command line
|
||||
or from within its ruby API. For example, from the command line, add `--skeleton` to
|
||||
generate a skeleton instead:
|
||||
|
||||
```
|
||||
ruby cmock.rb --skeleton ../create/c/for/this.h
|
||||
```
|
||||
|
||||
Config Options:
|
||||
---------------
|
||||
@@ -394,14 +410,14 @@ from the defaults. We've tried to specify what the defaults are below.
|
||||
* default: mocks
|
||||
|
||||
* `:mock_prefix`:
|
||||
The prefix to prepend to your mock files. For example, if it's “Mock”, a file
|
||||
The prefix to prepend to your mock files. For example, if it's `Mock`, a file
|
||||
“USART.h” will get a mock called “MockUSART.c”. This CAN be used with a suffix
|
||||
at the same time.
|
||||
|
||||
* default: Mock
|
||||
|
||||
* `:mock_suffix`:
|
||||
The suffix to append to your mock files. For example, it it's "_Mock", a file
|
||||
The suffix to append to your mock files. For example, it it's `_Mock`, a file
|
||||
"USART.h" will get a mock called "USART_Mock.h". This CAN be used with a prefix
|
||||
at the same time.
|
||||
|
||||
@@ -637,8 +653,8 @@ from the defaults. We've tried to specify what the defaults are below.
|
||||
Parameters must match *both* `:array_size_type` and `:array_size_name` (and
|
||||
must come right after a pointer parameter) to be treated as an array size.
|
||||
|
||||
Once you've told it how to recognize your arrays, CMock will give you _Expect
|
||||
calls that work more like _ExpectWithArray, and compare an array of objects
|
||||
Once you've told it how to recognize your arrays, CMock will give you `_Expect`
|
||||
calls that work more like `_ExpectWithArray`, and compare an array of objects
|
||||
rather than just a single object.
|
||||
|
||||
For example, if you write the following, CMock will check that GoBananas is
|
||||
@@ -653,14 +669,14 @@ from the defaults. We've tried to specify what the defaults are below.
|
||||
GoBananas_ExpectWithArray(b, 2, 2);
|
||||
|
||||
* `:fail_on_unexpected_calls`:
|
||||
By default, CMock will fail a test if a mock is called without _Expect and _Ignore
|
||||
By default, CMock will fail a test if a mock is called without `_Expect` and `_Ignore`
|
||||
called first. While this forces test writers to be more explicit in their expectations,
|
||||
it can clutter tests with _Expect or _Ignore calls for functions which are not the focus
|
||||
it can clutter tests with `_Expect` or `_Ignore` calls for functions which are not the focus
|
||||
of the test. While this is a good indicator that this module should be refactored, some
|
||||
users are not fans of the additional noise.
|
||||
|
||||
Therefore, :fail_on_unexpected_calls can be set to false to force all mocks to start with
|
||||
the assumption that they are operating as _Ignore unless otherwise specified.
|
||||
the assumption that they are operating as `_Ignore` unless otherwise specified.
|
||||
|
||||
* default: true
|
||||
* **note:**
|
||||
|
||||
+19
-1
@@ -32,6 +32,12 @@ class CMock
|
||||
end
|
||||
end
|
||||
|
||||
def setup_skeletons(files)
|
||||
[files].flatten.each do |src|
|
||||
generate_skeleton src
|
||||
end
|
||||
end
|
||||
|
||||
private ###############################
|
||||
|
||||
def generate_mock(src)
|
||||
@@ -39,6 +45,12 @@ class CMock
|
||||
puts "Creating mock for #{name}..." unless @silent
|
||||
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)))
|
||||
end
|
||||
|
||||
def generate_skeleton(src)
|
||||
name = File.basename(src, '.h')
|
||||
puts "Creating skeleton for #{name}..." unless @silent
|
||||
@cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src)))
|
||||
end
|
||||
end
|
||||
|
||||
def option_maker(options, key, val)
|
||||
@@ -75,6 +87,8 @@ if ($0 == __FILE__)
|
||||
ARGV.each do |arg|
|
||||
if (arg =~ /^-o\"?([a-zA-Z0-9._\\\/:\s]+)\"?/)
|
||||
options.merge! CMockConfig.load_config_file_from_yaml( arg.gsub(/^-o/,'') )
|
||||
elsif (arg == "--skeleton")
|
||||
options[:skeleton] = true
|
||||
elsif (arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]+)\"?/)
|
||||
options = option_maker(options, $1, $2)
|
||||
else
|
||||
@@ -82,5 +96,9 @@ if ($0 == __FILE__)
|
||||
end
|
||||
end
|
||||
|
||||
CMock.new(options).setup_mocks(filelist)
|
||||
if (options[:skeleton])
|
||||
CMock.new(options).setup_skeletons(filelist)
|
||||
else
|
||||
CMock.new(options).setup_mocks(filelist)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,6 +12,7 @@ class CMockConfig
|
||||
:mock_path => 'mocks',
|
||||
:mock_prefix => 'Mock',
|
||||
:mock_suffix => '',
|
||||
:skeleton_path => '',
|
||||
:weak => '',
|
||||
:subdir => nil,
|
||||
:plugins => [],
|
||||
@@ -40,6 +41,7 @@ class CMockConfig
|
||||
:orig_header_include_fmt => "#include \"%s\"",
|
||||
:array_size_type => [],
|
||||
:array_size_name => 'size|len',
|
||||
:skeleton => false,
|
||||
|
||||
# Format to look for inline functions.
|
||||
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
|
||||
|
||||
@@ -33,6 +33,14 @@ class CMockFileWriter
|
||||
update_file(full_file_name_done, full_file_name_temp)
|
||||
end
|
||||
|
||||
def append_file(filename, subdir)
|
||||
raise "Where's the block of data to create?" unless block_given?
|
||||
full_file_name = "#{@config.skeleton_path}/#{subdir+'/' if subdir}#{filename}"
|
||||
File.open(full_file_name, 'a') do |file|
|
||||
yield(file, filename)
|
||||
end
|
||||
end
|
||||
|
||||
private ###################################
|
||||
|
||||
def update_file(dest, src)
|
||||
|
||||
+37
-1
@@ -55,6 +55,11 @@ class CMockGenerator
|
||||
create_mock_source_file(parsed_stuff)
|
||||
end
|
||||
|
||||
def create_skeleton(module_name, parsed_stuff)
|
||||
@module_name = module_name
|
||||
create_skeleton_source_file(parsed_stuff)
|
||||
end
|
||||
|
||||
private if $ThisIsOnlyATest.nil? ##############################
|
||||
|
||||
def create_mock_subdir()
|
||||
@@ -94,6 +99,17 @@ class CMockGenerator
|
||||
end
|
||||
end
|
||||
|
||||
def create_skeleton_source_file(parsed_stuff)
|
||||
filename = "#{@config.mock_path}/#{@subdir+'/' if @subdir}#{module_name}.c"
|
||||
existing = File.exists?(filename) ? File.read(filename) : ""
|
||||
@file_writer.append_file(@module_name + ".c", @subdir) do |file, filename|
|
||||
create_source_header_section(file, filename, []) if existing.empty?
|
||||
parsed_stuff[:functions].each do |function|
|
||||
create_function_skeleton(file, function, existing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_mock_header_header(file, filename)
|
||||
define_name = @clean_mock_name.upcase
|
||||
orig_filename = (@subdir ? @subdir + "/" : "") + @module_name + ".h"
|
||||
@@ -146,7 +162,7 @@ class CMockGenerator
|
||||
|
||||
def create_source_header_section(file, filename, functions)
|
||||
header_file = (@subdir ? @subdir + '/' : '') + filename.gsub(".c",".h")
|
||||
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless functions.empty?
|
||||
file << "#include <string.h>\n"
|
||||
file << "#include <stdlib.h>\n"
|
||||
file << "#include <setjmp.h>\n"
|
||||
@@ -272,4 +288,24 @@ class CMockGenerator
|
||||
file << @utils.code_add_argument_loader(function)
|
||||
file << @plugins.run(:mock_interfaces, function)
|
||||
end
|
||||
|
||||
def create_function_skeleton(file, function, existing)
|
||||
# prepare return value and arguments
|
||||
function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") +
|
||||
(function[:return][:type]) +
|
||||
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
|
||||
args_string = function[:args_string]
|
||||
args_string += (", " + function[:var_arg]) unless (function[:var_arg].nil?)
|
||||
|
||||
decl = "#{function_mod_and_rettype} #{function[:name]}(#{args_string})"
|
||||
|
||||
unless (existing.include?(decl))
|
||||
file << "#{decl}\n"
|
||||
file << "{\n"
|
||||
file << " //TODO: Implement Me!\n"
|
||||
function[:args].each {|arg| file << " (void)#{arg[:name]};\n"}
|
||||
file << " return (#{(function[:return][:type])})0;\n" unless (function[:return][:void?])
|
||||
file << "}\n\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -79,4 +79,11 @@ class CMockGeneratorPluginCallback
|
||||
lines << " Mock.#{func_name}_CallbackBool = (int)0;\n"
|
||||
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
||||
end
|
||||
|
||||
def mock_verify(function)
|
||||
func_name = function[:name]
|
||||
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" \
|
||||
" call_instance = CMOCK_GUTS_NONE;\n" \
|
||||
" (void)call_instance;\n }\n"
|
||||
end
|
||||
end
|
||||
|
||||
+46
-13
@@ -16,7 +16,8 @@ class CMockHeaderParser
|
||||
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
||||
@treat_as_array = cfg.treat_as_array
|
||||
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
||||
@declaration_parse_matcher = /([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+-]*)\)$/m
|
||||
@function_declaration_parse_base_match = '([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+-]*)\)'
|
||||
@declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m
|
||||
@standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq
|
||||
@array_size_name = cfg.array_size_name
|
||||
@array_size_type = (['int', 'size_t'] + cfg.array_size_type).uniq
|
||||
@@ -107,31 +108,63 @@ class CMockHeaderParser
|
||||
square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets
|
||||
|
||||
# Convert user provided string patterns to regex
|
||||
# Use word bounderies before and after the user regex to limit matching to actual word iso part of a word
|
||||
@inline_function_patterns.each do |user_format_string|
|
||||
user_regex = Regexp.new(user_format_string)
|
||||
cleanup_spaces_after_user_regex = /\s*/
|
||||
inline_function_regex_formats << Regexp.new(user_regex.source + cleanup_spaces_after_user_regex.source)
|
||||
word_boundary_before_user_regex = /\b/
|
||||
cleanup_spaces_after_user_regex = /[ ]*\b/
|
||||
inline_function_regex_formats << Regexp.new(word_boundary_before_user_regex.source + user_regex.source + cleanup_spaces_after_user_regex.source)
|
||||
end
|
||||
|
||||
# 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
|
||||
# smush multiline macros into single line (checking for continuation character at end of line '\')
|
||||
# If the user uses a macro to declare an inline function,
|
||||
# smushing the macros makes it easier to recognize them as a macro and if required,
|
||||
# remove them later on in this function
|
||||
source.gsub!(/\s*\\\s*/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
|
||||
# Instead, look for an inline pattern (f.e. "static inline") and parse it.
|
||||
# Below is a small explanation on how the general mechanism works:
|
||||
# - 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
|
||||
# There are ofcourse some special cases (inline macro declarations, inline function declarations, ...) which are handled and explained below
|
||||
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
|
||||
|
||||
# 1. Determine if we are dealing with a user defined macro to declare inline functions
|
||||
# If the end of the pre-match string is a macro-declaration-like string,
|
||||
# we are dealing with a user defined macro to declare inline functions
|
||||
if /(#define\s*)\z/ === inline_function_match.pre_match
|
||||
# Remove the macro from the source
|
||||
stripped_pre_match = inline_function_match.pre_match.sub(/(#define\s*)\z/,'')
|
||||
stripped_post_match = inline_function_match.post_match.sub(/\A(.*[\n]?)/,'')
|
||||
source = stripped_pre_match + stripped_post_match
|
||||
next
|
||||
end
|
||||
|
||||
# 2. Determine if we are dealing with an inline function declaration iso function definition
|
||||
# If the start of the post-match string is a function-declaration-like string (something ending with semicolon after the function arguments),
|
||||
# we are dealing with a inline function declaration
|
||||
if /\A#{@function_declaration_parse_base_match}\s*;/m === inline_function_match.post_match
|
||||
# Only remove the inline part from the function declaration, leaving the function declaration won't do any harm
|
||||
source = inline_function_match.pre_match + inline_function_match.post_match
|
||||
next
|
||||
end
|
||||
|
||||
# 3. If we get here, we found an inline function declaration AND inline function body.
|
||||
# Remove the function body to transform it into a 'normal' function.
|
||||
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?
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ namespace :test do
|
||||
#individual system tests
|
||||
FileList['system/test_interactions/*.yml'].each do |test|
|
||||
basename = File.basename(test,'.*')
|
||||
desc "Run system test #{basename}"
|
||||
#desc "Run system test #{basename}"
|
||||
task basename do
|
||||
run_system_test_interactions([test])
|
||||
end
|
||||
|
||||
@@ -66,6 +66,7 @@ class SystemTestGenerator
|
||||
|
||||
generate_test_file(yaml_hash, namix, name)
|
||||
generate_source_file(yaml_hash, namix, name)
|
||||
generate_skeleton_file(yaml_hash, namix, name)
|
||||
end
|
||||
|
||||
def generate_types_file(yaml_hash, namix)
|
||||
@@ -136,11 +137,22 @@ class SystemTestGenerator
|
||||
includes << (namix + MOCKABLE_H) if not yaml_hash[:systest][:mockable].nil?
|
||||
includes << header_file
|
||||
|
||||
write_source_file(GENERATED_PATH + name + C_EXTENSION, includes.flatten) do |out|
|
||||
out.puts(source[:code])
|
||||
unless (source[:code].nil?)
|
||||
write_source_file(GENERATED_PATH + name + C_EXTENSION, includes.flatten) do |out|
|
||||
out.puts(source[:code])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_skeleton_file(yaml_hash, namix, name)
|
||||
source = yaml_hash[:systest][:skeleton]
|
||||
return if source.nil?
|
||||
|
||||
require 'cmock.rb'
|
||||
cmock = CMock.new(GENERATED_PATH + namix + 'cmock' + YAML_EXTENSION)
|
||||
cmock.setup_skeletons("#{$cfg['compiler']['source_path']}#{name}.h")
|
||||
end
|
||||
|
||||
def write_header_file(filename, upcase_name, include_list=[])
|
||||
File.open(filename, 'w') do |out|
|
||||
out.puts("#ifndef _#{upcase_name}")
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
:cmock:
|
||||
:plugins:
|
||||
- # none
|
||||
:skeleton_path: system/generated
|
||||
|
||||
:systest:
|
||||
:types: |
|
||||
#define UINT32 unsigned int
|
||||
|
||||
:mockable: |
|
||||
UINT32 something(int a);
|
||||
|
||||
:skeleton: skeleton.h
|
||||
|
||||
:source:
|
||||
:header: |
|
||||
void function_a(void);
|
||||
int function_b(int a, int b);
|
||||
const char* function_c(void);
|
||||
|
||||
# we are purposefully not including a :code section because it will be generated with skeleton
|
||||
|
||||
:tests:
|
||||
:common: |
|
||||
void setUp(void) {}
|
||||
void tearDown(void) {}
|
||||
|
||||
:units:
|
||||
- :pass: TRUE
|
||||
:should: 'generate an empty shell for functions with no return values'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
function_a();
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: 'return numerical zero for numerical return values'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, function_b(1, 2));
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: 'return null for pointer return values'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
TEST_ASSERT_NULL(function_c());
|
||||
}
|
||||
|
||||
|
||||
...
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
:cmock:
|
||||
:plugins:
|
||||
- # none
|
||||
:skeleton_path: system/generated
|
||||
|
||||
:systest:
|
||||
:types: |
|
||||
#define UINT32 unsigned int
|
||||
|
||||
:mockable: |
|
||||
UINT32 something(int a);
|
||||
|
||||
:skeleton: skeleton_update.h
|
||||
|
||||
:source:
|
||||
:header: |
|
||||
void function_a(void);
|
||||
int function_b(int a, int b);
|
||||
const char* function_c(void);
|
||||
|
||||
# note that this code section exists and will be updated by the skeleton generator
|
||||
:code: |
|
||||
const char* donuts = "donuts";
|
||||
const char* function_c(void)
|
||||
{
|
||||
return donuts;
|
||||
}
|
||||
|
||||
int function_d(void)
|
||||
{
|
||||
return 77;
|
||||
}
|
||||
|
||||
|
||||
:tests:
|
||||
:common: |
|
||||
void setUp(void) {}
|
||||
void tearDown(void) {}
|
||||
extern int function_d();
|
||||
|
||||
:units:
|
||||
- :pass: TRUE
|
||||
:should: 'generate an empty shell for functions with no return values'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
function_a();
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: 'return numerical zero for numerical return values'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(0, function_b(1, 2));
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: 'not overwrite functions that already exist'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_STRING("donuts", function_c());
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: 'leave functions it has never heard of'
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(77, function_d());
|
||||
}
|
||||
|
||||
|
||||
...
|
||||
@@ -2083,4 +2083,116 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "Transform inline functions can handle inline function declarations" do
|
||||
source =
|
||||
"static inline int dummy_func_decl(int a, char b, float c);\n" + # First declaration
|
||||
"static inline int dummy_func_decl2(int a, char b, float c)\n\n\n\n\n\n;\n" + # Second declaration with a lot of newlines before the semicolon to mess with the parser
|
||||
"static inline int staticinlinefunc(struct my_struct *s)\n" + # 'normal' inline pattern
|
||||
"{\n" +
|
||||
" return dummy_func_decl(1, 1, 1);\n" +
|
||||
"}\n" +
|
||||
"struct my_struct_with_inline_in_it\n" # struct definition in between to mess with the parser
|
||||
"{\n" +
|
||||
" int a;\n" +
|
||||
" char b;\n" +
|
||||
" float inlineb;\n" +
|
||||
"};\n" +
|
||||
"static inline int dummy_func_decl(int a, char b, float c) {\n" + # Second user pattern
|
||||
" return 42;\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
expected =
|
||||
"int dummy_func_decl(int a, char b, float c);\n" +
|
||||
"int dummy_func_decl2(int a, char b, float c)\n\n\n\n\n\n;\n" + # Second declaration with a lot of newlines until the semicolon to mess with the parser
|
||||
"int staticinlinefunc(struct my_struct *s);\n" +
|
||||
"struct my_struct_with_inline_in_it\n"
|
||||
"{\n" +
|
||||
" int a;\n" +
|
||||
" char b;\n" +
|
||||
" float inlineb;\n" +
|
||||
"};\n" +
|
||||
"int dummy_func_decl(int a, char b, float c);\n" +
|
||||
"\n"
|
||||
|
||||
@parser.treat_inlines = :include
|
||||
assert_equal(expected, @parser.transform_inline_functions(source))
|
||||
end
|
||||
|
||||
it "Transform inline functions can handle header with only inline function declarations" do
|
||||
source =
|
||||
"static inline int dummy_func_decl(int a, char b, float c);\n" +
|
||||
"\n"
|
||||
|
||||
expected =
|
||||
"int dummy_func_decl(int a, char b, float c);\n" +
|
||||
"\n"
|
||||
|
||||
@parser.treat_inlines = :include
|
||||
assert_equal(expected, @parser.transform_inline_functions(source))
|
||||
end
|
||||
|
||||
it "Transform inline functions takes user provided patterns into account" do
|
||||
source =
|
||||
"static __inline__ __attribute__ ((always_inline)) uint16_t _somefunc (uint32_t a)\n" +
|
||||
"{\n" +
|
||||
" return _someotherfunc (a);\n" +
|
||||
"}\n" +
|
||||
"static __inline__ uint16_t _somefunc_0 (uint32_t a)\n" +
|
||||
"{\n" +
|
||||
" return (uint16_t) a;\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
expected =
|
||||
"uint16_t _somefunc (uint32_t a);\n" +
|
||||
"uint16_t _somefunc_0 (uint32_t a);\n" +
|
||||
"\n"
|
||||
|
||||
@parser.treat_inlines = :include
|
||||
@parser.inline_function_patterns = ['static __inline__ __attribute__ \(\(always_inline\)\)', 'static __inline__']
|
||||
assert_equal(expected, @parser.transform_inline_functions(source))
|
||||
end
|
||||
|
||||
it "Transform inline functions limits deleting user macro to actual line/word" do
|
||||
source =
|
||||
"#if defined (FORCE_INLINE)\n" +
|
||||
"#define MY_LIBRARY_INLINE static __inline__ __attribute__ ((always_inline))\n" +
|
||||
"#else\n" +
|
||||
"#define MY_LIBRARY_INLINE\n" +
|
||||
"#endif\n" +
|
||||
"#define INLINE static __inline__ __attribute__ ((always_inline))\n" +
|
||||
"#define INLINE_TWO \\\nstatic\\\ninline\n" +
|
||||
"INLINE uint16_t _somefunc (uint32_t a)\n" +
|
||||
"{\n" +
|
||||
" return _someotherfunc (a);\n" +
|
||||
"}\n" +
|
||||
"static __inline__ uint16_t _somefunc_0 (uint32_t a)\n" +
|
||||
"{\n" +
|
||||
" return (uint16_t) a;\n" +
|
||||
"}\n" +
|
||||
"static __inline__ __attribute__ \(\(always_inline\)\) uint16_t _somefunc_1 (uint32_t a)\n" +
|
||||
"{\n" +
|
||||
" return (uint16_t) a;\n" +
|
||||
"}\n" +
|
||||
"INLINE_TWO uint16_t _somefunc_2(uint32_t a)\n" +
|
||||
"{\n" +
|
||||
" return (uint16_t) a;\n" +
|
||||
"}\n" +
|
||||
"#define INLINE_THREE \\\nstatic\\\ninline"
|
||||
|
||||
expected =
|
||||
"#if defined (FORCE_INLINE)\n" +
|
||||
"#else\n" +
|
||||
"#endif\n" +
|
||||
"uint16_t _somefunc (uint32_t a);\n" +
|
||||
"uint16_t _somefunc_0 (uint32_t a);\n" +
|
||||
"uint16_t _somefunc_1 (uint32_t a);\n" +
|
||||
"uint16_t _somefunc_2(uint32_t a);\n"
|
||||
|
||||
@parser.treat_inlines = :include
|
||||
@parser.inline_function_patterns = ['MY_LIBRARY_INLINE', 'INLINE_THREE', 'INLINE_TWO', 'INLINE', 'static __inline__ __attribute__ \(\(always_inline\)\)', 'static __inline__']
|
||||
assert_equal(expected, @parser.transform_inline_functions(source))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Vendored
+1
-1
Submodule vendor/unity updated: e3132cdddd...5e9acef74f
Reference in New Issue
Block a user