ceedling 1.2.1 → 1.2.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 +11 -9
- data/Rakefile +2 -1
- data/assets/features/ceedling +1 -1
- data/assets/fixtures/test_source_file_duplicate_basenames/test_calc_typo.c +14 -0
- data/assets/fixtures/tests_with_duplicate_test_names/test_foo.c +21 -0
- data/bin/actionator.rb +6 -12
- data/bin/app_cfg.rb +14 -1
- data/bin/ceedling +13 -3
- data/bin/cli.rb +25 -6
- data/bin/cli_handler.rb +113 -73
- data/bin/cli_helper.rb +51 -78
- data/bin/installation_selector.rb +81 -0
- data/bin/launchinator.rb +69 -0
- data/bin/mixin_resolvinator.rb +26 -36
- data/bin/objects.yml +13 -0
- data/bin/path_validator.rb +25 -29
- data/bin/versionator.rb +47 -48
- data/ceedling.gemspec +19 -15
- data/docs/BreakingChanges.md +70 -1
- data/docs/Changelog.md +74 -3
- data/docs/KnownIssues.md +90 -4
- data/docs/ReleaseNotes.md +13 -0
- data/lib/ceedling/build_log_writer.rb +33 -0
- data/lib/ceedling/config/build_root_policy.rb +70 -0
- data/lib/ceedling/config/configurator.rb +14 -16
- data/lib/ceedling/config/configurator_builder.rb +58 -28
- data/lib/ceedling/config/configurator_paths_validator.rb +179 -0
- data/lib/ceedling/config/configurator_plugins.rb +1 -1
- data/lib/ceedling/config/configurator_setup.rb +15 -28
- data/lib/ceedling/config/configurator_validator.rb +1 -110
- data/lib/ceedling/defaults.rb +4 -4
- data/lib/ceedling/dependencies/README.md +18 -16
- data/lib/ceedling/dependencies/dependency_cache_store.rb +20 -3
- data/lib/ceedling/dependencies/dependency_hasher.rb +35 -1
- data/lib/ceedling/filename_extension.rb +7 -1
- data/lib/ceedling/filesystem/FILE_TREE.md +253 -0
- data/lib/ceedling/filesystem/PATH_HANDLING.md +304 -0
- data/lib/ceedling/filesystem/README.md +41 -0
- data/lib/ceedling/filesystem/build_subpath.rb +102 -0
- data/lib/ceedling/filesystem/destination_collision.rb +25 -0
- data/lib/ceedling/{file_finder.rb → filesystem/file_finder.rb} +159 -104
- data/lib/ceedling/{file_finder_helper.rb → filesystem/file_finder_helper.rb} +36 -31
- data/lib/ceedling/filesystem/file_path_collection_utils.rb +183 -0
- data/lib/ceedling/{file_path_utils.rb → filesystem/file_path_utils.rb} +108 -97
- data/lib/ceedling/{file_system_wrapper.rb → filesystem/file_system_wrapper.rb} +6 -5
- data/lib/ceedling/filesystem/file_tree.rb +241 -0
- data/lib/ceedling/{file_wrapper.rb → filesystem/file_wrapper.rb} +45 -38
- data/lib/ceedling/filesystem/path_exclusions.rb +30 -0
- data/lib/ceedling/{path_matcher.rb → filesystem/path_matcher.rb} +27 -23
- data/lib/ceedling/{path_mirror.rb → filesystem/path_mirror.rb} +19 -18
- data/lib/ceedling/filesystem/path_spellings.rb +55 -0
- data/lib/ceedling/filesystem/project_paths.rb +184 -0
- data/lib/ceedling/filesystem/working_dir.rb +40 -0
- data/lib/ceedling/generators/generator.rb +5 -6
- data/lib/ceedling/generators/generator_partials.rb +1 -1
- data/lib/ceedling/generators/generator_test_results_backtrace.rb +7 -7
- data/lib/ceedling/handoff.rb +121 -0
- data/lib/ceedling/includes/include_factory.rb +3 -3
- data/lib/ceedling/includes/include_pathinator.rb +67 -10
- data/lib/ceedling/includes/includes.rb +1 -1
- data/lib/ceedling/installation.rb +92 -0
- data/lib/ceedling/library_resolver.rb +99 -0
- data/lib/ceedling/objects.yml +23 -2
- data/lib/ceedling/partials/partializer.rb +4 -4
- data/lib/ceedling/partials/partializer_config.rb +3 -1
- data/lib/ceedling/plugins/report_log_writer_plugin.rb +3 -5
- data/lib/ceedling/preprocess/preprocessinator_file_assembler.rb +1 -1
- data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +1 -1
- data/lib/ceedling/preprocess/preprocessinator_line_marker_includes_extractor.rb +1 -1
- data/lib/ceedling/rake_app/rakefile_component_resolver.rb +10 -17
- data/lib/ceedling/rakefile.rb +15 -1
- data/lib/ceedling/rakefiles/base/tasks_base.rake +1 -1
- data/lib/ceedling/rakefiles/release/rules_release.rake +4 -7
- data/lib/ceedling/release_invoker/release_build_executor.rb +33 -44
- data/lib/ceedling/release_invoker/release_build_planner.rb +14 -6
- data/lib/ceedling/reportinator.rb +3 -4
- data/lib/ceedling/setupinator.rb +94 -90
- data/lib/ceedling/test_context_extractor.rb +5 -1
- data/lib/ceedling/test_invoker/PIPELINE.md +9 -7
- data/lib/ceedling/test_invoker/mock_locator.rb +60 -2
- data/lib/ceedling/test_invoker/partials_manager.rb +12 -0
- data/lib/ceedling/test_invoker/standin_headerinator.rb +22 -13
- data/lib/ceedling/test_invoker/test_build_executor.rb +24 -40
- data/lib/ceedling/test_invoker/test_build_planner.rb +37 -18
- data/lib/ceedling/test_invoker/test_build_setup.rb +17 -12
- data/lib/ceedling/test_invoker/test_build_validations.rb +16 -31
- data/lib/ceedling/test_invoker/test_file_preprocessinator.rb +1 -1
- data/lib/ceedling/test_invoker/test_invoker.rb +6 -1
- data/lib/ceedling/test_invoker/test_pipeline_helpers.rb +1 -1
- data/lib/ceedling/test_invoker/test_source_file_directive_resolver.rb +40 -20
- data/lib/ceedling/tool_executor.rb +9 -3
- data/lib/ceedling/yaml_wrapper.rb +3 -2
- data/lib/version.rb +1 -1
- data/plugins/bullseye/config/defaults_bullseye.rb +1 -1
- data/plugins/bullseye/lib/bullseye.rb +9 -7
- data/plugins/cppcheck/config/defaults_cppcheck.rb +1 -1
- data/plugins/dependencies/config/defaults.yml +6 -6
- data/plugins/dependencies/dependencies.rake +4 -1
- data/plugins/dependencies/lib/dependencies.rb +18 -8
- data/plugins/dependencies/lib/dependency_spec.rb +17 -5
- data/plugins/fff/lib/fff.rb +45 -39
- data/plugins/fff/spec/fff_cmock_wrapper_spec.rb +128 -0
- data/plugins/gcov/config/defaults_gcov.rb +1 -1
- data/plugins/gcov/lib/console_reportinator.rb +4 -18
- data/plugins/gcov/lib/gcov.rb +9 -2
- data/plugins/gcov/lib/gcovr_reportinator.rb +8 -40
- data/plugins/gcov/lib/gcovr_thresholds.rb +74 -0
- data/plugins/gcov/lib/reportgenerator_reportinator.rb +1 -1
- data/plugins/module_generator/lib/module_generator.rb +3 -3
- data/plugins/report_tests_teamcity_stdout/lib/report_tests_teamcity_stdout.rb +53 -80
- data/plugins/sanitize/lib/sanitize_records.rb +3 -6
- data/plugins/valgrind/lib/valgrind.rb +14 -7
- data/site-local/configuration/reference/cmock.html +2 -1
- data/site-local/configuration/reference/files.html +9 -3
- data/site-local/configuration/reference/libraries.html +21 -3
- data/site-local/configuration/reference/paths.html +29 -6
- data/site-local/configuration/reference/project.html +17 -7
- data/site-local/configuration/reference/release-build.html +2 -0
- data/site-local/configuration/reference/tools.html +9 -0
- data/site-local/configuration/which-ceedling.html +377 -17
- data/site-local/development/releases.html +5 -1
- data/site-local/development/workflow.html +48 -43
- data/site-local/getting-started/builds.html +2 -0
- data/site-local/getting-started/command-line.html +56 -4
- data/site-local/plugins/dependencies.html +6 -3
- data/site-local/plugins/fff.html +42 -11
- data/site-local/plugins/gcov/gcovr.html +15 -12
- data/site-local/plugins/gcov/setup.html +2 -1
- data/site-local/plugins/report-tests-raw-output-log.html +3 -1
- data/site-local/plugins/report-tests-teamcity-stdout.html +6 -3
- data/site-local/plugins/sanitize.html +7 -6
- data/site-local/plugins/valgrind.html +8 -7
- data/site-local/project/upgrade.html +3 -0
- data/site-local/reference/command-line.html +9 -2
- data/site-local/sitemap.xml.gz +0 -0
- data/site-local/snapshot/plugins/bullseye/config/defaults_bullseye.rb +1 -1
- data/site-local/snapshot/plugins/gcov/config/defaults_gcov.rb +1 -1
- data/site-local/testing-guide/conventions.html +53 -0
- data/spec/integration/actionator_file_operations_spec.rb +91 -1
- data/spec/integration/compile_commands_json_db_spec.rb +1 -1
- data/spec/integration/configurator_validation_spec.rb +1 -1
- data/spec/integration/dependencies/dependency_tracker_cache_hardening_spec.rb +26 -0
- data/spec/integration/dependencies/dependency_tracker_core_spec.rb +22 -0
- data/spec/integration/launcher_handoff_spec.rb +297 -0
- data/spec/integration/mixin_loading_spec.rb +1 -1
- data/spec/integration/module_generator_spec.rb +3 -3
- data/spec/integration/nested_test_artifacts_spec.rb +99 -0
- data/spec/integration/partials_module_resolution_spec.rb +7 -4
- data/spec/integration/path_intake_scenarios_spec.rb +101 -0
- data/spec/integration/path_scenarios_spec.rb +322 -0
- data/spec/integration/quote_include_isolator_spec.rb +1 -1
- data/spec/integration/report_build_warnings_log_spec.rb +1 -1
- data/spec/integration/report_tests_log_factory_spec.rb +1 -1
- data/spec/integration/test_executable_manifest_spec.rb +1 -1
- data/spec/integration/test_includes_extractinator_spec.rb +2 -1
- data/spec/integration/test_naming_spec.rb +198 -0
- data/spec/integration/test_source_file_checks_spec.rb +166 -0
- data/spec/integration/tool_validator_spec.rb +1 -1
- data/spec/integration/upgrade_docs_spec.rb +84 -0
- data/spec/integration/vendor_copy_transient_io_retry_spec.rb +74 -5
- data/spec/support/file_tree_helper.rb +88 -0
- data/spec/support/integration/configurator_integration_helper.rb +6 -6
- data/spec/support/integration/dependency_tracker_integration_helper.rb +1 -1
- data/spec/support/integration/partials_generation_integration_helper.rb +2 -2
- data/spec/support/integration/path_scenario_harness.rb +173 -0
- data/spec/support/integration/spec_integration_helper.rb +1 -1
- data/spec/support/integration/test_includes_harness.rb +13 -2
- data/spec/support/spec_helper.rb +2 -0
- data/spec/support/system/spec_system_helper.rb +7 -6
- data/spec/support/system/system_context.rb +21 -3
- data/spec/support/working_dir_tracking.rb +49 -0
- data/spec/system/build_output_mirroring_spec.rb +2 -2
- data/spec/system/conditional_mock_includes_spec.rb +1 -1
- data/spec/system/delta_builds_spec.rb +137 -11
- data/spec/system/gcov_deployment_spec.rb +1 -0
- data/spec/system/header_include_path_validation_spec.rb +4 -4
- data/spec/system/launcher_handoff_spec.rb +82 -0
- data/spec/system/mock_include_folders_spec.rb +91 -0
- data/spec/system/parent_directory_reference_spec.rb +5 -3
- data/spec/system/path_handling_probes_spec.rb +192 -0
- data/spec/system/preprocessing_parameterized_tests_spec.rb +1 -1
- data/spec/system/rake_release_task_path_disambiguation_spec.rb +6 -6
- data/spec/system/rake_test_task_path_disambiguation_spec.rb +85 -0
- data/spec/system/special_path_characters_spec.rb +86 -0
- data/spec/system/support/common_test_cases.rb +23 -21
- data/spec/system/support/gcov_common_test_cases.rb +37 -9
- data/spec/system/support/sanitize_common_test_cases.rb +2 -2
- data/spec/system/support/valgrind_common_test_cases.rb +12 -12
- data/spec/system/test_pipeline_stop_points_spec.rb +4 -4
- data/spec/system/test_runner_system_include_spec.rb +1 -1
- data/spec/system/test_source_file_directive_spec.rb +34 -5
- data/spec/units/bin/actionator_spec.rb +14 -17
- data/spec/units/bin/app_cfg_spec.rb +37 -0
- data/spec/units/bin/cli_handler_spec.rb +282 -6
- data/spec/units/bin/cli_helper_spec.rb +116 -45
- data/spec/units/bin/installation_selector_spec.rb +114 -0
- data/spec/units/bin/launchinator_spec.rb +171 -0
- data/spec/units/bin/path_validator_spec.rb +10 -0
- data/spec/units/bin/versionator_spec.rb +38 -6
- data/spec/units/build_log_writer_spec.rb +57 -0
- data/spec/units/config/build_root_policy_spec.rb +61 -0
- data/spec/units/config/configurator_builder_spec.rb +37 -6
- data/spec/units/config/configurator_paths_validator_spec.rb +292 -0
- data/spec/units/config/configurator_setup_spec.rb +9 -65
- data/spec/units/config/configurator_spec.rb +27 -5
- data/spec/units/config/configurator_validator_spec.rb +1 -172
- data/spec/units/default_tools_quoting_spec.rb +83 -0
- data/spec/units/dependencies/dependency_cache_store_spec.rb +33 -2
- data/spec/units/dependencies/dependency_debug_tree_spec.rb +1 -1
- data/spec/units/dependencies/dependency_hasher_spec.rb +42 -1
- data/spec/units/dependencies/dependency_path_normalizer_spec.rb +1 -1
- data/spec/units/dependencies/dependency_tracker_spec.rb +3 -1
- data/spec/units/filename_extension_spec.rb +11 -0
- data/spec/units/filesystem/build_subpath_spec.rb +122 -0
- data/spec/units/filesystem/destination_collision_spec.rb +30 -0
- data/spec/units/{file_finder_helper_spec.rb → filesystem/file_finder_helper_spec.rb} +46 -1
- data/spec/units/{file_finder_spec.rb → filesystem/file_finder_spec.rb} +188 -22
- data/spec/units/{file_path_collection_utils_spec.rb → filesystem/file_path_collection_utils_spec.rb} +181 -1
- data/spec/units/{file_path_utils_spec.rb → filesystem/file_path_utils_spec.rb} +204 -87
- data/spec/units/filesystem/file_system_wrapper_spec.rb +33 -0
- data/spec/units/filesystem/file_tree_spec.rb +511 -0
- data/spec/units/filesystem/file_tree_windows_spec.rb +78 -0
- data/spec/units/{file_wrapper_spec.rb → filesystem/file_wrapper_spec.rb} +95 -12
- data/spec/units/{path_matcher_spec.rb → filesystem/path_matcher_spec.rb} +12 -1
- data/spec/units/{path_mirror_spec.rb → filesystem/path_mirror_spec.rb} +32 -4
- data/spec/units/filesystem/project_paths_spec.rb +147 -0
- data/spec/units/filesystem/working_dir_spec.rb +71 -0
- data/spec/units/generators/generator_spec.rb +12 -6
- data/spec/units/generators/generator_test_results_backtrace_spec.rb +50 -46
- data/spec/units/generators/generator_test_results_spec.rb +1 -1
- data/spec/units/handoff_spec.rb +205 -0
- data/spec/units/includes/include_factory_spec.rb +3 -3
- data/spec/units/includes/include_pathinator_spec.rb +46 -0
- data/spec/units/installation_spec.rb +228 -0
- data/spec/units/library_resolver_spec.rb +157 -0
- data/spec/units/mock_locator_spec.rb +76 -1
- data/spec/units/partials/partializer_config_spec.rb +7 -0
- data/spec/units/partials/partializer_spec.rb +1 -0
- data/spec/units/partials_manager_spec.rb +17 -0
- data/spec/units/plugins/bullseye_spec.rb +15 -2
- data/spec/units/plugins/console_reportinator_spec.rb +18 -20
- data/spec/units/plugins/dependencies_spec.rb +33 -7
- data/spec/units/plugins/dependency_spec_spec.rb +17 -0
- data/spec/units/plugins/gcov_spec.rb +28 -3
- data/spec/units/plugins/gcovr_reportinator_spec.rb +19 -47
- data/spec/units/plugins/gcovr_thresholds_spec.rb +95 -0
- data/spec/units/plugins/module_generator_spec.rb +5 -5
- data/spec/units/plugins/report_build_warnings_log_spec.rb +3 -3
- data/spec/units/plugins/report_log_writer_plugin_spec.rb +10 -1
- data/spec/units/plugins/report_tests_raw_output_log_spec.rb +13 -2
- data/spec/units/plugins/report_tests_teamcity_stdout_spec.rb +77 -3
- data/spec/units/plugins/reportgenerator_reportinator_spec.rb +1 -1
- data/spec/units/plugins/sanitize_records_spec.rb +3 -1
- data/spec/units/plugins/sanitize_spec.rb +1 -1
- data/spec/units/plugins/valgrind_spec.rb +23 -8
- data/spec/units/preprocess/preprocessinator_comment_stripper_spec.rb +1 -1
- data/spec/units/rake_app/rakefile_component_resolver_spec.rb +21 -0
- data/spec/units/release_build_executor_spec.rb +53 -14
- data/spec/units/release_build_planner_spec.rb +15 -3
- data/spec/units/reportinator_spec.rb +5 -5
- data/spec/units/standin_headerinator_spec.rb +31 -1
- data/spec/units/test_build_executor_spec.rb +65 -3
- data/spec/units/test_build_planner_spec.rb +104 -2
- data/spec/units/test_build_setup_spec.rb +96 -12
- data/spec/units/test_context_extractor_spec.rb +25 -0
- data/spec/units/test_file_preprocessinator_spec.rb +17 -1
- data/spec/units/test_includes_extractinator_spec.rb +5 -1
- data/spec/units/test_invoker/objects_wiring_spec.rb +6 -3
- data/spec/units/test_invoker_spec.rb +14 -1
- data/spec/units/test_source_file_directive_resolver_spec.rb +38 -7
- data/spec/units/tool_executor_spec.rb +26 -0
- data/spec/units/yaml_wrapper_spec.rb +11 -0
- metadata +109 -25
- data/lib/ceedling/file_path_collection_utils.rb +0 -164
|
@@ -50,7 +50,7 @@ describe Dependencies do
|
|
|
50
50
|
tool_validator: double( 'tool_validator' ).tap { |validator| allow(validator).to receive(:validate).and_return( true ) },
|
|
51
51
|
loginator: double( 'loginator', lazy: nil ).tap { |log| allow(log).to receive(:log) { |message, *| logged << message } },
|
|
52
52
|
file_path_collection_utils: double( 'file_path_collection_utils', collect_paths: [] ),
|
|
53
|
-
file_path_utils: double( 'file_path_utils',
|
|
53
|
+
file_path_utils: double( 'file_path_utils', form_test_build_map_filepath: 'map' ).tap { |utils| allow(utils).to receive(:form_release_build_list_filepath) { |path| path.ext( '.lst' ) } } }
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def dependency(name = 'dep', **overrides)
|
|
@@ -245,10 +245,15 @@ describe Dependencies do
|
|
|
245
245
|
end
|
|
246
246
|
|
|
247
247
|
describe 'libraries' do
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
248
|
+
# GH #1368: a link depends on each library's exact file, which a name can't always reach
|
|
249
|
+
it 'names every library, its directory, and its file for linking, leaving executables out' do
|
|
250
|
+
plugin = plugin_for( dependency( artifacts: { static_libraries: ['libw.a'], dynamic_libraries: ['sub/libv.so.1'], executables: ['bin/tool'] } ) )
|
|
251
|
+
|
|
252
|
+
expect(plugin.link_libraries).to eq(
|
|
253
|
+
names: ['w', 'v.so'],
|
|
254
|
+
paths: ['deps/dep/build', 'deps/dep/build/sub'],
|
|
255
|
+
files: ['deps/dep/build/libw.a', 'deps/dep/build/sub/libv.so.1']
|
|
256
|
+
)
|
|
252
257
|
end
|
|
253
258
|
end
|
|
254
259
|
|
|
@@ -266,7 +271,7 @@ describe Dependencies do
|
|
|
266
271
|
plugin_for( lib ).make_if_required( 'dep' )
|
|
267
272
|
|
|
268
273
|
expect(generator).to have_received(:generate_object_file_c)
|
|
269
|
-
.with( hash_including( source: 'cc/src/b.c', object: 'cc/build/b.o', search_paths: ['cc/inc'], defines: ['FAST'] ) )
|
|
274
|
+
.with( hash_including( source: 'cc/src/b.c', object: 'cc/build/src/b.o', search_paths: ['cc/inc'], defines: ['FAST'] ) )
|
|
270
275
|
expect(executed).not_to include( a_string_starting_with( 'cd ' ) )
|
|
271
276
|
end
|
|
272
277
|
|
|
@@ -274,10 +279,31 @@ describe Dependencies do
|
|
|
274
279
|
plugin_for( lib ).make_if_required( 'dep' )
|
|
275
280
|
|
|
276
281
|
expect(generator).to have_received(:generate_executable_file)
|
|
277
|
-
.with( anything, anything, ['cc/build/a.o', 'cc/build/b.o'], [], 'cc/build/libcc.a', 'map', [], [] )
|
|
282
|
+
.with( anything, anything, ['cc/build/a.o', 'cc/build/src/b.o'], [], 'cc/build/libcc.a', 'map', [], [] )
|
|
278
283
|
expect(file_wrapper).to have_received(:cp).with( 'cc/build/libcc.a', 'cc/out/libcc.a' )
|
|
279
284
|
end
|
|
280
285
|
|
|
286
|
+
it 'places two same-named sources\' objects apart, by their paths below the source path' do
|
|
287
|
+
allow(file_wrapper).to receive(:directory_listing) do |glob|
|
|
288
|
+
{ 'cc/**/*.c' => ['cc/a/x.c', 'cc/b/x.c'] }.fetch( glob, [] )
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
plugin_for( lib ).make_if_required( 'dep' )
|
|
292
|
+
|
|
293
|
+
expect(generator).to have_received(:generate_executable_file)
|
|
294
|
+
.with( anything, anything, ['cc/build/a/x.o', 'cc/build/b/x.o'], [], 'cc/build/libcc.a', 'map', [], [] )
|
|
295
|
+
expect(file_wrapper).to have_received(:mkdir).with( 'cc/build/a' )
|
|
296
|
+
expect(file_wrapper).to have_received(:mkdir).with( 'cc/build/b' )
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# The path handling audit around GH #1370: a list file named by its source alone lands in
|
|
300
|
+
# the working directory
|
|
301
|
+
it 'writes each object\'s list file beside it' do
|
|
302
|
+
plugin_for( lib ).make_if_required( 'dep' )
|
|
303
|
+
|
|
304
|
+
expect(generator).to have_received(:generate_object_file_c).with( hash_including( object: 'cc/build/src/b.o', list: 'cc/build/src/b.lst' ) )
|
|
305
|
+
end
|
|
306
|
+
|
|
281
307
|
it 'checks its compiler and archiver before building' do
|
|
282
308
|
plugin_for( lib ).make_if_required( 'dep' )
|
|
283
309
|
|
|
@@ -132,6 +132,23 @@ describe DependencySpec do
|
|
|
132
132
|
expect(spec.include_directories( ->( glob ) { ["#{glob}/a", "#{glob}/b"] } )).to eq( ['out/inc/**/a', 'out/inc/**/b'] )
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
+
# The path handling audit around GH #1370: an absolute artifact names itself
|
|
136
|
+
it 'keeps an absolute artifact or include path as written' do
|
|
137
|
+
lib = File.expand_path( '/opt/sdk/lib/libsdk.a' )
|
|
138
|
+
inc = File.expand_path( '/opt/sdk/inc' )
|
|
139
|
+
spec = spec_for( paths: { artifact: 'out' }, artifacts: { static_libraries: [lib], includes: [inc] } )
|
|
140
|
+
|
|
141
|
+
expect(spec.static_libraries).to eq( [lib] )
|
|
142
|
+
expect(spec.include_directories( ->( _glob ) { raise 'no glob here' } )).to eq( [inc] )
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'reads its configured paths as every configured path is read, `~` as the home directory' do
|
|
146
|
+
spec = spec_for( paths: { source: '~/deps/w\\src\\', artifact: '~/deps/w/out' } )
|
|
147
|
+
|
|
148
|
+
expect(spec.source_path).to eq( File.join( Dir.home, 'deps/w/src' ) )
|
|
149
|
+
expect(spec.static_libraries).to eq( [File.join( Dir.home, 'deps/w/out/libworker.a' )] )
|
|
150
|
+
end
|
|
151
|
+
|
|
135
152
|
it 'treats missing artifacts as empty' do
|
|
136
153
|
spec = DependencySpec.build_all( [{ name: 'tool', fetch: { method: :none } }] ).first
|
|
137
154
|
|
|
@@ -10,7 +10,7 @@ require 'yaml'
|
|
|
10
10
|
require 'ceedling/constants'
|
|
11
11
|
require 'ceedling/exceptions'
|
|
12
12
|
require 'ceedling/plugins/plugin'
|
|
13
|
-
require 'ceedling/path_mirror'
|
|
13
|
+
require 'ceedling/filesystem/path_mirror'
|
|
14
14
|
require 'ceedling/filename_extension'
|
|
15
15
|
|
|
16
16
|
PROJECT_BUILD_ROOT = 'build' unless defined?(PROJECT_BUILD_ROOT)
|
|
@@ -176,7 +176,7 @@ describe Gcov do
|
|
|
176
176
|
let(:test_build_setup) { double('test_build_setup', context_defines: [], flags: []) }
|
|
177
177
|
let(:dependinator) { double('dependinator', register: nil, register_gcc_deps_file: nil, flush: nil, mark_fresh: nil) }
|
|
178
178
|
let(:generator) { double('generator', generate_object_file_c: nil) }
|
|
179
|
-
let(:file_wrapper) { double('file_wrapper', exist?: false) }
|
|
179
|
+
let(:file_wrapper) { double('file_wrapper', exist?: false, mkdir: nil) }
|
|
180
180
|
let(:test_invoker) { double('test_invoker') }
|
|
181
181
|
|
|
182
182
|
def build_process_gcov(project_config, ivars = {})
|
|
@@ -215,7 +215,7 @@ describe Gcov do
|
|
|
215
215
|
|
|
216
216
|
it 'logs the full, sorted filepath list and records @untested_sources without compiling' do
|
|
217
217
|
gcov = build_process_gcov({ gcov_untested_sources: GCOV_UNTESTED_SOURCES_LIST })
|
|
218
|
-
expect(loginator).to receive(:log_list).with(['src/a.c', 'src/b.c'], kind_of(String), Verbosity::COMPLAIN
|
|
218
|
+
expect(loginator).to receive(:log_list).with(['src/a.c', 'src/b.c'], kind_of(String), Verbosity::COMPLAIN)
|
|
219
219
|
expect(generator).to_not receive(:generate_object_file_c)
|
|
220
220
|
gcov.process_untested_sources(sources: ['src/b.c', 'src/a.c'])
|
|
221
221
|
expect(gcov.instance_variable_get(:@untested_sources)).to eq(['src/b.c', 'src/a.c'])
|
|
@@ -243,6 +243,16 @@ describe Gcov do
|
|
|
243
243
|
gcov.process_untested_sources(sources: ['src/a.c'])
|
|
244
244
|
end
|
|
245
245
|
|
|
246
|
+
# An untested source's object sits at its path below the output root, in a
|
|
247
|
+
# directory no test build made
|
|
248
|
+
it 'makes the object\'s and dependencies file\'s directories before compiling' do
|
|
249
|
+
allow(dependinator).to receive(:stale?).and_return(true)
|
|
250
|
+
gcov = build_process_gcov({ gcov_untested_sources: GCOV_UNTESTED_SOURCES_COMPILE, gcov_mcdc: false })
|
|
251
|
+
expect(file_wrapper).to receive(:mkdir).with('build/gcov/out/src').twice.ordered
|
|
252
|
+
expect(generator).to receive(:generate_object_file_c).ordered
|
|
253
|
+
gcov.process_untested_sources(sources: ['src/a.c'])
|
|
254
|
+
end
|
|
255
|
+
|
|
246
256
|
it 'compiles a stale object and marks it fresh' do
|
|
247
257
|
allow(dependinator).to receive(:stale?).and_return(true)
|
|
248
258
|
gcov = build_process_gcov({ gcov_untested_sources: GCOV_UNTESTED_SOURCES_COMPILE, gcov_mcdc: false })
|
|
@@ -341,6 +351,21 @@ describe Gcov do
|
|
|
341
351
|
expect(succeeding).to have_received(:generate_reports)
|
|
342
352
|
end
|
|
343
353
|
|
|
354
|
+
# GH #1366: every violated coverage threshold is its own entry, so each gets its own bullet
|
|
355
|
+
it 'registers each coverage threshold violation as its own build failure' do
|
|
356
|
+
failing = double('failing_reportinator', artifacts_path: nil, name: 'Gcovr', summary: '')
|
|
357
|
+
allow(failing).to receive(:generate_reports).and_raise(GcovrThresholdError.new(['line low', 'condition low']))
|
|
358
|
+
|
|
359
|
+
plugin_manager = double('plugin_manager')
|
|
360
|
+
expect(plugin_manager).to receive(:register_build_failure).with(GCOV_SYM, 'line low').ordered
|
|
361
|
+
expect(plugin_manager).to receive(:register_build_failure).with(GCOV_SYM, 'condition low').ordered
|
|
362
|
+
|
|
363
|
+
gcov = build_gcov({}, reports_enabled: true, configurator: configurator, ceedling: { plugin_manager: plugin_manager })
|
|
364
|
+
allow(gcov).to receive(:build_reportinators).and_return([failing])
|
|
365
|
+
|
|
366
|
+
gcov.generate_coverage_reports
|
|
367
|
+
end
|
|
368
|
+
|
|
344
369
|
it 'logs the reportinator summary only when non-empty' do
|
|
345
370
|
r_with_summary = double('r1', artifacts_path: nil, generate_reports: nil, name: 'R1', summary: 'coverage: 80%')
|
|
346
371
|
r_without = double('r2', artifacts_path: nil, generate_reports: nil, name: 'R2', summary: '')
|
|
@@ -336,25 +336,30 @@ describe GcovrReportinator do
|
|
|
336
336
|
describe '#gcovr_exec_exception?' do
|
|
337
337
|
let(:reportinator) { build_reportinator({}) }
|
|
338
338
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
LINE_AND_CONDITION_STDERR = "(ERROR) Failed minimum line coverage (got 76.7%, minimum 100.0%)\n" +
|
|
340
|
+
"(ERROR) Failed minimum condition coverage (got 92.9%, minimum 100.0%)\n"
|
|
341
|
+
|
|
342
|
+
# GH #1366: a run failing line and condition coverage reported the line message twice
|
|
343
|
+
it 'raises one error carrying every violated threshold, each with its own gcovr message' do
|
|
344
|
+
opts = { fail_under_line: 100, fail_under_decision: 100 }
|
|
345
|
+
# exit code 10 = bit 2 (line) | bit 8 (condition or decision)
|
|
342
346
|
expect {
|
|
343
|
-
reportinator.send(:gcovr_exec_exception?, opts,
|
|
344
|
-
}.to raise_error(
|
|
345
|
-
expect(ex.
|
|
346
|
-
|
|
347
|
+
reportinator.send(:gcovr_exec_exception?, opts, 10, true, { stderr: LINE_AND_CONDITION_STDERR })
|
|
348
|
+
}.to raise_error(GcovrThresholdError) { |ex|
|
|
349
|
+
expect(ex.violations).to eq( [
|
|
350
|
+
'Gcovr ⏩️ Failed minimum line coverage (got 76.7%, minimum 100.0%)',
|
|
351
|
+
'Gcovr ⏩️ Failed minimum condition coverage (got 92.9%, minimum 100.0%)'
|
|
352
|
+
] )
|
|
347
353
|
}
|
|
348
354
|
end
|
|
349
355
|
|
|
350
|
-
it 'logs (not raises) every violation, clearing their bits, when boom is false' do
|
|
351
|
-
opts = { fail_under_line:
|
|
352
|
-
expect(loginator).to receive(:log).with(/
|
|
353
|
-
expect(loginator).to receive(:log).with(/
|
|
354
|
-
#
|
|
355
|
-
# thresholds above -- both bits clear, leaving no unexplained problem.
|
|
356
|
+
it 'logs (not raises) every violation once, clearing their bits, when boom is false' do
|
|
357
|
+
opts = { fail_under_line: 100, fail_under_decision: 100 }
|
|
358
|
+
expect(loginator).to receive(:log).with(/Failed minimum line coverage/, Verbosity::COMPLAIN).once
|
|
359
|
+
expect(loginator).to receive(:log).with(/Failed minimum condition coverage/, Verbosity::COMPLAIN).once
|
|
360
|
+
# Both bits are explained by the two configured thresholds, leaving no unexplained problem
|
|
356
361
|
expect(
|
|
357
|
-
reportinator.send(:gcovr_exec_exception?, opts,
|
|
362
|
+
reportinator.send(:gcovr_exec_exception?, opts, 10, false, { stderr: LINE_AND_CONDITION_STDERR })
|
|
358
363
|
).to eq(false)
|
|
359
364
|
end
|
|
360
365
|
|
|
@@ -698,39 +703,6 @@ describe GcovrReportinator do
|
|
|
698
703
|
end
|
|
699
704
|
end
|
|
700
705
|
|
|
701
|
-
describe '#extract_gcovr_error_message' do
|
|
702
|
-
let(:reportinator) { build_reportinator({}) }
|
|
703
|
-
|
|
704
|
-
it 'returns nil for a nil shell_result' do
|
|
705
|
-
expect( reportinator.send(:extract_gcovr_error_message, nil) ).to be_nil
|
|
706
|
-
end
|
|
707
|
-
|
|
708
|
-
it 'returns nil when stderr is empty' do
|
|
709
|
-
expect( reportinator.send(:extract_gcovr_error_message, { stderr: '' }) ).to be_nil
|
|
710
|
-
end
|
|
711
|
-
|
|
712
|
-
it 'captures, trims, and capitalizes an (ERROR)-prefixed line' do
|
|
713
|
-
result = reportinator.send(:extract_gcovr_error_message, { stderr: "(ERROR) something went wrong.\n" })
|
|
714
|
-
expect(result).to eq('Something went wrong.')
|
|
715
|
-
end
|
|
716
|
-
|
|
717
|
-
it 'matches case-insensitively' do
|
|
718
|
-
result = reportinator.send(:extract_gcovr_error_message, { stderr: "error: lowercase message\n" })
|
|
719
|
-
expect(result).to eq('Lowercase message')
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
it 'uses only the first matching line among several' do
|
|
723
|
-
stderr = "(ERROR) first problem\n(ERROR) second problem\n"
|
|
724
|
-
result = reportinator.send(:extract_gcovr_error_message, { stderr: stderr })
|
|
725
|
-
expect(result).to eq('First problem')
|
|
726
|
-
end
|
|
727
|
-
|
|
728
|
-
it 'returns nil when no error-prefixed line exists' do
|
|
729
|
-
result = reportinator.send(:extract_gcovr_error_message, { stderr: "just some noise\n" })
|
|
730
|
-
expect(result).to be_nil
|
|
731
|
-
end
|
|
732
|
-
end
|
|
733
|
-
|
|
734
706
|
describe '#extract_gcovr_summary' do
|
|
735
707
|
let(:reportinator) { build_reportinator({}) }
|
|
736
708
|
|
|
@@ -0,0 +1,95 @@
|
|
|
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/exceptions'
|
|
10
|
+
|
|
11
|
+
$: << File.expand_path('../../../../plugins/gcov/lib', __FILE__)
|
|
12
|
+
|
|
13
|
+
require 'gcovr_thresholds'
|
|
14
|
+
|
|
15
|
+
# GH #1366: every violated threshold took stderr's first (ERROR) line, so two violations
|
|
16
|
+
# reported the line-coverage message twice and lost the other
|
|
17
|
+
describe GcovrThresholds do
|
|
18
|
+
# gcovr 8.8, :mcdc on, --fail-under-line 100 --fail-under-decision 100 (exit 10 = 2 | 8).
|
|
19
|
+
# From 8.7, --fail-under-decision also checks condition coverage, so bit 8 carries two lines.
|
|
20
|
+
STDERR_8_8 = <<~STDERR
|
|
21
|
+
(ERROR) Failed minimum line coverage (got 50.0%, minimum 100.0%)
|
|
22
|
+
(ERROR) Failed minimum condition coverage (got 50.0%, minimum 100.0%)
|
|
23
|
+
(ERROR) Failed minimum decision coverage (got 0.0%, minimum 100.0%)
|
|
24
|
+
STDERR
|
|
25
|
+
|
|
26
|
+
def decode(opts, exitcode, stderr)
|
|
27
|
+
GcovrThresholds.decode( opts: opts, exitcode: exitcode, stderr: stderr )
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'reports each violated threshold with its own gcovr message, once' do
|
|
31
|
+
violations, unexplained = decode( {fail_under_line: 100, fail_under_decision: 100}, 10, STDERR_8_8 )
|
|
32
|
+
|
|
33
|
+
expect(violations).to eq( [
|
|
34
|
+
'Gcovr ⏩️ Failed minimum line coverage (got 50.0%, minimum 100.0%)',
|
|
35
|
+
'Gcovr ⏩️ Failed minimum condition coverage (got 50.0%, minimum 100.0%)',
|
|
36
|
+
'Gcovr ⏩️ Failed minimum decision coverage (got 0.0%, minimum 100.0%)'
|
|
37
|
+
] )
|
|
38
|
+
expect(unexplained).to eq( 0 )
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'reports a decision message alone, as gcovr before 8.7 writes it' do
|
|
42
|
+
stderr = "(ERROR) Failed minimum decision coverage (got 40.0%, minimum 90.0%)\n"
|
|
43
|
+
|
|
44
|
+
violations, _ = decode( {fail_under_decision: 90}, 8, stderr )
|
|
45
|
+
|
|
46
|
+
expect(violations).to eq( ['Gcovr ⏩️ Failed minimum decision coverage (got 40.0%, minimum 90.0%)'] )
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'keeps gcovr\'s capitalization' do
|
|
50
|
+
stderr = "(ERROR) Failed minimum branch coverage (got 1.0%, minimum MC/DC 2.0%)\n"
|
|
51
|
+
|
|
52
|
+
violations, _ = decode( {fail_under_branch: 2}, 4, stderr )
|
|
53
|
+
|
|
54
|
+
expect(violations.first).to end_with( 'Failed minimum branch coverage (got 1.0%, minimum MC/DC 2.0%)' )
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'capitalizes the message an older gcovr writes in lowercase' do
|
|
58
|
+
stderr = "(ERROR) failed minimum line coverage (got 50.0%, minimum 90.0%)\n"
|
|
59
|
+
|
|
60
|
+
violations, _ = decode( {fail_under_line: 90}, 2, stderr )
|
|
61
|
+
|
|
62
|
+
expect(violations).to eq( ['Gcovr ⏩️ Failed minimum line coverage (got 50.0%, minimum 90.0%)'] )
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'falls back to a description of each violated threshold that gcovr gave no message for' do
|
|
66
|
+
violations, _ = decode( {fail_under_line: 90, fail_under_decision: 80, fail_under_function: 70}, 2 | 8 | 16, '' )
|
|
67
|
+
|
|
68
|
+
expect(violations).to eq( [
|
|
69
|
+
'Gcovr ⏩️ Line coverage is less than the configured minimum of 90%',
|
|
70
|
+
'Gcovr ⏩️ Condition or decision coverage is less than the configured minimum of 80%',
|
|
71
|
+
'Gcovr ⏩️ Function coverage is less than the configured minimum of 70%'
|
|
72
|
+
] )
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'leaves unexplained every bit without a configured threshold' do
|
|
76
|
+
violations, unexplained = decode( {fail_under_line: 90}, 2 | 4 | 64, '' )
|
|
77
|
+
|
|
78
|
+
expect(violations.length).to eq( 1 )
|
|
79
|
+
expect(unexplained).to eq( 4 | 64 )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'reports nothing for a zero exit code, and accepts a nil stderr' do
|
|
83
|
+
expect( decode( {fail_under_line: 90}, 0, nil ) ).to eq( [[], 0] )
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe GcovrThresholdError do
|
|
88
|
+
it 'carries each violation, and joins them as its message' do
|
|
89
|
+
error = GcovrThresholdError.new( ['one', 'two'] )
|
|
90
|
+
|
|
91
|
+
expect(error).to be_a( CeedlingException )
|
|
92
|
+
expect(error.violations).to eq( ['one', 'two'] )
|
|
93
|
+
expect(error.message).to eq( "one\ntwo" )
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -105,7 +105,7 @@ describe ModuleGenerator do
|
|
|
105
105
|
config[:module_generator_update_svn] = true
|
|
106
106
|
allow(ModuleGeneratorUnity).to receive(:new).and_return( unity )
|
|
107
107
|
allow(unity).to receive(:generate)
|
|
108
|
-
expect(loginator).to receive(:log).with( /:update_svn.*deprecated/, Verbosity::COMPLAIN
|
|
108
|
+
expect(loginator).to receive(:log).with( /:update_svn.*deprecated/, Verbosity::COMPLAIN )
|
|
109
109
|
|
|
110
110
|
plugin.create( request( 'Lair' ) )
|
|
111
111
|
end
|
|
@@ -127,7 +127,7 @@ describe ModuleGenerator do
|
|
|
127
127
|
allow(ModuleGeneratorUnity).to receive(:new).and_return( unity )
|
|
128
128
|
allow(unity).to receive(:files_to_operate_on).with( 'Lair' ).and_return( [{ path: Pathname.new( 'src/Lair.c' ) }, planned_test( 'test/test_Lair.c' )] )
|
|
129
129
|
allow(unity).to receive(:generate)
|
|
130
|
-
expect(loginator).to receive(:log).with( /`test\/test_Lair.c`.*`#ifdef TEST`.*:defines/m, Verbosity::COMPLAIN
|
|
130
|
+
expect(loginator).to receive(:log).with( /`test\/test_Lair.c`.*`#ifdef TEST`.*:defines/m, Verbosity::COMPLAIN ).once
|
|
131
131
|
|
|
132
132
|
plugin.create( request( 'Lair' ) )
|
|
133
133
|
end
|
|
@@ -138,7 +138,7 @@ describe ModuleGenerator do
|
|
|
138
138
|
allow(ModuleGeneratorUnity).to receive(:new).and_return( unity )
|
|
139
139
|
allow(unity).to receive(:files_to_operate_on).and_return( [planned_test( 'test/test_Lair.c' )] )
|
|
140
140
|
allow(unity).to receive(:generate)
|
|
141
|
-
expect(loginator).to receive(:log).with( /`#if TEST`/, Verbosity::COMPLAIN
|
|
141
|
+
expect(loginator).to receive(:log).with( /`#if TEST`/, Verbosity::COMPLAIN )
|
|
142
142
|
|
|
143
143
|
plugin.create( request( 'Lair' ) )
|
|
144
144
|
end
|
|
@@ -156,7 +156,7 @@ describe ModuleGenerator do
|
|
|
156
156
|
config.merge!( collection_all_source: ['lib/Lair.c'], collection_all_headers: [], collection_all_tests: [] )
|
|
157
157
|
allow(ModuleGeneratorUnity).to receive(:new).and_return( unity )
|
|
158
158
|
allow(unity).to receive(:files_to_operate_on).with( 'Lair' ).and_return( [{ path: Pathname.new( 'src/Lair.c' ) }] )
|
|
159
|
-
expect(loginator).to receive(:log).with( /`src\/Lair.c`.*`lib\/Lair.c`/, Verbosity::COMPLAIN
|
|
159
|
+
expect(loginator).to receive(:log).with( /`src\/Lair.c`.*`lib\/Lair.c`/, Verbosity::COMPLAIN )
|
|
160
160
|
expect(unity).to receive(:generate).with( 'Lair' )
|
|
161
161
|
|
|
162
162
|
plugin.create( request( 'Lair' ) )
|
|
@@ -192,7 +192,7 @@ describe ModuleGenerator do
|
|
|
192
192
|
resolved_defines['test/test_widget.c'] = []
|
|
193
193
|
allow(file_wrapper).to receive(:exist?).with( 'test/test_widget.c' ).and_return( false )
|
|
194
194
|
allow(file_wrapper).to receive(:write)
|
|
195
|
-
expect(loginator).to receive(:log).with( /`test\/test_widget.c`.*`#ifdef TEST`/m, Verbosity::COMPLAIN
|
|
195
|
+
expect(loginator).to receive(:log).with( /`test\/test_widget.c`.*`#ifdef TEST`/m, Verbosity::COMPLAIN )
|
|
196
196
|
|
|
197
197
|
plugin.test( request( 'widget' ) )
|
|
198
198
|
end
|
|
@@ -53,7 +53,7 @@ describe ReportBuildWarningsLog do
|
|
|
53
53
|
describe '#post_build' do
|
|
54
54
|
it 'logs that no warnings were produced and never touches the filesystem when nothing was collected' do
|
|
55
55
|
expect(@loginator).to receive(:log).with("Build produced no warnings.\n")
|
|
56
|
-
expect(@file_wrapper).not_to receive(:
|
|
56
|
+
expect(@file_wrapper).not_to receive(:mkdir_for)
|
|
57
57
|
expect(@file_wrapper).not_to receive(:write)
|
|
58
58
|
|
|
59
59
|
@plugin.post_build(0)
|
|
@@ -91,7 +91,7 @@ describe ReportBuildWarningsLog do
|
|
|
91
91
|
collection: WarningCollector.new.warnings( "foo.c:3:5: warning: unused variable 'x'\nbar.c:9:1: warning: missing return\n" )
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
allow(@file_wrapper).to receive(:mkdir_for) { |path| path }
|
|
95
95
|
expect(@file_wrapper).to receive(:write).with(
|
|
96
96
|
File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'warnings.log'),
|
|
97
97
|
"foo.c:3:5: warning: unused variable 'x'\nbar.c:9:1: warning: missing return\n"
|
|
@@ -138,7 +138,7 @@ describe ReportBuildWarningsLog do
|
|
|
138
138
|
|
|
139
139
|
def written
|
|
140
140
|
files = []
|
|
141
|
-
allow(@file_wrapper).to receive(:
|
|
141
|
+
allow(@file_wrapper).to receive(:mkdir_for) { |path| path }
|
|
142
142
|
allow(@file_wrapper).to receive(:write) { |path, _| files << path }
|
|
143
143
|
return files
|
|
144
144
|
end
|
|
@@ -37,12 +37,21 @@ describe ReportLogWriterPlugin do
|
|
|
37
37
|
|
|
38
38
|
describe '#artifact_filepath' do
|
|
39
39
|
it 'ensures the per-context artifact directory exists and returns the joined filepath' do
|
|
40
|
-
expect(@file_wrapper).to receive(:
|
|
40
|
+
expect(@file_wrapper).to receive(:mkdir_for).with(File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'warnings.log')) { |path| path }
|
|
41
41
|
|
|
42
42
|
filepath = @plugin.send(:artifact_filepath, :test, 'warnings.log')
|
|
43
43
|
|
|
44
44
|
expect(filepath).to eq(File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'warnings.log'))
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
# GH #1364: a nested test's log sits in its own subdirectory
|
|
48
|
+
it 'ensures the directory of a filename with subdirectories exists' do
|
|
49
|
+
expect(@file_wrapper).to receive(:mkdir_for).with(File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'test/unit/test_foo.raw.log')) { |path| path }
|
|
50
|
+
|
|
51
|
+
filepath = @plugin.send(:artifact_filepath, :test, 'test/unit/test_foo.raw.log')
|
|
52
|
+
|
|
53
|
+
expect(filepath).to eq(File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'test/unit/test_foo.raw.log'))
|
|
54
|
+
end
|
|
46
55
|
end
|
|
47
56
|
|
|
48
57
|
describe '#flush_log' do
|
|
@@ -72,7 +72,7 @@ describe ReportTestsRawOutputLog do
|
|
|
72
72
|
describe '#post_build' do
|
|
73
73
|
it 'logs that no extra output was produced and never touches the filesystem when nothing was collected' do
|
|
74
74
|
expect(@loginator).to receive(:log).with("Tests produced no extra console output.\n")
|
|
75
|
-
expect(@file_wrapper).not_to receive(:
|
|
75
|
+
expect(@file_wrapper).not_to receive(:mkdir_for)
|
|
76
76
|
expect(@file_wrapper).not_to receive(:write)
|
|
77
77
|
|
|
78
78
|
@plugin.post_build(0)
|
|
@@ -86,7 +86,7 @@ describe ReportTestsRawOutputLog do
|
|
|
86
86
|
'TestFoo' => ["Debug: entering state X\n", "Debug: leaving state X\n"]
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
allow(@file_wrapper).to receive(:mkdir_for) { |path| path }
|
|
90
90
|
expect(@file_wrapper).to receive(:write).with(
|
|
91
91
|
File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'TestFoo.raw.log'),
|
|
92
92
|
"Debug: entering state X\nDebug: leaving state X\n"
|
|
@@ -94,5 +94,16 @@ describe ReportTestsRawOutputLog do
|
|
|
94
94
|
|
|
95
95
|
@plugin.post_build(0)
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
# GH #1364: a nested test's log sits beneath its name
|
|
99
|
+
it "makes the directory a nested test's log goes in" do
|
|
100
|
+
@plugin.instance_variable_get(:@raw_output)[:test] = { 'test/unit/test_foo' => ["Debug\n"] }
|
|
101
|
+
filepath = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, 'test', 'test/unit/test_foo.raw.log')
|
|
102
|
+
|
|
103
|
+
expect(@file_wrapper).to receive(:mkdir_for).with(filepath) { |path| path }
|
|
104
|
+
expect(@file_wrapper).to receive(:write).with(filepath, "Debug\n")
|
|
105
|
+
|
|
106
|
+
@plugin.post_build(0)
|
|
107
|
+
end
|
|
97
108
|
end
|
|
98
109
|
end
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
require 'spec_helper'
|
|
9
9
|
require 'stringio'
|
|
10
10
|
require 'ceedling/plugins/plugin'
|
|
11
|
+
require 'ceedling/filesystem/file_path_utils'
|
|
11
12
|
|
|
12
13
|
$: << File.expand_path('../../../../plugins/report_tests_teamcity_stdout/lib', __FILE__)
|
|
13
14
|
require 'report_tests_teamcity_stdout'
|
|
@@ -23,7 +24,10 @@ describe ReportTestsTeamcityStdout do
|
|
|
23
24
|
@plugin.instance_variable_set(:@flowid_count, 0)
|
|
24
25
|
@plugin.instance_variable_set(:@suites, {})
|
|
25
26
|
@plugin.instance_variable_set(:@stream, @stream)
|
|
26
|
-
@plugin.instance_variable_set(:@ceedling, {
|
|
27
|
+
@plugin.instance_variable_set(:@ceedling, {
|
|
28
|
+
plugin_reportinator: @plugin_reportinator,
|
|
29
|
+
file_path_utils: FilePathUtils.new( configurator: nil, file_wrapper: nil )
|
|
30
|
+
})
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
describe '#escape' do
|
|
@@ -38,8 +42,23 @@ describe ReportTestsTeamcityStdout do
|
|
|
38
42
|
@plugin.post_test('test/TestFoo.c')
|
|
39
43
|
|
|
40
44
|
lines = @stream.string.lines
|
|
41
|
-
expect(lines[0]).to eq("##teamcity[testSuiteStarted name='TestFoo' flowId='1']\n")
|
|
42
|
-
expect(lines[1]).to eq("##teamcity[testSuiteFinished name='TestFoo' flowId='1']\n")
|
|
45
|
+
expect(lines[0]).to eq("##teamcity[testSuiteStarted name='test/TestFoo' flowId='1']\n")
|
|
46
|
+
expect(lines[1]).to eq("##teamcity[testSuiteFinished name='test/TestFoo' flowId='1']\n")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# GH #1364: same-named tests in different directories are different suites
|
|
50
|
+
it 'names each suite by its test, so same-named tests are told apart' do
|
|
51
|
+
@plugin.pre_test('test/a/test_x.c')
|
|
52
|
+
@plugin.pre_test('test/b/test_x.c')
|
|
53
|
+
|
|
54
|
+
expect(@stream.string).to include("testSuiteStarted name='test/a/test_x'", "testSuiteStarted name='test/b/test_x'")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'escapes a suite name, as every TeamCity value is' do
|
|
58
|
+
@plugin.pre_test("test/o'neil/test_x.c")
|
|
59
|
+
@plugin.post_test("test/o'neil/test_x.c")
|
|
60
|
+
|
|
61
|
+
expect(@stream.string.lines).to all( include("name='test/o|'neil/test_x'") )
|
|
43
62
|
end
|
|
44
63
|
|
|
45
64
|
it 'gives each successive test its own flow id' do
|
|
@@ -108,6 +127,61 @@ describe ReportTestsTeamcityStdout do
|
|
|
108
127
|
end
|
|
109
128
|
end
|
|
110
129
|
|
|
130
|
+
# GH #1369: a reserved character in a test's path, case name, or failure location
|
|
131
|
+
# closed the quoted value early, and TeamCity misread or dropped the message
|
|
132
|
+
describe '#post_test_fixture_execute escaping' do
|
|
133
|
+
RESERVED_DIR = "test/o'neil|x"
|
|
134
|
+
RESERVED_CASE = 'test_value(1, [2])'
|
|
135
|
+
ESCAPED_NAME = "test.test/o|'neil||x/TestFoo.test_value(1, |[2|])"
|
|
136
|
+
|
|
137
|
+
before(:each) do
|
|
138
|
+
@plugin.instance_variable_get(:@suites)['test/TestFoo.c'] = { flowid: 1 }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def run_with(results)
|
|
142
|
+
allow(@plugin_reportinator).to receive(:assemble_test_results).and_return(
|
|
143
|
+
{ total_time: 1.0, counts: { passed: 1, failed: 1 }, successes: [], failures: [], ignores: [] }.merge( results )
|
|
144
|
+
)
|
|
145
|
+
@plugin.post_test_fixture_execute(context: :test, test_filepath: 'test/TestFoo.c', result_file: 'x')
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def source
|
|
149
|
+
{ dirname: RESERVED_DIR, basename: 'TestFoo.c', file: "#{RESERVED_DIR}/TestFoo.c" }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'escapes the names of testStarted and testFinished for a passing test' do
|
|
153
|
+
run_with( successes: [ { source: source, collection: [ { test: RESERVED_CASE } ] } ] )
|
|
154
|
+
|
|
155
|
+
expect(@stream.string).to include(
|
|
156
|
+
"##teamcity[testStarted name='#{ESCAPED_NAME}' flowId='1']\n",
|
|
157
|
+
"##teamcity[testFinished name='#{ESCAPED_NAME}' duration='500' flowId='1']\n"
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it 'escapes the name and details of testFailed, and the names around it' do
|
|
162
|
+
run_with( failures: [ { source: source, collection: [ { test: RESERVED_CASE, line: 7, message: 'm' } ] } ] )
|
|
163
|
+
|
|
164
|
+
expect(@stream.string).to include(
|
|
165
|
+
"##teamcity[testStarted name='#{ESCAPED_NAME}' flowId='1']\n",
|
|
166
|
+
"##teamcity[testFailed name='#{ESCAPED_NAME}' message='m' details='File: test/o|'neil||x/TestFoo.c Line: 7' flowId='1']\n",
|
|
167
|
+
"##teamcity[testFinished name='#{ESCAPED_NAME}' duration='500' flowId='1']\n"
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'escapes the name of testIgnored' do
|
|
172
|
+
run_with( ignores: [ { source: source, collection: [ { test: RESERVED_CASE } ] } ] )
|
|
173
|
+
|
|
174
|
+
expect(@stream.string).to eq( "##teamcity[testIgnored name='#{ESCAPED_NAME}' flowId='1']\n" )
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'keeps each message on one physical line when a name holds a line break' do
|
|
178
|
+
run_with( ignores: [ { source: source, collection: [ { test: "test_a\r\ntest_b" } ] } ] )
|
|
179
|
+
|
|
180
|
+
expect(@stream.string.lines.length).to eq( 1 )
|
|
181
|
+
expect(@stream.string).to include( 'TestFoo.test_a|r|ntest_b' )
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
111
185
|
# A TeamCity service message must stay on one physical line
|
|
112
186
|
describe '#escape' do
|
|
113
187
|
it 'escapes a real newline as |n, keeping the whole message on one physical output line' do
|
|
@@ -9,7 +9,7 @@ require 'spec_helper'
|
|
|
9
9
|
require 'ceedling/tool_executor'
|
|
10
10
|
require 'ceedling/constants'
|
|
11
11
|
require 'ceedling/exceptions'
|
|
12
|
-
require 'ceedling/file_path_utils'
|
|
12
|
+
require 'ceedling/filesystem/file_path_utils'
|
|
13
13
|
|
|
14
14
|
PROJECT_BUILD_ROOT = 'build' unless defined?(PROJECT_BUILD_ROOT)
|
|
15
15
|
PROJECT_BUILD_ARTIFACTS_ROOT = 'artifacts' unless defined?(PROJECT_BUILD_ARTIFACTS_ROOT)
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
require 'spec_helper'
|
|
9
9
|
require 'ceedling/constants'
|
|
10
10
|
|
|
11
|
+
# Ceedling runtime path constants sanitize_constants.rb needs at require time
|
|
12
|
+
PROJECT_BUILD_ROOT = 'build' unless defined?(PROJECT_BUILD_ROOT)
|
|
11
13
|
PROJECT_BUILD_ARTIFACTS_ROOT = 'build/artifacts' unless defined?(PROJECT_BUILD_ARTIFACTS_ROOT)
|
|
12
14
|
|
|
13
15
|
$: << File.expand_path('../../../../plugins/sanitize/lib', __FILE__)
|
|
@@ -15,7 +17,7 @@ require 'sanitize_findings'
|
|
|
15
17
|
require 'sanitize_records'
|
|
16
18
|
|
|
17
19
|
describe SanitizeRecords do
|
|
18
|
-
let(:file_wrapper) { double('file_wrapper', mkdir: nil, write: nil) }
|
|
20
|
+
let(:file_wrapper) { double('file_wrapper', mkdir: nil, write: nil, mkdir_for: nil) }
|
|
19
21
|
let(:loginator) { double('loginator', log: nil) }
|
|
20
22
|
let(:records) { described_class.new( file_wrapper: file_wrapper, loginator: loginator, reports: [] ) }
|
|
21
23
|
let(:log) { described_class.log_filepath( :sanitize, 'test_a' ) }
|
|
@@ -37,7 +37,7 @@ describe Sanitize do
|
|
|
37
37
|
|
|
38
38
|
let(:loginator) { double('loginator', log: nil) }
|
|
39
39
|
let(:dependinator) { double('dependinator', register: nil) }
|
|
40
|
-
let(:file_wrapper) { double('file_wrapper', write: nil, mkdir: nil) }
|
|
40
|
+
let(:file_wrapper) { double('file_wrapper', write: nil, mkdir: nil, mkdir_for: nil) }
|
|
41
41
|
let(:plugin_manager) { double('plugin_manager', register_build_failure: nil) }
|
|
42
42
|
let(:tracker) { double('rake_invocation_tracker', invoked?: true) }
|
|
43
43
|
let(:tool_validator) { double('tool_validator', validate: nil) }
|