ceedling 1.1.0 → 1.1.2
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 +10 -7
- data/assets/broken_uncovered_file.c +13 -0
- data/assets/test_example_file_2.c +22 -0
- data/assets/tests_with_partials_coverage/src/blanks.c +10 -0
- data/assets/tests_with_partials_coverage/src/blanks.h +1 -0
- data/assets/tests_with_partials_coverage/src/counter.c +12 -0
- data/assets/tests_with_partials_coverage/src/counter.h +1 -0
- data/assets/tests_with_partials_coverage/src/decorators.c +11 -0
- data/assets/tests_with_partials_coverage/src/decorators.h +4 -0
- data/assets/tests_with_partials_coverage/test/test_blanks.c +8 -0
- data/assets/tests_with_partials_coverage/test/test_counter.c +9 -0
- data/assets/tests_with_partials_coverage/test/test_decorators.c +8 -0
- data/docs/Changelog.md +80 -38
- data/docs/KnownIssues.md +9 -0
- data/docs/ReleaseNotes.md +5 -1
- data/docs/mkdocs/getting-started/installation.md +8 -1
- data/docs/mkdocs/getting-started/quick-start.md +20 -2
- data/docs/mkdocs/help.md +2 -2
- data/docs/mkdocs/index.md +13 -6
- data/docs/mkdocs/overview/build-system.md +4 -4
- data/docs/mkdocs/plugins/bullseye.md +6 -0
- data/docs/mkdocs/plugins/command-hooks.md +20 -15
- data/docs/mkdocs/plugins/gcov/gcovr.md +130 -109
- data/docs/mkdocs/plugins/gcov/index.md +6 -0
- data/docs/mkdocs/plugins/index.md +40 -0
- data/docs/mkdocs/plugins/valgrind.md +6 -0
- data/docs/mkdocs/testing-guide/partials/index.md +22 -13
- data/lib/ceedling/c_extractor/c_extractor_declarations.rb +3 -1
- data/lib/ceedling/c_extractor/c_extractor_preprocessing.rb +20 -7
- data/lib/ceedling/config/configurator.rb +2 -1
- data/lib/ceedling/generators/generator_partials.rb +13 -3
- data/lib/ceedling/objects.yml +1 -0
- data/lib/ceedling/preprocess/preprocessinator.rb +3 -2
- data/lib/ceedling/preprocess/preprocessinator_file_assembler.rb +37 -15
- data/lib/ceedling/preprocess/preprocessinator_reconstructor.rb +23 -15
- data/lib/ceedling/test_invoker/test_build_executor.rb +3 -4
- data/lib/ceedling/test_invoker/test_build_planner.rb +0 -2
- data/lib/ceedling/test_invoker/test_invoker_types.rb +1 -1
- data/lib/ceedling/tool_executor.rb +5 -0
- data/lib/version.rb +1 -1
- data/plugins/command_hooks/lib/command_hooks.rb +4 -0
- data/plugins/gcov/lib/console_reportinator.rb +3 -1
- data/plugins/gcov/lib/gcov.rb +3 -3
- data/plugins/gcov/lib/gcov_reportinator.rb +4 -0
- data/plugins/gcov/lib/gcovr_reportinator.rb +61 -14
- data/plugins/gcov/lib/reportgenerator_reportinator.rb +3 -1
- data/site-local/404.html +3 -3
- data/site-local/assets/javascripts/{bundle.79ae519e.min.js → bundle.d7400e89.min.js} +2 -2
- data/site-local/assets/javascripts/{bundle.79ae519e.min.js.map → bundle.d7400e89.min.js.map} +2 -2
- data/site-local/assets/stylesheets/main.ec1eaa64.min.css +1 -0
- data/site-local/assets/stylesheets/{main.484c7ddc.min.css.map → main.ec1eaa64.min.css.map} +1 -1
- data/site-local/configuration/environment-vars.html +3 -3
- data/site-local/configuration/global-collections.html +3 -3
- data/site-local/configuration/index.html +3 -3
- data/site-local/configuration/loading.html +3 -3
- data/site-local/configuration/mixins.html +3 -3
- data/site-local/configuration/parallel-builds.html +3 -3
- data/site-local/configuration/project-file.html +3 -3
- data/site-local/configuration/reference/cexception.html +3 -3
- data/site-local/configuration/reference/cmock.html +3 -3
- data/site-local/configuration/reference/defines.html +3 -3
- data/site-local/configuration/reference/environment.html +3 -3
- data/site-local/configuration/reference/extension.html +3 -3
- data/site-local/configuration/reference/files.html +3 -3
- data/site-local/configuration/reference/flags.html +3 -3
- data/site-local/configuration/reference/index.html +3 -3
- data/site-local/configuration/reference/libraries.html +3 -3
- data/site-local/configuration/reference/mixins.html +3 -3
- data/site-local/configuration/reference/paths.html +3 -3
- data/site-local/configuration/reference/plugins.html +3 -3
- data/site-local/configuration/reference/project.html +3 -3
- data/site-local/configuration/reference/release-build.html +3 -3
- data/site-local/configuration/reference/test-build.html +3 -3
- data/site-local/configuration/reference/test-runner.html +3 -3
- data/site-local/configuration/reference/tools.html +3 -3
- data/site-local/configuration/reference/unity.html +3 -3
- data/site-local/configuration/which-ceedling.html +3 -3
- data/site-local/development/index.html +3 -3
- data/site-local/development/plugins/configuration.html +3 -3
- data/site-local/development/plugins/index.html +3 -3
- data/site-local/development/plugins/plugin-subclass.html +3 -3
- data/site-local/development/plugins/rake-tasks.html +3 -3
- data/site-local/development/workflow.html +3 -3
- data/site-local/getting-started/command-line.html +3 -3
- data/site-local/getting-started/example-projects/cipher-quest.html +3 -3
- data/site-local/getting-started/example-projects/index.html +3 -3
- data/site-local/getting-started/example-projects/temp-sensor.html +3 -3
- data/site-local/getting-started/example-projects/wondrous-forest.html +3 -3
- data/site-local/getting-started/index.html +3 -3
- data/site-local/getting-started/installation.html +12 -4
- data/site-local/getting-started/quick-start.html +18 -4
- data/site-local/help.html +4 -4
- data/site-local/index.html +13 -8
- data/site-local/overview/build-system.html +6 -6
- data/site-local/overview/index.html +3 -3
- data/site-local/overview/test-environments.html +3 -3
- data/site-local/overview/tools-and-frameworks.html +3 -3
- data/site-local/plugins/beep.html +3 -3
- data/site-local/plugins/bullseye.html +9 -3
- data/site-local/plugins/command-hooks.html +42 -38
- data/site-local/plugins/compile-commands-json-db.html +3 -3
- data/site-local/plugins/cppcheck.html +3 -3
- data/site-local/plugins/dependencies.html +3 -3
- data/site-local/plugins/fff.html +3 -3
- data/site-local/plugins/gcov/examples.html +3 -3
- data/site-local/plugins/gcov/gcovr.html +325 -227
- data/site-local/plugins/gcov/index.html +9 -3
- data/site-local/plugins/gcov/overview.html +3 -3
- data/site-local/plugins/gcov/reportgenerator.html +3 -3
- data/site-local/plugins/gcov/reporting.html +3 -3
- data/site-local/plugins/gcov/setup.html +3 -3
- data/site-local/plugins/gcov/tool-versions.html +3 -3
- data/site-local/plugins/gcov/troubleshooting.html +3 -3
- data/site-local/plugins/index.html +79 -15
- data/site-local/plugins/module-generator.html +3 -3
- data/site-local/plugins/report-build-warnings-log.html +3 -3
- data/site-local/plugins/report-tests-gtestlike-stdout.html +3 -3
- data/site-local/plugins/report-tests-ide-stdout.html +3 -3
- data/site-local/plugins/report-tests-log-factory.html +3 -3
- data/site-local/plugins/report-tests-pretty-stdout.html +3 -3
- data/site-local/plugins/report-tests-raw-output-log.html +3 -3
- data/site-local/plugins/report-tests-teamcity-stdout.html +3 -3
- data/site-local/plugins/valgrind.html +9 -3
- data/site-local/project/release-history.html +3 -3
- data/site-local/project/upgrade.html +3 -3
- data/site-local/reference/build-directives.html +3 -3
- data/site-local/reference/command-line.html +3 -3
- data/site-local/reference/environment-vars.html +3 -3
- data/site-local/reference/gcov-plugin.html +3 -3
- data/site-local/reference/global-collections.html +3 -3
- data/site-local/reference/index.html +3 -3
- data/site-local/reference/partials-macros.html +3 -3
- data/site-local/reference/project-configuration.html +3 -3
- data/site-local/sitemap.xml.gz +0 -0
- data/site-local/snapshot/examples/cipher_quest/index.html +3 -3
- data/site-local/snapshot/examples/temp_sensor/index.html +3 -3
- data/site-local/snapshot/examples/wondrous_forest/index.html +3 -3
- data/site-local/testing-guide/build-directives.html +3 -3
- data/site-local/testing-guide/conventions.html +3 -3
- data/site-local/testing-guide/frameworks.html +3 -3
- data/site-local/testing-guide/index.html +3 -3
- data/site-local/testing-guide/partials/configuration.html +3 -3
- data/site-local/testing-guide/partials/conventions.html +3 -3
- data/site-local/testing-guide/partials/directives.html +3 -3
- data/site-local/testing-guide/partials/example.html +3 -3
- data/site-local/testing-guide/partials/index.html +25 -16
- data/site-local/testing-guide/partials/overview.html +3 -3
- data/site-local/testing-guide/partials/variables.html +3 -3
- data/site-local/testing-guide/test-cases.html +3 -3
- data/site-local/testing-guide/test-sample.html +3 -3
- data/site-local/testing-guide/test-suite-anatomy.html +3 -3
- data/spec/support/system/system_context.rb +3 -1
- data/spec/system/gcov_deployment_spec.rb +20 -6
- data/spec/system/support/gcov_common_test_cases.rb +34 -45
- data/spec/system/support/gcov_partials_test_cases.rb +116 -0
- data/spec/units/c_extractor/c_extractor_declarations_spec.rb +128 -0
- data/spec/units/c_extractor/c_extractor_definitions_spec.rb +7 -0
- data/spec/units/c_extractor/c_extractor_integration_spec.rb +17 -0
- data/spec/units/c_extractor/c_extractor_preprocessing_spec.rb +46 -0
- data/spec/units/generators/generator_partials_spec.rb +32 -6
- data/spec/units/preprocess/preprocessinator_file_assembler_spec.rb +250 -1
- data/spec/units/preprocess/preprocessinator_reconstructor_spec.rb +151 -1
- data/spec/units/test_build_executor_spec.rb +114 -0
- data/vendor/unity/auto/generate_test_runner.rb +55 -5
- data/vendor/unity/src/unity.h +1 -1
- data/vendor/unity/test/testdata/testRunnerGeneratorEmpty.c +13 -0
- data/vendor/unity/test/tests/test_generate_test_runner.rb +11 -0
- metadata +22 -7
- data/site-local/assets/stylesheets/main.484c7ddc.min.css +0 -1
- data/vendor/unity/auto/run_test.erb +0 -37
|
@@ -0,0 +1,116 @@
|
|
|
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 'rexml/document'
|
|
9
|
+
require_relative 'gcov_helpers'
|
|
10
|
+
|
|
11
|
+
module GcovPartialsTestCases
|
|
12
|
+
include GcovHelpers
|
|
13
|
+
|
|
14
|
+
# Runs `ceedling gcov:all` with Partials + Cobertura XML reporting enabled, then
|
|
15
|
+
# returns { line_number => hits } for `source_relpath` (e.g. 'src/blanks.c').
|
|
16
|
+
def partials_cobertura_hits_by_line(source_relpath)
|
|
17
|
+
@c.merge_project_yml_for_test({
|
|
18
|
+
:project => { :use_partials => true },
|
|
19
|
+
:gcov => { :reports => ['Cobertura'] }
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
output = @c.ceedling_build_exec("gcov:all")
|
|
23
|
+
expect(@c.last_exit_status).to eq(0)
|
|
24
|
+
|
|
25
|
+
cobertura_path = File.join('build', 'artifacts', 'gcov', 'gcovr', 'GcovCoverageCobertura.xml')
|
|
26
|
+
doc = REXML::Document.new(File.read(cobertura_path))
|
|
27
|
+
|
|
28
|
+
doc.elements.to_a("//class[@filename='#{source_relpath}']/lines/line").each_with_object({}) do |el, h|
|
|
29
|
+
h[el.attributes['number'].to_i] = el.attributes['hits'].to_i
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def gcov_partials_coverage_blank_lines_in_function_body
|
|
34
|
+
@c.with_context do
|
|
35
|
+
Dir.chdir @proj_name do
|
|
36
|
+
prep_project_yml_for_coverage
|
|
37
|
+
|
|
38
|
+
# Multiple consecutive blank lines inside a function body -- the same
|
|
39
|
+
# shape a stripped multi-line comment leaves behind -- sit between the
|
|
40
|
+
# opening brace and the one executed statement. Each function in a
|
|
41
|
+
# generated Partial gets exactly one #line directive, at its own first
|
|
42
|
+
# line; every line after that is trusted to match the original source
|
|
43
|
+
# 1:1. If any lines partway through the body go missing during
|
|
44
|
+
# reconstruction, gcov's line attribution for everything after that
|
|
45
|
+
# point in the function shifts up by the deficit.
|
|
46
|
+
asset_base = test_asset_path("tests_with_partials_coverage")
|
|
47
|
+
FileUtils.cp "#{asset_base}/src/blanks.h", 'src/'
|
|
48
|
+
FileUtils.cp "#{asset_base}/src/blanks.c", 'src/'
|
|
49
|
+
FileUtils.cp "#{asset_base}/test/test_blanks.c", 'test/'
|
|
50
|
+
|
|
51
|
+
hits = partials_cobertura_hits_by_line('src/blanks.c')
|
|
52
|
+
|
|
53
|
+
# `return;` is on source line 5 -- it must show as hit.
|
|
54
|
+
expect(hits[5]).to be > 0
|
|
55
|
+
# The blank lines (3-4) must not appear as executable/hit lines at all.
|
|
56
|
+
expect(hits[3]).to be_nil
|
|
57
|
+
expect(hits[4]).to be_nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def gcov_partials_coverage_decorators_on_own_lines
|
|
63
|
+
@c.with_context do
|
|
64
|
+
Dir.chdir @proj_name do
|
|
65
|
+
prep_project_yml_for_coverage
|
|
66
|
+
|
|
67
|
+
# `static` and `inline` each occupy their own line ahead of the return
|
|
68
|
+
# type. Partials strips both keywords from the front of the extracted
|
|
69
|
+
# function text (per the docs, functions are stripped of `static` and
|
|
70
|
+
# `inline`) and must bump the emitted #line directive forward by
|
|
71
|
+
# exactly the number of lines that stripping removed -- otherwise the
|
|
72
|
+
# whole body, including the blank line below, reports coverage against
|
|
73
|
+
# the wrong original source lines.
|
|
74
|
+
asset_base = test_asset_path("tests_with_partials_coverage")
|
|
75
|
+
FileUtils.cp "#{asset_base}/src/decorators.h", 'src/'
|
|
76
|
+
FileUtils.cp "#{asset_base}/src/decorators.c", 'src/'
|
|
77
|
+
FileUtils.cp "#{asset_base}/test/test_decorators.c", 'test/'
|
|
78
|
+
|
|
79
|
+
hits = partials_cobertura_hits_by_line('src/decorators.c')
|
|
80
|
+
|
|
81
|
+
# `return;` is on source line 7 -- it must show as hit.
|
|
82
|
+
expect(hits[7]).to be > 0
|
|
83
|
+
# The blank line (6) must not appear as an executable/hit line.
|
|
84
|
+
expect(hits[6]).to be_nil
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def gcov_partials_coverage_function_scope_static_promotion
|
|
90
|
+
@c.with_context do
|
|
91
|
+
Dir.chdir @proj_name do
|
|
92
|
+
prep_project_yml_for_coverage
|
|
93
|
+
|
|
94
|
+
# A function-scope `static` variable is replaced with a no-op and
|
|
95
|
+
# promoted to module scope so the Partial's testable copy of the
|
|
96
|
+
# function keeps the original's persistence semantics (per the docs'
|
|
97
|
+
# Partials creation steps). Confirms that substitution doesn't shift
|
|
98
|
+
# the lines after it out of alignment with their original source line
|
|
99
|
+
# numbers.
|
|
100
|
+
asset_base = test_asset_path("tests_with_partials_coverage")
|
|
101
|
+
FileUtils.cp "#{asset_base}/src/counter.h", 'src/'
|
|
102
|
+
FileUtils.cp "#{asset_base}/src/counter.c", 'src/'
|
|
103
|
+
FileUtils.cp "#{asset_base}/test/test_counter.c", 'test/'
|
|
104
|
+
|
|
105
|
+
hits = partials_cobertura_hits_by_line('src/counter.c')
|
|
106
|
+
|
|
107
|
+
# `count++;` (line 5) and `return count;` (line 7) must both show as
|
|
108
|
+
# hit, correctly separated by the blank lines around them (4 and 6).
|
|
109
|
+
expect(hits[5]).to be > 0
|
|
110
|
+
expect(hits[7]).to be > 0
|
|
111
|
+
expect(hits[4]).to be_nil
|
|
112
|
+
expect(hits[6]).to be_nil
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -445,6 +445,58 @@ describe CExtractorDeclarations do
|
|
|
445
445
|
end
|
|
446
446
|
end
|
|
447
447
|
|
|
448
|
+
context "escape sequences in string literal initializers" do
|
|
449
|
+
it "extracts pointer variable with escaped quote in string literal initializer" do
|
|
450
|
+
content = 'char* s = "say \"hi\"";'
|
|
451
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
452
|
+
|
|
453
|
+
expect(success).to be true
|
|
454
|
+
check_single(variable, name: 's', type: 'char*', text: 'char* s = "say \"hi\"";')
|
|
455
|
+
expect(pos).to eq(content.length)
|
|
456
|
+
expect(rest).to eq("")
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
it "extracts pointer variable with escaped backslash in string literal initializer" do
|
|
460
|
+
content = 'char* s = "C:\\\\dir";'
|
|
461
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
462
|
+
|
|
463
|
+
expect(success).to be true
|
|
464
|
+
check_single(variable, name: 's', type: 'char*', text: 'char* s = "C:\\\\dir";')
|
|
465
|
+
expect(pos).to eq(content.length)
|
|
466
|
+
expect(rest).to eq("")
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
it "extracts pointer variable with escaped newline in string literal initializer" do
|
|
470
|
+
content = 'char* s = "line1\\nline2";'
|
|
471
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
472
|
+
|
|
473
|
+
expect(success).to be true
|
|
474
|
+
check_single(variable, name: 's', type: 'char*', text: 'char* s = "line1\\nline2";')
|
|
475
|
+
expect(pos).to eq(content.length)
|
|
476
|
+
expect(rest).to eq("")
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it "extracts pointer variable with hex escape in string literal initializer" do
|
|
480
|
+
content = 'char* s = "\\x41\\x42";'
|
|
481
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
482
|
+
|
|
483
|
+
expect(success).to be true
|
|
484
|
+
check_single(variable, name: 's', type: 'char*', text: 'char* s = "\\x41\\x42";')
|
|
485
|
+
expect(pos).to eq(content.length)
|
|
486
|
+
expect(rest).to eq("")
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
it "extracts pointer variable with octal escape in string literal initializer" do
|
|
490
|
+
content = 'char* s = "\\101\\102";'
|
|
491
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
492
|
+
|
|
493
|
+
expect(success).to be true
|
|
494
|
+
check_single(variable, name: 's', type: 'char*', text: 'char* s = "\\101\\102";')
|
|
495
|
+
expect(pos).to eq(content.length)
|
|
496
|
+
expect(rest).to eq("")
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
|
|
448
500
|
context "qualified type declarations" do
|
|
449
501
|
it "extracts const variable" do
|
|
450
502
|
content = "const int value;"
|
|
@@ -685,6 +737,82 @@ describe CExtractorDeclarations do
|
|
|
685
737
|
end
|
|
686
738
|
end
|
|
687
739
|
|
|
740
|
+
context "multiline declarations" do
|
|
741
|
+
it "extracts array declaration whose closing brace and semicolon fall on the final line after multiline data (GH #1182)" do
|
|
742
|
+
content = "static uint8_t arr[10] = {\n 0x00, 0x01, 0x02, 0x03, 0x04,\n 0x05, 0x06, 0x07, 0x08, 0x09\n};"
|
|
743
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
744
|
+
|
|
745
|
+
expect(success).to be true
|
|
746
|
+
check_single(variable, name: 'arr', type: 'uint8_t', decorators: ['static'],
|
|
747
|
+
text: 'uint8_t arr[10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 };',
|
|
748
|
+
array_suffix: '[10]')
|
|
749
|
+
expect(pos).to eq(content.length)
|
|
750
|
+
expect(rest).to eq("")
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
it "extracts nested multi-dimensional array initializer whose closing braces and semicolon fall on the final line" do
|
|
754
|
+
content = "static int matrix[2][3] = {\n {1, 2, 3},\n {4, 5, 6}\n};"
|
|
755
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
756
|
+
|
|
757
|
+
expect(success).to be true
|
|
758
|
+
check_single(variable, name: 'matrix', type: 'int', decorators: ['static'],
|
|
759
|
+
text: 'int matrix[2][3] = { {1, 2, 3}, {4, 5, 6} };',
|
|
760
|
+
array_suffix: '[2][3]')
|
|
761
|
+
expect(pos).to eq(content.length)
|
|
762
|
+
expect(rest).to eq("")
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
it "expands a compound declaration whose second declarator has a multiline brace initializer" do
|
|
766
|
+
content = "static int a, arr[3] = {\n 1,\n 2,\n 3\n};"
|
|
767
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
768
|
+
|
|
769
|
+
expect(success).to be true
|
|
770
|
+
expect(variable.length).to eq 2
|
|
771
|
+
|
|
772
|
+
expect(variable[0].name).to eq 'a'
|
|
773
|
+
expect(variable[0].decorators).to eq ['static']
|
|
774
|
+
expect(variable[0].text).to eq 'int a;'
|
|
775
|
+
|
|
776
|
+
expect(variable[1].name).to eq 'arr'
|
|
777
|
+
expect(variable[1].decorators).to eq ['static']
|
|
778
|
+
expect(variable[1].array_suffix).to eq '[3]'
|
|
779
|
+
expect(variable[1].text).to eq 'int arr[3] = { 1, 2, 3 };'
|
|
780
|
+
|
|
781
|
+
expect(pos).to eq(content.length)
|
|
782
|
+
expect(rest).to eq("")
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
it "extracts a declaration with the type and name split across lines and no braces involved" do
|
|
786
|
+
content = "int\n x;"
|
|
787
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
788
|
+
|
|
789
|
+
expect(success).to be true
|
|
790
|
+
check_single(variable, name: 'x', type: 'int', text: 'int x;')
|
|
791
|
+
expect(pos).to eq(content.length)
|
|
792
|
+
expect(rest).to eq("")
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
it "extracts a declaration whose initializer value falls on the line after the assignment" do
|
|
796
|
+
content = "int x =\n 5;"
|
|
797
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
798
|
+
|
|
799
|
+
expect(success).to be true
|
|
800
|
+
check_single(variable, name: 'x', type: 'int', text: 'int x = 5;')
|
|
801
|
+
expect(pos).to eq(content.length)
|
|
802
|
+
expect(rest).to eq("")
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
it "extracts a declaration whose terminating semicolon is alone on the line following a bracketed declarator" do
|
|
806
|
+
content = "int arr[10]\n;"
|
|
807
|
+
success, variable, pos, rest = extract_variable.call(content)
|
|
808
|
+
|
|
809
|
+
expect(success).to be true
|
|
810
|
+
check_single(variable, name: 'arr', type: 'int', text: 'int arr[10] ;', array_suffix: '[10]')
|
|
811
|
+
expect(pos).to eq(content.length)
|
|
812
|
+
expect(rest).to eq("")
|
|
813
|
+
end
|
|
814
|
+
end
|
|
815
|
+
|
|
688
816
|
context "array_suffix field" do
|
|
689
817
|
it "returns empty string for a scalar variable" do
|
|
690
818
|
content = "static uint8 s_count;"
|
|
@@ -295,6 +295,13 @@ describe CExtractorDefinitions do
|
|
|
295
295
|
expect(pos).to eq input.length
|
|
296
296
|
end
|
|
297
297
|
|
|
298
|
+
it "extracts a named struct when the closing '}' and terminating ';' fall on separate lines" do
|
|
299
|
+
input = "struct Point {\n int x;\n}\n;\n"
|
|
300
|
+
result, pos = try_aggregate(input)
|
|
301
|
+
expect(result).to eq [true, input.chomp]
|
|
302
|
+
expect(pos).to eq input.length
|
|
303
|
+
end
|
|
304
|
+
|
|
298
305
|
it "extracts an anonymous struct (no tag name)" do
|
|
299
306
|
input = "struct { int x; int y; };\n"
|
|
300
307
|
result, pos = try_aggregate(input)
|
|
@@ -561,6 +561,23 @@ describe CExtractor do
|
|
|
561
561
|
expect( contents.variable_declarations.length ).to eq 0
|
|
562
562
|
end
|
|
563
563
|
|
|
564
|
+
it "should extract a function definition following a #define with an escaped character in a string literal (GH #1184)" do
|
|
565
|
+
file_contents = <<~'CONTENTS'
|
|
566
|
+
#include "world.h"
|
|
567
|
+
#define SZ1 sizeof("\n")
|
|
568
|
+
void helloWorld() { return; }
|
|
569
|
+
CONTENTS
|
|
570
|
+
|
|
571
|
+
contents = extract_from.call(file_contents)
|
|
572
|
+
|
|
573
|
+
expect( contents.macro_definitions.length ).to eq 1
|
|
574
|
+
expect( contents.macro_definitions[0].text ).to eq '#define SZ1 sizeof("\n")'
|
|
575
|
+
|
|
576
|
+
expect( contents.function_definitions.length ).to eq 1
|
|
577
|
+
expect( contents.function_definitions[0].name ).to eq 'helloWorld'
|
|
578
|
+
expect( contents.function_definitions[0].body ).to eq '{ return; }'
|
|
579
|
+
end
|
|
580
|
+
|
|
564
581
|
it "should consume #pragma and #include directives without storing them" do
|
|
565
582
|
file_contents = <<~CONTENTS
|
|
566
583
|
#pragma once
|
|
@@ -290,6 +290,45 @@ describe CExtractorPreprocessing do
|
|
|
290
290
|
expect(pos).to eq input.length
|
|
291
291
|
end
|
|
292
292
|
|
|
293
|
+
# --- Regression: GH #1184 — escape sequences inside a #define string literal ---
|
|
294
|
+
# A lone '\' preceding a string-literal escape (e.g. \n, \", \\) is not a line
|
|
295
|
+
# continuation and must not be mistaken for one, truncating the directive.
|
|
296
|
+
|
|
297
|
+
it "extracts a #define whose string literal contains an escaped newline" do
|
|
298
|
+
input = "#define SZ1 sizeof(\"\\n\")\n"
|
|
299
|
+
result, pos = try_directive(input)
|
|
300
|
+
expect(result).to eq [true, input.rstrip]
|
|
301
|
+
expect(pos).to eq input.length
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "extracts a #define whose string literal contains an escaped quote" do
|
|
305
|
+
input = "#define MSG \"say \\\"hi\\\"\"\n"
|
|
306
|
+
result, pos = try_directive(input)
|
|
307
|
+
expect(result).to eq [true, input.rstrip]
|
|
308
|
+
expect(pos).to eq input.length
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it "extracts a #define whose string literal contains an escaped backslash" do
|
|
312
|
+
input = "#define PATH \"C:\\\\dir\"\n"
|
|
313
|
+
result, pos = try_directive(input)
|
|
314
|
+
expect(result).to eq [true, input.rstrip]
|
|
315
|
+
expect(pos).to eq input.length
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "extracts a #define with an escaped character and no trailing newline (EOS)" do
|
|
319
|
+
input = "#define SZ1 sizeof(\"\\n\")"
|
|
320
|
+
result, pos = try_directive(input)
|
|
321
|
+
expect(result).to eq [true, input]
|
|
322
|
+
expect(pos).to eq input.length
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
it "does not consume a following function definition after a #define with an escaped character" do
|
|
326
|
+
input = "#define SZ1 sizeof(\"\\n\")\nvoid helloWorld() { return; }\n"
|
|
327
|
+
result, pos = try_directive(input)
|
|
328
|
+
expect(result).to eq [true, "#define SZ1 sizeof(\"\\n\")"]
|
|
329
|
+
expect(pos).to eq "#define SZ1 sizeof(\"\\n\")\n".length
|
|
330
|
+
end
|
|
331
|
+
|
|
293
332
|
it "stops at end of directive and does not consume following code" do
|
|
294
333
|
input = "#define FOO 1\nint x = 0;"
|
|
295
334
|
result, pos = try_directive(input)
|
|
@@ -483,6 +522,13 @@ describe CExtractorPreprocessing do
|
|
|
483
522
|
expect(pos).to eq input.length
|
|
484
523
|
end
|
|
485
524
|
|
|
525
|
+
it "handles a static assert whose terminating ';' falls on its own line after the closing ')'" do
|
|
526
|
+
input = "static_assert(sizeof(int) == 4, \"msg\")\n;\n"
|
|
527
|
+
result, pos = try_static_assert(input)
|
|
528
|
+
expect(result[0]).to be true
|
|
529
|
+
expect(pos).to eq input.length
|
|
530
|
+
end
|
|
531
|
+
|
|
486
532
|
# --- Boundary behaviour ---
|
|
487
533
|
|
|
488
534
|
it "stops at the ';' and does not consume following code" do
|
|
@@ -84,12 +84,14 @@ describe GeneratorPartials do
|
|
|
84
84
|
header_file_handle = double('header_file_handle')
|
|
85
85
|
source_file_handle = double('source_file_handle')
|
|
86
86
|
|
|
87
|
+
# Binary mode ('wb'): generated files carry embedded content whose line
|
|
88
|
+
# endings must reach disk unchanged, which text mode would not guarantee.
|
|
87
89
|
allow(@file_wrapper).to receive(:open)
|
|
88
|
-
.with(expected_header_filepath, '
|
|
90
|
+
.with(expected_header_filepath, 'wb')
|
|
89
91
|
.and_yield(header_file_handle)
|
|
90
92
|
|
|
91
93
|
allow(@file_wrapper).to receive(:open)
|
|
92
|
-
.with(expected_source_filepath, '
|
|
94
|
+
.with(expected_source_filepath, 'wb')
|
|
93
95
|
.and_yield(source_file_handle)
|
|
94
96
|
|
|
95
97
|
# Spy on generate_header and generate_source -- allow them to be called but track the calls
|
|
@@ -145,8 +147,8 @@ describe GeneratorPartials do
|
|
|
145
147
|
expect(@file_path_utils).to have_received(:form_partial_implementation_header_filename).with(name)
|
|
146
148
|
|
|
147
149
|
# Verify file operations
|
|
148
|
-
expect(@file_wrapper).to have_received(:open).with(expected_header_filepath, '
|
|
149
|
-
expect(@file_wrapper).to have_received(:open).with(expected_source_filepath, '
|
|
150
|
+
expect(@file_wrapper).to have_received(:open).with(expected_header_filepath, 'wb')
|
|
151
|
+
expect(@file_wrapper).to have_received(:open).with(expected_source_filepath, 'wb')
|
|
150
152
|
|
|
151
153
|
# Verify return value is the source filepath
|
|
152
154
|
expect(result).to eq(expected_source_filepath)
|
|
@@ -167,9 +169,11 @@ describe GeneratorPartials do
|
|
|
167
169
|
.and_return(header_filename)
|
|
168
170
|
|
|
169
171
|
# Mock FileWrapper.open to yield a file handle
|
|
172
|
+
# Binary mode ('wb'): generated files carry embedded content whose line
|
|
173
|
+
# endings must reach disk unchanged, which text mode would not guarantee.
|
|
170
174
|
file_handle = double('file_handle')
|
|
171
175
|
allow(@file_wrapper).to receive(:open)
|
|
172
|
-
.with(expected_filepath, '
|
|
176
|
+
.with(expected_filepath, 'wb')
|
|
173
177
|
.and_yield(file_handle)
|
|
174
178
|
|
|
175
179
|
# Spy on generate_header -- allow it to be called but track the call
|
|
@@ -211,7 +215,7 @@ describe GeneratorPartials do
|
|
|
211
215
|
expect(@file_path_utils).to have_received(:form_partial_interface_header_filename).with(name)
|
|
212
216
|
|
|
213
217
|
# Verify file operations
|
|
214
|
-
expect(@file_wrapper).to have_received(:open).with(expected_filepath, '
|
|
218
|
+
expect(@file_wrapper).to have_received(:open).with(expected_filepath, 'wb')
|
|
215
219
|
|
|
216
220
|
# Verify return value is the header filepath
|
|
217
221
|
expect(result).to eq(expected_filepath)
|
|
@@ -649,6 +653,28 @@ describe GeneratorPartials do
|
|
|
649
653
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
650
654
|
end
|
|
651
655
|
|
|
656
|
+
it "should pass a code_block's line endings through unchanged, including embedded CRLF" do
|
|
657
|
+
# code_block content is written to the IO handle exactly as given, byte for
|
|
658
|
+
# byte, since the file it ends up in is opened by its caller in binary mode
|
|
659
|
+
# specifically so nothing here alters a line ending already present in it.
|
|
660
|
+
code_block_with_crlf = "void helloBlanks(void) {\r\n\r\n return;\r\n}"
|
|
661
|
+
|
|
662
|
+
defn = Partials.manufacture_function_definition(
|
|
663
|
+
line_num: 2,
|
|
664
|
+
source_filepath: 'src/blanks.c',
|
|
665
|
+
name: 'helloBlanks',
|
|
666
|
+
signature: 'void helloBlanks(void)',
|
|
667
|
+
code_block: code_block_with_crlf
|
|
668
|
+
)
|
|
669
|
+
c_module = make_module(
|
|
670
|
+
CExtractorTypes::CFunctionDefinition.new(name: 'helloBlanks')
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
@generator.send(:generate_source, buf, [], [defn], c_module)
|
|
674
|
+
|
|
675
|
+
expect( buf.string ).to include( code_block_with_crlf )
|
|
676
|
+
end
|
|
677
|
+
|
|
652
678
|
it "should emit only variable declarations and function definitions from all four element_sequence categories" do
|
|
653
679
|
# Source generation emits two categories and silently skips two others:
|
|
654
680
|
# CVariableDeclaration → emitted as-is
|