ceedling 1.1.2 → 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_crash_sigsegv_with_param.c +32 -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/bin/actions_wrapper.rb +7 -6
- data/docs/Changelog.md +29 -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 +8 -1
- data/lib/ceedling/config/configurator_setup.rb +26 -0
- data/lib/ceedling/defaults.rb +16 -2
- 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 +268 -100
- data/lib/ceedling/generators/generator_test_runner.rb +20 -2
- 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/plugins/gcov/lib/gcov.rb +2 -2
- 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/support/system/system_context.rb +15 -0
- data/spec/system/deployment_as_gem_spec.rb +14 -0
- data/spec/system/deployment_as_vendor_spec.rb +19 -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 +227 -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/configurator_spec.rb +45 -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 +248 -41
- data/spec/units/generators/generator_test_runner_spec.rb +26 -2
- 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
- data/spec/units/test_context_extractor_spec.rb +3 -3
- metadata +20 -2
|
@@ -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()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# =========================================================================
|
|
2
|
+
# Ceedling - Test-Centered Build System for C
|
|
3
|
+
# ThrowTheSwitch.org
|
|
4
|
+
# Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
|
5
|
+
# SPDX-License-Identifier: MIT
|
|
6
|
+
# =========================================================================
|
|
7
|
+
|
|
8
|
+
require 'spec_helper'
|
|
9
|
+
require 'ceedling/config/configurator_setup'
|
|
10
|
+
require 'ceedling/reportinator'
|
|
11
|
+
|
|
12
|
+
# Only #validate_partials is covered here. The rest of ConfiguratorSetup has no unit spec
|
|
13
|
+
# at all today (its closest sibling, #validate_threads, is untested too) -- this file scopes
|
|
14
|
+
# itself to the new method rather than backfilling that existing gap.
|
|
15
|
+
describe ConfiguratorSetup do
|
|
16
|
+
before(:each) do
|
|
17
|
+
@configurator_builder = double('ConfiguratorBuilder')
|
|
18
|
+
@configurator_validator = double('ConfiguratorValidator')
|
|
19
|
+
@configurator_plugins = double('ConfiguratorPlugins')
|
|
20
|
+
@loginator = double('Loginator')
|
|
21
|
+
@reportinator = Reportinator.new
|
|
22
|
+
@file_wrapper = double('FileWrapper')
|
|
23
|
+
|
|
24
|
+
@setup = described_class.new(
|
|
25
|
+
{
|
|
26
|
+
configurator_builder: @configurator_builder,
|
|
27
|
+
configurator_validator: @configurator_validator,
|
|
28
|
+
configurator_plugins: @configurator_plugins,
|
|
29
|
+
loginator: @loginator,
|
|
30
|
+
reportinator: @reportinator,
|
|
31
|
+
file_wrapper: @file_wrapper
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "#validate_partials" do
|
|
37
|
+
it "accepts an integer at the minimum" do
|
|
38
|
+
config = { partials: { max_extraction_length: 10 } }
|
|
39
|
+
expect(@setup.validate_partials(config)).to be true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "accepts an integer above the minimum" do
|
|
43
|
+
config = { partials: { max_extraction_length: 5000 } }
|
|
44
|
+
expect(@setup.validate_partials(config)).to be true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "rejects a non-integer value" do
|
|
48
|
+
config = { partials: { max_extraction_length: '5000' } }
|
|
49
|
+
expect(@loginator).to receive(:log)
|
|
50
|
+
.with(/:partials ↳ :max_extraction_length is not an integer/, Verbosity::ERRORS)
|
|
51
|
+
expect(@setup.validate_partials(config)).to be false
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "rejects an integer below the minimum" do
|
|
55
|
+
config = { partials: { max_extraction_length: 9 } }
|
|
56
|
+
expect(@loginator).to receive(:log)
|
|
57
|
+
.with(/:partials ↳ :max_extraction_length must be at least 10/, Verbosity::ERRORS)
|
|
58
|
+
expect(@setup.validate_partials(config)).to be false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -9,6 +9,7 @@ require 'spec_helper'
|
|
|
9
9
|
require 'ceedling/config/configurator'
|
|
10
10
|
require 'ceedling/ruby_expandinator'
|
|
11
11
|
require 'ceedling/exceptions'
|
|
12
|
+
require 'ceedling/constants'
|
|
12
13
|
|
|
13
14
|
describe Configurator do
|
|
14
15
|
|
|
@@ -184,4 +185,48 @@ describe Configurator do
|
|
|
184
185
|
|
|
185
186
|
end
|
|
186
187
|
|
|
188
|
+
describe "#set_partials_derived_config" do
|
|
189
|
+
|
|
190
|
+
def partials_config
|
|
191
|
+
{ project: { use_partials: true }, defines: { test: ['TEST'] }, cmock: {} }
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "does nothing when :use_partials is disabled" do
|
|
195
|
+
config = partials_config
|
|
196
|
+
config[:project][:use_partials] = false
|
|
197
|
+
|
|
198
|
+
@configurator.set_partials_derived_config( config )
|
|
199
|
+
|
|
200
|
+
expect( config[:defines][:test] ).to eq( ['TEST'] )
|
|
201
|
+
expect( config[:defines] ).to_not have_key( :preprocess )
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "appends the partials prefix symbol to a simple :test: defines list" do
|
|
205
|
+
config = partials_config
|
|
206
|
+
|
|
207
|
+
@configurator.set_partials_derived_config( config )
|
|
208
|
+
|
|
209
|
+
expect( config[:defines][:test] ).to include( "CEEDLING_PARTIALS_PREFIX=#{PARTIAL_FILENAME_PREFIX}" )
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "leaves :preprocess: defines untouched when the project does not define that section" do
|
|
213
|
+
config = partials_config
|
|
214
|
+
|
|
215
|
+
@configurator.set_partials_derived_config( config )
|
|
216
|
+
|
|
217
|
+
expect( config[:defines] ).to_not have_key( :preprocess )
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "appends the partials prefix symbol under the :* matcher when the project defines its own :preprocess: matcher hash" do
|
|
221
|
+
config = partials_config
|
|
222
|
+
config[:defines][:preprocess] = { 'TestSoilMoisture.c' => ['CEEDLING_DELTA_PROBE'] }
|
|
223
|
+
|
|
224
|
+
@configurator.set_partials_derived_config( config )
|
|
225
|
+
|
|
226
|
+
expect( config[:defines][:preprocess][:*] ).to include( "CEEDLING_PARTIALS_PREFIX=#{PARTIAL_FILENAME_PREFIX}" )
|
|
227
|
+
expect( config[:defines][:preprocess]['TestSoilMoisture.c'] ).to eq( ['CEEDLING_DELTA_PROBE'] )
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
end
|
|
231
|
+
|
|
187
232
|
end
|
|
@@ -271,4 +271,21 @@ describe FilePathUtils do
|
|
|
271
271
|
end
|
|
272
272
|
end
|
|
273
273
|
|
|
274
|
+
describe '#form_partial_types_header_filename' do
|
|
275
|
+
before(:each) do
|
|
276
|
+
@fpu = described_class.new({
|
|
277
|
+
:configurator => double('configurator'),
|
|
278
|
+
:file_wrapper => double('file_wrapper')
|
|
279
|
+
})
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it 'forms a filename from the module name, the partial prefix, and a _types suffix' do
|
|
283
|
+
# Mirrors the sibling _interface/_impl header filename conventions -- a shared
|
|
284
|
+
# location for a module's typedefs and aggregate definitions needs a name
|
|
285
|
+
# distinct from those two generated headers so all three can coexist.
|
|
286
|
+
expect( @fpu.form_partial_types_header_filename('LightSensor') )
|
|
287
|
+
.to eq('ceedling_partial_LightSensor_types.h')
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
274
291
|
end
|
|
@@ -21,30 +21,57 @@ describe GeneratorHelper do
|
|
|
21
21
|
@helper = described_class.new({ :loginator => @loginator })
|
|
22
22
|
|
|
23
23
|
# A minimal status double for shell_result[:status].
|
|
24
|
-
@ok_status = double('status', termsig: nil)
|
|
24
|
+
@ok_status = double('status', termsig: nil, signaled?: false, exitstatus: 0, success?: true)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
# ---------------------------------------------------------------------------
|
|
29
29
|
# Helper: build a shell_result hash
|
|
30
30
|
# ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
# `success` left unspecified derives from `termsig`/`exitstatus` the way a real
|
|
32
|
+
# Process::Status would -- signaled or nonzero-exit is never success. Callers that
|
|
33
|
+
# need an inconsistent combination (a status that looks successful despite a nonzero
|
|
34
|
+
# exit, exercised nowhere here) can still pass `success:` explicitly.
|
|
35
|
+
def shell_result(output: VALID_STATS_OUTPUT, stderr: '', termsig: nil, exitstatus: 0, success: nil)
|
|
36
|
+
success = (termsig.nil? && exitstatus == 0) if success.nil?
|
|
37
|
+
status = double(
|
|
38
|
+
'status', termsig: termsig, signaled?: !termsig.nil?, exitstatus: exitstatus, success?: success
|
|
39
|
+
)
|
|
33
40
|
{ :output => output, :stderr => stderr, :status => status }
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
|
|
37
44
|
describe '#test_crash?' do
|
|
38
45
|
|
|
39
|
-
context '
|
|
40
|
-
it 'returns true when the process was terminated by signal 11' do
|
|
46
|
+
context 'signal death (any signal, not just SIGSEGV)' do
|
|
47
|
+
it 'returns true when the process was terminated by signal 11 (SIGSEGV)' do
|
|
41
48
|
result = shell_result(termsig: 11)
|
|
42
49
|
expect( @helper.test_crash?('test_foo.c', 'test_foo.out', result) ).to be true
|
|
43
50
|
end
|
|
44
51
|
|
|
45
|
-
it '
|
|
46
|
-
result = shell_result(termsig: 6)
|
|
52
|
+
it 'returns true when the process was terminated by signal 6 (SIGABRT) -- e.g. UBSan/ASan halt_on_error' do
|
|
53
|
+
result = shell_result(termsig: 6)
|
|
47
54
|
# output still has stats, stderr is empty → only the signal check matters here
|
|
55
|
+
expect( @helper.test_crash?('test_foo.c', 'test_foo.out', result) ).to be true
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context 'a clean summary contradicted by the real exit status' do
|
|
60
|
+
it 'returns true when 0 failures are reported but the real process exited nonzero and unsignaled' do
|
|
61
|
+
# e.g. LeakSanitizer detecting a leak during teardown, after every test case
|
|
62
|
+
# already printed and Unity's own summary already looked clean.
|
|
63
|
+
result = shell_result(output: VALID_STATS_OUTPUT, exitstatus: 1, success: false)
|
|
64
|
+
expect( @helper.test_crash?('test_foo.c', 'test_foo.out', result) ).to be true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'returns false when a nonzero real exit is consistent with Unity reporting real failures' do
|
|
68
|
+
failing_output = "\n---------\n2 Tests 1 Failures 0 Ignored\nFAIL\n"
|
|
69
|
+
result = shell_result(output: failing_output, exitstatus: 1, success: false)
|
|
70
|
+
expect( @helper.test_crash?('test_foo.c', 'test_foo.out', result) ).to be false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'returns false when 0 failures are reported and the real process exited successfully' do
|
|
74
|
+
result = shell_result(output: VALID_STATS_OUTPUT, exitstatus: 0, success: true)
|
|
48
75
|
expect( @helper.test_crash?('test_foo.c', 'test_foo.out', result) ).to be false
|
|
49
76
|
end
|
|
50
77
|
end
|
|
@@ -222,6 +222,80 @@ describe GeneratorPartials do
|
|
|
222
222
|
end
|
|
223
223
|
end
|
|
224
224
|
|
|
225
|
+
context "#generate_types" do
|
|
226
|
+
it "writes nothing and returns nil when the module has no typedefs or aggregate definitions" do
|
|
227
|
+
allow(@file_wrapper).to receive(:open)
|
|
228
|
+
|
|
229
|
+
c_module = make_module(
|
|
230
|
+
make_stmt(text: "#define FOO 1", line_num: 1),
|
|
231
|
+
make_var(name: 'counter', type: 'int', text: 'int counter;', line_num: 2)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
result = @generator.generate_types(
|
|
235
|
+
name: 'my_module',
|
|
236
|
+
c_module: c_module,
|
|
237
|
+
output_path: '/path/to/output'
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
expect(@file_wrapper).not_to have_received(:open)
|
|
241
|
+
expect(result).to be_nil
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it "writes only the typedefs and aggregate definitions, guarded and in element_sequence order, and returns the bare filename" do
|
|
245
|
+
file_contents = <<~CONTENTS
|
|
246
|
+
#ifndef __CEEDLING_GENERATED_MY_MODULE_TYPES_H__
|
|
247
|
+
#define __CEEDLING_GENERATED_MY_MODULE_TYPES_H__
|
|
248
|
+
|
|
249
|
+
typedef uint8_t Byte;
|
|
250
|
+
struct Config { int id; };
|
|
251
|
+
|
|
252
|
+
#endif // __CEEDLING_GENERATED_MY_MODULE_TYPES_H__
|
|
253
|
+
|
|
254
|
+
CONTENTS
|
|
255
|
+
|
|
256
|
+
output_path = '/path/to/output'
|
|
257
|
+
name = 'my_module'
|
|
258
|
+
header_filename = 'my_module_types.h'
|
|
259
|
+
expected_filepath = File.join(output_path, header_filename)
|
|
260
|
+
|
|
261
|
+
allow(@file_path_utils).to receive(:form_partial_types_header_filename)
|
|
262
|
+
.with(name)
|
|
263
|
+
.and_return(header_filename)
|
|
264
|
+
|
|
265
|
+
buf = StringIO.new()
|
|
266
|
+
allow(@file_wrapper).to receive(:open)
|
|
267
|
+
.with(expected_filepath, 'wb')
|
|
268
|
+
.and_yield(buf)
|
|
269
|
+
|
|
270
|
+
# A macro and a variable sit between the two type-defining statements in
|
|
271
|
+
# element_sequence; only the typedef and the aggregate belong in the shared
|
|
272
|
+
# types header, in their original relative order, and neither the macro nor
|
|
273
|
+
# the variable (which stay behind for generate_header) appear here at all.
|
|
274
|
+
typedef_stmt = CExtractorTypes::CStatement.new(text: "typedef uint8_t Byte;", line_num: 1)
|
|
275
|
+
macro_stmt = CExtractorTypes::CStatement.new(text: "#define FOO 1", line_num: 2)
|
|
276
|
+
var_decl = make_var(name: 'counter', type: 'int', text: 'int counter;', line_num: 3)
|
|
277
|
+
aggregate_stmt = CExtractorTypes::CStatement.new(text: "struct Config { int id; };", line_num: 4)
|
|
278
|
+
|
|
279
|
+
c_module = CExtractorTypes::CModule.new(
|
|
280
|
+
type_definitions: [typedef_stmt],
|
|
281
|
+
macro_definitions: [macro_stmt],
|
|
282
|
+
variable_declarations: [var_decl],
|
|
283
|
+
aggregate_definitions: [aggregate_stmt],
|
|
284
|
+
element_sequence: [typedef_stmt, macro_stmt, var_decl, aggregate_stmt]
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
result = @generator.generate_types(
|
|
288
|
+
name: name,
|
|
289
|
+
c_module: c_module,
|
|
290
|
+
output_path: output_path
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
294
|
+
expect(@file_wrapper).to have_received(:open).with(expected_filepath, 'wb')
|
|
295
|
+
expect(result).to eq(header_filename)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
225
299
|
context "#generate_header (private method)" do
|
|
226
300
|
# Define common StringIO buffer
|
|
227
301
|
let(:buf) { StringIO.new() }
|
|
@@ -282,6 +356,24 @@ describe GeneratorPartials do
|
|
|
282
356
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
283
357
|
end
|
|
284
358
|
|
|
359
|
+
it "should reapply a leading qualifier decorator to an extern declaration" do
|
|
360
|
+
c_module = make_module(
|
|
361
|
+
make_var(name: 'cmd', type: 'cmd_t', text: 'cmd_t cmd = { 0 };', decorators: ['static', 'volatile'])
|
|
362
|
+
)
|
|
363
|
+
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, true)
|
|
364
|
+
|
|
365
|
+
expect(buf.string).to include('extern volatile cmd_t cmd;')
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
it "should not reapply a qualifier already embedded in a pointer-level declarator" do
|
|
369
|
+
c_module = make_module(
|
|
370
|
+
make_var(name: 'lookup_table', type: 'uint8_t* const', text: 'uint8_t* const lookup_table;', decorators: ['static', 'const'])
|
|
371
|
+
)
|
|
372
|
+
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, true)
|
|
373
|
+
|
|
374
|
+
expect(buf.string).to include('extern const uint8_t* const lookup_table;')
|
|
375
|
+
end
|
|
376
|
+
|
|
285
377
|
it "should generate a header file with #include statements, variable declarations, and function signatures" do
|
|
286
378
|
file_contents = <<~CONTENTS
|
|
287
379
|
#ifndef __CEEDLING_GENERATED_APPLES_AND_BANANAS_H__
|
|
@@ -360,23 +452,29 @@ describe GeneratorPartials do
|
|
|
360
452
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
361
453
|
end
|
|
362
454
|
|
|
363
|
-
it "should emit
|
|
364
|
-
# One item of each category that can
|
|
365
|
-
# macro_definitions
|
|
366
|
-
# type_definitions
|
|
367
|
-
# aggregate_definitions → CStatement
|
|
368
|
-
# variable_declarations → CVariableDeclaration emitted as extern declaration
|
|
455
|
+
it "should emit macro and variable statements inline while routing typedefs and aggregates to the shared types header" do
|
|
456
|
+
# One item of each category that can appear in a generated Partial header:
|
|
457
|
+
# macro_definitions → CStatement emitted as-is, inline
|
|
458
|
+
# type_definitions → CStatement skipped here; belongs to generate_types instead
|
|
459
|
+
# aggregate_definitions → CStatement skipped here; belongs to generate_types instead
|
|
460
|
+
# variable_declarations → CVariableDeclaration emitted as extern declaration, inline
|
|
461
|
+
#
|
|
462
|
+
# A typedef or aggregate defines a type, and C rejects a second definition of the same
|
|
463
|
+
# type in one translation unit even when it's textually identical -- unlike a macro,
|
|
464
|
+
# which may legally repeat. Since a module's implementation and interface headers can
|
|
465
|
+
# both be included in the same test file, generate_header always defers type-defining
|
|
466
|
+
# content to the one shared types header generate_types produces, rather than risking
|
|
467
|
+
# two independent copies landing in the same translation unit.
|
|
369
468
|
#
|
|
370
469
|
# Ordering is intentionally interleaved (not grouped by category) to confirm that
|
|
371
|
-
# element_sequence — not typed-array membership — governs emit order
|
|
470
|
+
# element_sequence — not typed-array membership — governs emit order for the items
|
|
471
|
+
# that do remain inline.
|
|
372
472
|
file_contents = <<~CONTENTS
|
|
373
473
|
#ifndef __CEEDLING_GENERATED_ALL_STATEMENTS_H__
|
|
374
474
|
#define __CEEDLING_GENERATED_ALL_STATEMENTS_H__
|
|
375
475
|
|
|
376
476
|
#define MAX_ITEMS 16
|
|
377
|
-
typedef uint8_t Byte;
|
|
378
477
|
extern int item_count;
|
|
379
|
-
struct Config { int id; int flags; };
|
|
380
478
|
|
|
381
479
|
#endif // __CEEDLING_GENERATED_ALL_STATEMENTS_H__
|
|
382
480
|
|
|
@@ -443,13 +541,11 @@ describe GeneratorPartials do
|
|
|
443
541
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
444
542
|
end
|
|
445
543
|
|
|
446
|
-
it "should interleave functions with other elements in element_sequence order" do
|
|
544
|
+
it "should interleave functions with other elements in element_sequence order, skipping a leading typedef routed to the shared types header" do
|
|
447
545
|
file_contents = <<~CONTENTS
|
|
448
546
|
#ifndef __CEEDLING_GENERATED_INTERLEAVED_H__
|
|
449
547
|
#define __CEEDLING_GENERATED_INTERLEAVED_H__
|
|
450
548
|
|
|
451
|
-
typedef uint8_t Byte;
|
|
452
|
-
|
|
453
549
|
void foo(void);
|
|
454
550
|
|
|
455
551
|
extern int counter;
|
|
@@ -460,6 +556,8 @@ describe GeneratorPartials do
|
|
|
460
556
|
|
|
461
557
|
CONTENTS
|
|
462
558
|
|
|
559
|
+
# typedef_stmt is a member of type_definitions, so generate_header leaves it out here;
|
|
560
|
+
# it's the sole responsibility of generate_types (see the "shared types header" tests)
|
|
463
561
|
typedef_stmt = make_stmt(text: "typedef uint8_t Byte;", line_num: 1)
|
|
464
562
|
var_decl = make_var( name: 'counter', type: 'int', text: 'int counter;', line_num: 5)
|
|
465
563
|
|
|
@@ -568,6 +666,16 @@ describe GeneratorPartials do
|
|
|
568
666
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
569
667
|
end
|
|
570
668
|
|
|
669
|
+
it "should reapply a leading qualifier decorator to a variable definition" do
|
|
670
|
+
c_module = make_module(
|
|
671
|
+
make_var(name: 'cmd', type: 'cmd_t', text: 'cmd_t cmd = { 0 };', decorators: ['static', 'volatile'])
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
@generator.send(:generate_source, buf, [], [], c_module)
|
|
675
|
+
|
|
676
|
+
expect(buf.string).to include('volatile cmd_t cmd = { 0 };')
|
|
677
|
+
end
|
|
678
|
+
|
|
571
679
|
it "should generate a source file with include directives, variable declarations, and functions" do
|
|
572
680
|
file_contents = <<~CONTENTS
|
|
573
681
|
// Ceeding generated file
|