ceedling 1.1.3 → 1.1.4
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/README.md +1 -1
- data/assets/fake_crash_test_fixture.rb +14 -0
- data/assets/partial_all_module.h +11 -0
- data/assets/run_with_ubsan.rb +15 -0
- data/assets/same_dir_pairing_module.c +4 -0
- data/assets/same_dir_pairing_module.h +8 -0
- data/assets/same_dir_pairing_module_func.h +6 -0
- data/assets/same_dir_pairing_other.c +4 -0
- data/assets/same_dir_pairing_other.h +8 -0
- data/assets/test_example_file_ub_shift_overflow.c +22 -0
- data/assets/test_partial_all_module.c +16 -0
- data/assets/test_same_dir_pairing.c +23 -0
- data/docs/Changelog.md +21 -1
- data/docs/mkdocs/configuration/reference/index.md +8 -0
- data/docs/mkdocs/configuration/reference/partials.md +38 -0
- data/examples/wondrous_forest/src/LightSensor.c +21 -4
- data/examples/wondrous_forest/src/LightSensor.h +12 -4
- data/examples/wondrous_forest/test/TestLightSensor.c +34 -4
- data/lib/ceedling/c_extractor/c_extractor.rb +37 -11
- data/lib/ceedling/c_extractor/c_extractor_constants.rb +0 -3
- data/lib/ceedling/c_extractor/c_extractor_declarations.rb +26 -25
- data/lib/ceedling/c_extractor/c_extractor_functions.rb +5 -12
- data/lib/ceedling/config/configurator.rb +1 -0
- data/lib/ceedling/config/configurator_setup.rb +26 -0
- data/lib/ceedling/defaults.rb +8 -0
- data/lib/ceedling/file_path_utils.rb +7 -0
- data/lib/ceedling/file_wrapper.rb +8 -0
- data/lib/ceedling/generators/generator.rb +15 -0
- data/lib/ceedling/generators/generator_helper.rb +25 -6
- data/lib/ceedling/generators/generator_partials.rb +84 -3
- data/lib/ceedling/generators/generator_test_results_backtrace.rb +183 -83
- data/lib/ceedling/includes/includes.rb +66 -11
- data/lib/ceedling/objects.yml +5 -0
- data/lib/ceedling/partials/partializer.rb +18 -3
- data/lib/ceedling/partials/partializer_utils.rb +6 -1
- data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +43 -16
- data/lib/ceedling/test_invoker/test_build_executor.rb +19 -8
- data/lib/version.rb +1 -1
- data/mkdocs.yml +1 -0
- data/site-local/404.html +30 -0
- data/site-local/configuration/environment-vars.html +30 -0
- data/site-local/configuration/global-collections.html +30 -0
- data/site-local/configuration/index.html +30 -0
- data/site-local/configuration/loading.html +30 -0
- data/site-local/configuration/mixins.html +30 -0
- data/site-local/configuration/parallel-builds.html +30 -0
- data/site-local/configuration/project-file.html +30 -0
- data/site-local/configuration/reference/cexception.html +30 -0
- data/site-local/configuration/reference/cmock.html +30 -0
- data/site-local/configuration/reference/defines.html +30 -0
- data/site-local/configuration/reference/environment.html +30 -0
- data/site-local/configuration/reference/extension.html +30 -0
- data/site-local/configuration/reference/files.html +30 -0
- data/site-local/configuration/reference/flags.html +30 -0
- data/site-local/configuration/reference/index.html +36 -0
- data/site-local/configuration/reference/libraries.html +30 -0
- data/site-local/configuration/reference/mixins.html +30 -0
- data/site-local/configuration/reference/partials.html +4257 -0
- data/site-local/configuration/reference/paths.html +30 -0
- data/site-local/configuration/reference/plugins.html +30 -0
- data/site-local/configuration/reference/project.html +30 -0
- data/site-local/configuration/reference/release-build.html +31 -1
- data/site-local/configuration/reference/test-build.html +31 -1
- data/site-local/configuration/reference/test-runner.html +30 -0
- data/site-local/configuration/reference/tools.html +30 -0
- data/site-local/configuration/reference/unity.html +30 -0
- data/site-local/configuration/which-ceedling.html +30 -0
- data/site-local/development/index.html +30 -0
- data/site-local/development/plugins/configuration.html +30 -0
- data/site-local/development/plugins/index.html +30 -0
- data/site-local/development/plugins/plugin-subclass.html +30 -0
- data/site-local/development/plugins/rake-tasks.html +30 -0
- data/site-local/development/workflow.html +30 -0
- data/site-local/getting-started/command-line.html +30 -0
- data/site-local/getting-started/example-projects/cipher-quest.html +30 -0
- data/site-local/getting-started/example-projects/index.html +30 -0
- data/site-local/getting-started/example-projects/temp-sensor.html +30 -0
- data/site-local/getting-started/example-projects/wondrous-forest.html +30 -0
- data/site-local/getting-started/index.html +30 -0
- data/site-local/getting-started/installation.html +30 -0
- data/site-local/getting-started/quick-start.html +30 -0
- data/site-local/help.html +30 -0
- data/site-local/index.html +30 -0
- data/site-local/overview/build-system.html +30 -0
- data/site-local/overview/index.html +30 -0
- data/site-local/overview/test-environments.html +30 -0
- data/site-local/overview/tools-and-frameworks.html +30 -0
- data/site-local/plugins/beep.html +30 -0
- data/site-local/plugins/bullseye.html +30 -0
- data/site-local/plugins/command-hooks.html +30 -0
- data/site-local/plugins/compile-commands-json-db.html +30 -0
- data/site-local/plugins/cppcheck.html +30 -0
- data/site-local/plugins/dependencies.html +30 -0
- data/site-local/plugins/fff.html +30 -0
- data/site-local/plugins/gcov/examples.html +30 -0
- data/site-local/plugins/gcov/gcovr.html +30 -0
- data/site-local/plugins/gcov/index.html +30 -0
- data/site-local/plugins/gcov/overview.html +30 -0
- data/site-local/plugins/gcov/reportgenerator.html +30 -0
- data/site-local/plugins/gcov/reporting.html +30 -0
- data/site-local/plugins/gcov/setup.html +30 -0
- data/site-local/plugins/gcov/tool-versions.html +30 -0
- data/site-local/plugins/gcov/troubleshooting.html +30 -0
- data/site-local/plugins/index.html +30 -0
- data/site-local/plugins/module-generator.html +30 -0
- data/site-local/plugins/report-build-warnings-log.html +30 -0
- data/site-local/plugins/report-tests-gtestlike-stdout.html +30 -0
- data/site-local/plugins/report-tests-ide-stdout.html +30 -0
- data/site-local/plugins/report-tests-log-factory.html +30 -0
- data/site-local/plugins/report-tests-pretty-stdout.html +30 -0
- data/site-local/plugins/report-tests-raw-output-log.html +30 -0
- data/site-local/plugins/report-tests-teamcity-stdout.html +30 -0
- data/site-local/plugins/valgrind.html +30 -0
- data/site-local/project/release-history.html +30 -0
- data/site-local/project/upgrade.html +30 -0
- data/site-local/reference/build-directives.html +30 -0
- data/site-local/reference/command-line.html +30 -0
- data/site-local/reference/environment-vars.html +30 -0
- data/site-local/reference/gcov-plugin.html +30 -0
- data/site-local/reference/global-collections.html +30 -0
- data/site-local/reference/index.html +30 -0
- data/site-local/reference/partials-macros.html +30 -0
- data/site-local/reference/project-configuration.html +30 -0
- data/site-local/sitemap.xml.gz +0 -0
- data/site-local/snapshot/examples/cipher_quest/index.html +30 -0
- data/site-local/snapshot/examples/temp_sensor/index.html +30 -0
- data/site-local/snapshot/examples/wondrous_forest/index.html +30 -0
- data/site-local/testing-guide/build-directives.html +30 -0
- data/site-local/testing-guide/conventions.html +30 -0
- data/site-local/testing-guide/frameworks.html +30 -0
- data/site-local/testing-guide/index.html +30 -0
- data/site-local/testing-guide/partials/configuration.html +30 -0
- data/site-local/testing-guide/partials/conventions.html +30 -0
- data/site-local/testing-guide/partials/directives.html +30 -0
- data/site-local/testing-guide/partials/example.html +30 -0
- data/site-local/testing-guide/partials/index.html +30 -0
- data/site-local/testing-guide/partials/overview.html +30 -0
- data/site-local/testing-guide/partials/variables.html +30 -0
- data/site-local/testing-guide/test-cases.html +30 -0
- data/site-local/testing-guide/test-sample.html +30 -0
- data/site-local/testing-guide/test-suite-anatomy.html +30 -0
- data/spec/support/system/spec_system_helper.rb +25 -0
- data/spec/system/deployment_as_gem_spec.rb +12 -0
- data/spec/system/deployment_as_vendor_spec.rb +17 -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 +137 -0
- data/spec/units/c_extractor/c_extractor_declarations_spec.rb +27 -4
- data/spec/units/c_extractor/c_extractor_functions_spec.rb +1 -11
- data/spec/units/c_extractor/c_extractor_integration_spec.rb +18 -11
- data/spec/units/c_extractor/c_extractor_spec.rb +57 -1
- data/spec/units/config/configurator_setup_spec.rb +61 -0
- data/spec/units/file_path_utils_spec.rb +17 -0
- data/spec/units/generators/generator_helper_spec.rb +34 -7
- data/spec/units/generators/generator_partials_spec.rb +120 -12
- data/spec/units/generators/generator_test_results_backtrace_spec.rb +200 -37
- data/spec/units/includes/include_spec.rb +30 -18
- data/spec/units/includes/includes_spec.rb +100 -10
- data/spec/units/partials/partializer_spec.rb +113 -1
- data/spec/units/partials/partializer_utils_spec.rb +11 -0
- data/spec/units/preprocess/preprocessinator_includes_handler_spec.rb +96 -7
- data/spec/units/system_wrapper_spec.rb +72 -0
- metadata +19 -2
|
@@ -1865,6 +1865,8 @@
|
|
|
1865
1865
|
|
|
1866
1866
|
|
|
1867
1867
|
|
|
1868
|
+
|
|
1869
|
+
|
|
1868
1870
|
|
|
1869
1871
|
|
|
1870
1872
|
|
|
@@ -2012,6 +2014,34 @@
|
|
|
2012
2014
|
|
|
2013
2015
|
|
|
2014
2016
|
|
|
2017
|
+
<li class="md-nav__item">
|
|
2018
|
+
<a href="../configuration/reference/partials.html" class="md-nav__link">
|
|
2019
|
+
|
|
2020
|
+
|
|
2021
|
+
|
|
2022
|
+
<span class="md-ellipsis">
|
|
2023
|
+
|
|
2024
|
+
|
|
2025
|
+
Partials Settings
|
|
2026
|
+
|
|
2027
|
+
|
|
2028
|
+
|
|
2029
|
+
</span>
|
|
2030
|
+
|
|
2031
|
+
|
|
2032
|
+
|
|
2033
|
+
</a>
|
|
2034
|
+
</li>
|
|
2035
|
+
|
|
2036
|
+
|
|
2037
|
+
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
|
|
2041
|
+
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
|
|
2015
2045
|
<li class="md-nav__item">
|
|
2016
2046
|
<a href="../configuration/reference/release-build.html" class="md-nav__link">
|
|
2017
2047
|
|
|
@@ -1876,6 +1876,8 @@
|
|
|
1876
1876
|
|
|
1877
1877
|
|
|
1878
1878
|
|
|
1879
|
+
|
|
1880
|
+
|
|
1879
1881
|
|
|
1880
1882
|
|
|
1881
1883
|
|
|
@@ -2023,6 +2025,34 @@
|
|
|
2023
2025
|
|
|
2024
2026
|
|
|
2025
2027
|
|
|
2028
|
+
<li class="md-nav__item">
|
|
2029
|
+
<a href="../configuration/reference/partials.html" class="md-nav__link">
|
|
2030
|
+
|
|
2031
|
+
|
|
2032
|
+
|
|
2033
|
+
<span class="md-ellipsis">
|
|
2034
|
+
|
|
2035
|
+
|
|
2036
|
+
Partials Settings
|
|
2037
|
+
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
</span>
|
|
2041
|
+
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
</a>
|
|
2045
|
+
</li>
|
|
2046
|
+
|
|
2047
|
+
|
|
2048
|
+
|
|
2049
|
+
|
|
2050
|
+
|
|
2051
|
+
|
|
2052
|
+
|
|
2053
|
+
|
|
2054
|
+
|
|
2055
|
+
|
|
2026
2056
|
<li class="md-nav__item">
|
|
2027
2057
|
<a href="../configuration/reference/release-build.html" class="md-nav__link">
|
|
2028
2058
|
|
|
@@ -185,6 +185,21 @@ def valgrind_available?
|
|
|
185
185
|
tool_available?('valgrind --version 2>&1')
|
|
186
186
|
end
|
|
187
187
|
|
|
188
|
+
# Real UBSan support is Linux-specific in practice for this test suite -- macOS's
|
|
189
|
+
# system `gcc` is really Clang under a compatibility shim with different sanitizer
|
|
190
|
+
# runtime behavior, and MinGW gcc on Windows doesn't ship the sanitizer runtime at
|
|
191
|
+
# all. Restricting to Linux avoids flaky, platform-dependent compiler probing.
|
|
192
|
+
def ubsan_available?
|
|
193
|
+
return false unless RUBY_PLATFORM.downcase.include?('linux')
|
|
194
|
+
|
|
195
|
+
Dir.mktmpdir do |dir|
|
|
196
|
+
source = File.join(dir, 'ubsan_check.c')
|
|
197
|
+
binary = File.join(dir, 'ubsan_check')
|
|
198
|
+
File.write(source, "int main(void) { return 0; }\n")
|
|
199
|
+
tool_available?(%(gcc -fsanitize=undefined -o "#{binary}" "#{source}" 2>&1))
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
188
203
|
RSpec.shared_context "requires gdb" do
|
|
189
204
|
before :all do
|
|
190
205
|
@gdb_available = gdb_available?
|
|
@@ -204,3 +219,13 @@ RSpec.shared_context "requires valgrind" do
|
|
|
204
219
|
skip "valgrind is not installed or not in PATH" unless @valgrind_available
|
|
205
220
|
end
|
|
206
221
|
end
|
|
222
|
+
|
|
223
|
+
RSpec.shared_context "requires gcc with UBSan" do
|
|
224
|
+
before :all do
|
|
225
|
+
@ubsan_available = ubsan_available?
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
before do
|
|
229
|
+
skip "gcc UBSan support not available (Linux + gcc -fsanitize=undefined required)" unless @ubsan_available
|
|
230
|
+
end
|
|
231
|
+
end
|
|
@@ -62,6 +62,11 @@ ceedling_system_tests do
|
|
|
62
62
|
test_case :test_project_with_preprocessing_for_mocks
|
|
63
63
|
test_case :test_project_with_preprocessing_for_missing_mock
|
|
64
64
|
test_case :test_project_with_preprocessing_all
|
|
65
|
+
test_case :test_project_preprocessing_same_dir_mock_pairing
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe "Partials" do
|
|
69
|
+
test_case :test_project_partial_all_module_mocks_declaration_only_function
|
|
65
70
|
end
|
|
66
71
|
|
|
67
72
|
describe "Defines and configuration" do
|
|
@@ -92,6 +97,13 @@ ceedling_system_tests do
|
|
|
92
97
|
test_case :crash_simple_sigsegv_all_test_cases
|
|
93
98
|
test_case :crash_simple_sigabrt_assert_failure
|
|
94
99
|
test_case :crash_simple_sigsegv_with_parameterized_test
|
|
100
|
+
test_case :crash_simple_diagnostic_retry_disagrees_with_main_fixture
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe "Crash handling with real UBSan" do
|
|
104
|
+
include_context "requires gcc with UBSan"
|
|
105
|
+
|
|
106
|
+
test_case :crash_simple_ubsan_diagnostic_retry_disagrees_with_main_fixture
|
|
95
107
|
end
|
|
96
108
|
|
|
97
109
|
describe "Backtrace with GDB" do
|
|
@@ -65,6 +65,11 @@ ceedling_system_tests do
|
|
|
65
65
|
test_case :test_project_with_preprocessing_for_mocks
|
|
66
66
|
test_case :test_project_with_preprocessing_for_missing_mock
|
|
67
67
|
test_case :test_project_with_preprocessing_all
|
|
68
|
+
test_case :test_project_preprocessing_same_dir_mock_pairing
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "Partials" do
|
|
72
|
+
test_case :test_project_partial_all_module_mocks_declaration_only_function
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
describe "Defines and configuration" do
|
|
@@ -95,6 +100,13 @@ ceedling_system_tests do
|
|
|
95
100
|
test_case :crash_simple_sigsegv_all_test_cases
|
|
96
101
|
test_case :crash_simple_sigabrt_assert_failure
|
|
97
102
|
test_case :crash_simple_sigsegv_with_parameterized_test
|
|
103
|
+
test_case :crash_simple_diagnostic_retry_disagrees_with_main_fixture
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "Crash handling with real UBSan" do
|
|
107
|
+
include_context "requires gcc with UBSan"
|
|
108
|
+
|
|
109
|
+
test_case :crash_simple_ubsan_diagnostic_retry_disagrees_with_main_fixture
|
|
98
110
|
end
|
|
99
111
|
|
|
100
112
|
describe "Backtrace with GDB" do
|
|
@@ -172,6 +184,11 @@ ceedling_system_tests do
|
|
|
172
184
|
test_case :test_project_with_preprocessing_for_mocks
|
|
173
185
|
test_case :test_project_with_preprocessing_for_missing_mock
|
|
174
186
|
test_case :test_project_with_preprocessing_all
|
|
187
|
+
test_case :test_project_preprocessing_same_dir_mock_pairing
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
describe "Partials" do
|
|
191
|
+
test_case :test_project_partial_all_module_mocks_declaration_only_function
|
|
175
192
|
end
|
|
176
193
|
|
|
177
194
|
describe "Defines and configuration" do
|
|
@@ -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+67/)
|
|
135
|
+
expect(output).to match(/PASSED:\s+67/)
|
|
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+67/)
|
|
148
|
+
expect(output).to match(/PASSED:\s+67/)
|
|
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+67/)
|
|
50
|
+
expect(@output).to match(/PASSED:\s+67/)
|
|
51
51
|
expect(@output).to match(/FAILED:\s+0/)
|
|
52
52
|
end
|
|
53
53
|
end
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
# SPDX-License-Identifier: MIT
|
|
6
6
|
# =========================================================================
|
|
7
7
|
|
|
8
|
+
require 'rbconfig'
|
|
9
|
+
|
|
8
10
|
module CommonSystemTestCases
|
|
9
11
|
def can_report_version_no_git_commit_sha
|
|
10
12
|
@c.with_context do
|
|
@@ -437,6 +439,69 @@ module CommonSystemTestCases
|
|
|
437
439
|
end
|
|
438
440
|
end
|
|
439
441
|
|
|
442
|
+
# A module splits its function declarations (same_dir_pairing_module_func.h, mocked by
|
|
443
|
+
# this test) from its type declarations (same_dir_pairing_module.h, reached only
|
|
444
|
+
# transitively via same_dir_pairing_other.h, never included directly by the test). All
|
|
445
|
+
# of these files are colocated in the test's own directory, which is what exercises
|
|
446
|
+
# GCC's same-directory quoted #include resolution during bare-includes extraction.
|
|
447
|
+
# Auto source-pairing must not pull the real source implementing the type header's
|
|
448
|
+
# like-named stem into this build alongside its mock of the differently-named header.
|
|
449
|
+
def test_project_preprocessing_same_dir_mock_pairing
|
|
450
|
+
@c.with_context do
|
|
451
|
+
Dir.chdir @proj_name do
|
|
452
|
+
FileUtils.cp test_asset_path("same_dir_pairing_module.h"), 'test/'
|
|
453
|
+
FileUtils.cp test_asset_path("same_dir_pairing_module_func.h"), 'test/'
|
|
454
|
+
FileUtils.cp test_asset_path("same_dir_pairing_module.c"), 'test/'
|
|
455
|
+
FileUtils.cp test_asset_path("same_dir_pairing_other.h"), 'test/'
|
|
456
|
+
FileUtils.cp test_asset_path("same_dir_pairing_other.c"), 'test/'
|
|
457
|
+
FileUtils.cp test_asset_path("test_same_dir_pairing.c"), 'test/'
|
|
458
|
+
|
|
459
|
+
settings = {
|
|
460
|
+
:project => { :use_test_preprocessor => :all },
|
|
461
|
+
:paths => {
|
|
462
|
+
:source => ['src/**', 'test/**'],
|
|
463
|
+
:include => ['src/**', 'test/**']
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
@c.merge_project_yml_for_test(settings)
|
|
467
|
+
|
|
468
|
+
output = @c.ceedling_build_exec("test:same_dir_pairing")
|
|
469
|
+
expect(@c.last_exit_status).to eq(0) # Successful build and tests
|
|
470
|
+
expect(output).to match(/TESTED:\s+1/)
|
|
471
|
+
expect(output).to match(/PASSED:\s+1/)
|
|
472
|
+
expect(output).to match(/FAILED:\s+0/)
|
|
473
|
+
expect(output).not_to match(/multiple definition|duplicate symbol/)
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# A module header with both a plain (non-inline) function prototype and a `static
|
|
479
|
+
# inline` function, with no paired .c source providing a body for the plain prototype
|
|
480
|
+
# (so it exists only as a bare declaration, never a definition). MOCK_PARTIAL_ALL_MODULE()
|
|
481
|
+
# must mock both functions, not just the one with a body.
|
|
482
|
+
def test_project_partial_all_module_mocks_declaration_only_function
|
|
483
|
+
@c.with_context do
|
|
484
|
+
Dir.chdir @proj_name do
|
|
485
|
+
FileUtils.cp test_asset_path("partial_all_module.h"), 'src/'
|
|
486
|
+
FileUtils.cp test_asset_path("test_partial_all_module.c"), 'test/'
|
|
487
|
+
|
|
488
|
+
settings = {
|
|
489
|
+
:project => {
|
|
490
|
+
:use_partials => true,
|
|
491
|
+
:use_test_preprocessor => :all
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
@c.merge_project_yml_for_test(settings)
|
|
495
|
+
|
|
496
|
+
output = @c.ceedling_build_exec("test:partial_all_module")
|
|
497
|
+
expect(@c.last_exit_status).to eq(0) # Successful build and tests
|
|
498
|
+
expect(output).to match(/TESTED:\s+1/)
|
|
499
|
+
expect(output).to match(/PASSED:\s+1/)
|
|
500
|
+
expect(output).to match(/FAILED:\s+0/)
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
|
|
440
505
|
def test_project_fail
|
|
441
506
|
@c.with_context do
|
|
442
507
|
Dir.chdir @proj_name do
|
|
@@ -982,6 +1047,78 @@ module CommonSystemTestCases
|
|
|
982
1047
|
end
|
|
983
1048
|
end
|
|
984
1049
|
|
|
1050
|
+
# Regression test for issue #1198: a custom :test_fixture tool (e.g. a wrapper
|
|
1051
|
+
# enabling a sanitizer's halt-on-error) can correctly detect a crash on the main run,
|
|
1052
|
+
# only for that crash to be silently overwritten by a :simple backtrace diagnostic
|
|
1053
|
+
# retry that runs through a *different*, independently-configured tool
|
|
1054
|
+
# (test_fixture_simple_backtrace) and behaves differently there -- legitimately
|
|
1055
|
+
# passing in that other environment. fake_crash_test_fixture.rb reproduces the
|
|
1056
|
+
# mismatch without needing a real sanitizer: it always exits nonzero without ever
|
|
1057
|
+
# running the real, bug-free test executable it's given, while the unmodified default
|
|
1058
|
+
# backtrace retry tool runs that same executable directly and passes.
|
|
1059
|
+
def crash_simple_diagnostic_retry_disagrees_with_main_fixture
|
|
1060
|
+
@c.with_context do
|
|
1061
|
+
Dir.chdir @proj_name do
|
|
1062
|
+
FileUtils.cp test_asset_path("example_file.h"), 'src/'
|
|
1063
|
+
FileUtils.cp test_asset_path("example_file.c"), 'src/'
|
|
1064
|
+
FileUtils.cp test_asset_path("test_example_file_success.c"), 'test/'
|
|
1065
|
+
FileUtils.cp test_asset_path("fake_crash_test_fixture.rb"), 'test/'
|
|
1066
|
+
|
|
1067
|
+
@c.merge_project_yml_for_test({
|
|
1068
|
+
:project => { :use_backtrace => :simple },
|
|
1069
|
+
:tools => {
|
|
1070
|
+
:test_fixture => {
|
|
1071
|
+
:executable => RbConfig.ruby,
|
|
1072
|
+
:arguments => ['test/fake_crash_test_fixture.rb']
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
})
|
|
1076
|
+
|
|
1077
|
+
output = @c.ceedling_build_exec("test:all")
|
|
1078
|
+
expect(@c.last_exit_status).not_to eq(0)
|
|
1079
|
+
expect(output).to match(/Unit test failures/)
|
|
1080
|
+
expect(output).not_to match(/PASSED:\s+1/)
|
|
1081
|
+
end
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
# Same regression coverage as crash_simple_diagnostic_retry_disagrees_with_main_fixture
|
|
1086
|
+
# above, but with a real UBSan-triggered crash (matching issue #1198's own
|
|
1087
|
+
# reproduction exactly) instead of the portable simulated fixture. UBSan doesn't
|
|
1088
|
+
# produce an OS-level crash signal the way a segfault does -- run_with_ubsan.rb's
|
|
1089
|
+
# halt_on_error setting is what turns the undefined behavior into a hard stop, and
|
|
1090
|
+
# only the main :test_fixture invocation goes through that wrapper. Requires a Linux
|
|
1091
|
+
# gcc toolchain with -fsanitize=undefined support -- see "requires gcc with UBSan".
|
|
1092
|
+
def crash_simple_ubsan_diagnostic_retry_disagrees_with_main_fixture
|
|
1093
|
+
@c.with_context do
|
|
1094
|
+
Dir.chdir @proj_name do
|
|
1095
|
+
FileUtils.cp test_asset_path("test_example_file_ub_shift_overflow.c"), 'test/'
|
|
1096
|
+
FileUtils.cp test_asset_path("run_with_ubsan.rb"), 'test/'
|
|
1097
|
+
|
|
1098
|
+
@c.merge_project_yml_for_test({
|
|
1099
|
+
:project => { :use_backtrace => :simple },
|
|
1100
|
+
:flags => {
|
|
1101
|
+
:test => {
|
|
1102
|
+
:compile => { '*' => ['-fsanitize=undefined'] },
|
|
1103
|
+
:link => { '*' => ['-fsanitize=undefined'] }
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
:tools => {
|
|
1107
|
+
:test_fixture => {
|
|
1108
|
+
:executable => RbConfig.ruby,
|
|
1109
|
+
:arguments => ['test/run_with_ubsan.rb', '${1}']
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
})
|
|
1113
|
+
|
|
1114
|
+
output = @c.ceedling_build_exec("test:all")
|
|
1115
|
+
expect(@c.last_exit_status).not_to eq(0)
|
|
1116
|
+
expect(output).to match(/Unit test failures/)
|
|
1117
|
+
expect(output).not_to match(/PASSED:\s+1/)
|
|
1118
|
+
end
|
|
1119
|
+
end
|
|
1120
|
+
end
|
|
1121
|
+
|
|
985
1122
|
def project_with_test_file_directly_including_source_file
|
|
986
1123
|
@c.with_context do
|
|
987
1124
|
Dir.chdir @proj_name do
|
|
@@ -19,11 +19,10 @@ describe CExtractorDeclarations do
|
|
|
19
19
|
describe "#try_extract_variable" do
|
|
20
20
|
# Helper to create extractor and test variable extraction
|
|
21
21
|
let(:extract_variable) do
|
|
22
|
-
->(content
|
|
22
|
+
->(content) do
|
|
23
23
|
scanner = StringScanner.new(content)
|
|
24
24
|
declarations = CExtractorDeclarations.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
25
25
|
declarations.setup()
|
|
26
|
-
declarations.max_line_length = max_line_length
|
|
27
26
|
success, variable = declarations.try_extract_variable(scanner)
|
|
28
27
|
return [success, variable, scanner.pos, scanner.rest]
|
|
29
28
|
end
|
|
@@ -194,11 +193,35 @@ describe CExtractorDeclarations do
|
|
|
194
193
|
success, variable, pos, rest = extract_variable.call(content)
|
|
195
194
|
|
|
196
195
|
expect(success).to be true
|
|
197
|
-
# Leading `const` is a decorator;
|
|
198
|
-
|
|
196
|
+
# Leading `const` (qualifying `int`) is a decorator; the second `const`
|
|
197
|
+
# (qualifying the pointer itself) is part of the declarator and stays put
|
|
198
|
+
check_single(variable, name: 'ptr', type: 'int* const', decorators: ['const'], text: 'int* const ptr;')
|
|
199
199
|
expect(pos).to eq(21)
|
|
200
200
|
expect(rest).to eq("")
|
|
201
201
|
end
|
|
202
|
+
|
|
203
|
+
it "extracts volatile pointer to volatile" do
|
|
204
|
+
content = "volatile int* volatile ptr;"
|
|
205
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
206
|
+
|
|
207
|
+
expect(success).to be true
|
|
208
|
+
# Same as const/const above: only the leading qualifier is a decorator
|
|
209
|
+
check_single(variable, name: 'ptr', type: 'int* volatile', decorators: ['volatile'], text: 'int* volatile ptr;')
|
|
210
|
+
expect(pos).to eq(27)
|
|
211
|
+
expect(rest).to eq("")
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "extracts static const pointer to const" do
|
|
215
|
+
content = "static const int* const ptr;"
|
|
216
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
217
|
+
|
|
218
|
+
expect(success).to be true
|
|
219
|
+
# `static` and the leading `const` are decorators; the trailing `const`
|
|
220
|
+
# on the pointer itself is retained in both `.type` and `.text`
|
|
221
|
+
check_single(variable, name: 'ptr', type: 'int* const', decorators: ['static', 'const'], text: 'int* const ptr;')
|
|
222
|
+
expect(pos).to eq(28)
|
|
223
|
+
expect(rest).to eq("")
|
|
224
|
+
end
|
|
202
225
|
end
|
|
203
226
|
|
|
204
227
|
context "array variable declarations" do
|
|
@@ -20,11 +20,10 @@ describe CExtractorFunctions do
|
|
|
20
20
|
describe "#extract_function_signature (private method testing)" do
|
|
21
21
|
# Helper to access private method
|
|
22
22
|
let(:extract_signature) do
|
|
23
|
-
->(content, type
|
|
23
|
+
->(content, type) do
|
|
24
24
|
scanner = StringScanner.new(content)
|
|
25
25
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
26
26
|
functions.setup()
|
|
27
|
-
functions.max_line_length = max_line_length
|
|
28
27
|
signature = functions.send( :extract_function_signature, scanner, type )
|
|
29
28
|
return [signature, scanner.pos, scanner.rest]
|
|
30
29
|
end
|
|
@@ -797,7 +796,6 @@ describe CExtractorFunctions do
|
|
|
797
796
|
->(signature) do
|
|
798
797
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
799
798
|
functions.setup()
|
|
800
|
-
functions.max_line_length = 1000
|
|
801
799
|
name = functions.send( :extract_function_name, signature )
|
|
802
800
|
return name
|
|
803
801
|
end
|
|
@@ -1485,7 +1483,6 @@ describe CExtractorFunctions do
|
|
|
1485
1483
|
scanner = StringScanner.new(content)
|
|
1486
1484
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
1487
1485
|
functions.setup()
|
|
1488
|
-
functions.max_line_length = 1000
|
|
1489
1486
|
success, func = functions.try_extract_function_definition( scanner, filepath )
|
|
1490
1487
|
return [success, func, scanner.pos, scanner.rest]
|
|
1491
1488
|
end
|
|
@@ -2036,7 +2033,6 @@ describe CExtractorFunctions do
|
|
|
2036
2033
|
scanner = StringScanner.new(content)
|
|
2037
2034
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
2038
2035
|
functions.setup()
|
|
2039
|
-
functions.max_line_length = 1000
|
|
2040
2036
|
|
|
2041
2037
|
success1, func1 = functions.try_extract_function_definition(scanner, filepath)
|
|
2042
2038
|
expect(success1).to be true
|
|
@@ -2067,7 +2063,6 @@ describe CExtractorFunctions do
|
|
|
2067
2063
|
code_text = CExtractorCodeText.new()
|
|
2068
2064
|
functions = CExtractorFunctions.new({ c_extractor_code_text: code_text })
|
|
2069
2065
|
functions.setup()
|
|
2070
|
-
functions.max_line_length = 1000
|
|
2071
2066
|
|
|
2072
2067
|
success1, func1 = functions.try_extract_function_definition(scanner, filepath)
|
|
2073
2068
|
expect(success1).to be true
|
|
@@ -2106,7 +2101,6 @@ describe CExtractorFunctions do
|
|
|
2106
2101
|
scanner = StringScanner.new(content)
|
|
2107
2102
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
2108
2103
|
functions.setup()
|
|
2109
|
-
functions.max_line_length = 1000
|
|
2110
2104
|
|
|
2111
2105
|
success1, func1 = functions.try_extract_function_definition(scanner, filepath)
|
|
2112
2106
|
expect(success1).to be true
|
|
@@ -2130,7 +2124,6 @@ describe CExtractorFunctions do
|
|
|
2130
2124
|
let(:functions) do
|
|
2131
2125
|
f = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
2132
2126
|
f.setup()
|
|
2133
|
-
f.max_line_length = 1000
|
|
2134
2127
|
f
|
|
2135
2128
|
end
|
|
2136
2129
|
|
|
@@ -2364,7 +2357,6 @@ describe CExtractorFunctions do
|
|
|
2364
2357
|
let(:functions) do
|
|
2365
2358
|
f = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
2366
2359
|
f.setup()
|
|
2367
|
-
f.max_line_length = 1000
|
|
2368
2360
|
f
|
|
2369
2361
|
end
|
|
2370
2362
|
|
|
@@ -2482,7 +2474,6 @@ describe CExtractorFunctions do
|
|
|
2482
2474
|
scanner = StringScanner.new(content)
|
|
2483
2475
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
2484
2476
|
functions.setup()
|
|
2485
|
-
functions.max_line_length = 1000
|
|
2486
2477
|
success, decl = functions.try_extract_function_declaration(scanner)
|
|
2487
2478
|
return [success, decl, scanner.pos, scanner.rest]
|
|
2488
2479
|
end
|
|
@@ -2711,7 +2702,6 @@ describe CExtractorFunctions do
|
|
|
2711
2702
|
scanner = StringScanner.new(content)
|
|
2712
2703
|
functions = CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new() })
|
|
2713
2704
|
functions.setup()
|
|
2714
|
-
functions.max_line_length = 1000
|
|
2715
2705
|
success, func = functions.try_extract_function_definition( scanner, filepath )
|
|
2716
2706
|
return [success, func]
|
|
2717
2707
|
end
|
|
@@ -34,7 +34,11 @@ describe CExtractor do
|
|
|
34
34
|
c_extractor_functions: functions,
|
|
35
35
|
c_extractor_declarations: declarations,
|
|
36
36
|
c_extractor_preprocessing: preprocessing,
|
|
37
|
-
c_extractor_definitions: definitions
|
|
37
|
+
c_extractor_definitions: definitions,
|
|
38
|
+
# Bare double (no :partials_max_extraction_length stub) so #respond_to? is
|
|
39
|
+
# false and CExtractor falls back to its own built-in default buffer length.
|
|
40
|
+
configurator: double('Configurator'),
|
|
41
|
+
loginator: double('Loginator').as_null_object
|
|
38
42
|
}
|
|
39
43
|
)
|
|
40
44
|
extractor.setup()
|
|
@@ -602,18 +606,21 @@ describe CExtractor do
|
|
|
602
606
|
CONTENTS
|
|
603
607
|
|
|
604
608
|
# TODO: Test for function name extraction after implementing generic handling of feature summaries
|
|
605
|
-
expect { extractor.from_string(content: file_contents, chunk_size: 10, max_buffer_length: 20) }.to raise_error(CeedlingException, /
|
|
609
|
+
expect { extractor.from_string(content: file_contents, chunk_size: 10, max_buffer_length: 20) }.to raise_error(CeedlingException, /Extraction exceeded maximum length/)
|
|
606
610
|
end
|
|
607
611
|
|
|
608
|
-
it "should
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
612
|
+
it "should extract a variable declaration longer than 1000 characters" do
|
|
613
|
+
# A single limit governs every feature type (see extract_next_feature); this confirms a
|
|
614
|
+
# declaration comfortably longer than the old, now-removed 1000-character inner limit is
|
|
615
|
+
# captured rather than silently dropped, as long as it's within the (much larger) buffer
|
|
616
|
+
# ceiling -- the default here, since none is passed explicitly.
|
|
617
|
+
values = (1..400).map { |n| n.to_s }.join(', ')
|
|
618
|
+
file_contents = "static const int a_table[] = { #{values} };\n"
|
|
619
|
+
expect(file_contents.length).to be > 1000
|
|
620
|
+
|
|
621
|
+
contents = extractor.from_string(content: file_contents)
|
|
622
|
+
expect(contents.variable_declarations.length).to eq 1
|
|
623
|
+
expect(contents.variable_declarations[0].name).to eq 'a_table'
|
|
617
624
|
end
|
|
618
625
|
|
|
619
626
|
it "should extract typedef definitions and no other features from a typedefs-only input" do
|
|
@@ -21,6 +21,58 @@ require 'stringio'
|
|
|
21
21
|
##
|
|
22
22
|
describe CExtractor do
|
|
23
23
|
|
|
24
|
+
###
|
|
25
|
+
### setup() / default_max_buffer_length() -- :partials -> :max_extraction_length wiring
|
|
26
|
+
###
|
|
27
|
+
describe "#setup (private method testing)" do
|
|
28
|
+
# Helper to build a CExtractor with a given configurator double, without wiring the
|
|
29
|
+
# other collaborators -- default_max_buffer_length only reads @configurator
|
|
30
|
+
let(:build_extractor) do
|
|
31
|
+
->(configurator) do
|
|
32
|
+
extractor = CExtractor.new(
|
|
33
|
+
{
|
|
34
|
+
c_extractor_code_text: CExtractorCodeText.new,
|
|
35
|
+
c_extractor_functions: CExtractorFunctions.new({ c_extractor_code_text: CExtractorCodeText.new }),
|
|
36
|
+
c_extractor_declarations: CExtractorDeclarations.new({ c_extractor_code_text: CExtractorCodeText.new }),
|
|
37
|
+
c_extractor_preprocessing: CExtractorPreprocessing.new({ c_extractor_code_text: CExtractorCodeText.new }),
|
|
38
|
+
c_extractor_definitions: CExtractorDefinitions.new({ c_extractor_code_text: CExtractorCodeText.new }),
|
|
39
|
+
configurator: configurator,
|
|
40
|
+
loginator: double('Loginator').as_null_object
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
extractor.setup()
|
|
44
|
+
extractor
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "scales :partials_max_extraction_length by 1000 when the configurator provides it" do
|
|
49
|
+
configurator = double('Configurator', partials_max_extraction_length: 7)
|
|
50
|
+
extractor = build_extractor.call(configurator)
|
|
51
|
+
|
|
52
|
+
expect(extractor.send(:default_max_buffer_length)).to eq(7000)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "falls back to the built-in default when the configurator doesn't provide it" do
|
|
56
|
+
# A bare double with no stub -- #respond_to? is false, exactly like direct/test
|
|
57
|
+
# construction of this class where no real project configuration is available.
|
|
58
|
+
configurator = double('Configurator')
|
|
59
|
+
extractor = build_extractor.call(configurator)
|
|
60
|
+
|
|
61
|
+
expect(extractor.send(:default_max_buffer_length)).to eq(CExtractorConstants::DEFAULT_MAX_FUNCTION_LENGTH)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "setup() itself assigns @max_buffer_length from default_max_buffer_length" do
|
|
65
|
+
configurator = double('Configurator', partials_max_extraction_length: 3)
|
|
66
|
+
extractor = build_extractor.call(configurator)
|
|
67
|
+
|
|
68
|
+
# @max_buffer_length has no reader; drive behavior through from_string, which raises
|
|
69
|
+
# once the buffer set up by setup() is exceeded.
|
|
70
|
+
expect {
|
|
71
|
+
extractor.from_string(content: ('x' * 3001), chunk_size: 500)
|
|
72
|
+
}.to raise_error(CeedlingException, /exceeded maximum length of 3000 characters/)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
24
76
|
###
|
|
25
77
|
### extract_next_feature()
|
|
26
78
|
###
|
|
@@ -55,7 +107,11 @@ describe CExtractor do
|
|
|
55
107
|
c_extractor_functions: functions,
|
|
56
108
|
c_extractor_declarations: declarations,
|
|
57
109
|
c_extractor_preprocessing: preprocessing,
|
|
58
|
-
c_extractor_definitions: definitions
|
|
110
|
+
c_extractor_definitions: definitions,
|
|
111
|
+
# Bare double (no :partials_max_extraction_length stub) so #respond_to? is
|
|
112
|
+
# false and CExtractor falls back to its own built-in default buffer length.
|
|
113
|
+
configurator: double('Configurator'),
|
|
114
|
+
loginator: double('Loginator').as_null_object
|
|
59
115
|
}
|
|
60
116
|
)
|
|
61
117
|
extractor.setup()
|