ceedling 1.2.0 → 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 +57 -58
- data/Rakefile +5 -3
- 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 +35 -1
- data/bin/ceedling +13 -3
- data/bin/cli.rb +25 -6
- data/bin/cli_handler.rb +119 -73
- data/bin/cli_helper.rb +56 -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 +84 -3
- data/docs/KnownIssues.md +90 -4
- data/docs/ReleaseNotes.md +13 -0
- data/docs/overrides/main.html +11 -8
- 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 +19 -18
- 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 +39 -41
- 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} +65 -28
- 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/rake_app/test_task_name.rb +29 -0
- data/lib/ceedling/rakefile.rb +16 -1
- data/lib/ceedling/rakefiles/base/tasks_base.rake +1 -1
- data/lib/ceedling/rakefiles/release/rules_release.rake +4 -7
- data/lib/ceedling/rakefiles/tests/rules_tests.rake +3 -20
- data/lib/ceedling/rakefiles/tests/rules_tests_generate.rake +4 -30
- 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 +95 -87
- 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 +42 -41
- 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/bullseye.rake +6 -9
- 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/gcov.rake +6 -9
- 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/sanitize/sanitize.rake +6 -6
- data/plugins/valgrind/lib/valgrind.rb +14 -7
- data/plugins/valgrind/valgrind.rake +6 -6
- data/site-local/404.html +6 -20
- data/site-local/assets/javascripts/{bundle.d7400e89.min.js → bundle.c21346df.min.js} +3 -3
- data/site-local/assets/javascripts/{bundle.d7400e89.min.js.map → bundle.c21346df.min.js.map} +2 -2
- data/site-local/assets/javascripts/workers/{search.2c215733.min.js → search.a7633da7.min.js} +2 -2
- data/site-local/assets/javascripts/workers/{search.2c215733.min.js.map → search.a7633da7.min.js.map} +1 -1
- data/site-local/assets/stylesheets/main.57a0d79d.min.css +6 -0
- data/site-local/assets/stylesheets/main.57a0d79d.min.css.map +1 -0
- data/site-local/assets/stylesheets/palette.fb2fffe2.min.css +4 -0
- data/site-local/assets/stylesheets/palette.fb2fffe2.min.css.map +1 -0
- data/site-local/configuration/environment-vars.html +6 -20
- data/site-local/configuration/global-collections.html +6 -20
- data/site-local/configuration/index.html +6 -20
- data/site-local/configuration/loading.html +6 -20
- data/site-local/configuration/mixins.html +10 -24
- data/site-local/configuration/parallel-builds.html +6 -20
- data/site-local/configuration/project-file.html +8 -22
- data/site-local/configuration/reference/cexception.html +6 -20
- data/site-local/configuration/reference/cmock.html +8 -21
- data/site-local/configuration/reference/defines.html +16 -30
- data/site-local/configuration/reference/environment.html +10 -24
- data/site-local/configuration/reference/extension.html +6 -20
- data/site-local/configuration/reference/files.html +22 -30
- data/site-local/configuration/reference/flags.html +13 -27
- data/site-local/configuration/reference/index.html +6 -20
- data/site-local/configuration/reference/libraries.html +27 -23
- data/site-local/configuration/reference/mixins.html +6 -20
- data/site-local/configuration/reference/partials.html +6 -20
- data/site-local/configuration/reference/paths.html +38 -29
- data/site-local/configuration/reference/plugins.html +6 -20
- data/site-local/configuration/reference/project.html +32 -36
- data/site-local/configuration/reference/release-build.html +8 -20
- data/site-local/configuration/reference/test-build.html +6 -20
- data/site-local/configuration/reference/test-runner.html +6 -20
- data/site-local/configuration/reference/tools.html +27 -32
- data/site-local/configuration/reference/unity.html +6 -20
- data/site-local/configuration/which-ceedling.html +383 -37
- data/site-local/development/index.html +6 -20
- data/site-local/development/plugins/configuration.html +6 -20
- data/site-local/development/plugins/index.html +6 -20
- data/site-local/development/plugins/plugin-subclass.html +54 -68
- data/site-local/development/plugins/rake-tasks.html +8 -22
- data/site-local/development/releases.html +84 -29
- data/site-local/development/workflow.html +62 -71
- data/site-local/getting-started/builds.html +8 -20
- data/site-local/getting-started/command-line.html +62 -24
- data/site-local/getting-started/example-projects/cipher-quest.html +6 -20
- data/site-local/getting-started/example-projects/index.html +6 -20
- data/site-local/getting-started/example-projects/temp-sensor.html +6 -20
- data/site-local/getting-started/example-projects/wondrous-forest.html +6 -20
- data/site-local/getting-started/index.html +6 -20
- data/site-local/getting-started/installation.html +6 -20
- data/site-local/getting-started/quick-start.html +6 -20
- data/site-local/help.html +6 -20
- data/site-local/index.html +11 -24
- data/site-local/overview/build-system.html +6 -20
- data/site-local/overview/index.html +6 -20
- data/site-local/overview/test-environments.html +6 -20
- data/site-local/overview/tools-and-frameworks.html +6 -20
- data/site-local/plugins/beep.html +6 -20
- data/site-local/plugins/bullseye/index.html +13 -24
- data/site-local/plugins/bullseye/licensing.html +14 -28
- data/site-local/plugins/command-hooks.html +8 -22
- data/site-local/plugins/compile-commands-json-db.html +6 -20
- data/site-local/plugins/cppcheck.html +8 -22
- data/site-local/plugins/dependencies.html +16 -27
- data/site-local/plugins/fff.html +49 -32
- data/site-local/plugins/gcov/examples.html +7 -21
- data/site-local/plugins/gcov/gcovr.html +22 -33
- data/site-local/plugins/gcov/index.html +6 -20
- data/site-local/plugins/gcov/overview.html +9 -20
- data/site-local/plugins/gcov/reportgenerator.html +9 -23
- data/site-local/plugins/gcov/reporting.html +6 -20
- data/site-local/plugins/gcov/setup.html +8 -21
- data/site-local/plugins/gcov/tool-versions.html +6 -20
- data/site-local/plugins/gcov/troubleshooting.html +10 -24
- data/site-local/plugins/index.html +6 -20
- data/site-local/plugins/module-generator.html +21 -35
- data/site-local/plugins/report-build-warnings-log.html +53 -67
- data/site-local/plugins/report-tests-gtestlike-stdout.html +6 -20
- data/site-local/plugins/report-tests-ide-stdout.html +43 -57
- data/site-local/plugins/report-tests-log-factory.html +50 -64
- data/site-local/plugins/report-tests-pretty-stdout.html +7 -21
- data/site-local/plugins/report-tests-raw-output-log.html +9 -21
- data/site-local/plugins/report-tests-teamcity-stdout.html +20 -31
- data/site-local/plugins/sanitize.html +56 -65
- data/site-local/plugins/valgrind.html +49 -58
- data/site-local/project/index.html +6 -20
- data/site-local/project/release-history.html +6 -20
- data/site-local/project/sbom.html +6 -20
- data/site-local/project/upgrade.html +9 -20
- data/site-local/reference/build-directives.html +6 -20
- data/site-local/reference/command-line.html +15 -22
- data/site-local/reference/environment-vars.html +6 -20
- data/site-local/reference/gcov-plugin.html +6 -20
- data/site-local/reference/global-collections.html +6 -20
- data/site-local/reference/index.html +6 -20
- data/site-local/reference/partials-macros.html +6 -20
- data/site-local/reference/project-configuration.html +6 -20
- data/site-local/sitemap.xml.gz +0 -0
- data/site-local/snapshot/examples/cipher_quest/index.html +16 -30
- data/site-local/snapshot/examples/temp_sensor/index.html +8 -22
- data/site-local/snapshot/examples/wondrous_forest/index.html +6 -20
- 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/build-directives.html +14 -28
- data/site-local/testing-guide/conventions.html +66 -27
- data/site-local/testing-guide/frameworks.html +11 -25
- data/site-local/testing-guide/index.html +6 -20
- data/site-local/testing-guide/partials/configuration.html +8 -22
- data/site-local/testing-guide/partials/conventions.html +8 -22
- data/site-local/testing-guide/partials/directives.html +16 -30
- data/site-local/testing-guide/partials/example.html +14 -28
- data/site-local/testing-guide/partials/index.html +6 -20
- data/site-local/testing-guide/partials/overview.html +6 -20
- data/site-local/testing-guide/partials/variables.html +11 -25
- data/site-local/testing-guide/test-cases.html +13 -27
- data/site-local/testing-guide/test-sample.html +12 -26
- data/site-local/testing-guide/test-suite-anatomy.html +6 -20
- 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_pipeline_spec.rb +10 -0
- 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 +62 -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/rake_task_registry_plugins_spec.rb +95 -0
- 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 +192 -75
- data/spec/support/file_tree_helper.rb +88 -0
- data/spec/support/integration/configurator_integration_helper.rb +10 -7
- 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 +47 -0
- data/spec/units/bin/cli_handler_spec.rb +284 -7
- data/spec/units/bin/cli_helper_spec.rb +126 -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 +65 -103
- data/spec/units/config/configurator_spec.rb +37 -6
- 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} +154 -32
- 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/rake_app/test_task_name_spec.rb +47 -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 +107 -5
- 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 +122 -33
- data/lib/ceedling/file_path_collection_utils.rb +0 -164
- data/site-local/assets/stylesheets/main.ec1eaa64.min.css +0 -1
- data/site-local/assets/stylesheets/main.ec1eaa64.min.css.map +0 -1
- data/site-local/assets/stylesheets/palette.ab4e12ef.min.css +0 -1
- data/site-local/assets/stylesheets/palette.ab4e12ef.min.css.map +0 -1
|
@@ -0,0 +1,128 @@
|
|
|
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 'tmpdir'
|
|
9
|
+
require 'fileutils'
|
|
10
|
+
|
|
11
|
+
repo_root = File.expand_path( '../../..', __dir__ )
|
|
12
|
+
$LOAD_PATH.unshift( File.join( repo_root, 'lib' ), File.join( repo_root, 'vendor/cmock/lib' ) )
|
|
13
|
+
|
|
14
|
+
require 'fff.rb'
|
|
15
|
+
|
|
16
|
+
# GH #1377: A fake gets the extra includes CMock would give a mock of the same header.
|
|
17
|
+
# Each example runs the wrapper Ceedling swaps in for CMock, with Ceedling's own
|
|
18
|
+
# :includes default, and reads back the files it writes.
|
|
19
|
+
describe FffCMockWrapper do
|
|
20
|
+
|
|
21
|
+
around(:each) do |example|
|
|
22
|
+
Dir.mktmpdir do |root|
|
|
23
|
+
@root = root
|
|
24
|
+
@header = File.join( root, 'src', 'bar.h' )
|
|
25
|
+
FileUtils.mkdir_p( File.dirname( @header ) )
|
|
26
|
+
File.write( @header, "void bar_turn_on(void);\n" )
|
|
27
|
+
example.run
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fake(options = {})
|
|
32
|
+
mock_path = File.join( @root, 'mocks' )
|
|
33
|
+
config = { :mock_prefix => 'mock_', :mock_path => mock_path, :includes => [], :verbosity => 0 }
|
|
34
|
+
FffCMockWrapper.new( config.merge( options ) ).setup_mocks( @header )
|
|
35
|
+
return {
|
|
36
|
+
:h => File.readlines( File.join( mock_path, 'mock_bar.h' ), chomp: true ),
|
|
37
|
+
:c => File.readlines( File.join( mock_path, 'mock_bar.c' ), chomp: true )
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def position(lines, line)
|
|
42
|
+
index = lines.index( line )
|
|
43
|
+
expect( index ).not_to be_nil, "expected #{line.inspect} in:\n#{lines.join( "\n" )}"
|
|
44
|
+
return index
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def extra_includes(lines)
|
|
48
|
+
standard = ['#include <string.h>', '#include "fff.h"', '#include "fff_unity_helper.h"', '#include "bar.h"', '#include "mock_bar.h"']
|
|
49
|
+
return lines.grep( /\A#include / ) - standard
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'adds no includes when no setting names any' do
|
|
53
|
+
files = fake
|
|
54
|
+
|
|
55
|
+
expect( extra_includes( files[:h] ) ).to eq( [] )
|
|
56
|
+
expect( extra_includes( files[:c] ) ).to eq( [] )
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'includes :includes_c_pre_header in the source before the fake header' do
|
|
60
|
+
files = fake( :includes_c_pre_header => ['extra_c.h'] )
|
|
61
|
+
|
|
62
|
+
expect( position( files[:c], '#include "extra_c.h"' ) ).to be < position( files[:c], '#include "mock_bar.h"' )
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'includes :includes_c_post_header in the source after the fake header' do
|
|
66
|
+
files = fake( :includes_c_post_header => ['extra_c.h'] )
|
|
67
|
+
|
|
68
|
+
expect( position( files[:c], '#include "extra_c.h"' ) ).to be > position( files[:c], '#include "mock_bar.h"' )
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'includes :includes_h_pre_orig_header in the header before the original header' do
|
|
72
|
+
files = fake( :includes_h_pre_orig_header => ['extra_h.h'] )
|
|
73
|
+
|
|
74
|
+
expect( position( files[:h], '#include "extra_h.h"' ) ).to be < position( files[:h], '#include "bar.h"' )
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'includes :includes_h_post_orig_header in the header after the original header' do
|
|
78
|
+
files = fake( :includes_h_post_orig_header => ['extra_h.h'] )
|
|
79
|
+
|
|
80
|
+
expect( position( files[:h], '#include "extra_h.h"' ) ).to be > position( files[:h], '#include "bar.h"' )
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'merges :includes with :includes_h_pre_orig_header, :includes first, each once' do
|
|
84
|
+
files = fake( :includes => ['first.h', 'both.h'], :includes_h_pre_orig_header => ['both.h', 'second.h'] )
|
|
85
|
+
|
|
86
|
+
expect( extra_includes( files[:h] ) ).to eq( ['#include "first.h"', '#include "both.h"', '#include "second.h"'] )
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'keeps an angle-bracket include as written and quotes a bare name' do
|
|
90
|
+
files = fake( :includes_c_pre_header => ['<stdint.h>', 'extra_c.h'] )
|
|
91
|
+
|
|
92
|
+
expect( extra_includes( files[:c] ) ).to eq( ['#include <stdint.h>', '#include "extra_c.h"'] )
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'includes a Unity helper in the source after the fake header, by its path from the mock root' do
|
|
96
|
+
helper = File.join( @root, 'support', 'helper.h' )
|
|
97
|
+
FileUtils.mkdir_p( File.dirname( helper ) )
|
|
98
|
+
File.write( helper, "\n" )
|
|
99
|
+
|
|
100
|
+
files = fake( :unity_helper_path => [helper] )
|
|
101
|
+
|
|
102
|
+
expect( position( files[:c], '#include "../support/helper.h"' ) ).to be > position( files[:c], '#include "mock_bar.h"' )
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# CMock's :verbosity levels: 0 errors only, 1 warnings, 2 normal, 3 verbose
|
|
106
|
+
context 'at CMock\'s verbosity levels' do
|
|
107
|
+
|
|
108
|
+
it 'prints nothing for errors only or warnings' do
|
|
109
|
+
expect { fake( :verbosity => 0 ) }.not_to output.to_stdout
|
|
110
|
+
expect { fake( :verbosity => 1 ) }.not_to output.to_stdout
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'announces each fake at normal verbosity, as CMock announces each mock' do
|
|
114
|
+
expect { fake( :verbosity => 2 ) }.to output( "Creating fake functions for bar...\n" ).to_stdout
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'also names the files written at verbose' do
|
|
118
|
+
path = File.join( @root, 'mocks', 'mock_bar' )
|
|
119
|
+
|
|
120
|
+
expect { fake( :verbosity => 3 ) }.to output(
|
|
121
|
+
"Creating fake functions for bar...\n" \
|
|
122
|
+
"Creating fake functions: #{path}.h and #{path}.c\n"
|
|
123
|
+
).to_stdout
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
end
|
|
@@ -41,7 +41,7 @@ DEFAULT_GCOV_LINKER_TOOL = {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
DEFAULT_GCOV_FIXTURE_TOOL = {
|
|
44
|
-
:executable => '${1}'.freeze,
|
|
44
|
+
:executable => '"${1}"'.freeze, # Test executable, quoted as a path
|
|
45
45
|
:name => 'default_gcov_fixture'.freeze,
|
|
46
46
|
:optional => false.freeze,
|
|
47
47
|
:arguments => [].freeze
|
data/plugins/gcov/gcov.rake
CHANGED
|
@@ -38,11 +38,12 @@ namespace GCOV_SYM do
|
|
|
38
38
|
@ceedling[:gcov].process_untested_sources( sources:COLLECTION_ALL_SOURCE )
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
desc 'Run single test w/ coverage ([*] test or source file name,
|
|
41
|
+
desc 'Run single test w/ coverage ([*] test or source file name, with optional path).'
|
|
42
42
|
task :* do
|
|
43
43
|
message = "Oops! '#{GCOV_ROOT_NAME}:*' isn't a real task. " \
|
|
44
|
-
"Use a real test or source file name
|
|
45
|
-
"
|
|
44
|
+
"Use a real test or source file name in place of the wildcard, " \
|
|
45
|
+
"adding as much of its path as needed to identify one file among any same-named tests.\n" \
|
|
46
|
+
"Example: `ceedling #{GCOV_ROOT_NAME}:foo.c` or `ceedling #{GCOV_ROOT_NAME}:unit/foo.c`"
|
|
46
47
|
|
|
47
48
|
@ceedling[:loginator].log( message, Verbosity::ERRORS )
|
|
48
49
|
end
|
|
@@ -83,12 +84,8 @@ namespace GCOV_SYM do
|
|
|
83
84
|
# Use a rule to increase efficiency for large projects
|
|
84
85
|
rule(/^#{GCOV_TASK_ROOT}\S+$/ => [ # gcov test tasks by regex
|
|
85
86
|
proc do |task_name|
|
|
86
|
-
#
|
|
87
|
-
test =
|
|
88
|
-
EXTENSION_SOURCE.each { |ext| test = test.chomp( ext ) }
|
|
89
|
-
|
|
90
|
-
# Ensure the test name begins with a test name prefix
|
|
91
|
-
test = PROJECT_TEST_FILE_PREFIX + test if not (test.start_with?( PROJECT_TEST_FILE_PREFIX ))
|
|
87
|
+
# Any directory typed ahead of the name is kept. See TestTaskName.
|
|
88
|
+
test = TestTaskName.test_name( task_name, root: GCOV_TASK_ROOT )
|
|
92
89
|
|
|
93
90
|
# Provide the filepath for the target test task back to the Rake task
|
|
94
91
|
@ceedling[:file_finder].find_test_file_from_name( test )
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# =========================================================================
|
|
7
7
|
|
|
8
8
|
require 'ceedling/constants'
|
|
9
|
-
require 'ceedling/path_mirror'
|
|
9
|
+
require 'ceedling/filesystem/path_mirror'
|
|
10
10
|
require 'gcov_reportinator'
|
|
11
11
|
|
|
12
12
|
class ConsoleReportinator < GcovReportinator
|
|
@@ -173,22 +173,8 @@ class ConsoleReportinator < GcovReportinator
|
|
|
173
173
|
def run_gcov_summary(test, source, opts)
|
|
174
174
|
filename = File.basename(source)
|
|
175
175
|
|
|
176
|
-
#
|
|
177
|
-
|
|
178
|
-
# compile step already follows -- so the directory gcov is told to search must include that
|
|
179
|
-
# mirrored subdirectory too, not just the flat <build>/gcov/out/<test name> root.
|
|
180
|
-
# A generated Partial sits below its own test's Partials build root rather than a
|
|
181
|
-
# configured source root, so the source roots mirror nothing for it. Its own root is
|
|
182
|
-
# what carries the module's subdirectory.
|
|
183
|
-
roots =
|
|
184
|
-
if File.basename(source).match?(PATTERNS::PARTIAL_IMPL_FILENAME)
|
|
185
|
-
[File.join( @configurator.project_test_partials_path, test )]
|
|
186
|
-
else
|
|
187
|
-
@configurator.paths_source + @configurator.paths_support
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
subdir = PathMirror.relative_subdir( source, roots )
|
|
191
|
-
obj_dir = subdir.empty? ? File.join(GCOV_BUILD_OUTPUT_PATH, test) : File.join(GCOV_BUILD_OUTPUT_PATH, test, subdir)
|
|
176
|
+
# The coverage data sits beside the object, wherever the test's build placed it
|
|
177
|
+
obj_dir = File.dirname( @file_path_utils.form_test_object_filepath( source, name: test, context: GCOV_SYM ) )
|
|
192
178
|
|
|
193
179
|
# Run gcov to extract the coverage summary
|
|
194
180
|
command = @tool_executor.build_command_line(
|
|
@@ -197,7 +183,7 @@ class ConsoleReportinator < GcovReportinator
|
|
|
197
183
|
(opts[:gcov_mcdc] ? ['-g'] : []),
|
|
198
184
|
# Argument replacement
|
|
199
185
|
filename, # .c source file compiled with coverage
|
|
200
|
-
obj_dir # <build>/gcov/out/<test name>[/
|
|
186
|
+
obj_dir # <build>/gcov/out/<test name>[/source directory] for coverage data files
|
|
201
187
|
)
|
|
202
188
|
|
|
203
189
|
# Do not raise an exception if `gcov` terminates with a non-zero exit code, just note it and move on.
|
data/plugins/gcov/lib/gcov.rb
CHANGED
|
@@ -12,6 +12,7 @@ require 'gcov_constants'
|
|
|
12
12
|
require 'gcov_types'
|
|
13
13
|
require 'gcov_reportinator'
|
|
14
14
|
require 'console_reportinator'
|
|
15
|
+
require 'gcovr_thresholds'
|
|
15
16
|
require 'gcovr_reportinator'
|
|
16
17
|
require 'reportgenerator_reportinator'
|
|
17
18
|
|
|
@@ -141,7 +142,7 @@ class Gcov < Plugin
|
|
|
141
142
|
|
|
142
143
|
# Full filepaths (not basenames)
|
|
143
144
|
header = "Untested source files not in the coverage report (:untested_sources is :list):"
|
|
144
|
-
@loginator.log_list( untested_sources.sort, header, Verbosity::COMPLAIN
|
|
145
|
+
@loginator.log_list( untested_sources.sort, header, Verbosity::COMPLAIN )
|
|
145
146
|
|
|
146
147
|
when GCOV_UNTESTED_SOURCES_COMPILE
|
|
147
148
|
validate_mcdc_gcc_version!
|
|
@@ -163,7 +164,7 @@ class Gcov < Plugin
|
|
|
163
164
|
untested_sources.each do |filepath|
|
|
164
165
|
filename = File.basename(filepath)
|
|
165
166
|
object = @file_path_utils.form_test_object_filepath( filepath, context:GCOV_SYM )
|
|
166
|
-
dependencies = @file_path_utils.form_test_dependencies_filepath(
|
|
167
|
+
dependencies = @file_path_utils.form_test_dependencies_filepath( object, context:GCOV_SYM )
|
|
167
168
|
search_paths = @configurator.collection_paths_include
|
|
168
169
|
# Defines and flags resolve as a tested source's do, against this source's filepath
|
|
169
170
|
defines = @test_build_setup.context_defines( context:GCOV_SYM, filepath:filepath )
|
|
@@ -196,6 +197,9 @@ class Gcov < Plugin
|
|
|
196
197
|
next
|
|
197
198
|
end
|
|
198
199
|
|
|
200
|
+
@file_wrapper.mkdir( File.dirname( object ) )
|
|
201
|
+
@file_wrapper.mkdir( File.dirname( dependencies ) )
|
|
202
|
+
|
|
199
203
|
begin
|
|
200
204
|
@generator.generate_object_file_c(
|
|
201
205
|
tool: TOOLS_GCOV_COMPILER,
|
|
@@ -382,6 +386,9 @@ class Gcov < Plugin
|
|
|
382
386
|
|
|
383
387
|
begin
|
|
384
388
|
reportinator.generate_reports( @configurator.project_config_hash )
|
|
389
|
+
rescue GcovrThresholdError => ex
|
|
390
|
+
# Each violated threshold is its own build failure
|
|
391
|
+
ex.violations.each { |violation| @ceedling[:plugin_manager].register_build_failure( GCOV_SYM, violation ) }
|
|
385
392
|
rescue => ex
|
|
386
393
|
# Register the exception as a build failure
|
|
387
394
|
@ceedling[:plugin_manager].register_build_failure( GCOV_SYM, ex.message )
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
require 'ceedling/exceptions'
|
|
9
9
|
require 'ceedling/constants'
|
|
10
|
+
require 'ceedling/filename_extension'
|
|
10
11
|
require 'gcov_types'
|
|
11
12
|
require 'gcov_reportinator'
|
|
13
|
+
require 'gcovr_thresholds'
|
|
12
14
|
|
|
13
15
|
class GcovrReportinator < GcovReportinator
|
|
14
16
|
|
|
@@ -507,9 +509,8 @@ class GcovrReportinator < GcovReportinator
|
|
|
507
509
|
data = build_exclusion_data
|
|
508
510
|
patterns = []
|
|
509
511
|
|
|
510
|
-
# A source extension can be configured as more than one string, so
|
|
511
|
-
|
|
512
|
-
src_extension_alternation = data[:src_extension].to_a.map { |ext| Regexp.escape(ext) }.join('|')
|
|
512
|
+
# A source extension can be configured as more than one string, so any one of them matches
|
|
513
|
+
src_extension_alternation = FilenameExtension.new( data[:src_extension] ).pattern
|
|
513
514
|
test_prefix = Regexp.escape(data[:test_prefix].to_s)
|
|
514
515
|
build_root = Regexp.escape(strip_leading_dot_slash(data[:build_root].to_s))
|
|
515
516
|
|
|
@@ -576,23 +577,6 @@ class GcovrReportinator < GcovReportinator
|
|
|
576
577
|
end
|
|
577
578
|
|
|
578
579
|
|
|
579
|
-
# Returns the error message text from gcovr stderr, or nil if none found.
|
|
580
|
-
# Matches lines beginning with "error" or "(ERROR)" and extracts the trailing message.
|
|
581
|
-
def extract_gcovr_error_message(shell_result)
|
|
582
|
-
return nil if shell_result.nil?
|
|
583
|
-
|
|
584
|
-
stderr = shell_result[:stderr]
|
|
585
|
-
return nil if stderr.nil? || stderr.empty?
|
|
586
|
-
|
|
587
|
-
stderr.each_line do |line|
|
|
588
|
-
match = line.match( /^\(?error\S*\s+(.+)/i )
|
|
589
|
-
return match[1].strip.capitalize if match
|
|
590
|
-
end
|
|
591
|
-
|
|
592
|
-
nil
|
|
593
|
-
end
|
|
594
|
-
|
|
595
|
-
|
|
596
580
|
# Extract the last contiguous block of lines containing '%' from gcovr stdout.
|
|
597
581
|
# gcovr --print-summary emits lines like "lines: 69.6% (80 out of 115)" — this
|
|
598
582
|
# locates that block generically without depending on exact line labels.
|
|
@@ -620,33 +604,17 @@ class GcovrReportinator < GcovReportinator
|
|
|
620
604
|
end
|
|
621
605
|
|
|
622
606
|
|
|
623
|
-
#
|
|
624
|
-
#
|
|
625
|
-
# gcovr's composite exit code bit-ORs every violated :fail_under_* threshold together --
|
|
626
|
-
# every violated bit is collected and reported, not just whichever is checked first.
|
|
607
|
+
# Reports every :fail_under_* threshold a gcovr run violated, raising when boom is set and
|
|
608
|
+
# logging otherwise. Returns whether the exit code holds a problem no threshold explains.
|
|
627
609
|
def gcovr_exec_exception?(opts, exitcode, boom, shell_result=nil)
|
|
628
|
-
violations =
|
|
629
|
-
|
|
630
|
-
{
|
|
631
|
-
2 => [:fail_under_line, 'Line'],
|
|
632
|
-
4 => [:fail_under_branch, 'Branch'],
|
|
633
|
-
8 => [:fail_under_decision, 'Decision'],
|
|
634
|
-
16 => [:fail_under_function, 'Function'],
|
|
635
|
-
}.each do |bit, (option, label)|
|
|
636
|
-
next unless ((exitcode & bit) == bit) && !opts[option].nil?
|
|
637
|
-
|
|
638
|
-
fallback = "#{label} coverage is less than the configured minimum of #{opts[option]}%"
|
|
639
|
-
violations << "Gcovr ⏩️ #{extract_gcovr_error_message( shell_result ) || fallback}"
|
|
640
|
-
exitcode &= ~bit
|
|
641
|
-
end
|
|
610
|
+
violations, exitcode = GcovrThresholds.decode( opts: opts, exitcode: exitcode, stderr: shell_result&.dig( :stderr ) )
|
|
642
611
|
|
|
643
612
|
if boom
|
|
644
|
-
raise
|
|
613
|
+
raise GcovrThresholdError.new( violations ) unless violations.empty?
|
|
645
614
|
else
|
|
646
615
|
violations.each { |msg| @loginator.log( msg, Verbosity::COMPLAIN ) }
|
|
647
616
|
end
|
|
648
617
|
|
|
649
|
-
# A non-zero exit code is a problem
|
|
650
618
|
return (exitcode != 0)
|
|
651
619
|
end
|
|
652
620
|
|
|
@@ -0,0 +1,74 @@
|
|
|
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 'ceedling/exceptions'
|
|
9
|
+
|
|
10
|
+
# Coverage thresholds a gcovr run violated, one message each
|
|
11
|
+
class GcovrThresholdError < CeedlingException
|
|
12
|
+
|
|
13
|
+
attr_reader :violations
|
|
14
|
+
|
|
15
|
+
def initialize(violations)
|
|
16
|
+
@violations = violations
|
|
17
|
+
super( violations.join( "\n" ) )
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Decodes gcovr's exit status and stderr into the :fail_under_* thresholds a run violated.
|
|
23
|
+
# Each violated threshold sets a bit of the exit status and writes a line of its own to
|
|
24
|
+
# stderr. Bit 8 covers both condition and decision coverage, which from gcovr 8.7 may
|
|
25
|
+
# each write a line.
|
|
26
|
+
module GcovrThresholds
|
|
27
|
+
|
|
28
|
+
BITS = {
|
|
29
|
+
2 => { option: :fail_under_line, label: 'Line', kinds: ['line'] },
|
|
30
|
+
4 => { option: :fail_under_branch, label: 'Branch', kinds: ['branch'] },
|
|
31
|
+
8 => { option: :fail_under_decision, label: 'Condition or decision', kinds: ['condition', 'decision'] },
|
|
32
|
+
16 => { option: :fail_under_function, label: 'Function', kinds: ['function'] },
|
|
33
|
+
}.freeze
|
|
34
|
+
|
|
35
|
+
MESSAGE_PATTERN = /^\(?error\)?:?\s+(failed minimum (\w+) coverage.*?)\s*$/i
|
|
36
|
+
|
|
37
|
+
# Returns the violation messages, and the exit status bits no configured threshold explains
|
|
38
|
+
def self.decode(opts:, exitcode:, stderr:)
|
|
39
|
+
messages = messages_by_kind( stderr )
|
|
40
|
+
violations = []
|
|
41
|
+
|
|
42
|
+
BITS.each do |bit, threshold|
|
|
43
|
+
next unless (exitcode & bit) == bit && !opts[threshold[:option]].nil?
|
|
44
|
+
|
|
45
|
+
violations.concat( violations_for( threshold, opts, messages ) )
|
|
46
|
+
exitcode &= ~bit
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
return violations, exitcode
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# gcovr's own messages, grouped by the coverage kind each names. Older gcovr writes them in
|
|
53
|
+
# lowercase, so the first letter is capitalized, and nothing else is touched.
|
|
54
|
+
def self.messages_by_kind(stderr)
|
|
55
|
+
messages = Hash.new { |hash, kind| hash[kind] = [] }
|
|
56
|
+
|
|
57
|
+
stderr.to_s.each_line do |line|
|
|
58
|
+
match = line.match( MESSAGE_PATTERN )
|
|
59
|
+
messages[match[2].downcase] << match[1].sub( /\A./ ) { |first| first.upcase } if match
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
return messages
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.violations_for(threshold, opts, messages)
|
|
66
|
+
found = threshold[:kinds].flat_map { |kind| messages[kind] }
|
|
67
|
+
found = ["#{threshold[:label]} coverage is less than the configured minimum of #{opts[threshold[:option]]}%"] if found.empty?
|
|
68
|
+
|
|
69
|
+
return found.map { |message| "Gcovr ⏩️ #{message}" }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private_class_method :messages_by_kind, :violations_for
|
|
73
|
+
|
|
74
|
+
end
|
|
@@ -110,7 +110,7 @@ class ModuleGenerator < Plugin
|
|
|
110
110
|
|
|
111
111
|
@ceedling[:loginator].log(
|
|
112
112
|
'Module Generator :update_svn is deprecated and ignored. Add generated files to source control with your own tools.',
|
|
113
|
-
Verbosity::COMPLAIN
|
|
113
|
+
Verbosity::COMPLAIN
|
|
114
114
|
)
|
|
115
115
|
end
|
|
116
116
|
|
|
@@ -119,7 +119,7 @@ class ModuleGenerator < Plugin
|
|
|
119
119
|
project.same_named( files.map { |file| file[:path].to_s } ).each do |planned, existing|
|
|
120
120
|
@ceedling[:loginator].log(
|
|
121
121
|
"Module file `#{planned}` shares its name with #{existing.map { |path| "`#{path}`" }.join( ', ' )}.",
|
|
122
|
-
Verbosity::COMPLAIN
|
|
122
|
+
Verbosity::COMPLAIN
|
|
123
123
|
)
|
|
124
124
|
end
|
|
125
125
|
end
|
|
@@ -133,7 +133,7 @@ class ModuleGenerator < Plugin
|
|
|
133
133
|
@ceedling[:loginator].log(
|
|
134
134
|
"Generated test `#{path}` is wrapped in `##{options.test_guard} #{define}`, but its build does not " \
|
|
135
135
|
"define #{define}. Add it under :defines ↳ :test, or the test compiles to nothing.",
|
|
136
|
-
Verbosity::COMPLAIN
|
|
136
|
+
Verbosity::COMPLAIN
|
|
137
137
|
)
|
|
138
138
|
end
|
|
139
139
|
end
|
|
@@ -39,18 +39,13 @@ class ReportTestsTeamcityStdout < Plugin
|
|
|
39
39
|
def pre_test(test)
|
|
40
40
|
return if !@output_enabled
|
|
41
41
|
|
|
42
|
-
# Generate a new Flow ID and
|
|
42
|
+
# Generate a new Flow ID and open the test's suite. A suite is named for its test,
|
|
43
|
+
# which tells same-named tests in different directories apart.
|
|
43
44
|
@mutex.synchronize do
|
|
44
45
|
@flowid_count += 1
|
|
45
|
-
@suites[test] = { :flowid => @flowid_count }
|
|
46
|
-
end
|
|
46
|
+
@suites[test] = { :flowid => @flowid_count, :name => escape( @ceedling[:file_path_utils].form_test_name( test ) ) }
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
@mutex.synchronize do
|
|
50
|
-
teamcity_service_message(
|
|
51
|
-
"testSuiteStarted name='#{File.basename(test, '.*')}'",
|
|
52
|
-
@suites[test][:flowid]
|
|
53
|
-
)
|
|
48
|
+
teamcity_service_message( "testSuiteStarted name='#{@suites[test][:name]}'", @suites[test][:flowid] )
|
|
54
49
|
end
|
|
55
50
|
end
|
|
56
51
|
|
|
@@ -58,103 +53,81 @@ class ReportTestsTeamcityStdout < Plugin
|
|
|
58
53
|
def post_test_fixture_execute(arg_hash)
|
|
59
54
|
return if !@output_enabled
|
|
60
55
|
|
|
61
|
-
flowId =
|
|
62
|
-
test_key = arg_hash[:test_filepath]
|
|
63
|
-
|
|
64
|
-
# Get unique Flow ID
|
|
65
|
-
@mutex.synchronize do
|
|
66
|
-
flowId = @suites[test_key][:flowid]
|
|
67
|
-
end
|
|
56
|
+
flowId = @mutex.synchronize { @suites[arg_hash[:test_filepath]][:flowid] }
|
|
68
57
|
|
|
69
58
|
# Gather test results for this test executable
|
|
70
59
|
results = @ceedling[:plugin_reportinator].assemble_test_results( [arg_hash[:result_file]] )
|
|
71
|
-
|
|
72
|
-
# Apportion total run time of test executable equally to each test case within it.
|
|
73
|
-
duration_ms = results[:total_time] * 1000.0
|
|
74
|
-
avg_duration = (duration_ms / [1, results[:counts][:passed] + results[:counts][:failed]].max).round
|
|
60
|
+
duration = average_duration( results )
|
|
75
61
|
|
|
76
62
|
context = arg_hash[:context]
|
|
77
63
|
|
|
78
|
-
|
|
79
|
-
results[:
|
|
80
|
-
|
|
64
|
+
report_successes( results[:successes], context, flowId, duration )
|
|
65
|
+
report_failures( results[:failures], context, flowId, duration )
|
|
66
|
+
report_ignores( results[:ignores], context, flowId )
|
|
67
|
+
end
|
|
81
68
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
teamcity_service_message(
|
|
94
|
-
"testFinished name='#{context}.#{filepath}.#{_test}' duration='#{avg_duration}'",
|
|
95
|
-
flowId
|
|
96
|
-
)
|
|
97
|
-
end
|
|
69
|
+
# `Plugin` build step hook
|
|
70
|
+
def post_test(test)
|
|
71
|
+
return if !@output_enabled
|
|
72
|
+
|
|
73
|
+
@mutex.synchronize do
|
|
74
|
+
teamcity_service_message(
|
|
75
|
+
"testSuiteFinished name='#{@suites[test][:name]}'",
|
|
76
|
+
@suites[test][:flowid]
|
|
77
|
+
)
|
|
98
78
|
end
|
|
79
|
+
end
|
|
99
80
|
|
|
100
|
-
|
|
101
|
-
results[:failures].each do |failure|
|
|
102
|
-
failure[:collection].each do |test|
|
|
103
|
-
filepath = File.join( failure[:source][:dirname], File.basename( failure[:source][:basename], '.*' ) )
|
|
81
|
+
### Private
|
|
104
82
|
|
|
105
|
-
|
|
106
|
-
_message = test[:message]
|
|
83
|
+
private
|
|
107
84
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
85
|
+
# Total run time of a test executable, apportioned equally to each test case within it, in ms
|
|
86
|
+
def average_duration(results)
|
|
87
|
+
duration_ms = results[:total_time] * 1000.0
|
|
112
88
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
_message =
|
|
116
|
-
"testFailed name='#{context}.#{filepath}.#{_test}' " +
|
|
117
|
-
"message='#{escape(_message)}' " +
|
|
118
|
-
"details='File: #{failure[:source][:file]} Line: #{test[:line]}'"
|
|
89
|
+
return (duration_ms / [1, results[:counts][:passed] + results[:counts][:failed]].max).round
|
|
90
|
+
end
|
|
119
91
|
|
|
120
|
-
|
|
92
|
+
def report_successes(successes, context, flowId, duration)
|
|
93
|
+
successes.each do |success|
|
|
94
|
+
success[:collection].each do |test|
|
|
95
|
+
name = test_name( context, success[:source], test[:test] )
|
|
121
96
|
|
|
122
|
-
teamcity_service_message(
|
|
123
|
-
|
|
124
|
-
flowId
|
|
125
|
-
)
|
|
97
|
+
teamcity_service_message( "testStarted name='#{name}'", flowId )
|
|
98
|
+
teamcity_service_message( "testFinished name='#{name}' duration='#{duration}'", flowId )
|
|
126
99
|
end
|
|
127
100
|
end
|
|
101
|
+
end
|
|
128
102
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
service_message = "testIgnored name='#{context}.#{filepath}.#{_test}'"
|
|
103
|
+
def report_failures(failures, context, flowId, duration)
|
|
104
|
+
failures.each do |failure|
|
|
105
|
+
failure[:collection].each do |test|
|
|
106
|
+
name = test_name( context, failure[:source], test[:test] )
|
|
107
|
+
details = escape( "File: #{failure[:source][:file]} Line: #{test[:line]}" )
|
|
136
108
|
|
|
137
|
-
teamcity_service_message(
|
|
109
|
+
teamcity_service_message( "testStarted name='#{name}'", flowId )
|
|
110
|
+
teamcity_service_message( "testFailed name='#{name}' message='#{escape( test[:message] )}' details='#{details}'", flowId )
|
|
111
|
+
teamcity_service_message( "testFinished name='#{name}' duration='#{duration}'", flowId )
|
|
138
112
|
end
|
|
139
113
|
end
|
|
140
|
-
|
|
141
114
|
end
|
|
142
115
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
teamcity_service_message(
|
|
149
|
-
"testSuiteFinished name='#{File.basename(test, '.*')}'",
|
|
150
|
-
@suites[test][:flowid]
|
|
151
|
-
)
|
|
116
|
+
def report_ignores(ignores, context, flowId)
|
|
117
|
+
ignores.each do |ignored|
|
|
118
|
+
ignored[:collection].each do |test|
|
|
119
|
+
teamcity_service_message( "testIgnored name='#{test_name( context, ignored[:source], test[:test] )}'", flowId )
|
|
120
|
+
end
|
|
152
121
|
end
|
|
153
122
|
end
|
|
154
123
|
|
|
155
|
-
|
|
124
|
+
# A Java-like name per TeamCity convention `package_or_namespace.ClassName.TestName`
|
|
125
|
+
# ==> `context.TestFilepath.TestCaseName`, escaped
|
|
126
|
+
def test_name(context, source, test)
|
|
127
|
+
filepath = File.join( source[:dirname], File.basename( source[:basename], '.*' ) )
|
|
156
128
|
|
|
157
|
-
|
|
129
|
+
return escape( "#{context}.#{filepath}.#{test}" )
|
|
130
|
+
end
|
|
158
131
|
|
|
159
132
|
def escape(string)
|
|
160
133
|
# https://www.jetbrains.com/help/teamcity/service-messages.html#Escaped+Values
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
# =========================================================================
|
|
7
7
|
|
|
8
8
|
require 'ceedling/constants'
|
|
9
|
+
require 'ceedling/build_log_writer'
|
|
9
10
|
require 'sanitize_constants'
|
|
10
11
|
require 'sanitize_reports'
|
|
11
12
|
|
|
@@ -20,7 +21,7 @@ class SanitizeRecords
|
|
|
20
21
|
@loginator = loginator
|
|
21
22
|
@reports = reports
|
|
22
23
|
@records = []
|
|
23
|
-
@
|
|
24
|
+
@log_writer = BuildLogWriter.new( file_wrapper: file_wrapper )
|
|
24
25
|
@written = []
|
|
25
26
|
@mutex = Mutex.new
|
|
26
27
|
end
|
|
@@ -101,11 +102,7 @@ class SanitizeRecords
|
|
|
101
102
|
|
|
102
103
|
# A build's first report for a test replaces the last build's log, and later ones follow it
|
|
103
104
|
def write_log(log, findings)
|
|
104
|
-
|
|
105
|
-
text = findings.map( &:text ).join( "\n" )
|
|
106
|
-
|
|
107
|
-
@file_wrapper.mkdir( File.dirname( log ) )
|
|
108
|
-
@file_wrapper.write( log, first ? text : "\n#{text}", first ? 'w' : 'a' )
|
|
105
|
+
@log_writer.write( log, findings.map( &:text ).join( "\n" ), separator: "\n" )
|
|
109
106
|
end
|
|
110
107
|
|
|
111
108
|
def pluralize(count, word)
|