ceedling 1.1.5 → 1.1.7
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/Gemfile +4 -0
- data/Gemfile.lock +2 -0
- data/README.md +4 -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 +31 -1
- data/docs/KnownIssues.md +1 -0
- data/docs/mkdocs/configuration/project-file.md +25 -7
- data/docs/mkdocs/configuration/reference/cexception.md +1 -1
- data/docs/mkdocs/configuration/reference/cmock.md +1 -1
- data/docs/mkdocs/configuration/reference/unity.md +1 -1
- data/docs/mkdocs/getting-started/quick-start.md +11 -8
- data/docs/mkdocs/plugins/gcov/gcovr.md +324 -189
- data/docs/mkdocs/plugins/gcov/reportgenerator.md +113 -31
- data/docs/mkdocs/reference/gcov-plugin.md +21 -3
- data/docs/mkdocs/snapshot/plugins/gcov/config/defaults.yml +0 -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_results_backtrace.rb +16 -8
- data/lib/ceedling/generators/generator_test_runner.rb +25 -1
- data/lib/ceedling/partials/partializer.rb +8 -1
- data/lib/ceedling/plugins/plugin_reportinator.rb +9 -0
- data/lib/ceedling/plugins/report_tests_stdout_plugin.rb +1 -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/plugins/gcov/config/defaults.yml +0 -1
- data/plugins/gcov/lib/gcov.rb +35 -16
- data/plugins/gcov/lib/gcovr_reportinator.rb +31 -1
- data/plugins/valgrind/lib/valgrind.rb +1 -1
- data/site-local/configuration/project-file.html +78 -8
- data/site-local/configuration/reference/cexception.html +5 -5
- data/site-local/configuration/reference/cmock.html +5 -5
- data/site-local/configuration/reference/unity.html +5 -5
- data/site-local/getting-started/quick-start.html +13 -9
- data/site-local/plugins/gcov/gcovr.html +1215 -255
- data/site-local/plugins/gcov/reportgenerator.html +404 -46
- data/site-local/reference/gcov-plugin.html +40 -7
- data/site-local/sitemap.xml.gz +0 -0
- data/site-local/snapshot/plugins/gcov/config/defaults.yml +0 -1
- data/spec/support/system/spec_system_helper.rb +11 -0
- data/spec/support/system/system_context.rb +25 -12
- data/spec/system/conditional_include_macro_visibility_spec.rb +152 -0
- data/spec/system/deployment_as_gem_spec.rb +2 -0
- data/spec/system/deployment_as_vendor_spec.rb +2 -0
- data/spec/system/encoding_stress_spec.rb +4 -4
- data/spec/system/example_wondrous_forest_spec.rb +2 -2
- data/spec/system/gcov_deployment_spec.rb +2 -0
- data/spec/system/support/common_test_cases.rb +47 -1
- data/spec/system/support/gcov_common_test_cases.rb +52 -0
- data/spec/system/test_runner_system_include_spec.rb +90 -0
- data/spec/units/generators/generator_test_results_backtrace_spec.rb +51 -0
- data/spec/units/generators/generator_test_runner_spec.rb +69 -0
- data/spec/units/partials/partializer_spec.rb +69 -0
- data/spec/units/plugin_reportinator_spec.rb +38 -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 +23 -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
|
|
|
@@ -226,8 +235,11 @@ class SystemContext
|
|
|
226
235
|
# encoding regardless of their actual content, so any project source content the
|
|
227
236
|
# subprocess echoes (verbose logging, compiler output, etc.) can make later regex
|
|
228
237
|
# matching against this string raise. Sanitize once here, the same way Ceedling itself
|
|
229
|
-
# sanitizes file content it scans
|
|
230
|
-
|
|
238
|
+
# sanitizes file content it scans -- reused for both the raw output and the failure
|
|
239
|
+
# report below, since a real compiler's own diagnostic text (e.g. clang's curly-quoted
|
|
240
|
+
# identifiers) is exactly the kind of non-ASCII content this needs to survive too.
|
|
241
|
+
stdout, stderr = stdout.clean_encoding, stderr.clean_encoding
|
|
242
|
+
@raw_output = stdout + stderr
|
|
231
243
|
@console_summary = compose_failure_report(stdout, stderr)
|
|
232
244
|
|
|
233
245
|
SystemTestOutput.new(@raw_output)
|
|
@@ -241,7 +253,8 @@ class SystemContext
|
|
|
241
253
|
|
|
242
254
|
@last_cmd = cmd
|
|
243
255
|
@last_exit_status = status.exitstatus
|
|
244
|
-
|
|
256
|
+
stdout, stderr = stdout.clean_encoding, stderr.clean_encoding
|
|
257
|
+
@raw_output = stdout + stderr
|
|
245
258
|
@console_summary = compose_failure_report(stdout, stderr)
|
|
246
259
|
|
|
247
260
|
SystemTestOutput.new(@raw_output)
|
|
@@ -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
|
|
@@ -87,6 +87,8 @@ ceedling_system_tests do
|
|
|
87
87
|
|
|
88
88
|
describe "Verbosity and output" do
|
|
89
89
|
test_case :test_project_with_named_verbosity
|
|
90
|
+
test_case :test_project_with_warnings_verbosity_prints_overall_summary
|
|
91
|
+
test_case :test_project_with_errors_verbosity_prints_overall_summary_on_passing_run
|
|
90
92
|
test_case :test_project_with_numerical_verbosity
|
|
91
93
|
test_case :report_tests_raw_output_log_plugin
|
|
92
94
|
end
|
|
@@ -90,6 +90,8 @@ ceedling_system_tests do
|
|
|
90
90
|
|
|
91
91
|
describe "Verbosity and output" do
|
|
92
92
|
test_case :test_project_with_named_verbosity
|
|
93
|
+
test_case :test_project_with_warnings_verbosity_prints_overall_summary
|
|
94
|
+
test_case :test_project_with_errors_verbosity_prints_overall_summary_on_passing_run
|
|
93
95
|
test_case :test_project_with_numerical_verbosity
|
|
94
96
|
test_case :report_tests_raw_output_log_plugin
|
|
95
97
|
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
|
|
@@ -33,8 +33,10 @@ ceedling_system_tests do
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
test_case :project_with_gcov_enabled_test_all_does_not_require_gcovr
|
|
36
37
|
test_case :project_with_gcov_success
|
|
37
38
|
test_case :project_with_gcov_fail
|
|
39
|
+
test_case :project_with_gcov_fail_under_decision
|
|
38
40
|
test_case :gcov_console_report_with_system_header
|
|
39
41
|
test_case :gcov_console_report_with_partial
|
|
40
42
|
# TODO: Restore these tests when the :abort_on_uncovered option is restored in the Gcov plugin
|
|
@@ -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
|
|
@@ -197,6 +201,48 @@ module CommonSystemTestCases
|
|
|
197
201
|
end
|
|
198
202
|
end
|
|
199
203
|
|
|
204
|
+
# The Overall Test Summary must still print at :warnings verbosity
|
|
205
|
+
# (`--verbosity=warnings`, Verbosity::COMPLAIN) on an all-passing run, not just
|
|
206
|
+
# when verbosity is :normal or higher, or when a test fails.
|
|
207
|
+
def test_project_with_warnings_verbosity_prints_overall_summary
|
|
208
|
+
@c.with_context do
|
|
209
|
+
Dir.chdir @proj_name do
|
|
210
|
+
FileUtils.cp test_asset_path("example_file.h"), 'src/'
|
|
211
|
+
FileUtils.cp test_asset_path("example_file.c"), 'src/'
|
|
212
|
+
FileUtils.cp test_asset_path("test_example_file_success.c"), 'test/'
|
|
213
|
+
|
|
214
|
+
output = @c.ceedling_build_exec("--verbosity=warnings")
|
|
215
|
+
expect(@c.last_exit_status).to eq(0)
|
|
216
|
+
expect(output).to match(/OVERALL TEST SUMMARY/)
|
|
217
|
+
expect(output).to match(/TESTED:\s+\d/)
|
|
218
|
+
expect(output).to match(/PASSED:\s+\d/)
|
|
219
|
+
expect(output).to match(/FAILED:\s+\d/)
|
|
220
|
+
expect(output).to match(/IGNORED:\s+\d/)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# ERRORS is the true floor for the Overall Test Summary -- a build's own
|
|
226
|
+
# test results are core information, visible even at the most restrictive
|
|
227
|
+
# verbosity short of :silent, whether the run passed or failed.
|
|
228
|
+
def test_project_with_errors_verbosity_prints_overall_summary_on_passing_run
|
|
229
|
+
@c.with_context do
|
|
230
|
+
Dir.chdir @proj_name do
|
|
231
|
+
FileUtils.cp test_asset_path("example_file.h"), 'src/'
|
|
232
|
+
FileUtils.cp test_asset_path("example_file.c"), 'src/'
|
|
233
|
+
FileUtils.cp test_asset_path("test_example_file_success.c"), 'test/'
|
|
234
|
+
|
|
235
|
+
output = @c.ceedling_build_exec("--verbosity=errors")
|
|
236
|
+
expect(@c.last_exit_status).to eq(0)
|
|
237
|
+
expect(output).to match(/OVERALL TEST SUMMARY/)
|
|
238
|
+
expect(output).to match(/TESTED:\s+\d/)
|
|
239
|
+
expect(output).to match(/PASSED:\s+\d/)
|
|
240
|
+
expect(output).to match(/FAILED:\s+\d/)
|
|
241
|
+
expect(output).to match(/IGNORED:\s+\d/)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
200
246
|
def test_project_with_numerical_verbosity
|
|
201
247
|
@c.with_context do
|
|
202
248
|
Dir.chdir @proj_name do
|
|
@@ -10,6 +10,38 @@ require_relative 'gcov_helpers'
|
|
|
10
10
|
module GcovCommonTestCases
|
|
11
11
|
include GcovHelpers
|
|
12
12
|
|
|
13
|
+
# #1252 -- Enabling the gcov plugin must not make gcovr a hard dependency of every
|
|
14
|
+
# build. Deliberately does NOT call prep_project_yml_for_coverage (which conditionally
|
|
15
|
+
# strips :utilities ➡️ gcovr when the host lacks a real gcovr) -- the point here is
|
|
16
|
+
# gcovr enabled in config but genuinely unreachable, reproducing #1252 regardless of
|
|
17
|
+
# what's actually installed on the machine running this spec.
|
|
18
|
+
def project_with_gcov_enabled_test_all_does_not_require_gcovr
|
|
19
|
+
@c.with_context do
|
|
20
|
+
Dir.chdir @proj_name do
|
|
21
|
+
@c.uncomment_project_yml_option_for_test("- gcov")
|
|
22
|
+
# Default :gcov ↳ :utilities already includes gcovr and :reports already
|
|
23
|
+
# includes HtmlBasic -- exactly the enabled-but-unused shape #1252 reported.
|
|
24
|
+
@c.merge_project_yml_for_test(
|
|
25
|
+
{ :tools => { :gcov_gcovr_report => { :executable => 'nonexistent_gcovr_binary_for_1252_test' } } }
|
|
26
|
+
)
|
|
27
|
+
FileUtils.cp test_asset_path("example_file.h"), 'src/'
|
|
28
|
+
FileUtils.cp test_asset_path("example_file.c"), 'src/'
|
|
29
|
+
FileUtils.cp test_asset_path("test_example_file_success.c"), 'test/'
|
|
30
|
+
|
|
31
|
+
# An ordinary test:all run must succeed -- it never needs gcovr at all.
|
|
32
|
+
output = @c.ceedling_build_exec("test:all")
|
|
33
|
+
expect(@c.last_exit_status).to eq(0)
|
|
34
|
+
expect(output).to_not match(/nonexistent_gcovr_binary_for_1252_test/)
|
|
35
|
+
|
|
36
|
+
# A real gcov: build still needs gcovr and must still fail loudly when it's missing --
|
|
37
|
+
# the fix defers gcovr's tool validation, it doesn't remove it.
|
|
38
|
+
output = @c.ceedling_build_exec("gcov:all")
|
|
39
|
+
expect(@c.last_exit_status).to_not eq(0)
|
|
40
|
+
expect(output).to match(/nonexistent_gcovr_binary_for_1252_test/)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
13
45
|
def project_with_gcov_success
|
|
14
46
|
@c.with_context do
|
|
15
47
|
Dir.chdir @proj_name do
|
|
@@ -46,6 +78,26 @@ module GcovCommonTestCases
|
|
|
46
78
|
end
|
|
47
79
|
end
|
|
48
80
|
|
|
81
|
+
# gcovr's own --fail-under-decision is a no-op without --decisions also present --
|
|
82
|
+
# Ceedling supplies --decisions automatically whenever :fail_under_decision is
|
|
83
|
+
# configured, so a passing run reports success instead of gcovr's own opaque
|
|
84
|
+
# "need also option --decision" CLI error.
|
|
85
|
+
def project_with_gcov_fail_under_decision
|
|
86
|
+
@c.with_context do
|
|
87
|
+
Dir.chdir @proj_name do
|
|
88
|
+
prep_project_yml_for_coverage
|
|
89
|
+
@c.merge_project_yml_for_test( { :gcov => { :gcovr => { :fail_under_decision => 1 } } } )
|
|
90
|
+
FileUtils.cp test_asset_path("example_file.h"), 'src/'
|
|
91
|
+
FileUtils.cp test_asset_path("example_file.c"), 'src/'
|
|
92
|
+
FileUtils.cp test_asset_path("test_example_file_success.c"), 'test/'
|
|
93
|
+
|
|
94
|
+
output = @c.ceedling_build_exec("gcov:all")
|
|
95
|
+
expect(@c.last_exit_status).to eq(0)
|
|
96
|
+
expect(output).to_not match(/need also option --decision/)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
49
101
|
# TODO: Restore this test when the :abort_on_uncovered option is restored in the Gcov plugin
|
|
50
102
|
# def project_with_gcov_fail_because_of_uncovered_files
|
|
51
103
|
# @c.with_context do
|
|
@@ -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
|
|
@@ -130,6 +130,7 @@ SIMPLE_ASSERT_CRASH_OUTPUT =
|
|
|
130
130
|
SIMPLE_PASS_OUTPUT = "test_lib.c:3:test_empty:PASS\n---------\n1 Tests 0 Failures 0 Ignored\nOK\n"
|
|
131
131
|
SIMPLE_FAIL_OUTPUT = "test_lib.c:8:test_bad:FAIL: Expected 1 Was 2\n---------\n1 Tests 1 Failures 0 Ignored\nFAIL\n"
|
|
132
132
|
SIMPLE_IGNORE_OUTPUT = "test_lib.c:12:test_skip:IGNORE\n---------\n1 Tests 0 Failures 1 Ignored\nOK\n"
|
|
133
|
+
SIMPLE_IGNORE_WITH_MESSAGE_OUTPUT = "test_lib.c:12:test_skip:IGNORE: Not yet implemented\n---------\n1 Tests 0 Failures 1 Ignored\nOK\n"
|
|
133
134
|
|
|
134
135
|
|
|
135
136
|
describe GeneratorTestResultsBacktrace do
|
|
@@ -255,6 +256,31 @@ describe GeneratorTestResultsBacktrace do
|
|
|
255
256
|
expect(expected_output_lines).to include('test_lib.c:9:test_asserting:FAIL: Expected 1 Was 2')
|
|
256
257
|
end
|
|
257
258
|
|
|
259
|
+
# Ignored-crash false positive: a TEST_IGNORE_MESSAGE(...) test case carries a
|
|
260
|
+
# trailing message, same as FAIL. Before this fix, only FAIL tolerated one --
|
|
261
|
+
# a message-carrying IGNORE fell through to "unresolved" and was misreported
|
|
262
|
+
# as crash evidence (a second @file_wrapper.write, for a companion_case that
|
|
263
|
+
# never actually crashed).
|
|
264
|
+
it 'handles an IGNORE test case with a trailing message and does not write a log' do
|
|
265
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
266
|
+
{ output: GDB_NO_SIGNAL_OUTPUT, time: 0.1, exit_code: 1, stderr: '', status: @ok_status },
|
|
267
|
+
{ output: "test_lib.c:9:test_asserting:IGNORE: Not yet implemented\n---------\n1 Tests 0 Failures 1 Ignored\nOK\n",
|
|
268
|
+
time: 0.1, exit_code: 0, stderr: '', status: @ok_status }
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
expect(@file_wrapper).to receive(:write).once.with(%r{test_crashes_elsewhere}, anything, anything)
|
|
272
|
+
|
|
273
|
+
expected_output_lines = []
|
|
274
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
275
|
+
expected_output_lines = kwargs[:output]
|
|
276
|
+
'regenerated'
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
@backtrace.do_gdb( filename, executable, shell_result, [companion_case] + test_cases, context: :test )
|
|
280
|
+
|
|
281
|
+
expect(expected_output_lines).to include('test_lib.c:9:test_asserting:IGNORE: Not yet implemented')
|
|
282
|
+
end
|
|
283
|
+
|
|
258
284
|
it "does not trust a matched PASS line when the retry's own real status contradicts it" do
|
|
259
285
|
# Regression test for issue #1198: a diagnostic retry can print a clean Unity
|
|
260
286
|
# result line while its own real process outcome says otherwise.
|
|
@@ -471,6 +497,31 @@ describe GeneratorTestResultsBacktrace do
|
|
|
471
497
|
expect(expected_output_lines).to include('test_lib.c:12:test_skip:IGNORE')
|
|
472
498
|
end
|
|
473
499
|
|
|
500
|
+
# Ignored-crash false positive: a TEST_IGNORE_MESSAGE(...) test case carries a
|
|
501
|
+
# trailing message, same as FAIL (handled just above). Before this fix, only FAIL
|
|
502
|
+
# tolerated one -- a message-carrying IGNORE fell through to the "no result line"
|
|
503
|
+
# branch and was misreported as a second crashed test case (test_skip, alongside
|
|
504
|
+
# the real crash attributed to test_crashes_elsewhere).
|
|
505
|
+
it 'handles an IGNORE test case with a trailing message' do
|
|
506
|
+
test_cases_ignore = [{ test: 'test_crashes_elsewhere', line_number: 20 }, { test: 'test_skip', line_number: 12 }]
|
|
507
|
+
|
|
508
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
509
|
+
{ output: SIMPLE_ASSERT_CRASH_OUTPUT, time: 0.1, exit_code: 134, stderr: '', status: @ok_status },
|
|
510
|
+
{ output: SIMPLE_IGNORE_WITH_MESSAGE_OUTPUT, time: 0.02, exit_code: 0, stderr: '', status: @ok_status }
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
expected_output_lines = []
|
|
514
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
515
|
+
expected_output_lines = kwargs[:output]
|
|
516
|
+
'regenerated'
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
@backtrace.do_simple( filename, executable, shell_result, test_cases_ignore, context: :test )
|
|
520
|
+
|
|
521
|
+
expect(expected_output_lines).to include('test_lib.c:12:test_skip:IGNORE: Not yet implemented')
|
|
522
|
+
expect(expected_output_lines).to_not include(a_string_matching(/test_skip:FAIL/))
|
|
523
|
+
end
|
|
524
|
+
|
|
474
525
|
it "does not trust a matched PASS line when the retry's own real status contradicts it" do
|
|
475
526
|
# Regression test for issue #1198: a diagnostic retry can print a clean Unity
|
|
476
527
|
# result line while its own real process outcome says otherwise.
|
|
@@ -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
|