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
|
@@ -7,15 +7,22 @@
|
|
|
7
7
|
|
|
8
8
|
require 'rubygems'
|
|
9
9
|
require 'rake' # for adding ext() method to string
|
|
10
|
+
require 'set'
|
|
10
11
|
require 'ceedling/exceptions'
|
|
11
|
-
require 'ceedling/path_matcher'
|
|
12
|
-
require 'ceedling/path_mirror'
|
|
13
|
-
require 'ceedling/file_path_utils'
|
|
12
|
+
require 'ceedling/filesystem/path_matcher'
|
|
13
|
+
require 'ceedling/filesystem/path_mirror'
|
|
14
|
+
require 'ceedling/filesystem/file_path_utils'
|
|
15
|
+
require 'ceedling/filesystem/project_paths'
|
|
16
|
+
require 'ceedling/filesystem/build_subpath'
|
|
14
17
|
|
|
15
18
|
class FileFinder
|
|
16
19
|
|
|
17
20
|
constructor :configurator, :file_finder_helper, :file_path_utils, :file_wrapper, :yaml_wrapper
|
|
18
21
|
|
|
22
|
+
def setup
|
|
23
|
+
@test_names_lock = Mutex.new
|
|
24
|
+
end
|
|
25
|
+
|
|
19
26
|
|
|
20
27
|
# `collection`, when given, is a caller's own already-ordered, per-test header list
|
|
21
28
|
# (see IncludePathinator#ordered_header_files) reflecting that one test's real search-path
|
|
@@ -59,7 +66,7 @@ class FileFinder
|
|
|
59
66
|
source = find_header_input_for_mock(mock, collection: collection, complain: complain)
|
|
60
67
|
return [nil, nil] if source.nil?
|
|
61
68
|
|
|
62
|
-
subdir = PathMirror.
|
|
69
|
+
subdir = PathMirror.relative_subdir_from_clean_roots( source, @configurator.collection_mirror_roots_headers )
|
|
63
70
|
return [source, subdir]
|
|
64
71
|
end
|
|
65
72
|
|
|
@@ -72,11 +79,10 @@ class FileFinder
|
|
|
72
79
|
# compilation step downstream to catch a wrong guess the way there is for a header
|
|
73
80
|
# or source file resolved during a build.
|
|
74
81
|
#
|
|
75
|
-
# A task name
|
|
76
|
-
#
|
|
77
|
-
# named error rather than falling through to a generic file-not-found further down.
|
|
82
|
+
# A task name is relative to the working directory, as every collected path is, so a
|
|
83
|
+
# leading `..` names a test outside the project.
|
|
78
84
|
def find_test_file_from_name(name)
|
|
79
|
-
name = PathMatcher.resolve_relative(name)
|
|
85
|
+
name = PathMatcher.resolve_relative(name, anchor: '')
|
|
80
86
|
return find_first_candidate(name, @configurator.extension_source, @configurator.collection_all_tests, :error, strict: true)
|
|
81
87
|
end
|
|
82
88
|
|
|
@@ -107,9 +113,8 @@ class FileFinder
|
|
|
107
113
|
# Some legacy files can include naming conventions like <name>.##.<ext> for versioning.
|
|
108
114
|
# If we use .ext() below we'll clobber the dotted portion of the filename
|
|
109
115
|
|
|
110
|
-
# Generated test runners --
|
|
111
|
-
#
|
|
112
|
-
# further, so two same-named tests' runners are never mistaken for each other
|
|
116
|
+
# Generated test runners -- searched for in the runners directory of this test's name,
|
|
117
|
+
# so two same-named tests' runners are never mistaken for each other
|
|
113
118
|
if (!release) and
|
|
114
119
|
(source_file =~ /^#{Regexp.escape(@configurator.project_test_file_prefix)}.+#{Regexp.escape(@configurator.test_runner_file_suffix)}$/)
|
|
115
120
|
_source_file = source_file + EXTENSION_CORE_SOURCE
|
|
@@ -140,9 +145,7 @@ class FileFinder
|
|
|
140
145
|
found_file =
|
|
141
146
|
@file_finder_helper.find_file_in_collection(
|
|
142
147
|
_source_file,
|
|
143
|
-
@
|
|
144
|
-
File.join(mocks_root, ('**/*' + EXTENSION_CORE_SOURCE))
|
|
145
|
-
),
|
|
148
|
+
own_generated_files( @configurator.cmock_mock_path, test_context ),
|
|
146
149
|
complain)
|
|
147
150
|
|
|
148
151
|
# Generated partials -- same per-test scoping rationale as mocks, above
|
|
@@ -157,10 +160,7 @@ class FileFinder
|
|
|
157
160
|
_source_file = source_file + EXTENSION_CORE_SOURCE
|
|
158
161
|
_source_file = File.join( subdir, _source_file ) unless subdir.empty?
|
|
159
162
|
|
|
160
|
-
collection =
|
|
161
|
-
@file_wrapper.directory_listing(
|
|
162
|
-
File.join(partials_root, ('**/*' + EXTENSION_CORE_SOURCE))
|
|
163
|
-
)
|
|
163
|
+
collection = own_generated_files( @configurator.project_test_partials_path, test_context )
|
|
164
164
|
|
|
165
165
|
# Ambiguity is detected here rather than rescued from the matching below. One
|
|
166
166
|
# matching implementation stays in force, and the message is composed from the
|
|
@@ -180,12 +180,11 @@ class FileFinder
|
|
|
180
180
|
@configurator.collection_existing_test_build_input,
|
|
181
181
|
complain)
|
|
182
182
|
|
|
183
|
-
# The test file's own object
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
# another same-named test exists elsewhere
|
|
183
|
+
# The test file's own object resolves to the test it names. A name is the test's path,
|
|
184
|
+
# so the lookup is exact. Searching by name instead is ambiguous wherever one test's
|
|
185
|
+
# name ends another test's path.
|
|
187
186
|
elsif (!release) and !test_context.empty? and (source_file == File.basename( test_context ))
|
|
188
|
-
found_file =
|
|
187
|
+
found_file = test_files_by_name[test_context]
|
|
189
188
|
|
|
190
189
|
end
|
|
191
190
|
|
|
@@ -202,37 +201,16 @@ class FileFinder
|
|
|
202
201
|
# We save the existence handling until the end.
|
|
203
202
|
#
|
|
204
203
|
|
|
205
|
-
# A module-under-test or release
|
|
206
|
-
#
|
|
207
|
-
#
|
|
208
|
-
|
|
209
|
-
query_file = mirrored_query(filepath, release: release, test: test, context: context)
|
|
204
|
+
# A module-under-test or release object sits at its source's own path below its build
|
|
205
|
+
# root, so that path recovers the one source, rather than a bare basename that is
|
|
206
|
+
# ambiguous the moment another same-named source exists elsewhere.
|
|
207
|
+
query_file, exact = mirrored_query(filepath, release: release, test: test, context: context)
|
|
210
208
|
|
|
211
|
-
|
|
212
|
-
if release and @configurator.release_build_use_assembly
|
|
213
|
-
found_file = try_extensions(query_file, @configurator.extension_assembly, @configurator.collection_release_build_input)
|
|
214
|
-
|
|
215
|
-
# Assembly files for test build
|
|
216
|
-
elsif (!release) and @configurator.test_build_use_assembly
|
|
217
|
-
found_file = try_extensions(query_file, @configurator.extension_assembly, @configurator.collection_existing_test_build_input)
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
if !found_file.nil?
|
|
221
|
-
return found_file
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
# Release build C files
|
|
225
|
-
if release
|
|
226
|
-
found_file = try_extensions(query_file, @configurator.extension_source, @configurator.collection_release_build_input)
|
|
227
|
-
|
|
228
|
-
# Test build C files
|
|
229
|
-
else
|
|
230
|
-
found_file = try_extensions(query_file, @configurator.extension_source, @configurator.collection_existing_test_build_input)
|
|
231
|
-
end
|
|
209
|
+
found_file = find_compiled_input( query_file, release: release, exact: exact )
|
|
232
210
|
|
|
233
211
|
if found_file.nil?
|
|
234
|
-
# Every name actually attempted
|
|
235
|
-
#
|
|
212
|
+
# Every name actually attempted, in the order tried, so a missing-file complaint
|
|
213
|
+
# names every filename ceedling went looking for.
|
|
236
214
|
tried = @configurator.extension_source.map { |ext| query_file + ext }
|
|
237
215
|
tried += @configurator.extension_assembly.map { |ext| query_file + ext } if @configurator.release_build_use_assembly
|
|
238
216
|
@file_finder_helper.handle_missing_file(tried.join(' or '), complain)
|
|
@@ -265,6 +243,24 @@ class FileFinder
|
|
|
265
243
|
|
|
266
244
|
private
|
|
267
245
|
|
|
246
|
+
# A C or assembly build input for `query`, assembly first where the build uses it. An
|
|
247
|
+
# exact query is the file's own path, matched as such before any tail match.
|
|
248
|
+
def find_compiled_input(query, release:, exact:)
|
|
249
|
+
collection = release ? @configurator.collection_release_build_input : @configurator.collection_existing_test_build_input
|
|
250
|
+
|
|
251
|
+
compiled_extensions( release ).each do |extension|
|
|
252
|
+
found = (exact && exact_file( query, extension, collection )) || try_extensions( query, extension, collection )
|
|
253
|
+
return found unless found.nil?
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
return nil
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def compiled_extensions(release)
|
|
260
|
+
assembly = release ? @configurator.release_build_use_assembly : @configurator.test_build_use_assembly
|
|
261
|
+
return assembly ? [@configurator.extension_assembly, @configurator.extension_source] : [@configurator.extension_source]
|
|
262
|
+
end
|
|
263
|
+
|
|
268
264
|
# Translates a generated-Partial ambiguity into the test author's own terms. The query
|
|
269
265
|
# here is a generated filename under a build directory, neither of which the author
|
|
270
266
|
# typed, so reporting them offers nothing to act on. Candidates render as extensionless
|
|
@@ -299,74 +295,133 @@ class FileFinder
|
|
|
299
295
|
raise CeedlingException.new( message )
|
|
300
296
|
end
|
|
301
297
|
|
|
302
|
-
# A test object's build directory
|
|
303
|
-
#
|
|
304
|
-
# a
|
|
305
|
-
#
|
|
306
|
-
#
|
|
307
|
-
# exists elsewhere.
|
|
298
|
+
# A test object's build directory is its test's name, the test's path from the project
|
|
299
|
+
# root (e.g. `test/unit/test_foo` for `test/unit/test_foo.c`). Recovering that name from
|
|
300
|
+
# a build artifact's own path lets a lookup go straight to the one test it belongs to,
|
|
301
|
+
# rather than searching the whole project by bare basename -- exactly the query shape
|
|
302
|
+
# that's ambiguous when another same-named test exists elsewhere.
|
|
308
303
|
#
|
|
309
304
|
# A filepath that isn't under the test build root at all (a source-tree-relative query
|
|
310
305
|
# from an #include or TEST_SOURCE_FILE(), rather than a build artifact's own path) has no
|
|
311
306
|
# test identity to recover -- empty string, never a directory name that could coincidentally
|
|
312
307
|
# match some unrelated file's own basename.
|
|
308
|
+
#
|
|
309
|
+
# A test's build directory also holds its objects at their sources' own paths, so the
|
|
310
|
+
# name is the longest one of a known test that the directory begins with.
|
|
313
311
|
def test_context_of(filepath)
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
312
|
+
subdir = ProjectPaths.subdir_below( @configurator.project_test_build_output_path, File.dirname( filepath ) )
|
|
313
|
+
return '' if subdir.nil?
|
|
314
|
+
|
|
315
|
+
parts = subdir.split( '/' )
|
|
316
|
+
parts.length.downto( 1 ) do |count|
|
|
317
|
+
name = parts.first( count ).join( '/' )
|
|
318
|
+
return name if test_files_by_name.key?( name )
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
return ''
|
|
317
322
|
end
|
|
318
323
|
|
|
319
|
-
# A
|
|
320
|
-
#
|
|
321
|
-
# further -- mirroring FilePathUtils#form_test_runners_path's own directory-forming rule.
|
|
322
|
-
# Takes the test identity already recovered by the caller rather than a raw filepath, so
|
|
323
|
-
# it isn't independently re-deriving what the caller already has in hand.
|
|
324
|
+
# A test's runner lives where FilePathUtils#form_test_runners_path puts it. Takes the test
|
|
325
|
+
# identity the caller already recovered rather than a raw filepath.
|
|
324
326
|
def runner_scope_dir(test_context)
|
|
325
|
-
|
|
326
|
-
root = @configurator.project_test_runners_path
|
|
327
|
-
return subdir == '.' ? root : File.join(root, subdir)
|
|
327
|
+
return @file_path_utils.form_test_runners_path( test_context )
|
|
328
328
|
end
|
|
329
329
|
|
|
330
|
-
#
|
|
331
|
-
#
|
|
332
|
-
#
|
|
333
|
-
|
|
334
|
-
|
|
330
|
+
# Every test file by its name. Names are paths, and a build stops before its first lookup
|
|
331
|
+
# if two tests in it share one. Built once, on first use, since build threads share this
|
|
332
|
+
# finder.
|
|
333
|
+
def test_files_by_name
|
|
334
|
+
@test_names_lock.synchronize do
|
|
335
|
+
@test_files_by_name ||= @configurator.collection_all_tests.to_h { |test| [@file_path_utils.form_test_name( test ), test.to_s] }
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# For each test's name, the names of the tests nested beneath it (`test/test_foo/test_bar`
|
|
340
|
+
# beneath `test/test_foo`)
|
|
341
|
+
def nested_test_names
|
|
342
|
+
names = test_files_by_name.keys
|
|
343
|
+
@test_names_lock.synchronize do
|
|
344
|
+
@nested_test_names ||= nest_names( names )
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Files each name under every other name that is one of its parent directories
|
|
349
|
+
def nest_names(names)
|
|
350
|
+
known = names.to_set
|
|
351
|
+
nested = Hash.new { |hash, name| hash[name] = [] }
|
|
352
|
+
|
|
353
|
+
names.each do |name|
|
|
354
|
+
parts = name.split( '/' )
|
|
355
|
+
(1...parts.length).each do |count|
|
|
356
|
+
parent = parts.first( count ).join( '/' )
|
|
357
|
+
nested[parent] << name if known.include?( parent )
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
return nested
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# A test's generated mocks or Partials, beneath its own directory below `base`. A test
|
|
365
|
+
# whose name continues this one's (`test/test_foo/test_bar` after `test/test_foo`) has its
|
|
366
|
+
# directory nested here, and the files in it are that test's own.
|
|
367
|
+
def own_generated_files(base, test_context)
|
|
368
|
+
listing = @file_wrapper.directory_listing( FilePathUtils.glob( File.join( base, test_context ), '**/*' + EXTENSION_CORE_SOURCE ) )
|
|
369
|
+
nested = nested_test_names.fetch( test_context, [] ).map { |name| File.join( base, name ) + '/' }
|
|
370
|
+
return listing if nested.empty?
|
|
371
|
+
|
|
372
|
+
return listing.reject { |file| nested.any? { |dir| file.start_with?( dir ) } }
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# The query for the source of a release or module-under-test object, and whether it is
|
|
376
|
+
# exact. Such an object sits at its source's own path below the release output root, or
|
|
377
|
+
# below the build path of the test it belongs to, so decoding that path names the source.
|
|
335
378
|
#
|
|
336
|
-
# A filepath
|
|
337
|
-
#
|
|
338
|
-
#
|
|
339
|
-
#
|
|
340
|
-
# root when one contains it (see header_root_relative_query below).
|
|
379
|
+
# A filepath outside the build root is a source-tree-relative query in its own right,
|
|
380
|
+
# from an #include or a TEST_SOURCE_FILE() directive, say. It keeps whatever path it
|
|
381
|
+
# carries, reduced to its namespace below a configured include root when one contains it
|
|
382
|
+
# (see header_root_relative_query below).
|
|
341
383
|
#
|
|
342
|
-
# A filepath
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
# peel back a known per-test root (test build input queried without a test identity),
|
|
346
|
-
# falls back to the bare basename -- exactly what every caller has always seen for those
|
|
347
|
-
# cases.
|
|
384
|
+
# A filepath below the build root in a context this method doesn't know (a plugin's own
|
|
385
|
+
# object output, e.g. build/valgrind/out/...), or test build input queried without a test
|
|
386
|
+
# identity, falls back to the bare basename.
|
|
348
387
|
def mirrored_query(filepath, release:, test:, context:)
|
|
349
|
-
|
|
350
|
-
build_root = @configurator.project_build_root
|
|
388
|
+
return [source_tree_query( filepath ), false] unless ProjectPaths.contains?( @configurator.project_build_root, filepath )
|
|
351
389
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
390
|
+
root = placement_root( release, test, context )
|
|
391
|
+
subdir = root.nil? ? nil : ProjectPaths.subdir_below( root, File.dirname( filepath ) )
|
|
392
|
+
basename = File.basename( filepath ).ext('')
|
|
393
|
+
return [basename, false] if subdir.nil? || subdir.empty?
|
|
394
|
+
|
|
395
|
+
return [File.join( BuildSubpath.decode( subdir ), basename ), true]
|
|
396
|
+
end
|
|
356
397
|
|
|
357
|
-
|
|
398
|
+
def source_tree_query(filepath)
|
|
399
|
+
query = header_root_relative_query( filepath )
|
|
400
|
+
return query.nil? ? filepath.ext('') : query
|
|
401
|
+
end
|
|
358
402
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
@file_path_utils.form_test_build_path(test, context: context)
|
|
364
|
-
end
|
|
403
|
+
# The root a release or test object is placed below, or nil where none is known
|
|
404
|
+
def placement_root(release, test, context)
|
|
405
|
+
return @configurator.project_release_build_output_path if release
|
|
406
|
+
return nil if test.nil?
|
|
365
407
|
|
|
366
|
-
return
|
|
408
|
+
return @file_path_utils.form_test_build_path( test, context: context )
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# The file of `collection` at exactly `query` plus one of `extension`'s spellings, or nil.
|
|
412
|
+
# Compared by absolute path, through an index built once per collection, since build
|
|
413
|
+
# threads share this finder.
|
|
414
|
+
def exact_file(query, extension, collection)
|
|
415
|
+
index = @test_names_lock.synchronize do
|
|
416
|
+
(@exact_indexes ||= {}.compare_by_identity)[collection] ||= collection.to_h { |file| [ProjectPaths.absolute( file ), file.to_s] }
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
extension.to_a.each do |ext|
|
|
420
|
+
found = index[ProjectPaths.absolute( query + ext )]
|
|
421
|
+
return found unless found.nil?
|
|
422
|
+
end
|
|
367
423
|
|
|
368
|
-
|
|
369
|
-
return subdir.empty? ? basename : File.join(subdir, basename)
|
|
424
|
+
return nil
|
|
370
425
|
end
|
|
371
426
|
|
|
372
427
|
# The subdirectory a generated file's query carries, mirroring the module it belongs to.
|
|
@@ -399,9 +454,9 @@ class FileFinder
|
|
|
399
454
|
|
|
400
455
|
return '' if dir == '.'
|
|
401
456
|
|
|
402
|
-
#
|
|
403
|
-
#
|
|
404
|
-
return '' if
|
|
457
|
+
# Compared as directories. A directory merely beginning with the build root's own name
|
|
458
|
+
# is an ordinary relative directory and still names its module.
|
|
459
|
+
return '' if ProjectPaths.contains?( root, dir )
|
|
405
460
|
|
|
406
461
|
return dir
|
|
407
462
|
end
|
|
@@ -415,7 +470,7 @@ class FileFinder
|
|
|
415
470
|
# Only the root is dropped. The namespace is preserved, since that is what keeps two
|
|
416
471
|
# same-basename modules apart.
|
|
417
472
|
def header_root_relative_query(filepath)
|
|
418
|
-
subdir = PathMirror.
|
|
473
|
+
subdir = PathMirror.relative_subdir_if_rooted_in_clean_roots( filepath, @configurator.collection_mirror_roots_include )
|
|
419
474
|
|
|
420
475
|
return nil if subdir.nil?
|
|
421
476
|
|
|
@@ -8,12 +8,16 @@
|
|
|
8
8
|
require 'fileutils'
|
|
9
9
|
require 'ceedling/constants' # for Verbosity enumeration
|
|
10
10
|
require 'ceedling/exceptions'
|
|
11
|
-
require 'ceedling/path_matcher'
|
|
11
|
+
require 'ceedling/filesystem/path_matcher'
|
|
12
12
|
|
|
13
13
|
class FileFinderHelper
|
|
14
14
|
|
|
15
15
|
constructor :loginator
|
|
16
16
|
|
|
17
|
+
def setup
|
|
18
|
+
@noticed = []
|
|
19
|
+
@notice_mutex = Mutex.new
|
|
20
|
+
end
|
|
17
21
|
|
|
18
22
|
def find_file_in_collection(filename, file_list, complain)
|
|
19
23
|
found = PathMatcher.match(filename, file_list)
|
|
@@ -25,7 +29,8 @@ class FileFinderHelper
|
|
|
25
29
|
# As `#find_file_in_collection`, but never raises on ambiguity -- a query matching
|
|
26
30
|
# more than one file resolves to the first entry in `file_list`'s own order (which
|
|
27
31
|
# already reflects real project path priority), with an ℹ️ NOTICE naming what else
|
|
28
|
-
# matched so the choice isn't silent.
|
|
32
|
+
# matched so the choice isn't silent. Every test that names the file makes the same
|
|
33
|
+
# choice, so a build notes it once.
|
|
29
34
|
def resolve_file_in_collection(filename, file_list, complain)
|
|
30
35
|
found, others = PathMatcher.resolve(filename, file_list)
|
|
31
36
|
return not_found_in_collection(filename, file_list, complain) if found.nil?
|
|
@@ -34,7 +39,8 @@ class FileFinderHelper
|
|
|
34
39
|
msg = "Multiple files matched '#{filename}' but chose '#{found}' by search-path priority. " \
|
|
35
40
|
"Other candidates: #{others.join(', ')}. Add more path to '#{filename}' at its point " \
|
|
36
41
|
"of reference to select a different file."
|
|
37
|
-
@
|
|
42
|
+
first = @notice_mutex.synchronize { !@noticed.include?( msg ) && @noticed << msg }
|
|
43
|
+
@loginator.log( msg, Verbosity::COMPLAIN, LogLabels::NOTICE ) if first
|
|
38
44
|
end
|
|
39
45
|
|
|
40
46
|
return found
|
|
@@ -45,35 +51,14 @@ class FileFinderHelper
|
|
|
45
51
|
raise "No path list provided for #{description} search" if path_list.nil?
|
|
46
52
|
return pathname if path_list.include?(pathname)
|
|
47
53
|
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
path_list.each_with_index do |p,i|
|
|
53
|
-
reverse_match_pieces = p.split(/(?:\\|\/)/).reverse
|
|
54
|
-
#
|
|
55
|
-
num = reverse_original_pieces.zip(reverse_match_pieces).inject(0){|s,v| v[0] == v[1] ? s+3 : s}
|
|
56
|
-
num = reverse_original_pieces.inject(num){|s,v| reverse_match_pieces.include?(v) ? s+1 : s}
|
|
57
|
-
if num > best_match_value
|
|
58
|
-
best_match_index = i
|
|
59
|
-
best_match_value = num
|
|
60
|
-
end
|
|
61
|
-
end
|
|
54
|
+
# The closest match shares the most path segments, especially those ENDING the same. The
|
|
55
|
+
# first of equally close matches wins, and the first path when none shares a segment.
|
|
56
|
+
pieces = reversed_pieces( pathname )
|
|
57
|
+
scores = path_list.map { |path| match_score( pieces, reversed_pieces( path ) ) }
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
if (best_match_value == 0) && (reverse_original_pieces.length > 0)
|
|
65
|
-
case (complain)
|
|
66
|
-
when :error
|
|
67
|
-
raise CeedlingException.new( "Found no path `#{pathname}` in #{description} search paths." )
|
|
68
|
-
when :warn
|
|
69
|
-
warning = "Found no path `#{pathname}` in #{description} search paths."
|
|
70
|
-
@loginator.log( warning, Verbosity::COMPLAIN )
|
|
71
|
-
when :ignore
|
|
72
|
-
# nothing further to do
|
|
73
|
-
end
|
|
74
|
-
end
|
|
59
|
+
complain_of_no_path( "Found no path `#{pathname}` in #{description} search paths.", complain ) if scores.max.to_i.zero? and !pieces.empty?
|
|
75
60
|
|
|
76
|
-
return path_list[
|
|
61
|
+
return path_list[best_index( scores )]
|
|
77
62
|
end
|
|
78
63
|
|
|
79
64
|
def handle_missing_file(filename, complain)
|
|
@@ -122,6 +107,26 @@ class FileFinderHelper
|
|
|
122
107
|
@loginator.log( warning, Verbosity::COMPLAIN )
|
|
123
108
|
end
|
|
124
109
|
|
|
125
|
-
|
|
110
|
+
def reversed_pieces(path)
|
|
111
|
+
return path.split( /(?:\\|\/)/ ).reverse
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Three for each trailing segment matched in place, and one for each segment found anywhere
|
|
115
|
+
def match_score(pieces, candidate)
|
|
116
|
+
in_place = pieces.zip( candidate ).count { |piece, other| piece == other }
|
|
117
|
+
return (in_place * 3) + pieces.count { |piece| candidate.include?( piece ) }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# The first of the highest scores, or the first when none scores
|
|
121
|
+
def best_index(scores)
|
|
122
|
+
best = scores.max.to_i
|
|
123
|
+
return best.zero? ? 0 : scores.index( best )
|
|
124
|
+
end
|
|
126
125
|
|
|
126
|
+
def complain_of_no_path(message, complain)
|
|
127
|
+
raise CeedlingException.new( message ) if complain == :error
|
|
127
128
|
|
|
129
|
+
@loginator.log( message, Verbosity::COMPLAIN ) if complain == :warn
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|