ceedling 0.29.0 → 0.29.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/assets/project_as_gem.yml +2 -5
- data/assets/project_with_guts.yml +2 -5
- data/assets/project_with_guts_gcov.yml +2 -5
- data/bin/ceedling +14 -12
- data/ceedling.sublime-project +26 -23
- data/docs/CeedlingPacket.md +17 -2
- data/docs/CeedlingUpgrade.md +83 -0
- data/lib/ceedling/build_invoker_utils.rb +1 -1
- data/lib/ceedling/cacheinator_helper.rb +2 -2
- data/lib/ceedling/dependinator.rb +2 -2
- data/lib/ceedling/generator_test_results.rb +13 -2
- data/lib/ceedling/tasks_base.rake +17 -23
- data/lib/ceedling/tasks_filesystem.rake +12 -3
- data/lib/ceedling/tasks_tests.rake +1 -1
- data/lib/ceedling/test_invoker.rb +1 -1
- data/lib/ceedling/version.rb +28 -14
- data/plugins/gcov/gcov.rake +3 -3
- data/plugins/junit_tests_report/lib/junit_tests_report.rb +4 -3
- data/spec/spec_system_helper.rb +42 -2
- data/spec/support/test_example.fail +2 -0
- data/spec/support/test_example.pass +2 -0
- data/spec/support/test_example_ignore.pass +2 -0
- data/spec/support/test_example_mangled.pass +1 -0
- data/spec/support/test_example_with_time.pass +2 -0
- data/spec/system/deployment_spec.rb +6 -0
- data/vendor/cmock/docs/CMock_Summary.md +8 -1
- data/vendor/cmock/lib/cmock_config.rb +11 -1
- data/vendor/cmock/lib/cmock_generator.rb +7 -0
- data/vendor/cmock/lib/cmock_generator_plugin_callback.rb +2 -2
- data/vendor/cmock/lib/cmock_header_parser.rb +123 -13
- data/vendor/cmock/src/cmock.h +1 -1
- data/vendor/cmock/test/system/test_compilation/config.yml +1 -0
- data/vendor/cmock/test/system/test_compilation/inline.h +23 -0
- data/vendor/cmock/test/system/test_interactions/all_plugins_coexist.yml +1 -0
- data/vendor/cmock/test/unit/cmock_config_test.rb +3 -0
- data/vendor/cmock/test/unit/cmock_config_test.yml +2 -1
- data/vendor/cmock/test/unit/cmock_generator_main_test.rb +3 -0
- data/vendor/cmock/test/unit/cmock_generator_plugin_callback_test.rb +4 -4
- data/vendor/cmock/test/unit/cmock_header_parser_test.rb +272 -0
- metadata +4 -3
- data/out.fail +0 -22
@@ -129,7 +129,7 @@ class TestInvoker
|
|
129
129
|
@dependinator.enhance_test_build_object_dependencies( objects )
|
130
130
|
|
131
131
|
# associate object files with executable
|
132
|
-
@dependinator.
|
132
|
+
@dependinator.enhance_test_executable_dependencies( test, objects )
|
133
133
|
|
134
134
|
# build test objects
|
135
135
|
@task_invoker.invoke_test_objects( objects )
|
data/lib/ceedling/version.rb
CHANGED
@@ -2,35 +2,49 @@
|
|
2
2
|
# @private
|
3
3
|
module Ceedling
|
4
4
|
module Version
|
5
|
-
|
6
|
-
|
7
|
-
"CEXCEPTION" => File.join("
|
8
|
-
"CMOCK" => File.join("vendor","cmock","src","cmock.h"),
|
9
|
-
"UNITY" => File.join("vendor","unity","src","unity.h"),
|
5
|
+
{ "UNITY" => File.join("unity","src","unity.h"),
|
6
|
+
"CMOCK" => File.join("cmock","src","cmock.h"),
|
7
|
+
"CEXCEPTION" => File.join("c_exception","lib","CException.h")
|
10
8
|
}.each_pair do |name, path|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
# Check for local or global version of vendor directory in order to look up versions
|
10
|
+
path1 = File.expand_path( File.join("..","..","vendor",path) )
|
11
|
+
path2 = File.expand_path( File.join(File.dirname(__FILE__),"..","..","vendor",path) )
|
12
|
+
filename = if (File.exists?(path1))
|
13
|
+
path1
|
14
|
+
elsif (File.exists?(path2))
|
15
|
+
path2
|
16
|
+
elsif exists?(CEEDLING_VENDOR)
|
17
|
+
path3 = File.expand_path( File.join(CEEDLING_VENDOR,path) )
|
18
|
+
if (File.exists?(path3))
|
19
|
+
path3
|
20
|
+
else
|
21
|
+
basepath = File.join( CEEDLING_VENDOR, path.split(/\\\//)[0], 'release')
|
22
|
+
begin
|
23
|
+
[ @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'version.info') ).strip,
|
24
|
+
@ceedling[:file_wrapper].read( File.join(base_path, 'release', 'build.info') ).strip ].join('.')
|
25
|
+
rescue
|
26
|
+
"unknown"
|
27
|
+
end
|
28
|
+
end
|
15
29
|
else
|
16
|
-
|
30
|
+
module_eval("#{name} = 'unknown'")
|
17
31
|
continue
|
18
32
|
end
|
19
33
|
|
20
34
|
# Actually look up the versions
|
21
35
|
a = [0,0,0]
|
22
|
-
File.readlines(filename) do |line|
|
36
|
+
File.readlines(filename).each do |line|
|
23
37
|
["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i|
|
24
38
|
m = line.match(/#{name}_#{field}\s+(\d+)/)
|
25
39
|
a[i] = m[1] unless (m.nil?)
|
26
40
|
end
|
27
41
|
end
|
28
42
|
|
29
|
-
#
|
30
|
-
eval
|
43
|
+
# splat it to return the final value
|
44
|
+
eval("#{name} = '#{a.join(".")}'")
|
31
45
|
end
|
32
46
|
|
33
|
-
GEM = "0.29.
|
47
|
+
GEM = "0.29.1"
|
34
48
|
CEEDLING = GEM
|
35
49
|
end
|
36
50
|
end
|
data/plugins/gcov/gcov.rake
CHANGED
@@ -156,7 +156,7 @@ end
|
|
156
156
|
namespace UTILS_SYM do
|
157
157
|
def gcov_args_builder(opts)
|
158
158
|
args = ""
|
159
|
-
args += "-r \"#{opts[:gcov_report_root] || '.'}\" "
|
159
|
+
args += "-r \"#{opts[:gcov_report_root] || '.'}\" "
|
160
160
|
args += "-f \"#{opts[:gcov_report_include]}\" " unless opts[:gcov_report_include].nil?
|
161
161
|
args += "-e \"#{opts[:gcov_report_exclude] || GCOV_FILTER_EXCLUDE}\" "
|
162
162
|
[ :gcov_fail_under_line, :gcov_fail_under_branch, :gcov_html_medium_threshold, :gcov_html_high_threshold].each do |opt|
|
@@ -165,7 +165,7 @@ namespace UTILS_SYM do
|
|
165
165
|
return args
|
166
166
|
end
|
167
167
|
|
168
|
-
desc 'Create gcov code coverage html report (must run ceedling gcov first)'
|
168
|
+
desc 'Create gcov code coverage html/xml report (must run ceedling gcov first).'
|
169
169
|
task GCOV_SYM do
|
170
170
|
|
171
171
|
if !File.directory? GCOV_ARTIFACTS_PATH
|
@@ -211,7 +211,7 @@ namespace UTILS_SYM do
|
|
211
211
|
|
212
212
|
if xml_enabled
|
213
213
|
puts "Creating an xml report of gcov results in #{GCOV_ARTIFACTS_FILE_XML}..."
|
214
|
-
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_XML, [],
|
214
|
+
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_XML, [], args)
|
215
215
|
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
216
216
|
end
|
217
217
|
|
@@ -109,11 +109,12 @@ class JunitTestsReport < Plugin
|
|
109
109
|
|
110
110
|
def write_test( test, stream )
|
111
111
|
test[:test].gsub!('"', '"')
|
112
|
+
pp test
|
112
113
|
case test[:result]
|
113
114
|
when :success
|
114
|
-
stream.puts(' <testcase name="%<test>s" />' % test)
|
115
|
+
stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>f"/>' % test)
|
115
116
|
when :failed
|
116
|
-
stream.puts(' <testcase name="%<test>s">' % test)
|
117
|
+
stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>f">' % test)
|
117
118
|
if test[:message].empty?
|
118
119
|
stream.puts(' <failure />')
|
119
120
|
else
|
@@ -121,7 +122,7 @@ class JunitTestsReport < Plugin
|
|
121
122
|
end
|
122
123
|
stream.puts(' </testcase>')
|
123
124
|
when :ignored
|
124
|
-
stream.puts(' <testcase name="%<test>s">' % test)
|
125
|
+
stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>f">' % test)
|
125
126
|
stream.puts(' <skipped />')
|
126
127
|
stream.puts(' </testcase>')
|
127
128
|
end
|
data/spec/spec_system_helper.rb
CHANGED
@@ -38,6 +38,24 @@ def _add_path_in_section(project_file_path, path, section)
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
def _add_define_in_section(project_file_path, define, section)
|
42
|
+
project_file_contents = File.readlines(project_file_path)
|
43
|
+
defines_index = project_file_contents.index(":defines:\n")
|
44
|
+
|
45
|
+
if defines_index.nil?
|
46
|
+
# Something wrong with project.yml file, no defines?
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
section_index = defines_index + project_file_contents[defines_index..-1].index(" :#{section}:\n")
|
51
|
+
|
52
|
+
project_file_contents.insert(section_index + 1, " - #{define}\n")
|
53
|
+
|
54
|
+
File.open(project_file_path, "w+") do |f|
|
55
|
+
f.puts(project_file_contents)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
41
59
|
def add_source_path(path)
|
42
60
|
_add_path_in_section("project.yml", path, "source")
|
43
61
|
end
|
@@ -46,6 +64,10 @@ def add_test_path(path)
|
|
46
64
|
_add_path_in_section("project.yml", path, "test")
|
47
65
|
end
|
48
66
|
|
67
|
+
def add_test_define(define)
|
68
|
+
_add_define_in_section("project.yml", define, "test")
|
69
|
+
end
|
70
|
+
|
49
71
|
def add_module_generator_section(project_file_path, mod_gen)
|
50
72
|
project_file_contents = File.readlines(project_file_path)
|
51
73
|
module_gen_index = project_file_contents.index(":module_generator:\n")
|
@@ -198,7 +220,7 @@ module CeedlingTestCases
|
|
198
220
|
|
199
221
|
def can_upgrade_projects
|
200
222
|
@c.with_context do
|
201
|
-
output = `bundle exec ruby -S ceedling upgrade
|
223
|
+
output = `bundle exec ruby -S ceedling upgrade #{@proj_name} 2>&1`
|
202
224
|
expect($?.exitstatus).to match(0)
|
203
225
|
expect(output).to match(/upgraded!/i)
|
204
226
|
Dir.chdir @proj_name do
|
@@ -206,7 +228,6 @@ module CeedlingTestCases
|
|
206
228
|
expect(File.exists?("src")).to eq true
|
207
229
|
expect(File.exists?("test")).to eq true
|
208
230
|
all_docs = Dir["vendor/ceedling/docs/*.pdf"].length + Dir["vendor/ceedling/docs/*.md"].length
|
209
|
-
expect(all_docs).to be >= 4
|
210
231
|
end
|
211
232
|
end
|
212
233
|
end
|
@@ -296,6 +317,24 @@ module CeedlingTestCases
|
|
296
317
|
end
|
297
318
|
end
|
298
319
|
|
320
|
+
def can_test_projects_with_unity_exec_time
|
321
|
+
@c.with_context do
|
322
|
+
Dir.chdir @proj_name do
|
323
|
+
FileUtils.cp test_asset_path("example_file.h"), 'src/'
|
324
|
+
FileUtils.cp test_asset_path("example_file.c"), 'src/'
|
325
|
+
FileUtils.cp test_asset_path("test_example_file_success.c"), 'test/'
|
326
|
+
add_test_define("UNITY_INCLUDE_EXEC_TIME")
|
327
|
+
|
328
|
+
output = `bundle exec ruby -S ceedling 2>&1`
|
329
|
+
expect($?.exitstatus).to match(0) # Since a test either pass or are ignored, we return success here
|
330
|
+
expect(output).to match(/TESTED:\s+\d/)
|
331
|
+
expect(output).to match(/PASSED:\s+\d/)
|
332
|
+
expect(output).to match(/FAILED:\s+\d/)
|
333
|
+
expect(output).to match(/IGNORED:\s+\d/)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
299
338
|
def can_test_projects_with_fail
|
300
339
|
@c.with_context do
|
301
340
|
Dir.chdir @proj_name do
|
@@ -312,6 +351,7 @@ module CeedlingTestCases
|
|
312
351
|
end
|
313
352
|
end
|
314
353
|
end
|
354
|
+
|
315
355
|
def can_test_projects_with_fail_alias
|
316
356
|
@c.with_context do
|
317
357
|
Dir.chdir @proj_name do
|
@@ -30,6 +30,7 @@ describe "Ceedling" do
|
|
30
30
|
it { can_test_projects_with_success }
|
31
31
|
it { can_test_projects_with_success_test_alias }
|
32
32
|
it { can_test_projects_with_success_default }
|
33
|
+
it { can_test_projects_with_unity_exec_time }
|
33
34
|
it { can_test_projects_with_fail }
|
34
35
|
it { can_test_projects_with_fail_alias }
|
35
36
|
it { can_test_projects_with_fail_default }
|
@@ -76,6 +77,7 @@ describe "Ceedling" do
|
|
76
77
|
it { can_test_projects_with_success }
|
77
78
|
it { can_test_projects_with_success_test_alias }
|
78
79
|
it { can_test_projects_with_success_default }
|
80
|
+
it { can_test_projects_with_unity_exec_time }
|
79
81
|
it { can_test_projects_with_fail }
|
80
82
|
it { can_test_projects_with_fail_alias }
|
81
83
|
it { can_test_projects_with_fail_default }
|
@@ -103,6 +105,7 @@ describe "Ceedling" do
|
|
103
105
|
it { can_test_projects_with_success }
|
104
106
|
it { can_test_projects_with_success_test_alias }
|
105
107
|
it { can_test_projects_with_success_default }
|
108
|
+
it { can_test_projects_with_unity_exec_time }
|
106
109
|
it { can_test_projects_with_fail }
|
107
110
|
it { can_test_projects_with_fail_alias }
|
108
111
|
it { can_test_projects_with_fail_default }
|
@@ -117,11 +120,13 @@ describe "Ceedling" do
|
|
117
120
|
|
118
121
|
it { can_upgrade_projects }
|
119
122
|
it { contains_a_vendor_directory }
|
123
|
+
it { does_not_contain_documentation }
|
120
124
|
it { can_fetch_non_project_help }
|
121
125
|
it { can_fetch_project_help }
|
122
126
|
it { can_test_projects_with_success }
|
123
127
|
it { can_test_projects_with_success_test_alias }
|
124
128
|
it { can_test_projects_with_success_default }
|
129
|
+
it { can_test_projects_with_unity_exec_time }
|
125
130
|
it { can_test_projects_with_fail }
|
126
131
|
it { can_test_projects_with_fail_alias }
|
127
132
|
it { can_test_projects_with_fail_default }
|
@@ -149,6 +154,7 @@ describe "Ceedling" do
|
|
149
154
|
it { can_test_projects_with_success }
|
150
155
|
it { can_test_projects_with_success_test_alias }
|
151
156
|
it { can_test_projects_with_success_default }
|
157
|
+
it { can_test_projects_with_unity_exec_time }
|
152
158
|
it { can_test_projects_with_fail }
|
153
159
|
it { can_test_projects_with_compile_error }
|
154
160
|
it { can_use_the_module_plugin }
|
@@ -518,6 +518,14 @@ from the defaults. We've tried to specify what the defaults are below.
|
|
518
518
|
* `:include` will mock externed functions
|
519
519
|
* `:exclude` will ignore externed functions (default).
|
520
520
|
|
521
|
+
* `:treat_inlines`:
|
522
|
+
This specifies how you want CMock to handle functions that have been
|
523
|
+
marked as inline in the header file. Should it mock them?
|
524
|
+
|
525
|
+
* `:include` will mock inlined functions
|
526
|
+
* `:exclude` will ignore inlined functions (default).
|
527
|
+
|
528
|
+
|
521
529
|
* `:unity_helper_path`:
|
522
530
|
If you have created a header with your own extensions to unity to
|
523
531
|
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
|
|
686
694
|
using [Ceedling](https://throwtheswitch.org/ceedling). Please note that
|
687
695
|
these examples are meant to show how the build process works. They have
|
688
696
|
failing tests ON PURPOSE to show what that would look like. Don't be alarmed. ;)
|
689
|
-
|
@@ -29,6 +29,7 @@ class CMockConfig
|
|
29
29
|
:when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart
|
30
30
|
:verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
|
31
31
|
:treat_externs => :exclude, #the options being :include or :exclude
|
32
|
+
:treat_inlines => :exclude, #the options being :include or :exclude
|
32
33
|
:callback_include_count => true,
|
33
34
|
:callback_after_arg_check => false,
|
34
35
|
:includes => nil,
|
@@ -64,7 +65,16 @@ class CMockConfig
|
|
64
65
|
end
|
65
66
|
options[:unity_helper_path] ||= options[:unity_helper]
|
66
67
|
options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String
|
67
|
-
|
68
|
+
|
69
|
+
if options[:unity_helper_path]
|
70
|
+
require 'pathname'
|
71
|
+
includes1 = options[:includes_c_post_header] || []
|
72
|
+
includes2 = options[:unity_helper_path].map do |path|
|
73
|
+
Pathname(path).relative_path_from(Pathname(options[:mock_path])).to_s
|
74
|
+
end
|
75
|
+
options[:includes_c_post_header] = (includes1 + includes2).uniq
|
76
|
+
end
|
77
|
+
|
68
78
|
options[:plugins].compact!
|
69
79
|
options[:plugins].map! {|p| p.to_sym}
|
70
80
|
@options = options
|
@@ -16,6 +16,7 @@ class CMockGenerator
|
|
16
16
|
@prefix = @config.mock_prefix
|
17
17
|
@suffix = @config.mock_suffix
|
18
18
|
@weak = @config.weak
|
19
|
+
@include_inline = @config.treat_inlines
|
19
20
|
@ordered = @config.enforce_strict_ordering
|
20
21
|
@framework = @config.framework.to_s
|
21
22
|
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
|
@@ -61,6 +62,12 @@ class CMockGenerator
|
|
61
62
|
end
|
62
63
|
|
63
64
|
def create_mock_header_file(parsed_stuff)
|
65
|
+
if @include_inline == :include
|
66
|
+
@file_writer.create_file(@module_name + ".h", @subdir) do |file, filename|
|
67
|
+
file << parsed_stuff[:normalized_source]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
64
71
|
@file_writer.create_file(@mock_name + ".h", @subdir) do |file, filename|
|
65
72
|
create_mock_header_header(file, filename)
|
66
73
|
create_mock_header_service_call_declarations(file)
|
@@ -60,9 +60,9 @@ class CMockGeneratorPluginCallback
|
|
60
60
|
" UNITY_CLR_DETAILS();\n" \
|
61
61
|
" return;\n }\n"
|
62
62
|
else
|
63
|
-
" #{function[:return][:type]}
|
63
|
+
" #{function[:return][:type]} cmock_cb_ret = #{generate_call(function)};\n" \
|
64
64
|
" UNITY_CLR_DETAILS();\n" \
|
65
|
-
" return
|
65
|
+
" return cmock_cb_ret;\n }\n"
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
class CMockHeaderParser
|
8
8
|
|
9
|
-
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs
|
9
|
+
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs, :treat_inlines
|
10
10
|
|
11
11
|
def initialize(cfg)
|
12
12
|
@funcs = []
|
@@ -24,13 +24,16 @@ class CMockHeaderParser
|
|
24
24
|
@local_as_void = @treat_as_void
|
25
25
|
@verbosity = cfg.verbosity
|
26
26
|
@treat_externs = cfg.treat_externs
|
27
|
+
@treat_inlines = cfg.treat_inlines
|
27
28
|
@c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs
|
29
|
+
@c_strippables += ['inline'] if (@treat_inlines == :include) #we'll need to remove the attribute if we're allowing inlines
|
28
30
|
end
|
29
31
|
|
30
32
|
def parse(name, source)
|
31
33
|
@module_name = name.gsub(/\W/,'')
|
32
34
|
@typedefs = []
|
33
35
|
@funcs = []
|
36
|
+
@normalized_source = nil
|
34
37
|
function_names = []
|
35
38
|
|
36
39
|
parse_functions( import_source(source) ).map do |decl|
|
@@ -41,14 +44,113 @@ class CMockHeaderParser
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
47
|
+
@normalized_source = if (@treat_inlines == :include)
|
48
|
+
transform_inline_functions(source)
|
49
|
+
else
|
50
|
+
''
|
51
|
+
end
|
52
|
+
|
44
53
|
{ :includes => nil,
|
45
54
|
:functions => @funcs,
|
46
|
-
:typedefs => @typedefs
|
55
|
+
:typedefs => @typedefs,
|
56
|
+
:normalized_source => @normalized_source
|
47
57
|
}
|
48
58
|
end
|
49
59
|
|
50
60
|
private if $ThisIsOnlyATest.nil? ################
|
51
61
|
|
62
|
+
def remove_nested_pairs_of_braces(source)
|
63
|
+
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
|
64
|
+
if (RUBY_VERSION.split('.')[0].to_i > 1)
|
65
|
+
#we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
|
66
|
+
r = "\\{([^\\{\\}]*|\\g<0>)*\\}"
|
67
|
+
source.gsub!(/#{r}/m, '{ }')
|
68
|
+
else
|
69
|
+
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
return source
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return the number of pairs of braces/square brackets in the function provided by the user
|
77
|
+
# +source+:: String containing the function to be processed
|
78
|
+
def count_number_of_pairs_of_braces_in_function(source)
|
79
|
+
is_function_start_found = false
|
80
|
+
curr_level = 0
|
81
|
+
total_pairs = 0
|
82
|
+
|
83
|
+
source.each_char do |c|
|
84
|
+
if ("{" == c)
|
85
|
+
curr_level += 1
|
86
|
+
total_pairs +=1
|
87
|
+
is_function_start_found = true
|
88
|
+
elsif ("}" == c)
|
89
|
+
curr_level -=1
|
90
|
+
end
|
91
|
+
|
92
|
+
break if is_function_start_found && curr_level == 0 # We reached the end of the inline function body
|
93
|
+
end
|
94
|
+
|
95
|
+
if 0 != curr_level
|
96
|
+
total_pairs = 0 # Something is fishy about this source, not enough closing braces?
|
97
|
+
end
|
98
|
+
|
99
|
+
return total_pairs
|
100
|
+
end
|
101
|
+
|
102
|
+
# Transform inline functions to regular functions in the source by the user
|
103
|
+
# +source+:: String containing the source to be processed
|
104
|
+
def transform_inline_functions(source)
|
105
|
+
# Format to look for inline functions.
|
106
|
+
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
|
107
|
+
# There are several possibilities:
|
108
|
+
# - sometimes they appear together, sometimes individually,
|
109
|
+
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
|
110
|
+
# so we check for word boundaries when searching for them
|
111
|
+
# - We first remove "static inline" combinations and boil down to single inline or static statements
|
112
|
+
inline_function_regex_formats = [
|
113
|
+
/(static\s+inline|inline\s+static)\s*/, # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
114
|
+
/(\bstatic\b|\binline\b)\s*/, # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
115
|
+
]
|
116
|
+
square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets
|
117
|
+
|
118
|
+
# let's clean up the encoding in case they've done anything weird with the characters we might find
|
119
|
+
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil)
|
120
|
+
|
121
|
+
# - 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
|
122
|
+
# Instead, look for "static inline" and parse it:
|
123
|
+
# - Everything before the match should just be copied, we don't want
|
124
|
+
# to touch anything but the inline functions.
|
125
|
+
# - Remove the implementation of the inline function (this is enclosed
|
126
|
+
# in square brackets) and replace it with ";" to complete the
|
127
|
+
# transformation to normal/non-inline function.
|
128
|
+
# To ensure proper removal of the function body, we count the number of square-bracket pairs
|
129
|
+
# and remove the pairs one-by-one.
|
130
|
+
# - Copy everything after the inline function implementation and start the parsing of the next inline function
|
131
|
+
|
132
|
+
inline_function_regex_formats.each do |format|
|
133
|
+
loop do
|
134
|
+
inline_function_match = source.match(/#{format}/) # Search for inline function declaration
|
135
|
+
break if nil == inline_function_match # No inline functions so nothing to do
|
136
|
+
|
137
|
+
total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match)
|
138
|
+
|
139
|
+
break if 0 == total_pairs_to_remove # Bad source?
|
140
|
+
|
141
|
+
inline_function_stripped = inline_function_match.post_match
|
142
|
+
|
143
|
+
total_pairs_to_remove.times do
|
144
|
+
inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ";") # Remove inline implementation (+ some whitespace because it's prettier)
|
145
|
+
end
|
146
|
+
|
147
|
+
source = inline_function_match.pre_match + inline_function_stripped # Make new source with the inline function removed and move on to the next
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
return source
|
152
|
+
end
|
153
|
+
|
52
154
|
def import_source(source)
|
53
155
|
|
54
156
|
# 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
|
|
100
202
|
"#{functype} #{$2.strip}(#{$3});"
|
101
203
|
end
|
102
204
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
|
110
|
-
end
|
205
|
+
source = remove_nested_pairs_of_braces(source)
|
206
|
+
|
207
|
+
if (@treat_inlines == :include)
|
208
|
+
# Functions having "{ }" at this point are/were inline functions,
|
209
|
+
# User wants them in so 'disguise' them as normal functions with the ";"
|
210
|
+
source.gsub!("{ }", ";")
|
111
211
|
end
|
112
212
|
|
213
|
+
|
113
214
|
# remove function definitions by stripping off the arguments right now
|
114
215
|
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ";")
|
115
216
|
|
@@ -124,11 +225,20 @@ class CMockHeaderParser
|
|
124
225
|
src_lines = source.split(/\s*;\s*/).uniq
|
125
226
|
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
|
126
227
|
src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays
|
127
|
-
|
128
|
-
|
228
|
+
|
229
|
+
unless (@treat_externs == :include)
|
230
|
+
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern)\s+/).nil?} # remove extern functions
|
231
|
+
end
|
232
|
+
|
233
|
+
if (@treat_inlines == :include)
|
234
|
+
src_lines.each {
|
235
|
+
|src_line|
|
236
|
+
src_line.gsub!(/^inline/, "") # Remove "inline" so that they are 'normal' functions
|
237
|
+
}
|
129
238
|
else
|
130
|
-
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:
|
239
|
+
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
|
131
240
|
end
|
241
|
+
|
132
242
|
src_lines.delete_if {|line| line.empty? } #drop empty lines
|
133
243
|
end
|
134
244
|
|