ceedling 0.29.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|