ceedling 1.1.5 → 1.1.6
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/GIT_COMMIT_SHA +1 -1
- data/assets/tests_with_conditional_includes/src/feature_config.h +13 -0
- data/assets/tests_with_conditional_includes/src/feature_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/local_flag_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/nested_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/nested_wrapper.h +16 -0
- data/assets/tests_with_conditional_includes/src/project_flag_extra.h +13 -0
- data/assets/tests_with_conditional_includes/src/widget.c +48 -0
- data/assets/tests_with_conditional_includes/src/widget.h +15 -0
- data/assets/tests_with_conditional_includes/src/widget_feature.c +29 -0
- data/assets/tests_with_conditional_includes/src/widget_feature.h +13 -0
- data/assets/tests_with_conditional_includes/test/test_widget.c +44 -0
- data/assets/tests_with_conditional_includes/test/test_widget_feature.c +31 -0
- data/docs/Changelog.md +20 -1
- data/examples/wondrous_forest/src/SensorHal.h +13 -0
- data/examples/wondrous_forest/src/TemperatureSensor.c +12 -5
- data/examples/wondrous_forest/src/TemperatureSensor.h +5 -4
- data/examples/wondrous_forest/test/TestTemperatureSensor.c +32 -3
- data/lib/ceedling/generators/generator_test_runner.rb +25 -1
- data/lib/ceedling/partials/partializer.rb +8 -1
- data/lib/ceedling/preprocess/preprocessinator.rb +22 -0
- data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +33 -0
- data/lib/version.rb +1 -1
- data/site-local/sitemap.xml.gz +0 -0
- data/spec/support/system/spec_system_helper.rb +11 -0
- data/spec/support/system/system_context.rb +18 -9
- data/spec/system/conditional_include_macro_visibility_spec.rb +152 -0
- data/spec/system/encoding_stress_spec.rb +4 -4
- data/spec/system/example_wondrous_forest_spec.rb +2 -2
- data/spec/system/support/common_test_cases.rb +5 -1
- data/spec/system/test_runner_system_include_spec.rb +90 -0
- data/spec/units/generators/generator_test_runner_spec.rb +69 -0
- data/spec/units/partials/partializer_spec.rb +69 -0
- data/spec/units/preprocess/preprocessinator_includes_handler_spec.rb +61 -0
- data/spec/units/preprocess/preprocessinator_spec.rb +136 -0
- data/vendor/c_exception/lib/CException.h +1 -1
- data/vendor/c_exception/project.yml +2 -2
- data/vendor/c_exception/test/TestException.c +1 -1
- data/vendor/c_exception/test/support/CExceptionConfig.h +5 -11
- data/vendor/cmock/docs/CMockChangeLog.md +23 -22
- data/vendor/cmock/scripts/create_makefile.rb +4 -3
- data/vendor/cmock/src/cmock.h +1 -1
- data/vendor/cmock/vendor/c_exception/lib/CException.h +1 -1
- data/vendor/cmock/vendor/c_exception/project.yml +2 -2
- data/vendor/cmock/vendor/c_exception/test/TestException.c +1 -1
- data/vendor/cmock/vendor/c_exception/test/support/CExceptionConfig.h +5 -11
- data/vendor/cmock/vendor/unity/auto/generate_test_runner.rb +85 -29
- data/vendor/cmock/vendor/unity/docs/UnityChangeLog.md +1 -0
- data/vendor/cmock/vendor/unity/examples/unity_config.h +8 -0
- data/vendor/cmock/vendor/unity/src/unity.c +9 -1
- data/vendor/cmock/vendor/unity/src/unity.h +1 -1
- data/vendor/cmock/vendor/unity/test/rakefile +2 -1
- data/vendor/cmock/vendor/unity/test/testdata/testRunnerGeneratorEmpty.c +13 -0
- data/vendor/cmock/vendor/unity/test/tests/test_generate_test_runner.rb +31 -0
- data/vendor/unity/auto/generate_test_runner.rb +63 -57
- data/vendor/unity/docs/UnityChangeLog.md +1 -0
- data/vendor/unity/examples/unity_config.h +8 -0
- data/vendor/unity/src/unity.c +9 -1
- data/vendor/unity/src/unity.h +1 -1
- data/vendor/unity/test/rakefile +2 -1
- data/vendor/unity/test/tests/test_generate_test_runner.rb +20 -0
- metadata +21 -3
- data/vendor/cmock/vendor/unity/auto/run_test.erb +0 -37
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
# =========================================================================
|
|
7
7
|
|
|
8
8
|
require 'fileutils'
|
|
9
|
+
require 'bundler'
|
|
9
10
|
require 'ceedling/encodinator'
|
|
10
11
|
require_relative 'gem_dir_layout'
|
|
11
12
|
|
|
@@ -44,16 +45,26 @@ class SystemContext
|
|
|
44
45
|
)
|
|
45
46
|
|
|
46
47
|
Dir.chdir(shared_dir) do
|
|
47
|
-
saved = ENV.to_hash
|
|
48
48
|
begin
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
|
|
49
|
+
# Bundler.with_unbundled_env restores the pre-`bundle exec` environment for this
|
|
50
|
+
# block -- clearing not just BUNDLE_GEMFILE/BUNDLE_BIN_PATH/RUBYOPT (the previous,
|
|
51
|
+
# incomplete hand-rolled list here) but also GEM_HOME/GEM_PATH/RUBYLIB/PATH and every
|
|
52
|
+
# other var Bundler sets when this spec suite itself runs under `bundle exec` against
|
|
53
|
+
# a non-default GEM_HOME (e.g. `bundle install --path vendor/bundle`). Any one of
|
|
54
|
+
# those left in place is enough on its own for the `bundle exec ruby -S ceedling
|
|
55
|
+
# version` verification below to load the *outer* project's bundler/gems instead of
|
|
56
|
+
# this shared gem's own `--local path` install, and fail to find this Gemfile's exact
|
|
57
|
+
# pinned versions there.
|
|
58
|
+
deploy_output = Bundler.with_unbundled_env do
|
|
59
|
+
output = `bundle config set --local path '#{shared_gem.install_dir}' 2>&1`
|
|
60
|
+
# --prefer-local: Without it, Bundler resolves gems (e.g. `erb`) fresh from
|
|
61
|
+
# rubygems repository even when Ruby's default-gem copy satisfies the Gemfile constraint.
|
|
62
|
+
output += `bundle install --prefer-local 2>&1`
|
|
63
|
+
output
|
|
64
|
+
end
|
|
54
65
|
raise VerificationFailed, "bundle install failed:\n#{deploy_output}" unless $?.success?
|
|
55
66
|
|
|
56
|
-
verify = `bundle exec ruby -S ceedling version 2>&1`
|
|
67
|
+
verify = Bundler.with_unbundled_env { `bundle exec ruby -S ceedling version 2>&1` }
|
|
57
68
|
unless $?.success?
|
|
58
69
|
raise VerificationFailed,
|
|
59
70
|
"Ceedling does not appear to be installed or ready for use.\n" \
|
|
@@ -62,8 +73,6 @@ class SystemContext
|
|
|
62
73
|
rescue
|
|
63
74
|
FileUtils.rm_rf(shared_dir)
|
|
64
75
|
raise
|
|
65
|
-
ensure
|
|
66
|
-
ENV.replace(saved)
|
|
67
76
|
end
|
|
68
77
|
end
|
|
69
78
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# =========================================================================
|
|
2
|
+
# Ceedling - Test-Centered Build System for C
|
|
3
|
+
# ThrowTheSwitch.org
|
|
4
|
+
# Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
|
5
|
+
# SPDX-License-Identifier: MIT
|
|
6
|
+
# =========================================================================
|
|
7
|
+
|
|
8
|
+
require 'spec_system_helper'
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
## Conditional-#include Macro-Visibility Tests (directives-only preprocessing)
|
|
12
|
+
## =============================================================================
|
|
13
|
+
##
|
|
14
|
+
## Ceedling discovers a file's #includes via two preprocessor passes reconciled
|
|
15
|
+
## into one list: a "bare" pass and an accurate pass (gcc -E -fdirectives-only
|
|
16
|
+
## against the real file with real search paths -- genuinely opens every
|
|
17
|
+
## header). Reconciliation keeps an accurate-pass entry only if bare also found
|
|
18
|
+
## it, to filter out headers reached only via a deeper, nested path.
|
|
19
|
+
##
|
|
20
|
+
## "Bare" is itself two things unioned together: a gcc -M -MG -MP pass against
|
|
21
|
+
## an isolated, sibling-free copy of the file (so it never actually opens any
|
|
22
|
+
## header the file #includes, but can still resolve an #include whose own
|
|
23
|
+
## target is a macro, since command-line -D defines are visible even in
|
|
24
|
+
## isolation), and a plain literal text scan of the file's own #include lines
|
|
25
|
+
## (no conditional evaluation at all, so it sees past a guard the isolated gcc
|
|
26
|
+
## pass can't evaluate -- but also can't resolve a macro-computed #include
|
|
27
|
+
## target, since there's no literal filename in the source text to find).
|
|
28
|
+
## Neither replaces the other; each catches what the other structurally can't.
|
|
29
|
+
##
|
|
30
|
+
## These tests characterize that reconciliation's behavior for #include
|
|
31
|
+
## directives guarded by an #if/#ifdef, across the different places the
|
|
32
|
+
## guarding macro can come from -- some already handled correctly, one
|
|
33
|
+
## (issue #1223) fixed by adding the text-scan half of "bare" above.
|
|
34
|
+
##
|
|
35
|
+
## Test assets: assets/tests_with_conditional_includes/
|
|
36
|
+
## - widget.c/.h: three scenarios that already work correctly:
|
|
37
|
+
## (a) conditional include gated on a project :defines macro
|
|
38
|
+
## (b) conditional include gated on a same-file #define
|
|
39
|
+
## (c) a header reached only transitively (nested_wrapper.h's own
|
|
40
|
+
## #include, never itself directly #include'd by widget.c) --
|
|
41
|
+
## must not appear duplicated in as a false top-level entry
|
|
42
|
+
## - widget_feature.c/.h + feature_config.h + feature_extra.h: issue #1223
|
|
43
|
+
## itself -- a conditional include gated on a macro defined by an
|
|
44
|
+
## *earlier #include in the same file* (feature_config.h's FEATURE_LEVEL),
|
|
45
|
+
## which the isolated bare pass can never see, silently dropping
|
|
46
|
+
## feature_extra.h and leaving FEATURE_EXTRA_MACRO undeclared.
|
|
47
|
+
##
|
|
48
|
+
|
|
49
|
+
ceedling_system_tests do
|
|
50
|
+
|
|
51
|
+
before :all do
|
|
52
|
+
@c = SystemContext.new
|
|
53
|
+
@c.deploy_gem
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
after :all do
|
|
57
|
+
@c.done!
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
before { @proj_name = unique_proj_name("cond_inc") }
|
|
61
|
+
|
|
62
|
+
describe "Deployed as a gem" do
|
|
63
|
+
before do
|
|
64
|
+
@c.with_context do
|
|
65
|
+
@c.ceedling_appcmd_exec("new #{@proj_name}")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# =========================================================================
|
|
70
|
+
describe "Conditional includes that already resolve correctly today" do
|
|
71
|
+
# =========================================================================
|
|
72
|
+
|
|
73
|
+
before do
|
|
74
|
+
@c.with_context do
|
|
75
|
+
Dir.chdir @proj_name do
|
|
76
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/widget.h"), 'src/'
|
|
77
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/widget.c"), 'src/'
|
|
78
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/project_flag_extra.h"), 'src/'
|
|
79
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/local_flag_extra.h"), 'src/'
|
|
80
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/nested_wrapper.h"), 'src/'
|
|
81
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/nested_extra.h"), 'src/'
|
|
82
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/test/test_widget.c"), 'test/'
|
|
83
|
+
|
|
84
|
+
settings = {
|
|
85
|
+
:project => { :use_partials => true },
|
|
86
|
+
:defines => { :test => ['PROJECT_FLAG'] }
|
|
87
|
+
}
|
|
88
|
+
@c.merge_project_yml_for_test(settings)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "resolves a project-:defines-gated include, a same-file-#define-gated include, and correctly excludes a transitively-nested header from duplication" do
|
|
94
|
+
@c.with_context do
|
|
95
|
+
Dir.chdir @proj_name do
|
|
96
|
+
output = @c.ceedling_build_exec("test:widget")
|
|
97
|
+
expect(@c.last_exit_status).to eq(0)
|
|
98
|
+
expect(output).to match(/TESTED:\s+3/)
|
|
99
|
+
expect(output).to match(/PASSED:\s+3/)
|
|
100
|
+
expect(output).to match(/FAILED:\s+0/)
|
|
101
|
+
|
|
102
|
+
# (c) nested_extra.h is reached only transitively, through
|
|
103
|
+
# nested_wrapper.h's own #include -- confirm it is not promoted
|
|
104
|
+
# into a spurious, duplicated top-level #include in the generated
|
|
105
|
+
# Partial implementation (the exact filtering property the #1223
|
|
106
|
+
# fix must not break).
|
|
107
|
+
generated = Dir.glob('build/test/partials/**/*_impl.c').first
|
|
108
|
+
expect(generated).not_to be_nil
|
|
109
|
+
contents = File.read(generated)
|
|
110
|
+
expect(contents.scan(/#include\s+"nested_extra\.h"/).length).to eq(0)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# =========================================================================
|
|
118
|
+
describe "Conditional include gated on a macro from an earlier #include in the same file (issue #1223)" do
|
|
119
|
+
# =========================================================================
|
|
120
|
+
|
|
121
|
+
before do
|
|
122
|
+
@c.with_context do
|
|
123
|
+
Dir.chdir @proj_name do
|
|
124
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/widget_feature.h"), 'src/'
|
|
125
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/widget_feature.c"), 'src/'
|
|
126
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/feature_config.h"), 'src/'
|
|
127
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/src/feature_extra.h"), 'src/'
|
|
128
|
+
FileUtils.cp test_asset_path("tests_with_conditional_includes/test/test_widget_feature.c"), 'test/'
|
|
129
|
+
|
|
130
|
+
settings = { :project => { :use_partials => true } }
|
|
131
|
+
@c.merge_project_yml_for_test(settings)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "keeps FEATURE_EXTRA_MACRO visible in the generated Partial so the build compiles" do
|
|
137
|
+
@c.with_context do
|
|
138
|
+
Dir.chdir @proj_name do
|
|
139
|
+
output = @c.ceedling_build_exec("test:widget_feature")
|
|
140
|
+
expect(@c.last_exit_status).to eq(0)
|
|
141
|
+
expect(output).to match(/TESTED:\s+1/)
|
|
142
|
+
expect(output).to match(/PASSED:\s+1/)
|
|
143
|
+
expect(output).to match(/FAILED:\s+0/)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
@@ -131,8 +131,8 @@ ceedling_system_tests do
|
|
|
131
131
|
@c.merge_project_yml_for_test({ :test_build => { :preprocess_force_fallback => false } })
|
|
132
132
|
output = @c.ceedling_build_exec("test:all")
|
|
133
133
|
expect(@c.last_exit_status).to eq(0)
|
|
134
|
-
expect(output).to match(/TESTED:\s+
|
|
135
|
-
expect(output).to match(/PASSED:\s+
|
|
134
|
+
expect(output).to match(/TESTED:\s+68/)
|
|
135
|
+
expect(output).to match(/PASSED:\s+68/)
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
end
|
|
@@ -144,8 +144,8 @@ ceedling_system_tests do
|
|
|
144
144
|
@c.merge_project_yml_for_test({ :test_build => { :preprocess_force_fallback => true } })
|
|
145
145
|
output = @c.ceedling_build_exec("test:all")
|
|
146
146
|
expect(@c.last_exit_status).to eq(0)
|
|
147
|
-
expect(output).to match(/TESTED:\s+
|
|
148
|
-
expect(output).to match(/PASSED:\s+
|
|
147
|
+
expect(output).to match(/TESTED:\s+68/)
|
|
148
|
+
expect(output).to match(/PASSED:\s+68/)
|
|
149
149
|
end
|
|
150
150
|
end
|
|
151
151
|
end
|
|
@@ -46,8 +46,8 @@ ceedling_system_tests do
|
|
|
46
46
|
@c.with_context do
|
|
47
47
|
Dir.chdir "wondrous_forest" do
|
|
48
48
|
@output = @c.ceedling_build_exec("test:all")
|
|
49
|
-
expect(@output).to match(/TESTED:\s+
|
|
50
|
-
expect(@output).to match(/PASSED:\s+
|
|
49
|
+
expect(@output).to match(/TESTED:\s+68/)
|
|
50
|
+
expect(@output).to match(/PASSED:\s+68/)
|
|
51
51
|
expect(@output).to match(/FAILED:\s+0/)
|
|
52
52
|
end
|
|
53
53
|
end
|
|
@@ -114,7 +114,11 @@ module CommonSystemTestCases
|
|
|
114
114
|
@c.with_context do
|
|
115
115
|
Dir.chdir @proj_name do
|
|
116
116
|
all_docs = Dir["docs/*"]
|
|
117
|
-
|
|
117
|
+
# docs/ceedling only exists when this repo's own local HTML docs bundle
|
|
118
|
+
# (site-local/) was available to copy in -- see html_docs_bundle_available?.
|
|
119
|
+
expected = ['docs/unity', 'docs/cmock', 'docs/c_exception', 'docs/license.txt']
|
|
120
|
+
expected << 'docs/ceedling' if html_docs_bundle_available?
|
|
121
|
+
expect(all_docs).to contain_exactly(*expected)
|
|
118
122
|
end
|
|
119
123
|
end
|
|
120
124
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# =========================================================================
|
|
2
|
+
# Ceedling - Test-Centered Build System for C
|
|
3
|
+
# ThrowTheSwitch.org
|
|
4
|
+
# Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
|
5
|
+
# SPDX-License-Identifier: MIT
|
|
6
|
+
# =========================================================================
|
|
7
|
+
|
|
8
|
+
require 'spec_system_helper'
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
## Generated Runner Preserves System #include Directory/Brackets (issue #1236)
|
|
12
|
+
## =============================================================================
|
|
13
|
+
##
|
|
14
|
+
## A test file directly #include-ing a system header with a directory component
|
|
15
|
+
## (e.g. `#include <sys/stat.h>`) previously produced a generated runner containing
|
|
16
|
+
## `#include "stat.h"` -- the directory component and the system-include `<>`
|
|
17
|
+
## delimiters were both lost, since GeneratorTestRunner#generate rendered every
|
|
18
|
+
## include (mocks aside) down to its bare basename with no `<>` for system headers.
|
|
19
|
+
## The test file itself compiled fine; only the separately generated runner file
|
|
20
|
+
## failed, with a "No such file or directory" error on the mangled include.
|
|
21
|
+
##
|
|
22
|
+
|
|
23
|
+
TEST_RUNNER_SYSTEM_INCLUDE_C = <<~C
|
|
24
|
+
#include <sys/stat.h>
|
|
25
|
+
|
|
26
|
+
#include "unity.h"
|
|
27
|
+
|
|
28
|
+
void setUp(void) {}
|
|
29
|
+
void tearDown(void) {}
|
|
30
|
+
|
|
31
|
+
void test_runner_preserves_system_include_path(void)
|
|
32
|
+
{
|
|
33
|
+
struct stat value;
|
|
34
|
+
TEST_ASSERT_EQUAL_UINT(sizeof(value), sizeof(struct stat));
|
|
35
|
+
}
|
|
36
|
+
C
|
|
37
|
+
|
|
38
|
+
ceedling_system_tests do
|
|
39
|
+
|
|
40
|
+
before :all do
|
|
41
|
+
@c = SystemContext.new
|
|
42
|
+
@c.deploy_gem
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
after :all do
|
|
46
|
+
@c.done!
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
before { @proj_name = unique_proj_name("runner_sys_inc") }
|
|
50
|
+
|
|
51
|
+
describe "Deployed as a gem" do
|
|
52
|
+
before do
|
|
53
|
+
@c.with_context do
|
|
54
|
+
@c.ceedling_appcmd_exec("new #{@proj_name}")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
before do
|
|
59
|
+
@c.with_context do
|
|
60
|
+
Dir.chdir @proj_name do
|
|
61
|
+
File.write('test/test_runner_system_include.c', TEST_RUNNER_SYSTEM_INCLUDE_C)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "preserves a system include's directory component and angle brackets in the generated runner" do
|
|
67
|
+
@c.with_context do
|
|
68
|
+
Dir.chdir @proj_name do
|
|
69
|
+
output = @c.ceedling_build_exec("test:all")
|
|
70
|
+
|
|
71
|
+
expect(@c.last_exit_status).to eq(0)
|
|
72
|
+
expect(output).to match(/TESTED:\s+1/)
|
|
73
|
+
expect(output).to match(/PASSED:\s+1/)
|
|
74
|
+
expect(output).to match(/FAILED:\s+0/)
|
|
75
|
+
|
|
76
|
+
# The generated runner is what actually failed to compile in the reported
|
|
77
|
+
# issue -- assert on its content directly rather than just overall build
|
|
78
|
+
# success, since only the runner (not the test file itself) was affected.
|
|
79
|
+
runner_path = Dir.glob('build/test/runners/*_runner.c').first
|
|
80
|
+
expect(runner_path).not_to be_nil
|
|
81
|
+
|
|
82
|
+
runner_contents = File.read(runner_path)
|
|
83
|
+
expect(runner_contents).to include('#include <sys/stat.h>')
|
|
84
|
+
expect(runner_contents).not_to include('#include "stat.h"')
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
require 'spec_helper'
|
|
9
9
|
require 'ceedling/generators/generator_test_runner'
|
|
10
10
|
require 'ceedling/parsing_parcels'
|
|
11
|
+
require 'ceedling/includes/includes'
|
|
11
12
|
|
|
12
13
|
describe GeneratorTestRunner do
|
|
13
14
|
before(:each) do
|
|
@@ -141,4 +142,72 @@ describe GeneratorTestRunner do
|
|
|
141
142
|
)
|
|
142
143
|
end
|
|
143
144
|
end
|
|
145
|
+
|
|
146
|
+
# ===========================================================================
|
|
147
|
+
describe '#generate' do
|
|
148
|
+
# ===========================================================================
|
|
149
|
+
# Regression coverage for https://github.com/ThrowTheSwitch/Ceedling/issues/1236:
|
|
150
|
+
# a system #include with a directory component (e.g. <sys/stat.h>) was rendered
|
|
151
|
+
# into the generated runner as a bare, unbracketed basename ("stat.h"), losing
|
|
152
|
+
# both the directory and the user/system distinction, breaking runner compilation.
|
|
153
|
+
#
|
|
154
|
+
# @unity_runner_generator is a real UnityTestRunnerGenerator, constructed directly
|
|
155
|
+
# inside #initialize rather than injected -- swapped out for a double here so these
|
|
156
|
+
# specs assert on exactly what GeneratorTestRunner itself hands off, independent of
|
|
157
|
+
# Unity's own generated file formatting.
|
|
158
|
+
def build_and_capture_includes(includes:, mocks: [])
|
|
159
|
+
runner = build_runner( test_file_contents: "void test_Thing(void) {}\n" )
|
|
160
|
+
|
|
161
|
+
captured = nil
|
|
162
|
+
fake_generator = double('unity_runner_generator')
|
|
163
|
+
allow(fake_generator).to receive(:generate) do |*args|
|
|
164
|
+
captured = args[4]
|
|
165
|
+
end
|
|
166
|
+
runner.instance_variable_set(:@unity_runner_generator, fake_generator)
|
|
167
|
+
|
|
168
|
+
runner.generate(
|
|
169
|
+
module_name: 'test_thing',
|
|
170
|
+
runner_filepath: '/build/test/runners/test_thing_runner.c',
|
|
171
|
+
mocks: mocks,
|
|
172
|
+
includes: includes
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return captured
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'renders a system include with a directory component in angle brackets, directory intact' do
|
|
179
|
+
captured = build_and_capture_includes( includes: [ SystemInclude.new('sys/stat.h') ] )
|
|
180
|
+
|
|
181
|
+
expect( captured ).to eq( ['<sys/stat.h>'] )
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'prefers a reconciled system include\'s include_path over its resolved filepath' do
|
|
185
|
+
# Mirrors what Includes.reconcile actually produces: filepath is the real,
|
|
186
|
+
# resolved (possibly absolute) location; include_path is the original,
|
|
187
|
+
# as-written directive text that must be what's rendered.
|
|
188
|
+
reconciled = SystemInclude.new('/usr/include/sys/stat.h', include_path: 'sys/stat.h')
|
|
189
|
+
|
|
190
|
+
captured = build_and_capture_includes( includes: [ reconciled ] )
|
|
191
|
+
|
|
192
|
+
expect( captured ).to eq( ['<sys/stat.h>'] )
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it 'renders a user include with a directory component down to its bare filename, unchanged from prior behavior' do
|
|
196
|
+
# Unlike a system header, a project's own directories are exposed to the
|
|
197
|
+
# compiler as a flat list of -I search paths -- rendering a user include's
|
|
198
|
+
# own directory component here breaks resolution rather than fixing anything,
|
|
199
|
+
# so this behavior is intentionally unchanged by the issue #1236 fix.
|
|
200
|
+
captured = build_and_capture_includes( includes: [ UserInclude.new('sub/header.h') ] )
|
|
201
|
+
|
|
202
|
+
expect( captured ).to eq( ['header.h'] )
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it 'renders a mixed list of system and user includes each in their own correct form' do
|
|
206
|
+
captured = build_and_capture_includes(
|
|
207
|
+
includes: [ SystemInclude.new('sys/stat.h'), UserInclude.new('sub/header.h') ]
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
expect( captured ).to eq( ['<sys/stat.h>', 'header.h'] )
|
|
211
|
+
end
|
|
212
|
+
end
|
|
144
213
|
end
|
|
@@ -871,6 +871,75 @@ describe Partializer do
|
|
|
871
871
|
expect(result).not_to include(UserInclude.new('partial_module.h'))
|
|
872
872
|
end
|
|
873
873
|
|
|
874
|
+
# Regression test for #1215: PUBLIC/PRIVATE were once the only mock modes that existed,
|
|
875
|
+
# so this method's own "does this module have a mock to redirect to" check only ever
|
|
876
|
+
# listed those two. DEDUCT (MOCK_PARTIAL_ALL_MODULE) was added later without updating
|
|
877
|
+
# this check, so a module mocked via MOCK_PARTIAL_ALL_MODULE -- e.g. a vendor header
|
|
878
|
+
# whose only mockable functions are static inline, which requires DEDUCT to select at
|
|
879
|
+
# all -- was silently never redirected to its mock interface header.
|
|
880
|
+
it "remaps mockable deduct (ALL_MODULE) partial to interface header" do
|
|
881
|
+
includes = [UserInclude.new('header1.h'), UserInclude.new('partial_module.h'), UserInclude.new('header2.h')]
|
|
882
|
+
partials = {
|
|
883
|
+
'partial_module' => make_partial_config(mocks_type: Partials::DEDUCT)
|
|
884
|
+
}
|
|
885
|
+
impl_filename = 'module_impl.h'
|
|
886
|
+
interface_filename = 'partial_module_interface.h'
|
|
887
|
+
impl_header = UserInclude.new(impl_filename)
|
|
888
|
+
interface_header = UserInclude.new(interface_filename)
|
|
889
|
+
|
|
890
|
+
allow(@file_path_utils).to receive(:form_partial_implementation_header_filename)
|
|
891
|
+
.with('module')
|
|
892
|
+
.and_return(impl_filename)
|
|
893
|
+
|
|
894
|
+
allow(@file_path_utils).to receive(:form_partial_interface_header_filename)
|
|
895
|
+
.with('partial_module')
|
|
896
|
+
.and_return(interface_filename)
|
|
897
|
+
|
|
898
|
+
result = @partializer.remap_implementation_source_includes(
|
|
899
|
+
name: 'module',
|
|
900
|
+
includes: includes,
|
|
901
|
+
partials: partials
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
expect(result).to include(impl_header)
|
|
905
|
+
expect(result).to include(interface_header)
|
|
906
|
+
expect(result).to include(UserInclude.new('header1.h'))
|
|
907
|
+
expect(result).to include(UserInclude.new('header2.h'))
|
|
908
|
+
expect(result).not_to include(UserInclude.new('partial_module.h'))
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
# Same regression as the DEDUCT case above, for ACCUMULATE (MOCK_PARTIAL_MODULE).
|
|
912
|
+
it "remaps mockable accumulate partial to interface header" do
|
|
913
|
+
includes = [UserInclude.new('header1.h'), UserInclude.new('partial_module.h'), UserInclude.new('header2.h')]
|
|
914
|
+
partials = {
|
|
915
|
+
'partial_module' => make_partial_config(mocks_type: Partials::ACCUMULATE)
|
|
916
|
+
}
|
|
917
|
+
impl_filename = 'module_impl.h'
|
|
918
|
+
interface_filename = 'partial_module_interface.h'
|
|
919
|
+
impl_header = UserInclude.new(impl_filename)
|
|
920
|
+
interface_header = UserInclude.new(interface_filename)
|
|
921
|
+
|
|
922
|
+
allow(@file_path_utils).to receive(:form_partial_implementation_header_filename)
|
|
923
|
+
.with('module')
|
|
924
|
+
.and_return(impl_filename)
|
|
925
|
+
|
|
926
|
+
allow(@file_path_utils).to receive(:form_partial_interface_header_filename)
|
|
927
|
+
.with('partial_module')
|
|
928
|
+
.and_return(interface_filename)
|
|
929
|
+
|
|
930
|
+
result = @partializer.remap_implementation_source_includes(
|
|
931
|
+
name: 'module',
|
|
932
|
+
includes: includes,
|
|
933
|
+
partials: partials
|
|
934
|
+
)
|
|
935
|
+
|
|
936
|
+
expect(result).to include(impl_header)
|
|
937
|
+
expect(result).to include(interface_header)
|
|
938
|
+
expect(result).to include(UserInclude.new('header1.h'))
|
|
939
|
+
expect(result).to include(UserInclude.new('header2.h'))
|
|
940
|
+
expect(result).not_to include(UserInclude.new('partial_module.h'))
|
|
941
|
+
end
|
|
942
|
+
|
|
874
943
|
it "remaps multiple mockable partials to interface headers" do
|
|
875
944
|
includes = [
|
|
876
945
|
UserInclude.new('header1.h'),
|
|
@@ -339,6 +339,67 @@ RSpec.describe PreprocessinatorIncludesHandler do
|
|
|
339
339
|
end
|
|
340
340
|
|
|
341
341
|
|
|
342
|
+
# ===========================================================================
|
|
343
|
+
describe '#extract_bare_includes_from_text' do
|
|
344
|
+
# ===========================================================================
|
|
345
|
+
|
|
346
|
+
let(:filepath) { '/src/module.c' }
|
|
347
|
+
|
|
348
|
+
it 'extracts a simple user include' do
|
|
349
|
+
stub_file_open(filepath, "#include \"foo.h\"\n")
|
|
350
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
351
|
+
expect(result.map(&:filename)).to include('foo.h')
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it 'extracts a system include too, unlike extract_user_includes_from_text' do
|
|
355
|
+
stub_file_open(filepath, "#include <stdio.h>\n")
|
|
356
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
357
|
+
expect(result.map(&:filename)).to include('stdio.h')
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it 'returns plain Include objects, not UserInclude/SystemInclude' do
|
|
361
|
+
stub_file_open(filepath, "#include \"foo.h\"\n#include <stdio.h>\n")
|
|
362
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
363
|
+
expect(result).to all( be_an_instance_of(Include) )
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
it 'ignores includes inside line comments' do
|
|
367
|
+
stub_file_open(filepath, "// #include \"commented_out.h\"\n")
|
|
368
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
369
|
+
expect(result).to be_empty
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it 'ignores includes inside block comments' do
|
|
373
|
+
content = "/* #include \"in_block.h\" */\n#include \"real.h\"\n"
|
|
374
|
+
stub_file_open(filepath, content)
|
|
375
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
376
|
+
expect(result.map(&:filename)).to contain_exactly('real.h')
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# The defining difference from extract_user_includes_from_text: no conditional
|
|
380
|
+
# tracking at all -- an #include inside an #ifdef for an undefined macro is
|
|
381
|
+
# still captured, since this method's whole purpose is to see past a guard
|
|
382
|
+
# whose condition can't be evaluated without opening another header (issue #1223).
|
|
383
|
+
it 'captures a conditionally-guarded include regardless of whether the guard could be evaluated true' do
|
|
384
|
+
content = <<~C
|
|
385
|
+
#ifdef UNDEFINED_MACRO
|
|
386
|
+
#include "conditional.h"
|
|
387
|
+
#endif
|
|
388
|
+
C
|
|
389
|
+
stub_file_open(filepath, content)
|
|
390
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
391
|
+
expect(result.map(&:filename)).to include('conditional.h')
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
it 'removes a self-referential include matching the file being scanned' do
|
|
395
|
+
stub_file_open(filepath, "#include \"#{filepath}\"\n#include \"foo.h\"\n")
|
|
396
|
+
result = subject.extract_bare_includes_from_text(filepath: filepath)
|
|
397
|
+
expect(result.map(&:filename)).to contain_exactly('foo.h')
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
|
|
342
403
|
# ===========================================================================
|
|
343
404
|
describe '#extract_system_includes_from_text' do
|
|
344
405
|
# ===========================================================================
|