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
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
require 'spec_helper'
|
|
9
9
|
require 'ceedling/generators/generator_test_results_backtrace'
|
|
10
|
+
require 'ceedling/generators/generator_helper'
|
|
10
11
|
require 'ceedling/constants'
|
|
12
|
+
require 'ceedling/exceptions'
|
|
11
13
|
|
|
12
14
|
# ── Representative gdb output constants ──────────────────────────────────────
|
|
13
15
|
|
|
@@ -125,9 +127,9 @@ SIMPLE_ASSERT_CRASH_OUTPUT =
|
|
|
125
127
|
"test_lib.out: src/lib.c:5: asserting: Assertion `0' failed.\n" \
|
|
126
128
|
"Aborted (core dumped)\n"
|
|
127
129
|
|
|
128
|
-
SIMPLE_PASS_OUTPUT = "test_lib.c:3:test_empty:PASS\n"
|
|
129
|
-
SIMPLE_FAIL_OUTPUT = "test_lib.c:8:test_bad:FAIL: Expected 1 Was 2\n"
|
|
130
|
-
SIMPLE_IGNORE_OUTPUT = "test_lib.c:12:test_skip:IGNORE\n"
|
|
130
|
+
SIMPLE_PASS_OUTPUT = "test_lib.c:3:test_empty:PASS\n---------\n1 Tests 0 Failures 0 Ignored\nOK\n"
|
|
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
|
+
SIMPLE_IGNORE_OUTPUT = "test_lib.c:12:test_skip:IGNORE\n---------\n1 Tests 0 Failures 1 Ignored\nOK\n"
|
|
131
133
|
|
|
132
134
|
|
|
133
135
|
describe GeneratorTestResultsBacktrace do
|
|
@@ -140,16 +142,28 @@ describe GeneratorTestResultsBacktrace do
|
|
|
140
142
|
@generator_test_results = instance_double('GeneratorTestResults')
|
|
141
143
|
@file_path_utils = instance_double('FilePathUtils')
|
|
142
144
|
@file_wrapper = instance_double('FileWrapper')
|
|
145
|
+
@loginator = double('loginator').as_null_object
|
|
146
|
+
# A real GeneratorHelper, not a double -- these tests exercise the actual crash
|
|
147
|
+
# detection logic a retry's status is checked against, not a stubbed stand-in for it.
|
|
148
|
+
@generator_helper = GeneratorHelper.new({ :loginator => @loginator })
|
|
143
149
|
|
|
144
150
|
@backtrace = described_class.new({
|
|
145
151
|
:configurator => @configurator,
|
|
146
152
|
:tool_executor => @tool_executor,
|
|
147
153
|
:generator_test_results => @generator_test_results,
|
|
154
|
+
:generator_helper => @generator_helper,
|
|
148
155
|
:file_path_utils => @file_path_utils,
|
|
149
|
-
:file_wrapper => @file_wrapper
|
|
156
|
+
:file_wrapper => @file_wrapper,
|
|
157
|
+
:loginator => @loginator
|
|
150
158
|
})
|
|
151
159
|
@backtrace.setup()
|
|
152
160
|
|
|
161
|
+
# A healthy retry sub-process status -- the common case for most stubs below. Crash
|
|
162
|
+
# scenarios that already resolve via a missing result-line match (the pre-existing
|
|
163
|
+
# "unresolved" path) don't depend on this value at all; it's included on every stub
|
|
164
|
+
# anyway so `crash_result[:status]` is never unexpectedly missing.
|
|
165
|
+
@ok_status = double('status', signaled?: false, success?: true, exitstatus: 0, termsig: nil)
|
|
166
|
+
|
|
153
167
|
# Standard stubs used by most tests
|
|
154
168
|
allow(@tool_executor).to receive(:build_command_line).and_return({ options: {} })
|
|
155
169
|
allow(@file_path_utils).to receive(:form_test_gdb_log) do |test, context:, name:|
|
|
@@ -173,37 +187,113 @@ describe GeneratorTestResultsBacktrace do
|
|
|
173
187
|
allow(@configurator).to receive(:tools_test_backtrace_gdb).and_return({})
|
|
174
188
|
end
|
|
175
189
|
|
|
190
|
+
# Companion helper: a genuinely-crashing group paired alongside the group under
|
|
191
|
+
# test, matching realistic multi-test-case usage -- do_gdb only ever runs because
|
|
192
|
+
# the main run already crashed, so an isolated group with nothing but a clean match
|
|
193
|
+
# is indistinguishable from the #1198 bug pattern (every retry legitimately clean,
|
|
194
|
+
# contradicting the crash that triggered this method) and correctly falls back on
|
|
195
|
+
# its own, tested separately below.
|
|
196
|
+
let(:companion_case) { { test: 'test_crashes_elsewhere', symbol: 'test_crashes_elsewhere', line_number: 20 } }
|
|
197
|
+
|
|
176
198
|
it 'handles a PASS test case and does not write a log' do
|
|
177
|
-
allow(@tool_executor).to receive(:exec)
|
|
178
|
-
|
|
199
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
200
|
+
{ output: GDB_NO_SIGNAL_OUTPUT, time: 0.1, exit_code: 1, stderr: '', status: @ok_status },
|
|
201
|
+
{ output: "test_lib.c:9:test_asserting:PASS\n---------\n1 Tests 0 Failures 0 Ignored\nOK\n",
|
|
202
|
+
time: 0.1, exit_code: 0, stderr: '', status: @ok_status }
|
|
203
|
+
)
|
|
179
204
|
|
|
180
|
-
expect(@file_wrapper).
|
|
205
|
+
expect(@file_wrapper).to receive(:write).once.with(%r{test_crashes_elsewhere}, anything, anything)
|
|
181
206
|
|
|
182
|
-
|
|
207
|
+
expected_output_lines = []
|
|
208
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
209
|
+
expected_output_lines = kwargs[:output]
|
|
210
|
+
'regenerated'
|
|
211
|
+
end
|
|
183
212
|
|
|
184
|
-
|
|
213
|
+
@backtrace.do_gdb( filename, executable, shell_result, [companion_case] + test_cases, context: :test )
|
|
214
|
+
|
|
215
|
+
expect(expected_output_lines).to include('test_lib.c:9:test_asserting:PASS')
|
|
185
216
|
end
|
|
186
217
|
|
|
187
218
|
it 'handles an IGNORE test case and does not write a log' do
|
|
188
|
-
allow(@tool_executor).to receive(:exec)
|
|
189
|
-
|
|
219
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
220
|
+
{ output: GDB_NO_SIGNAL_OUTPUT, time: 0.1, exit_code: 1, stderr: '', status: @ok_status },
|
|
221
|
+
{ output: "test_lib.c:9:test_asserting:IGNORE\n---------\n1 Tests 0 Failures 1 Ignored\nOK\n",
|
|
222
|
+
time: 0.1, exit_code: 0, stderr: '', status: @ok_status }
|
|
223
|
+
)
|
|
190
224
|
|
|
191
|
-
expect(@file_wrapper).
|
|
225
|
+
expect(@file_wrapper).to receive(:write).once.with(%r{test_crashes_elsewhere}, anything, anything)
|
|
192
226
|
|
|
193
|
-
|
|
227
|
+
expected_output_lines = []
|
|
228
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
229
|
+
expected_output_lines = kwargs[:output]
|
|
230
|
+
'regenerated'
|
|
231
|
+
end
|
|
194
232
|
|
|
195
|
-
|
|
233
|
+
@backtrace.do_gdb( filename, executable, shell_result, [companion_case] + test_cases, context: :test )
|
|
234
|
+
|
|
235
|
+
expect(expected_output_lines).to include('test_lib.c:9:test_asserting:IGNORE')
|
|
196
236
|
end
|
|
197
237
|
|
|
198
238
|
it 'handles a FAIL test case and does not write a log' do
|
|
199
|
-
allow(@tool_executor).to receive(:exec)
|
|
200
|
-
|
|
239
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
240
|
+
{ output: GDB_NO_SIGNAL_OUTPUT, time: 0.1, exit_code: 1, stderr: '', status: @ok_status },
|
|
241
|
+
{ output: "test_lib.c:9:test_asserting:FAIL: Expected 1 Was 2\n---------\n1 Tests 1 Failures 0 Ignored\nFAIL\n",
|
|
242
|
+
time: 0.1, exit_code: 1, stderr: '', status: @ok_status }
|
|
243
|
+
)
|
|
201
244
|
|
|
202
|
-
expect(@file_wrapper).
|
|
245
|
+
expect(@file_wrapper).to receive(:write).once.with(%r{test_crashes_elsewhere}, anything, anything)
|
|
246
|
+
|
|
247
|
+
expected_output_lines = []
|
|
248
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
249
|
+
expected_output_lines = kwargs[:output]
|
|
250
|
+
'regenerated'
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
@backtrace.do_gdb( filename, executable, shell_result, [companion_case] + test_cases, context: :test )
|
|
254
|
+
|
|
255
|
+
expect(expected_output_lines).to include('test_lib.c:9:test_asserting:FAIL: Expected 1 Was 2')
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it "does not trust a matched PASS line when the retry's own real status contradicts it" do
|
|
259
|
+
# Regression test for issue #1198: a diagnostic retry can print a clean Unity
|
|
260
|
+
# result line while its own real process outcome says otherwise.
|
|
261
|
+
bad_status = double('status', signaled?: false, success?: false, exitstatus: 1, termsig: nil)
|
|
262
|
+
|
|
263
|
+
allow(@tool_executor).to receive(:exec).and_return({
|
|
264
|
+
output: "test_lib.c:9:test_asserting:PASS\n---------\n1 Tests 0 Failures 0 Ignored\nOK\n",
|
|
265
|
+
time: 0.1, exit_code: 0, stderr: '', status: bad_status
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
expected_output_lines = []
|
|
269
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
270
|
+
expected_output_lines = kwargs[:output]
|
|
271
|
+
'regenerated'
|
|
272
|
+
end
|
|
203
273
|
|
|
204
274
|
result = @backtrace.do_gdb( filename, executable, shell_result, test_cases, context: :test )
|
|
205
275
|
|
|
206
276
|
expect(result[:exit_code]).to eq(1)
|
|
277
|
+
expect(expected_output_lines.first).to include(':FAIL:')
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'falls back to a whole-file crash failure when no retry ever reproduces the crash the main run detected' do
|
|
281
|
+
# Regression test for issue #1198: every retry can legitimately pass in its own,
|
|
282
|
+
# differently-configured environment even though the main run genuinely crashed.
|
|
283
|
+
# An all-clean diagnostic must not be allowed to overrule that.
|
|
284
|
+
allow(@tool_executor).to receive(:exec).and_return({
|
|
285
|
+
output: "test_lib.c:9:test_asserting:PASS\n---------\n1 Tests 0 Failures 0 Ignored\nOK\n",
|
|
286
|
+
time: 0.1, exit_code: 0, stderr: '', status: @ok_status
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
fallback_result = { output: 'crash-failure-output', exit_code: 1 }
|
|
290
|
+
expect(@generator_test_results).to receive(:create_crash_failure)
|
|
291
|
+
.with(filename, shell_result, test_cases)
|
|
292
|
+
.and_return(fallback_result)
|
|
293
|
+
|
|
294
|
+
result = @backtrace.do_gdb( filename, executable, shell_result, test_cases, context: :test )
|
|
295
|
+
|
|
296
|
+
expect(result).to eq(fallback_result)
|
|
207
297
|
end
|
|
208
298
|
|
|
209
299
|
it 'handles a SIGSEGV crash — writes log, includes signal label, backtick source line, and log path' do
|
|
@@ -211,7 +301,7 @@ describe GeneratorTestResultsBacktrace do
|
|
|
211
301
|
filename_sigsegv = 'TestUsartModel.c'
|
|
212
302
|
|
|
213
303
|
allow(@tool_executor).to receive(:exec)
|
|
214
|
-
.and_return({ output: GDB_SIGSEGV_OUTPUT, time: 0.5, exit_code: 139 })
|
|
304
|
+
.and_return({ output: GDB_SIGSEGV_OUTPUT, time: 0.5, exit_code: 139, stderr: '', status: @ok_status })
|
|
215
305
|
|
|
216
306
|
expected_output_lines = []
|
|
217
307
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -241,7 +331,7 @@ describe GeneratorTestResultsBacktrace do
|
|
|
241
331
|
filename_param = 'test_module_d.c'
|
|
242
332
|
|
|
243
333
|
allow(@tool_executor).to receive(:exec)
|
|
244
|
-
.and_return({ output: GDB_SIGSEGV_PARAM_OUTPUT, time: 0.5, exit_code: 139 })
|
|
334
|
+
.and_return({ output: GDB_SIGSEGV_PARAM_OUTPUT, time: 0.5, exit_code: 139, stderr: '', status: @ok_status })
|
|
245
335
|
|
|
246
336
|
expected_output_lines = []
|
|
247
337
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -267,7 +357,7 @@ describe GeneratorTestResultsBacktrace do
|
|
|
267
357
|
test_cases_assert = [{ test: 'test_asserting', symbol: 'test_asserting', line_number: 8 }]
|
|
268
358
|
|
|
269
359
|
allow(@tool_executor).to receive(:exec)
|
|
270
|
-
.and_return({ output: GDB_SIGABRT_ASSERT_OUTPUT, time: 0.3, exit_code: 134 })
|
|
360
|
+
.and_return({ output: GDB_SIGABRT_ASSERT_OUTPUT, time: 0.3, exit_code: 134, stderr: '', status: @ok_status })
|
|
271
361
|
|
|
272
362
|
expected_output_lines = []
|
|
273
363
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -288,7 +378,7 @@ describe GeneratorTestResultsBacktrace do
|
|
|
288
378
|
|
|
289
379
|
it 'handles a crash with no identifiable signal — fallback message, log path without "log: " prefix' do
|
|
290
380
|
allow(@tool_executor).to receive(:exec)
|
|
291
|
-
.and_return({ output: GDB_NO_SIGNAL_OUTPUT, time: 0.1, exit_code: 1 })
|
|
381
|
+
.and_return({ output: GDB_NO_SIGNAL_OUTPUT, time: 0.1, exit_code: 1, stderr: '', status: @ok_status })
|
|
292
382
|
|
|
293
383
|
expected_output_lines = []
|
|
294
384
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -317,42 +407,115 @@ describe GeneratorTestResultsBacktrace do
|
|
|
317
407
|
allow(@configurator).to receive(:tools_test_fixture_simple_backtrace).and_return({})
|
|
318
408
|
end
|
|
319
409
|
|
|
410
|
+
# Each of the three cases below is paired with a companion group that genuinely
|
|
411
|
+
# crashes -- a realistic multi-test-case file, where the group under test is only
|
|
412
|
+
# one of several. Without a companion, an isolated group with nothing but a clean
|
|
413
|
+
# match is indistinguishable from the #1198 bug pattern (every retry legitimately
|
|
414
|
+
# clean, contradicting the crash do_simple only ever runs because of) and correctly
|
|
415
|
+
# triggers the whole-file fallback tested below in its own right.
|
|
416
|
+
|
|
320
417
|
it 'handles a PASS test case' do
|
|
321
|
-
|
|
322
|
-
.and_return({ output: SIMPLE_PASS_OUTPUT, time: 0.05, exit_code: 0 })
|
|
418
|
+
test_cases_multi = [{ test: 'test_crashes_elsewhere', line_number: 20 }] + test_cases
|
|
323
419
|
|
|
324
|
-
|
|
420
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
421
|
+
{ output: SIMPLE_ASSERT_CRASH_OUTPUT, time: 0.1, exit_code: 134, stderr: '', status: @ok_status },
|
|
422
|
+
{ output: SIMPLE_PASS_OUTPUT, time: 0.05, exit_code: 0, stderr: '', status: @ok_status }
|
|
423
|
+
)
|
|
325
424
|
|
|
326
|
-
|
|
425
|
+
expected_output_lines = []
|
|
426
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
427
|
+
expected_output_lines = kwargs[:output]
|
|
428
|
+
'regenerated'
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
@backtrace.do_simple( filename, executable, shell_result, test_cases_multi, context: :test )
|
|
432
|
+
|
|
433
|
+
expect(expected_output_lines).to include('test_lib.c:3:test_empty:PASS')
|
|
327
434
|
end
|
|
328
435
|
|
|
329
436
|
it 'handles a FAIL test case with a message' do
|
|
330
|
-
test_cases_fail = [{ test: 'test_bad', line_number: 8 }]
|
|
437
|
+
test_cases_fail = [{ test: 'test_crashes_elsewhere', line_number: 20 }, { test: 'test_bad', line_number: 8 }]
|
|
331
438
|
|
|
332
|
-
allow(@tool_executor).to receive(:exec)
|
|
333
|
-
|
|
439
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
440
|
+
{ output: SIMPLE_ASSERT_CRASH_OUTPUT, time: 0.1, exit_code: 134, stderr: '', status: @ok_status },
|
|
441
|
+
{ output: SIMPLE_FAIL_OUTPUT, time: 0.05, exit_code: 1, stderr: '', status: @ok_status }
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
expected_output_lines = []
|
|
445
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
446
|
+
expected_output_lines = kwargs[:output]
|
|
447
|
+
'regenerated'
|
|
448
|
+
end
|
|
334
449
|
|
|
335
|
-
|
|
450
|
+
@backtrace.do_simple( filename, executable, shell_result, test_cases_fail, context: :test )
|
|
336
451
|
|
|
337
|
-
expect(
|
|
452
|
+
expect(expected_output_lines).to include('test_lib.c:8:test_bad:FAIL: Expected 1 Was 2')
|
|
338
453
|
end
|
|
339
454
|
|
|
340
455
|
it 'handles an IGNORE test case' do
|
|
341
|
-
test_cases_ignore = [{ test: 'test_skip', line_number: 12 }]
|
|
456
|
+
test_cases_ignore = [{ test: 'test_crashes_elsewhere', line_number: 20 }, { test: 'test_skip', line_number: 12 }]
|
|
457
|
+
|
|
458
|
+
allow(@tool_executor).to receive(:exec).and_return(
|
|
459
|
+
{ output: SIMPLE_ASSERT_CRASH_OUTPUT, time: 0.1, exit_code: 134, stderr: '', status: @ok_status },
|
|
460
|
+
{ output: SIMPLE_IGNORE_OUTPUT, time: 0.02, exit_code: 0, stderr: '', status: @ok_status }
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
expected_output_lines = []
|
|
464
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
465
|
+
expected_output_lines = kwargs[:output]
|
|
466
|
+
'regenerated'
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
@backtrace.do_simple( filename, executable, shell_result, test_cases_ignore, context: :test )
|
|
470
|
+
|
|
471
|
+
expect(expected_output_lines).to include('test_lib.c:12:test_skip:IGNORE')
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
it "does not trust a matched PASS line when the retry's own real status contradicts it" do
|
|
475
|
+
# Regression test for issue #1198: a diagnostic retry can print a clean Unity
|
|
476
|
+
# result line while its own real process outcome says otherwise.
|
|
477
|
+
bad_status = double('status', signaled?: false, success?: false, exitstatus: 1, termsig: nil)
|
|
342
478
|
|
|
343
479
|
allow(@tool_executor).to receive(:exec)
|
|
344
|
-
.and_return({ output:
|
|
480
|
+
.and_return({ output: SIMPLE_PASS_OUTPUT, time: 0.05, exit_code: 0, stderr: '', status: bad_status })
|
|
345
481
|
|
|
346
|
-
|
|
482
|
+
expected_output_lines = []
|
|
483
|
+
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
484
|
+
expected_output_lines = kwargs[:output]
|
|
485
|
+
'regenerated'
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
result = @backtrace.do_simple( filename, executable, shell_result, test_cases, context: :test )
|
|
489
|
+
|
|
490
|
+
expect(result[:exit_code]).to eq(1)
|
|
491
|
+
expect(expected_output_lines.first).to include(':FAIL:')
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
it 'falls back to a whole-file crash failure when no retry ever reproduces the crash the main run detected' do
|
|
495
|
+
# Regression test for issue #1198: the exact reported scenario -- a custom
|
|
496
|
+
# :test_fixture wrapper enables sanitizer halt-on-error and the main run crashes,
|
|
497
|
+
# but the unrelated, independently-configured test_fixture_simple_backtrace tool
|
|
498
|
+
# runs the same executable directly, without the wrapper, and it legitimately
|
|
499
|
+
# passes. Every retry can be entirely clean and still must not overrule a crash
|
|
500
|
+
# Ceedling already established.
|
|
501
|
+
allow(@tool_executor).to receive(:exec)
|
|
502
|
+
.and_return({ output: SIMPLE_PASS_OUTPUT, time: 0.05, exit_code: 0, stderr: '', status: @ok_status })
|
|
503
|
+
|
|
504
|
+
fallback_result = { output: 'crash-failure-output', exit_code: 1 }
|
|
505
|
+
expect(@generator_test_results).to receive(:create_crash_failure)
|
|
506
|
+
.with(filename, shell_result, test_cases)
|
|
507
|
+
.and_return(fallback_result)
|
|
508
|
+
|
|
509
|
+
result = @backtrace.do_simple( filename, executable, shell_result, test_cases, context: :test )
|
|
347
510
|
|
|
348
|
-
expect(result
|
|
511
|
+
expect(result).to eq(fallback_result)
|
|
349
512
|
end
|
|
350
513
|
|
|
351
514
|
it 'handles a crash and includes extra executable output in the failure message' do
|
|
352
515
|
test_cases_crash = [{ test: 'test_asserting', line_number: 8 }]
|
|
353
516
|
|
|
354
517
|
allow(@tool_executor).to receive(:exec)
|
|
355
|
-
.and_return({ output: SIMPLE_ASSERT_CRASH_OUTPUT, time: 0.1, exit_code: 134 })
|
|
518
|
+
.and_return({ output: SIMPLE_ASSERT_CRASH_OUTPUT, time: 0.1, exit_code: 134, stderr: '', status: @ok_status })
|
|
356
519
|
|
|
357
520
|
expected_output_lines = []
|
|
358
521
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -372,7 +535,7 @@ describe GeneratorTestResultsBacktrace do
|
|
|
372
535
|
test_cases_crash = [{ test: 'test_asserting', line_number: 8 }]
|
|
373
536
|
|
|
374
537
|
allow(@tool_executor).to receive(:exec)
|
|
375
|
-
.and_return({ output: "\n\n\n", time: 0.1, exit_code: 134 })
|
|
538
|
+
.and_return({ output: "\n\n\n", time: 0.1, exit_code: 134, stderr: '', status: @ok_status })
|
|
376
539
|
|
|
377
540
|
expected_output_lines = []
|
|
378
541
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -515,7 +678,7 @@ describe GeneratorTestResultsBacktrace do
|
|
|
515
678
|
|
|
516
679
|
it 'uses assertion label and metadata line number when no crash location frame is found' do
|
|
517
680
|
allow(@tool_executor).to receive(:exec)
|
|
518
|
-
.and_return({ output: GDB_WINDOWS_ASSERT_BRIEF_OUTPUT, time: 0.1, exit_code: 3 })
|
|
681
|
+
.and_return({ output: GDB_WINDOWS_ASSERT_BRIEF_OUTPUT, time: 0.1, exit_code: 3, stderr: '', status: @ok_status })
|
|
519
682
|
|
|
520
683
|
expected_output_lines = []
|
|
521
684
|
allow(@generator_test_results).to receive(:regenerate_test_executable_stdout) do |**kwargs|
|
|
@@ -30,9 +30,9 @@ describe UserInclude do
|
|
|
30
30
|
expect(include_obj).to eq('header.h')
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
it "creates a UserInclude with
|
|
34
|
-
include_obj = UserInclude.new("path/to/header.h",
|
|
35
|
-
|
|
33
|
+
it "creates a UserInclude with an include_path override used in string expansion" do
|
|
34
|
+
include_obj = UserInclude.new("path/to/header.h", include_path: "path/to/header.h")
|
|
35
|
+
|
|
36
36
|
expect(include_obj.filename).to eq("header.h")
|
|
37
37
|
expect(include_obj.filepath).to eq("path/to/header.h")
|
|
38
38
|
expect("#{include_obj}").to eq('#include "path/to/header.h"')
|
|
@@ -110,14 +110,26 @@ describe SystemInclude do
|
|
|
110
110
|
expect(include_obj).to eq('header.h')
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
it "creates a SystemInclude with
|
|
114
|
-
include_obj = SystemInclude.new("path/to/header.h",
|
|
115
|
-
|
|
113
|
+
it "creates a SystemInclude with an include_path override used in string expansion" do
|
|
114
|
+
include_obj = SystemInclude.new("path/to/header.h", include_path: "path/to/header.h")
|
|
115
|
+
|
|
116
116
|
expect(include_obj.filename).to eq("header.h")
|
|
117
117
|
expect(include_obj.filepath).to eq("path/to/header.h")
|
|
118
118
|
expect("#{include_obj}").to eq('#include <path/to/header.h>')
|
|
119
119
|
expect(include_obj).to eq('path/to/header.h')
|
|
120
120
|
end
|
|
121
|
+
|
|
122
|
+
it "renders include_path instead of the bare filename, while filepath/filename keep the resolved identity" do
|
|
123
|
+
include_obj = SystemInclude.new(
|
|
124
|
+
"/usr/include/x86_64-linux-gnu/sys/stat.h", include_path: "sys/stat.h"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
expect(include_obj.filepath).to eq("/usr/include/x86_64-linux-gnu/sys/stat.h")
|
|
128
|
+
expect(include_obj.filename).to eq("stat.h")
|
|
129
|
+
expect(include_obj.include_path).to eq("sys/stat.h")
|
|
130
|
+
expect("#{include_obj}").to eq('#include <sys/stat.h>')
|
|
131
|
+
expect(include_obj).to eq('sys/stat.h')
|
|
132
|
+
end
|
|
121
133
|
end
|
|
122
134
|
|
|
123
135
|
describe "Graceful handling of input" do
|
|
@@ -189,9 +201,9 @@ describe "Include equality" do
|
|
|
189
201
|
end
|
|
190
202
|
|
|
191
203
|
it "compares not equal to another UserInclude with same filename but different paths" do
|
|
192
|
-
include1 = UserInclude.new("path1/header.h",
|
|
193
|
-
include2 = UserInclude.new("path2/header.h",
|
|
194
|
-
|
|
204
|
+
include1 = UserInclude.new("path1/header.h", include_path: "path1/header.h")
|
|
205
|
+
include2 = UserInclude.new("path2/header.h", include_path: "path2/header.h")
|
|
206
|
+
|
|
195
207
|
expect(include1).not_to eq(include2)
|
|
196
208
|
expect(include2).not_to eq(include1)
|
|
197
209
|
end
|
|
@@ -266,9 +278,9 @@ describe "Include equality" do
|
|
|
266
278
|
end
|
|
267
279
|
|
|
268
280
|
it "compares not equal to another SystemInclude with same filename but different paths" do
|
|
269
|
-
include1 = SystemInclude.new("sys/stdio.h",
|
|
270
|
-
include2 = SystemInclude.new("other/stdio.h",
|
|
271
|
-
|
|
281
|
+
include1 = SystemInclude.new("sys/stdio.h", include_path: "sys/stdio.h")
|
|
282
|
+
include2 = SystemInclude.new("other/stdio.h", include_path: "other/stdio.h")
|
|
283
|
+
|
|
272
284
|
expect(include1).not_to eq(include2)
|
|
273
285
|
expect(include2).not_to eq(include1)
|
|
274
286
|
end
|
|
@@ -342,9 +354,9 @@ describe "Include equality" do
|
|
|
342
354
|
end
|
|
343
355
|
|
|
344
356
|
it "compares not equal to another MockInclude with same filename but different paths" do
|
|
345
|
-
include1 = MockInclude.new("mocks/mock_module.h",
|
|
346
|
-
include2 = MockInclude.new("test/mocks/mock_module.h",
|
|
347
|
-
|
|
357
|
+
include1 = MockInclude.new("mocks/mock_module.h", include_path: "mocks/mock_module.h")
|
|
358
|
+
include2 = MockInclude.new("test/mocks/mock_module.h", include_path: "test/mocks/mock_module.h")
|
|
359
|
+
|
|
348
360
|
expect(include1).not_to eq(include2)
|
|
349
361
|
expect(include2).not_to eq(include1)
|
|
350
362
|
end
|
|
@@ -547,9 +559,9 @@ describe "Include string coercion (to_str)" do
|
|
|
547
559
|
expect(include_obj.to_str).to eq("header.h")
|
|
548
560
|
end
|
|
549
561
|
|
|
550
|
-
it "returns the
|
|
551
|
-
include_obj = UserInclude.new("sub/dir/header.h",
|
|
552
|
-
# to_str always returns @filename (the basename) regardless of
|
|
562
|
+
it "returns the basename even when constructed with an include_path override" do
|
|
563
|
+
include_obj = UserInclude.new("sub/dir/header.h", include_path: "sub/dir/header.h")
|
|
564
|
+
# to_str always returns @filename (the basename) regardless of include_path
|
|
553
565
|
expect(include_obj.to_str).to eq("header.h")
|
|
554
566
|
end
|
|
555
567
|
end
|
|
@@ -111,20 +111,38 @@ describe "Includes serialization" do
|
|
|
111
111
|
expect(restored.map(&:filename)).to eq(["first.h", "second.h", "third.h", "fourth.h"])
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
it "handles includes with
|
|
114
|
+
it "handles includes with an include_path override during serialization" do
|
|
115
115
|
original = [
|
|
116
|
-
UserInclude.new("path/to/header.h",
|
|
117
|
-
SystemInclude.new("sys/stdio.h",
|
|
118
|
-
MockInclude.new("mocks/mock_module.h"
|
|
116
|
+
UserInclude.new("path/to/header.h", include_path: "path/to/header.h"),
|
|
117
|
+
SystemInclude.new("sys/stdio.h", include_path: "sys/stdio.h"),
|
|
118
|
+
MockInclude.new("mocks/mock_module.h")
|
|
119
119
|
]
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
hashes = Includes.to_hashes(original)
|
|
122
122
|
restored = Includes.from_hashes(hashes)
|
|
123
|
-
|
|
123
|
+
|
|
124
124
|
expect(restored.length).to eq(3)
|
|
125
125
|
expect(restored[0].filepath).to eq("path/to/header.h")
|
|
126
126
|
expect(restored[1].filepath).to eq("sys/stdio.h")
|
|
127
127
|
expect(restored[2].filepath).to eq("mocks/mock_module.h")
|
|
128
|
+
# `include_path` must itself round-trip, not merely `filepath` -- otherwise a cached
|
|
129
|
+
# build silently reverts to filename-only rendering on its next, cache-hit run.
|
|
130
|
+
expect("#{restored[0]}").to eq('#include "path/to/header.h"')
|
|
131
|
+
expect("#{restored[1]}").to eq('#include <sys/stdio.h>')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "round-trips include_path, and has it take rendering precedence over filepath/filename" do
|
|
135
|
+
original = [
|
|
136
|
+
SystemInclude.new("/usr/include/x86_64-linux-gnu/sys/stat.h", include_path: "sys/stat.h")
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
hashes = Includes.to_hashes(original)
|
|
140
|
+
restored = Includes.from_hashes(hashes)
|
|
141
|
+
|
|
142
|
+
expect(restored.length).to eq(1)
|
|
143
|
+
expect(restored[0].filepath).to eq("/usr/include/x86_64-linux-gnu/sys/stat.h")
|
|
144
|
+
expect(restored[0].include_path).to eq("sys/stat.h")
|
|
145
|
+
expect("#{restored[0]}").to eq("#include <sys/stat.h>")
|
|
128
146
|
end
|
|
129
147
|
|
|
130
148
|
it "handles empty array" do
|
|
@@ -1054,16 +1072,88 @@ describe "Includes reconciliation" do
|
|
|
1054
1072
|
Include.new("subdir/header.h"),
|
|
1055
1073
|
Include.new("sys/types.h")
|
|
1056
1074
|
]
|
|
1057
|
-
|
|
1075
|
+
|
|
1058
1076
|
user = [UserInclude.new("header.h")]
|
|
1059
1077
|
system = [SystemInclude.new("types.h")]
|
|
1060
|
-
|
|
1078
|
+
|
|
1061
1079
|
result = Includes.reconcile(bare: bare, user: user, system: system)
|
|
1062
|
-
|
|
1080
|
+
|
|
1063
1081
|
# Should match by filename only
|
|
1064
1082
|
expect(result.length).to eq(2)
|
|
1065
1083
|
expect(result[0].filename).to eq("types.h")
|
|
1066
1084
|
expect(result[1].filename).to eq("header.h")
|
|
1067
1085
|
end
|
|
1086
|
+
|
|
1087
|
+
it "preserves a system include directive's original directory components instead of collapsing to its bare filename" do
|
|
1088
|
+
bare = [Include.new("sys/stat.h")]
|
|
1089
|
+
user = []
|
|
1090
|
+
system = [SystemInclude.new("/usr/include/x86_64-linux-gnu/sys/stat.h")]
|
|
1091
|
+
|
|
1092
|
+
result = Includes.reconcile(bare: bare, user: user, system: system)
|
|
1093
|
+
|
|
1094
|
+
expect(result.length).to eq(1)
|
|
1095
|
+
expect(result[0]).to be_a(SystemInclude)
|
|
1096
|
+
expect(result[0].filepath).to eq("/usr/include/x86_64-linux-gnu/sys/stat.h")
|
|
1097
|
+
expect("#{result[0]}").to eq("#include <sys/stat.h>")
|
|
1098
|
+
expect(Includes.from_hashes(Includes.to_hashes(result)).map(&:to_s)).to eq(["#include <sys/stat.h>"])
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
it "prefers the more specific bare entry when a system header's basename collides with an unrelated bare entry" do
|
|
1102
|
+
# A project's own quoted `#include "stat.h"` sitting alongside a system
|
|
1103
|
+
# `#include <sys/stat.h>` in the same file: both reach `bare` as plain, untyped
|
|
1104
|
+
# Include objects, and the short entry trivially "corresponds" to any longer
|
|
1105
|
+
# resolved path ending in the same filename. The longer, genuinely-corresponding
|
|
1106
|
+
# entry must still win, regardless of which one happens to appear first in `bare`.
|
|
1107
|
+
bare = [
|
|
1108
|
+
Include.new("stat.h"),
|
|
1109
|
+
Include.new("sys/stat.h")
|
|
1110
|
+
]
|
|
1111
|
+
user = []
|
|
1112
|
+
system = [SystemInclude.new("/usr/include/x86_64-linux-gnu/sys/stat.h")]
|
|
1113
|
+
|
|
1114
|
+
result = Includes.reconcile(bare: bare, user: user, system: system)
|
|
1115
|
+
|
|
1116
|
+
expect(result.length).to eq(1)
|
|
1117
|
+
expect("#{result[0]}").to eq("#include <sys/stat.h>")
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
it "falls back to a same-filename bare entry when nothing corresponds by path" do
|
|
1121
|
+
# The compiler's real search-path structure can diverge from a directive's own
|
|
1122
|
+
# literal spelling (a symlinked or vendored include root, for instance), so a
|
|
1123
|
+
# resolved system path may not share any trailing segment with its bare entry
|
|
1124
|
+
# beyond the filename itself. Rendering the bare entry's own spelling is still
|
|
1125
|
+
# strictly better than collapsing to the bare filename alone.
|
|
1126
|
+
bare = [Include.new("compat/stat.h")]
|
|
1127
|
+
user = []
|
|
1128
|
+
system = [SystemInclude.new("/usr/include/x86_64-linux-gnu/bits/stat.h")]
|
|
1129
|
+
|
|
1130
|
+
result = Includes.reconcile(bare: bare, user: user, system: system)
|
|
1131
|
+
|
|
1132
|
+
expect(result.length).to eq(1)
|
|
1133
|
+
expect("#{result[0]}").to eq("#include <compat/stat.h>")
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
it "does not hard-error over two same-named system headers, a normal toolchain wrapper-chain pattern rather than a project-file conflict" do
|
|
1137
|
+
# e.g. a compiler-provided stdint.h #include_next-ing its libc counterpart --
|
|
1138
|
+
# both real, both legitimately entered, both sharing a basename, neither a
|
|
1139
|
+
# project file whose identity is actually in question.
|
|
1140
|
+
bare = [Include.new("stdint.h")]
|
|
1141
|
+
|
|
1142
|
+
user = []
|
|
1143
|
+
system = [
|
|
1144
|
+
SystemInclude.new("/usr/lib/gcc/x86_64-linux-gnu/14/include/stdint.h"),
|
|
1145
|
+
SystemInclude.new("/usr/include/stdint.h")
|
|
1146
|
+
]
|
|
1147
|
+
|
|
1148
|
+
result = nil
|
|
1149
|
+
expect {
|
|
1150
|
+
result = Includes.reconcile(bare: bare, user: user, system: system)
|
|
1151
|
+
}.not_to raise_error
|
|
1152
|
+
|
|
1153
|
+
expect(result.length).to eq(2)
|
|
1154
|
+
expect(result.map(&:filepath)).to include(
|
|
1155
|
+
"/usr/lib/gcc/x86_64-linux-gnu/14/include/stdint.h", "/usr/include/stdint.h"
|
|
1156
|
+
)
|
|
1157
|
+
end
|
|
1068
1158
|
end
|
|
1069
|
-
end
|
|
1159
|
+
end
|