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.
Files changed (276) hide show
  1. checksums.yaml +4 -4
  2. data/GIT_COMMIT_SHA +1 -1
  3. data/README.md +11 -9
  4. data/Rakefile +2 -1
  5. data/assets/features/ceedling +1 -1
  6. data/assets/fixtures/test_source_file_duplicate_basenames/test_calc_typo.c +14 -0
  7. data/assets/fixtures/tests_with_duplicate_test_names/test_foo.c +21 -0
  8. data/bin/actionator.rb +6 -12
  9. data/bin/app_cfg.rb +14 -1
  10. data/bin/ceedling +13 -3
  11. data/bin/cli.rb +25 -6
  12. data/bin/cli_handler.rb +113 -73
  13. data/bin/cli_helper.rb +51 -78
  14. data/bin/installation_selector.rb +81 -0
  15. data/bin/launchinator.rb +69 -0
  16. data/bin/mixin_resolvinator.rb +26 -36
  17. data/bin/objects.yml +13 -0
  18. data/bin/path_validator.rb +25 -29
  19. data/bin/versionator.rb +47 -48
  20. data/ceedling.gemspec +19 -15
  21. data/docs/BreakingChanges.md +70 -1
  22. data/docs/Changelog.md +74 -3
  23. data/docs/KnownIssues.md +90 -4
  24. data/docs/ReleaseNotes.md +13 -0
  25. data/lib/ceedling/build_log_writer.rb +33 -0
  26. data/lib/ceedling/config/build_root_policy.rb +70 -0
  27. data/lib/ceedling/config/configurator.rb +14 -16
  28. data/lib/ceedling/config/configurator_builder.rb +58 -28
  29. data/lib/ceedling/config/configurator_paths_validator.rb +179 -0
  30. data/lib/ceedling/config/configurator_plugins.rb +1 -1
  31. data/lib/ceedling/config/configurator_setup.rb +15 -28
  32. data/lib/ceedling/config/configurator_validator.rb +1 -110
  33. data/lib/ceedling/defaults.rb +4 -4
  34. data/lib/ceedling/dependencies/README.md +18 -16
  35. data/lib/ceedling/dependencies/dependency_cache_store.rb +20 -3
  36. data/lib/ceedling/dependencies/dependency_hasher.rb +35 -1
  37. data/lib/ceedling/filename_extension.rb +7 -1
  38. data/lib/ceedling/filesystem/FILE_TREE.md +253 -0
  39. data/lib/ceedling/filesystem/PATH_HANDLING.md +304 -0
  40. data/lib/ceedling/filesystem/README.md +41 -0
  41. data/lib/ceedling/filesystem/build_subpath.rb +102 -0
  42. data/lib/ceedling/filesystem/destination_collision.rb +25 -0
  43. data/lib/ceedling/{file_finder.rb → filesystem/file_finder.rb} +159 -104
  44. data/lib/ceedling/{file_finder_helper.rb → filesystem/file_finder_helper.rb} +36 -31
  45. data/lib/ceedling/filesystem/file_path_collection_utils.rb +183 -0
  46. data/lib/ceedling/{file_path_utils.rb → filesystem/file_path_utils.rb} +108 -97
  47. data/lib/ceedling/{file_system_wrapper.rb → filesystem/file_system_wrapper.rb} +6 -5
  48. data/lib/ceedling/filesystem/file_tree.rb +241 -0
  49. data/lib/ceedling/{file_wrapper.rb → filesystem/file_wrapper.rb} +45 -38
  50. data/lib/ceedling/filesystem/path_exclusions.rb +30 -0
  51. data/lib/ceedling/{path_matcher.rb → filesystem/path_matcher.rb} +27 -23
  52. data/lib/ceedling/{path_mirror.rb → filesystem/path_mirror.rb} +19 -18
  53. data/lib/ceedling/filesystem/path_spellings.rb +55 -0
  54. data/lib/ceedling/filesystem/project_paths.rb +184 -0
  55. data/lib/ceedling/filesystem/working_dir.rb +40 -0
  56. data/lib/ceedling/generators/generator.rb +5 -6
  57. data/lib/ceedling/generators/generator_partials.rb +1 -1
  58. data/lib/ceedling/generators/generator_test_results_backtrace.rb +7 -7
  59. data/lib/ceedling/handoff.rb +121 -0
  60. data/lib/ceedling/includes/include_factory.rb +3 -3
  61. data/lib/ceedling/includes/include_pathinator.rb +67 -10
  62. data/lib/ceedling/includes/includes.rb +1 -1
  63. data/lib/ceedling/installation.rb +92 -0
  64. data/lib/ceedling/library_resolver.rb +99 -0
  65. data/lib/ceedling/objects.yml +23 -2
  66. data/lib/ceedling/partials/partializer.rb +4 -4
  67. data/lib/ceedling/partials/partializer_config.rb +3 -1
  68. data/lib/ceedling/plugins/report_log_writer_plugin.rb +3 -5
  69. data/lib/ceedling/preprocess/preprocessinator_file_assembler.rb +1 -1
  70. data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +1 -1
  71. data/lib/ceedling/preprocess/preprocessinator_line_marker_includes_extractor.rb +1 -1
  72. data/lib/ceedling/rake_app/rakefile_component_resolver.rb +10 -17
  73. data/lib/ceedling/rakefile.rb +15 -1
  74. data/lib/ceedling/rakefiles/base/tasks_base.rake +1 -1
  75. data/lib/ceedling/rakefiles/release/rules_release.rake +4 -7
  76. data/lib/ceedling/release_invoker/release_build_executor.rb +33 -44
  77. data/lib/ceedling/release_invoker/release_build_planner.rb +14 -6
  78. data/lib/ceedling/reportinator.rb +3 -4
  79. data/lib/ceedling/setupinator.rb +94 -90
  80. data/lib/ceedling/test_context_extractor.rb +5 -1
  81. data/lib/ceedling/test_invoker/PIPELINE.md +9 -7
  82. data/lib/ceedling/test_invoker/mock_locator.rb +60 -2
  83. data/lib/ceedling/test_invoker/partials_manager.rb +12 -0
  84. data/lib/ceedling/test_invoker/standin_headerinator.rb +22 -13
  85. data/lib/ceedling/test_invoker/test_build_executor.rb +24 -40
  86. data/lib/ceedling/test_invoker/test_build_planner.rb +37 -18
  87. data/lib/ceedling/test_invoker/test_build_setup.rb +17 -12
  88. data/lib/ceedling/test_invoker/test_build_validations.rb +16 -31
  89. data/lib/ceedling/test_invoker/test_file_preprocessinator.rb +1 -1
  90. data/lib/ceedling/test_invoker/test_invoker.rb +6 -1
  91. data/lib/ceedling/test_invoker/test_pipeline_helpers.rb +1 -1
  92. data/lib/ceedling/test_invoker/test_source_file_directive_resolver.rb +40 -20
  93. data/lib/ceedling/tool_executor.rb +9 -3
  94. data/lib/ceedling/yaml_wrapper.rb +3 -2
  95. data/lib/version.rb +1 -1
  96. data/plugins/bullseye/config/defaults_bullseye.rb +1 -1
  97. data/plugins/bullseye/lib/bullseye.rb +9 -7
  98. data/plugins/cppcheck/config/defaults_cppcheck.rb +1 -1
  99. data/plugins/dependencies/config/defaults.yml +6 -6
  100. data/plugins/dependencies/dependencies.rake +4 -1
  101. data/plugins/dependencies/lib/dependencies.rb +18 -8
  102. data/plugins/dependencies/lib/dependency_spec.rb +17 -5
  103. data/plugins/fff/lib/fff.rb +45 -39
  104. data/plugins/fff/spec/fff_cmock_wrapper_spec.rb +128 -0
  105. data/plugins/gcov/config/defaults_gcov.rb +1 -1
  106. data/plugins/gcov/lib/console_reportinator.rb +4 -18
  107. data/plugins/gcov/lib/gcov.rb +9 -2
  108. data/plugins/gcov/lib/gcovr_reportinator.rb +8 -40
  109. data/plugins/gcov/lib/gcovr_thresholds.rb +74 -0
  110. data/plugins/gcov/lib/reportgenerator_reportinator.rb +1 -1
  111. data/plugins/module_generator/lib/module_generator.rb +3 -3
  112. data/plugins/report_tests_teamcity_stdout/lib/report_tests_teamcity_stdout.rb +53 -80
  113. data/plugins/sanitize/lib/sanitize_records.rb +3 -6
  114. data/plugins/valgrind/lib/valgrind.rb +14 -7
  115. data/site-local/configuration/reference/cmock.html +2 -1
  116. data/site-local/configuration/reference/files.html +9 -3
  117. data/site-local/configuration/reference/libraries.html +21 -3
  118. data/site-local/configuration/reference/paths.html +29 -6
  119. data/site-local/configuration/reference/project.html +17 -7
  120. data/site-local/configuration/reference/release-build.html +2 -0
  121. data/site-local/configuration/reference/tools.html +9 -0
  122. data/site-local/configuration/which-ceedling.html +377 -17
  123. data/site-local/development/releases.html +5 -1
  124. data/site-local/development/workflow.html +48 -43
  125. data/site-local/getting-started/builds.html +2 -0
  126. data/site-local/getting-started/command-line.html +56 -4
  127. data/site-local/plugins/dependencies.html +6 -3
  128. data/site-local/plugins/fff.html +42 -11
  129. data/site-local/plugins/gcov/gcovr.html +15 -12
  130. data/site-local/plugins/gcov/setup.html +2 -1
  131. data/site-local/plugins/report-tests-raw-output-log.html +3 -1
  132. data/site-local/plugins/report-tests-teamcity-stdout.html +6 -3
  133. data/site-local/plugins/sanitize.html +7 -6
  134. data/site-local/plugins/valgrind.html +8 -7
  135. data/site-local/project/upgrade.html +3 -0
  136. data/site-local/reference/command-line.html +9 -2
  137. data/site-local/sitemap.xml.gz +0 -0
  138. data/site-local/snapshot/plugins/bullseye/config/defaults_bullseye.rb +1 -1
  139. data/site-local/snapshot/plugins/gcov/config/defaults_gcov.rb +1 -1
  140. data/site-local/testing-guide/conventions.html +53 -0
  141. data/spec/integration/actionator_file_operations_spec.rb +91 -1
  142. data/spec/integration/compile_commands_json_db_spec.rb +1 -1
  143. data/spec/integration/configurator_validation_spec.rb +1 -1
  144. data/spec/integration/dependencies/dependency_tracker_cache_hardening_spec.rb +26 -0
  145. data/spec/integration/dependencies/dependency_tracker_core_spec.rb +22 -0
  146. data/spec/integration/launcher_handoff_spec.rb +297 -0
  147. data/spec/integration/mixin_loading_spec.rb +1 -1
  148. data/spec/integration/module_generator_spec.rb +3 -3
  149. data/spec/integration/nested_test_artifacts_spec.rb +99 -0
  150. data/spec/integration/partials_module_resolution_spec.rb +7 -4
  151. data/spec/integration/path_intake_scenarios_spec.rb +101 -0
  152. data/spec/integration/path_scenarios_spec.rb +322 -0
  153. data/spec/integration/quote_include_isolator_spec.rb +1 -1
  154. data/spec/integration/report_build_warnings_log_spec.rb +1 -1
  155. data/spec/integration/report_tests_log_factory_spec.rb +1 -1
  156. data/spec/integration/test_executable_manifest_spec.rb +1 -1
  157. data/spec/integration/test_includes_extractinator_spec.rb +2 -1
  158. data/spec/integration/test_naming_spec.rb +198 -0
  159. data/spec/integration/test_source_file_checks_spec.rb +166 -0
  160. data/spec/integration/tool_validator_spec.rb +1 -1
  161. data/spec/integration/upgrade_docs_spec.rb +84 -0
  162. data/spec/integration/vendor_copy_transient_io_retry_spec.rb +74 -5
  163. data/spec/support/file_tree_helper.rb +88 -0
  164. data/spec/support/integration/configurator_integration_helper.rb +6 -6
  165. data/spec/support/integration/dependency_tracker_integration_helper.rb +1 -1
  166. data/spec/support/integration/partials_generation_integration_helper.rb +2 -2
  167. data/spec/support/integration/path_scenario_harness.rb +173 -0
  168. data/spec/support/integration/spec_integration_helper.rb +1 -1
  169. data/spec/support/integration/test_includes_harness.rb +13 -2
  170. data/spec/support/spec_helper.rb +2 -0
  171. data/spec/support/system/spec_system_helper.rb +7 -6
  172. data/spec/support/system/system_context.rb +21 -3
  173. data/spec/support/working_dir_tracking.rb +49 -0
  174. data/spec/system/build_output_mirroring_spec.rb +2 -2
  175. data/spec/system/conditional_mock_includes_spec.rb +1 -1
  176. data/spec/system/delta_builds_spec.rb +137 -11
  177. data/spec/system/gcov_deployment_spec.rb +1 -0
  178. data/spec/system/header_include_path_validation_spec.rb +4 -4
  179. data/spec/system/launcher_handoff_spec.rb +82 -0
  180. data/spec/system/mock_include_folders_spec.rb +91 -0
  181. data/spec/system/parent_directory_reference_spec.rb +5 -3
  182. data/spec/system/path_handling_probes_spec.rb +192 -0
  183. data/spec/system/preprocessing_parameterized_tests_spec.rb +1 -1
  184. data/spec/system/rake_release_task_path_disambiguation_spec.rb +6 -6
  185. data/spec/system/rake_test_task_path_disambiguation_spec.rb +85 -0
  186. data/spec/system/special_path_characters_spec.rb +86 -0
  187. data/spec/system/support/common_test_cases.rb +23 -21
  188. data/spec/system/support/gcov_common_test_cases.rb +37 -9
  189. data/spec/system/support/sanitize_common_test_cases.rb +2 -2
  190. data/spec/system/support/valgrind_common_test_cases.rb +12 -12
  191. data/spec/system/test_pipeline_stop_points_spec.rb +4 -4
  192. data/spec/system/test_runner_system_include_spec.rb +1 -1
  193. data/spec/system/test_source_file_directive_spec.rb +34 -5
  194. data/spec/units/bin/actionator_spec.rb +14 -17
  195. data/spec/units/bin/app_cfg_spec.rb +37 -0
  196. data/spec/units/bin/cli_handler_spec.rb +282 -6
  197. data/spec/units/bin/cli_helper_spec.rb +116 -45
  198. data/spec/units/bin/installation_selector_spec.rb +114 -0
  199. data/spec/units/bin/launchinator_spec.rb +171 -0
  200. data/spec/units/bin/path_validator_spec.rb +10 -0
  201. data/spec/units/bin/versionator_spec.rb +38 -6
  202. data/spec/units/build_log_writer_spec.rb +57 -0
  203. data/spec/units/config/build_root_policy_spec.rb +61 -0
  204. data/spec/units/config/configurator_builder_spec.rb +37 -6
  205. data/spec/units/config/configurator_paths_validator_spec.rb +292 -0
  206. data/spec/units/config/configurator_setup_spec.rb +9 -65
  207. data/spec/units/config/configurator_spec.rb +27 -5
  208. data/spec/units/config/configurator_validator_spec.rb +1 -172
  209. data/spec/units/default_tools_quoting_spec.rb +83 -0
  210. data/spec/units/dependencies/dependency_cache_store_spec.rb +33 -2
  211. data/spec/units/dependencies/dependency_debug_tree_spec.rb +1 -1
  212. data/spec/units/dependencies/dependency_hasher_spec.rb +42 -1
  213. data/spec/units/dependencies/dependency_path_normalizer_spec.rb +1 -1
  214. data/spec/units/dependencies/dependency_tracker_spec.rb +3 -1
  215. data/spec/units/filename_extension_spec.rb +11 -0
  216. data/spec/units/filesystem/build_subpath_spec.rb +122 -0
  217. data/spec/units/filesystem/destination_collision_spec.rb +30 -0
  218. data/spec/units/{file_finder_helper_spec.rb → filesystem/file_finder_helper_spec.rb} +46 -1
  219. data/spec/units/{file_finder_spec.rb → filesystem/file_finder_spec.rb} +188 -22
  220. data/spec/units/{file_path_collection_utils_spec.rb → filesystem/file_path_collection_utils_spec.rb} +181 -1
  221. data/spec/units/{file_path_utils_spec.rb → filesystem/file_path_utils_spec.rb} +204 -87
  222. data/spec/units/filesystem/file_system_wrapper_spec.rb +33 -0
  223. data/spec/units/filesystem/file_tree_spec.rb +511 -0
  224. data/spec/units/filesystem/file_tree_windows_spec.rb +78 -0
  225. data/spec/units/{file_wrapper_spec.rb → filesystem/file_wrapper_spec.rb} +95 -12
  226. data/spec/units/{path_matcher_spec.rb → filesystem/path_matcher_spec.rb} +12 -1
  227. data/spec/units/{path_mirror_spec.rb → filesystem/path_mirror_spec.rb} +32 -4
  228. data/spec/units/filesystem/project_paths_spec.rb +147 -0
  229. data/spec/units/filesystem/working_dir_spec.rb +71 -0
  230. data/spec/units/generators/generator_spec.rb +12 -6
  231. data/spec/units/generators/generator_test_results_backtrace_spec.rb +50 -46
  232. data/spec/units/generators/generator_test_results_spec.rb +1 -1
  233. data/spec/units/handoff_spec.rb +205 -0
  234. data/spec/units/includes/include_factory_spec.rb +3 -3
  235. data/spec/units/includes/include_pathinator_spec.rb +46 -0
  236. data/spec/units/installation_spec.rb +228 -0
  237. data/spec/units/library_resolver_spec.rb +157 -0
  238. data/spec/units/mock_locator_spec.rb +76 -1
  239. data/spec/units/partials/partializer_config_spec.rb +7 -0
  240. data/spec/units/partials/partializer_spec.rb +1 -0
  241. data/spec/units/partials_manager_spec.rb +17 -0
  242. data/spec/units/plugins/bullseye_spec.rb +15 -2
  243. data/spec/units/plugins/console_reportinator_spec.rb +18 -20
  244. data/spec/units/plugins/dependencies_spec.rb +33 -7
  245. data/spec/units/plugins/dependency_spec_spec.rb +17 -0
  246. data/spec/units/plugins/gcov_spec.rb +28 -3
  247. data/spec/units/plugins/gcovr_reportinator_spec.rb +19 -47
  248. data/spec/units/plugins/gcovr_thresholds_spec.rb +95 -0
  249. data/spec/units/plugins/module_generator_spec.rb +5 -5
  250. data/spec/units/plugins/report_build_warnings_log_spec.rb +3 -3
  251. data/spec/units/plugins/report_log_writer_plugin_spec.rb +10 -1
  252. data/spec/units/plugins/report_tests_raw_output_log_spec.rb +13 -2
  253. data/spec/units/plugins/report_tests_teamcity_stdout_spec.rb +77 -3
  254. data/spec/units/plugins/reportgenerator_reportinator_spec.rb +1 -1
  255. data/spec/units/plugins/sanitize_records_spec.rb +3 -1
  256. data/spec/units/plugins/sanitize_spec.rb +1 -1
  257. data/spec/units/plugins/valgrind_spec.rb +23 -8
  258. data/spec/units/preprocess/preprocessinator_comment_stripper_spec.rb +1 -1
  259. data/spec/units/rake_app/rakefile_component_resolver_spec.rb +21 -0
  260. data/spec/units/release_build_executor_spec.rb +53 -14
  261. data/spec/units/release_build_planner_spec.rb +15 -3
  262. data/spec/units/reportinator_spec.rb +5 -5
  263. data/spec/units/standin_headerinator_spec.rb +31 -1
  264. data/spec/units/test_build_executor_spec.rb +65 -3
  265. data/spec/units/test_build_planner_spec.rb +104 -2
  266. data/spec/units/test_build_setup_spec.rb +96 -12
  267. data/spec/units/test_context_extractor_spec.rb +25 -0
  268. data/spec/units/test_file_preprocessinator_spec.rb +17 -1
  269. data/spec/units/test_includes_extractinator_spec.rb +5 -1
  270. data/spec/units/test_invoker/objects_wiring_spec.rb +6 -3
  271. data/spec/units/test_invoker_spec.rb +14 -1
  272. data/spec/units/test_source_file_directive_resolver_spec.rb +38 -7
  273. data/spec/units/tool_executor_spec.rb +26 -0
  274. data/spec/units/yaml_wrapper_spec.rb +11 -0
  275. metadata +109 -25
  276. data/lib/ceedling/file_path_collection_utils.rb +0 -164
@@ -29,7 +29,9 @@ class TestBuildExecutor
29
29
  :dependinator,
30
30
  :gcc_dependency_parser,
31
31
  :quote_include_isolator,
32
- :generator_helper
32
+ :generator_helper,
33
+ :library_resolver,
34
+ :mock_locator
33
35
  )
34
36
 
35
37
  # Stage 9: Preprocess header files to be mocked.
@@ -148,9 +150,10 @@ class TestBuildExecutor
148
150
  details = mock.details
149
151
  testable = mock.testable
150
152
 
151
- output_path = @file_path_utils.form_mock_output_path( testable.paths[:mocks], details.path )
152
- folder, output_path = mock_folder_and_path( testable.paths[:mocks], output_path, details.include_path )
153
- @file_wrapper.mkdir( output_path )
153
+ placement = @mock_locator.placement( mocks_root: testable.paths[:mocks], subdir: details.path, include_path: details.include_path )
154
+ output_path = placement.directory
155
+ # The compiler reaches a climbing folder's mock only through CMock's root
156
+ @mock_locator.search_directories( placement ).each { |dir| @file_wrapper.mkdir( dir ) }
154
157
 
155
158
  # `details.input` -- not the stage 9 preprocessed target -- is the
156
159
  # correct antecedent here: it's exactly what CMock reads, whether or not
@@ -191,7 +194,8 @@ class TestBuildExecutor
191
194
  test: testable.name,
192
195
  input_filepath: details.input,
193
196
  output_path: output_path,
194
- folder: folder,
197
+ mock_root: placement.root,
198
+ folder: placement.folder,
195
199
  overrides: overrides
196
200
  }
197
201
 
@@ -278,7 +282,8 @@ class TestBuildExecutor
278
282
  # Stage 16: Link test executables.
279
283
  def stage_build_executables(state)
280
284
  lib_args = convert_libraries_to_arguments()
281
- lib_paths = get_library_paths_to_arguments()
285
+ lib_paths = @library_resolver.search_path_arguments()
286
+ libraries = @library_resolver.link_files( test_library_entries() )
282
287
  skipped = 0
283
288
 
284
289
  @batchinator.exec(workload: :compile, things: state.testables) do |_, testable|
@@ -287,10 +292,14 @@ class TestBuildExecutor
287
292
  link_flags = testable.link_flags
288
293
  tool, link_flags = resolve_link_tool( context: state.context, tool: @configurator.tools_test_linker, flags: link_flags, executable: testable.executable )
289
294
 
295
+ # Staleness checks only the files registered here, so an object or library dropped from
296
+ # the link (a source deleted, excluded, or moved out of the configured paths) changes
297
+ # nothing they see. The object and library lists as meta do change.
298
+ objects = testable.objects.to_a
290
299
  @dependinator.register(
291
300
  testable.executable,
292
- files: testable.objects,
293
- meta: { flags: link_flags, lib_args: lib_args, lib_paths: lib_paths, tools: [tool] }
301
+ files: objects + libraries,
302
+ meta: { flags: link_flags, lib_args: lib_args, lib_paths: lib_paths, tools: [tool], objects: objects, libraries: libraries }
294
303
  )
295
304
  stale = @dependinator.stale?( testable.executable )
296
305
 
@@ -380,11 +389,9 @@ class TestBuildExecutor
380
389
 
381
390
  @batchinator.exec(workload: :test, things: state.testables) do |_, testable|
382
391
  begin
383
- # `paths[:results]` is only per-test-unique for a test mirrored into its own
384
- # subdirectory -- a test with no mirrored subdir shares that directory with
385
- # every other such test, so the marker's own filename (not just its directory)
386
- # must be test-specific too, matching clean_test_results' own `test + '.*'`
387
- # naming below.
392
+ # `paths[:results]` is the directory of the test's name, which every test beside
393
+ # it shares, so the marker's own filename must be test-specific too, matching
394
+ # clean_test_results' own `test + '.*'` naming below.
388
395
  fixture_target = File.join( testable.paths[:results], "#{File.basename( testable.name )}.fixture_run" )
389
396
 
390
397
  fixture_tool = resolve_fixture_tool( context: state.context, tool: @configurator.tools_test_fixture, test_name: testable.name, target: fixture_target )
@@ -546,41 +553,18 @@ class TestBuildExecutor
546
553
  end
547
554
 
548
555
  def convert_libraries_to_arguments()
549
- args = ((@configurator.project_config_hash[:libraries_test] || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten
556
+ args = test_library_entries()
550
557
  if (defined? LIBRARIES_FLAG)
551
558
  args.map! { |v| LIBRARIES_FLAG.gsub( /\$\{1\}/, v ) }
552
559
  end
553
560
  return args
554
561
  end
555
562
 
556
- def get_library_paths_to_arguments()
557
- paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : []
558
- if (defined? LIBRARIES_PATH_FLAG)
559
- paths.map! { |v| LIBRARIES_PATH_FLAG.gsub( /\$\{1\}/, v ) }
560
- end
561
- return paths
562
- end
563
-
564
563
  private
565
564
 
566
- # Finds the folder a mock's #include names and the directory the mock is written to.
567
- #
568
- # CMock names a mock's guard and lifecycle functions by that folder, and the runner names
569
- # its calls by the same #include. Two same-named mocks stay distinct only if the folder
570
- # reaches CMock. CMock writes below its own root at that folder, so the folder must end the
571
- # mock's directory. A folder trailing the mirrored location keeps that location. An #include
572
- # spelling more path than the mirror holds moves its mock below the per-test root at the
573
- # written path, which the root search path still reaches. A bare #include has no folder.
574
- # Without :mock_name_include_folder no folder is passed, and CMock names by filename alone.
575
- def mock_folder_and_path(mocks_root, output_path, include_path)
576
- return [nil, output_path] unless @configurator.cmock_mock_name_include_folder
577
-
578
- folder = File.dirname( include_path.to_s ).sub( %r{\A(?:\./)+}, '' )
579
-
580
- return [nil, output_path] if folder.empty? || folder == '.'
581
- return [folder, output_path] if output_path.end_with?( File.join( '', folder ) )
582
-
583
- return [folder, File.join( mocks_root, folder )]
565
+ # The :libraries entries a test links, whatever form each takes
566
+ def test_library_entries()
567
+ return ((@configurator.project_config_hash[:libraries_test] || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten
584
568
  end
585
569
 
586
570
  # Compile a single C or assembly source file into an object file. Returns
@@ -6,6 +6,7 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'ceedling/constants'
9
+ require 'ceedling/filesystem/project_paths'
9
10
  require 'ceedling/test_invoker/test_invoker_types'
10
11
  require 'ceedling/test_invoker/test_pipeline_helpers'
11
12
  require 'ceedling/test_invoker/test_build_validations'
@@ -48,6 +49,10 @@ class TestBuildPlanner
48
49
  mocks = {}
49
50
  _mocks = @context_extractor.lookup_mock_header_includes_list( filepath )
50
51
 
52
+ # Built at the first real mock and shared by the rest, since nothing here changes
53
+ # this test's search paths
54
+ collection = nil
55
+
51
56
  _mocks.each do |include|
52
57
  name = File.basename( include.filename ).ext()
53
58
  source = nil
@@ -60,7 +65,8 @@ class TestBuildPlanner
60
65
  input = source
61
66
  subdir = partial_mock_subdir( include )
62
67
  else
63
- source, subdir = @mock_locator.locate( include, collection: ordered_mock_header_collection( testable ) )
68
+ collection ||= ordered_mock_header_collection( testable )
69
+ source, subdir = @mock_locator.locate( include, collection: collection )
64
70
  preprocessed_input = @file_path_utils.form_preprocessed_file_filepath( source, test )
65
71
  input = (@configurator.project_use_test_preprocessor_mocks ? preprocessed_input : source)
66
72
  end
@@ -72,11 +78,11 @@ class TestBuildPlanner
72
78
  # the mock stays findable by the compiler regardless
73
79
  # of how much path the #include itself happened to spell out.
74
80
  #
75
- # Keyed by that directory alongside the name. Two modules sharing a basename are
76
- # two modules, each needing its own mock, and a key of the name alone lets the
77
- # second displace the first. `name` stays bare: it is the filename the mock is
78
- # written under, joined with `path` at generation.
79
- mocks[mock_key( name, subdir )] = MockDetails.new(
81
+ # Keyed by the directory the mock is written to alongside the name. Two modules
82
+ # sharing a basename are two modules, each needing its own mock, and a key of the
83
+ # name alone lets the second displace the first. `name` stays bare: it is the
84
+ # filename the mock is written under, at generation.
85
+ mocks[mock_key( name, partial ? subdir : placed_subdir( testable, subdir, include ) )] = MockDetails.new(
80
86
  name: name,
81
87
  filepath: source,
82
88
  path: subdir,
@@ -185,7 +191,7 @@ class TestBuildPlanner
185
191
  test_no_link_objects =
186
192
  @file_path_utils.form_test_build_objects_filelist(
187
193
  testable.paths[:build],
188
- fetch_shallow_source_includes( filepath ),
194
+ fetch_shallow_source_includes( filepath, state.context, testable.name ),
189
195
  extra_roots: generated_roots
190
196
  )
191
197
 
@@ -237,10 +243,11 @@ class TestBuildPlanner
237
243
  sources << File.join( PROJECT_BUILD_VENDOR_CEXCEPTION_PATH, CEXCEPTION_C_FILE ) if @configurator.project_use_exceptions
238
244
 
239
245
  if @configurator.project_use_mocks
246
+ # :unity_helper_path names a helper's header, or its path without an extension. The
247
+ # source beside it is what compiles.
240
248
  @configurator.cmock_unity_helper_path.each do |helper|
241
- if @file_wrapper.exist?( helper.ext( EXTENSION_SOURCE.primary ) )
242
- sources << helper
243
- end
249
+ source = helper.ext( EXTENSION_SOURCE.primary )
250
+ sources << source if @file_wrapper.exist?( source )
244
251
  end
245
252
  end
246
253
 
@@ -313,8 +320,12 @@ class TestBuildPlanner
313
320
  )
314
321
  end
315
322
 
316
- def fetch_shallow_source_includes(test_filepath)
317
- return @test_context_extractor.lookup_source_includes_list( test_filepath )
323
+ # The sources a test #includes, which it must not link a second time. Each is the file its
324
+ # #include names, since that file's object sits at its own path, not the #include's.
325
+ def fetch_shallow_source_includes(test_filepath, context, test_name)
326
+ return @test_context_extractor.lookup_source_includes_list( test_filepath ).map do |include|
327
+ @file_finder.find_build_input_file( filepath: include.filepath, complain: :ignore, context: context, test: test_name ) || include.filepath
328
+ end
318
329
  end
319
330
 
320
331
  # Every stage resolving a mock's real header must agree on the same winner, or a
@@ -323,6 +334,16 @@ class TestBuildPlanner
323
334
  @mock_locator.header_collection( testable.search_paths, testable.mock_search_paths )
324
335
  end
325
336
 
337
+ # The mock's directory below its test's mock root, where generation writes it. Two
338
+ # same-named headers may mirror alike and differ only by the folders their #includes name.
339
+ def placed_subdir(testable, subdir, include)
340
+ root = testable.paths[:mocks]
341
+ return subdir if root.nil?
342
+
343
+ placement = @mock_locator.placement( mocks_root: root, subdir: subdir, include_path: include.filepath )
344
+ return ProjectPaths.subdir_below( root, placement.directory ) || subdir
345
+ end
346
+
326
347
  # One mock's identity within its test. A mock directly in the mock root keeps the bare
327
348
  # name it has always had, so nothing changes for a project without same-named mocks.
328
349
  def mock_key(name, subdir)
@@ -331,8 +352,8 @@ class TestBuildPlanner
331
352
  return File.join( subdir, name ).to_sym
332
353
  end
333
354
 
334
- # Each mock's own generated source, below this test's mock root in the subdirectory
335
- # mirroring whatever it mocks -- the same place mock generation writes it.
355
+ # Each mock's own generated source, below this test's mock root where mock generation
356
+ # writes it (MockLocator#placement)
336
357
  #
337
358
  # Named by its own path rather than its basename so two same-named mocks in one test
338
359
  # stay distinct, and so each one's object mirrors that subdirectory too.
@@ -342,10 +363,8 @@ class TestBuildPlanner
342
363
  return [] if root.nil?
343
364
 
344
365
  testable.mocks.each_value.map do |details|
345
- File.join(
346
- @file_path_utils.form_mock_output_path( root, details.path ),
347
- details.name + EXTENSION_CORE_SOURCE
348
- )
366
+ placement = @mock_locator.placement( mocks_root: root, subdir: details.path, include_path: details.include_path )
367
+ File.join( placement.directory, details.name + EXTENSION_CORE_SOURCE )
349
368
  end
350
369
  end
351
370
 
@@ -13,7 +13,6 @@ require 'ceedling/partials/partials'
13
13
  require 'ceedling/test_invoker/test_invoker_types'
14
14
  require 'ceedling/test_invoker/test_pipeline_helpers'
15
15
  require 'ceedling/test_invoker/test_build_validations'
16
- require 'ceedling/path_mirror'
17
16
 
18
17
  class TestBuildSetup
19
18
 
@@ -36,7 +35,8 @@ class TestBuildSetup
36
35
  :test_runner_manager,
37
36
  :dependinator,
38
37
  :test_search_paths,
39
- :mock_locator
38
+ :mock_locator,
39
+ :test_source_file_directive_resolver
40
40
  )
41
41
 
42
42
  def setup()
@@ -44,14 +44,15 @@ class TestBuildSetup
44
44
  end
45
45
 
46
46
  # Stage 1: Create per-test build/results/mock/partial directory structure
47
- # and populate the testables hash with initial entries.
47
+ # and populate the testables hash with initial entries. Stops first if two
48
+ # tests in the build share a name.
48
49
  def stage_prepare_build_paths(state)
49
- clean_test_roots = PathMirror.clean_roots( @configurator.paths_test )
50
+ validate_unique_test_names!( tests: state.tests )
50
51
 
51
52
  @batchinator.exec(workload: :compile, things: state.tests) do |filepath|
52
53
  filepath = filepath.to_s
53
- key = testable_symbolize( filepath, clean_test_roots )
54
- name = key.to_s
54
+ name = @file_path_utils.form_test_name( filepath )
55
+ key = name.to_sym
55
56
 
56
57
  state.lock.synchronize do
57
58
  state.testables[key] = Testable.new(
@@ -114,8 +115,10 @@ class TestBuildSetup
114
115
  filepath = testable.filepath
115
116
  filename = File.basename( filepath )
116
117
 
118
+ # Only a scan without test preprocessing finds TEST_SOURCE_FILE() entries, so a cache
119
+ # from the other mode is stale
117
120
  cache_target = @file_path_utils.form_test_build_directives_cache_filepath( filepath, testable.name )
118
- @dependinator.register( cache_target, files: [filepath] )
121
+ @dependinator.register( cache_target, files: [filepath], meta: { source_files_scanned: !@configurator.project_use_test_preprocessor_tests } )
119
122
  directives_stale = @dependinator.stale?( cache_target )
120
123
 
121
124
  contexts = [TestContextExtractor::Context::INCLUDES]
@@ -167,6 +170,8 @@ class TestBuildSetup
167
170
  state.lock.synchronize { skipped += 1 }
168
171
  end
169
172
 
173
+ validate_source_file_directives( testable, state.context )
174
+
170
175
  validate_mocks_in_use(
171
176
  filename: filename,
172
177
  mocks: @context_extractor.lookup_mock_header_includes_list( filepath )
@@ -321,12 +326,12 @@ class TestBuildSetup
321
326
 
322
327
  private
323
328
 
324
- def testable_symbolize(filepath, clean_roots)
325
- basename = File.basename( filepath ).ext( '' )
326
- subdir = PathMirror.relative_subdir_from_clean_roots( filepath, clean_roots )
327
- name = subdir.empty? ? basename : File.join( subdir, basename )
329
+ # Without test preprocessing, stage 11 never runs, and only stage 2's scan finds a test's
330
+ # TEST_SOURCE_FILE() entries
331
+ def validate_source_file_directives(testable, context)
332
+ return if @configurator.project_use_test_preprocessor_tests
328
333
 
329
- return name.to_sym
334
+ @test_source_file_directive_resolver.validate!( test: testable.name, test_filepath: testable.filepath, context: context )
330
335
  end
331
336
 
332
337
  end
@@ -5,15 +5,29 @@
5
5
  # SPDX-License-Identifier: MIT
6
6
  # =========================================================================
7
7
 
8
+ require 'ceedling/filesystem/destination_collision'
9
+
8
10
  # Test-build configuration validators shared by more than one test pipeline stage
9
11
  # class -- each raises CeedlingException on a real, user-facing mistake it's
10
- # positioned to catch (a project using mocking, Partials, or a build-directive
11
- # source without configuring for it, or a header that doesn't actually resolve).
12
+ # positioned to catch (a project using mocking or Partials without configuring for
13
+ # it, a header that doesn't actually resolve, or two tests sharing one name).
12
14
  # Relies on whichever including class's own constructor DI already provides the
13
15
  # collaborators a given validator needs, the same way TestPipelineHelpers is
14
16
  # mixed in without any DI wiring of its own.
15
17
  module TestBuildValidations
16
18
 
19
+ # A name is its test's path without its extension, so two tests share one only when they
20
+ # differ in extension alone (`test_a.c` and `test_a.cpp`). Sharing would silently drop one
21
+ # test, so a build with them in it stops. A build without them is unaffected.
22
+ def validate_unique_test_names!(tests:)
23
+ shared = DestinationCollision.find( @configurator.collection_all_tests.map( &:to_s ) ) { |test| @file_path_utils.form_test_name( test ) }
24
+
25
+ tests.each do |test|
26
+ name = @file_path_utils.form_test_name( test )
27
+ DestinationCollision.raise_for( name, shared[name], 'share the build name' ) if shared.key?( name )
28
+ end
29
+ end
30
+
17
31
  def validate_mocks_in_use(filename:, mocks:)
18
32
  if !@configurator.project_use_mocks and !mocks.empty?
19
33
  _mocks = mocks.map { |include| include.filename }
@@ -70,33 +84,4 @@ module TestBuildValidations
70
84
  end
71
85
  end
72
86
 
73
- # A TEST_SOURCE_FILE() entry must name a real, recognized file whether it
74
- # adds or removes -- a typo or a nonexistent path is worth failing loudly
75
- # on either side of the +:/-: convention, the same way a missing file has
76
- # always been treated for a plain, additive entry.
77
- def validate!(test:, filepath:)
78
- sources = @test_context_extractor.lookup_build_directive_sources_list( filepath )
79
-
80
- ext_message = @configurator.extension_source.to_s
81
- ext_message += " or #{@configurator.extension_assembly}" if @configurator.test_build_use_assembly
82
-
83
- sources.each do |raw_source|
84
- source = FilePathUtils.no_aggregation_decorators( raw_source )
85
- valid_extension =
86
- if @configurator.test_build_use_assembly
87
- @configurator.extension_assembly.match?( source ) || @configurator.extension_source.match?( source )
88
- else
89
- @configurator.extension_source.match?( source )
90
- end
91
-
92
- unless valid_extension
93
- raise CeedlingException.new( "File '#{source}' specified with TEST_SOURCE_FILE() in #{test} is not a #{ext_message} source file" )
94
- end
95
-
96
- if @file_finder.find_build_input_file( filepath: source, complain: :ignore, context: TEST_SYM ).nil?
97
- raise CeedlingException.new( "File '#{source}' specified with TEST_SOURCE_FILE() in #{test} cannot be found in the source file collection" )
98
- end
99
- end
100
- end
101
-
102
87
  end
@@ -50,7 +50,7 @@ class TestFilePreprocessinator
50
50
  state.lock.synchronize { skipped += 1 } unless stale
51
51
 
52
52
  stale ? scan_source_directives( testable ) : recall_source_directives( testable )
53
- state.testables.each_value { |each| @test_source_file_directive_resolver.validate!( test: testable.name, filepath: each.filepath ) }
53
+ @test_source_file_directive_resolver.validate!( test: testable.name, test_filepath: testable.filepath, context: state.context )
54
54
  end
55
55
 
56
56
  log_skip_summary( task: "test file preprocessing", count: skipped, noun: "test files" )
@@ -22,7 +22,8 @@ class TestInvoker
22
22
  :dependinator,
23
23
  :loginator,
24
24
  :verbosinator,
25
- :test_pipeline_manager
25
+ :test_pipeline_manager,
26
+ :include_pathinator
26
27
  )
27
28
 
28
29
  def setup
@@ -40,6 +41,10 @@ class TestInvoker
40
41
  timestamp_s = SystemWrapper.time_stopwatch_s()
41
42
  @plugin_manager.pre_test_build( context, timestamp_s )
42
43
 
44
+ # After the hook, so a header it writes is listed, and once per run, so a later run in
45
+ # the same process lists every search path afresh
46
+ @include_pathinator.forget_header_listings
47
+
43
48
  # `identifier: context` isolates this run's own cache file (see Dependinator#open) --
44
49
  # a plugin building its own variant of the test pipeline under a distinct context
45
50
  # (:gcov, :valgrind, ...) gets its own cache automatically, never sharing one with
@@ -5,7 +5,7 @@
5
5
  # SPDX-License-Identifier: MIT
6
6
  # =========================================================================
7
7
 
8
- require 'ceedling/path_mirror'
8
+ require 'ceedling/filesystem/path_mirror'
9
9
 
10
10
  # Small helpers shared by more than one test pipeline stage class. Relies on
11
11
  # `@reportinator`/`@loginator` already being present via whichever including
@@ -7,9 +7,8 @@
7
7
 
8
8
  require 'ceedling/constants'
9
9
  require 'ceedling/exceptions'
10
- require 'ceedling/file_path_utils'
11
- require 'ceedling/path_matcher'
12
- require 'ceedling/test_invoker/test_build_validations'
10
+ require 'ceedling/filesystem/file_path_utils'
11
+ require 'ceedling/filesystem/path_matcher'
13
12
 
14
13
  # Owns everything about the TEST_SOURCE_FILE() build directive's own path
15
14
  # content: collecting a test's raw directive strings, telling additive
@@ -20,8 +19,6 @@ require 'ceedling/test_invoker/test_build_validations'
20
19
  # becomes a real filepath.
21
20
  class TestSourceFileDirectiveResolver
22
21
 
23
- include TestBuildValidations
24
-
25
22
  constructor :test_context_extractor, :file_finder, :configurator, :loginator
26
23
 
27
24
  # Splits a test's TEST_SOURCE_FILE() entries into files to add and files to
@@ -33,31 +30,33 @@ class TestSourceFileDirectiveResolver
33
30
  def resolve(test_filepath, context)
34
31
  raw = @test_context_extractor.lookup_build_directive_sources_list( test_filepath )
35
32
  additive, subtractive = raw.partition { |source| FilePathUtils.add_path?( source ) }
36
-
37
- # A directive's own text is written directly in the test file, so its `..`, if
38
- # any, is anchored to that same test file's own directory -- exactly as a
39
- # directory-relative #include would be.
40
33
  anchor = File.dirname( test_filepath )
41
34
 
42
- find = -> (source) {
43
- stripped = FilePathUtils.no_aggregation_decorators( source )
44
- @file_finder.find_build_input_file(
45
- filepath: PathMatcher.resolve_relative( stripped, anchor: anchor ),
46
- complain: :ignore,
47
- context: context
48
- )
49
- }
50
-
51
- additive_sources = additive.map(&find).compact
35
+ additive_sources = additive.filter_map { |source| locate( source, anchor: anchor, context: context ) }
52
36
 
53
37
  subtractive_sources = subtractive.each_with_object({}) do |source, hash|
54
- resolved = find.call( source )
38
+ resolved = locate( source, anchor: anchor, context: context )
55
39
  hash[resolved] = source unless resolved.nil?
56
40
  end
57
41
 
58
42
  return [additive_sources, subtractive_sources]
59
43
  end
60
44
 
45
+ # A TEST_SOURCE_FILE() entry must name a real, recognized file whether it adds or removes.
46
+ # A typo fails loudly on either side of the +:/-: convention, naming the test that holds
47
+ # it. Entries are found exactly as `resolve` finds them, so any entry a build uses passes.
48
+ def validate!(test:, test_filepath:, context:)
49
+ anchor = File.dirname( test_filepath )
50
+
51
+ @test_context_extractor.lookup_build_directive_sources_list( test_filepath ).each do |entry|
52
+ source = FilePathUtils.no_aggregation_decorators( entry )
53
+ validate_extension!( test, source )
54
+ next unless locate( entry, anchor: anchor, context: context ).nil?
55
+
56
+ raise CeedlingException.new( "File '#{source}' specified with TEST_SOURCE_FILE() in #{test} cannot be found in the source file collection" )
57
+ end
58
+ end
59
+
61
60
  # Applies this test's TEST_SOURCE_FILE("-:...") entries against the fully
62
61
  # assembled source list, regardless of how each removed file originally got
63
62
  # there -- the implicit header/source convention, a positive directive, or
@@ -75,4 +74,25 @@ class TestSourceFileDirectiveResolver
75
74
  return sources - subtractive.keys
76
75
  end
77
76
 
77
+ private
78
+
79
+ # An entry's text is written in its test file, so its `..`, if any, is anchored to that
80
+ # test file's directory, as a directory-relative #include is
81
+ def locate(entry, anchor:, context:)
82
+ stripped = FilePathUtils.no_aggregation_decorators( entry )
83
+ return @file_finder.find_build_input_file(
84
+ filepath: PathMatcher.resolve_relative( stripped, anchor: anchor ), complain: :ignore, context: context
85
+ )
86
+ end
87
+
88
+ def validate_extension!(test, source)
89
+ assembly = @configurator.test_build_use_assembly
90
+ return if @configurator.extension_source.match?( source )
91
+ return if assembly && @configurator.extension_assembly.match?( source )
92
+
93
+ extensions = @configurator.extension_source.to_s
94
+ extensions += " or #{@configurator.extension_assembly}" if assembly
95
+ raise CeedlingException.new( "File '#{source}' specified with TEST_SOURCE_FILE() in #{test} is not a #{extensions} source file" )
96
+ end
97
+
78
98
  end
@@ -189,8 +189,8 @@ class ToolExecutor
189
189
 
190
190
  # Handle array or anything else passed into method to be expanded in place of replacement operators
191
191
  case (to_process)
192
- when Array then to_process.each {|value| build_string.concat( "#{element.sub(match, value.to_s)} " ) } if (to_process.size > 0)
193
- else build_string.concat( element.sub(match, to_process.to_s) )
192
+ when Array then to_process.each {|value| build_string.concat( "#{substitute( element, match, value )} " ) } if (to_process.size > 0)
193
+ else build_string.concat( substitute( element, match, to_process ) )
194
194
  end
195
195
 
196
196
  # Handle inline ruby string substitution
@@ -256,7 +256,7 @@ class ToolExecutor
256
256
  # expand elements (whether string or array) into substitution string & replace escaped '\$'
257
257
  elements.flatten!
258
258
  elements.each do |element|
259
- build_string.concat( substitution.sub(/([^\\]*)\$/, "\\1#{element}") ) # don't replace escaped '\$' but allow us to replace just a lonesome '$'
259
+ build_string.concat( substitute( substitution, /(?<!\\)\$/, element ) ) # don't replace escaped '\$' but allow us to replace just a lonesome '$'
260
260
  build_string.gsub!(/\\\$/, '$')
261
261
  build_string.concat(' ')
262
262
  end
@@ -264,6 +264,12 @@ class ToolExecutor
264
264
  return build_string.strip
265
265
  end
266
266
 
267
+ # Replaces the first match of pattern in template with value, taken literally. A
268
+ # replacement string would read a path's `\0`, `\1` or `\\` as a back-reference.
269
+ def substitute(template, pattern, value)
270
+ return template.sub( pattern ) { value.to_s }
271
+ end
272
+
267
273
  def pretty_tool_name(command)
268
274
  # Titleize command's name -- each word capitalized plus underscores replaced with spaces
269
275
  name = "#{command[:name].split(/ |\_/).map(&:capitalize).join(" ")}"
@@ -82,8 +82,9 @@ class YamlWrapper
82
82
  # already picks the right calling convention for the installed Psych, so this should be
83
83
  # unreachable in practice; it exists as a last-resort safety net for an unanticipated
84
84
  # Psych version/interface mismatch, reported distinctly so it isn't mistaken for a user
85
- # YAML-authoring error.
86
- rescue ArgumentError => e
85
+ # YAML-authoring error. `::ArgumentError` names Ruby's own class, which the constructor
86
+ # gem's same-named class would otherwise shadow here.
87
+ rescue ::ArgumentError => e
87
88
  raise YamlLoadException.new(
88
89
  reason: :incompatible, source: source_label, original_error: e,
89
90
  message: "Installed Psych YAML library (#{Psych::VERSION}) does not support a safe-loading feature Ceedling requires ⏩️ #{e.message}"
data/lib/version.rb CHANGED
@@ -21,7 +21,7 @@ module Ceedling
21
21
  # Target version for the current release cycle. Maintained by hand, one edit
22
22
  # per minor or major cycle. Never edited to match a release tag. The release
23
23
  # pipeline rewrites this line from the tag that triggered it.
24
- BASE = '1.2.1'
24
+ BASE = '1.2.2'
25
25
 
26
26
  # Marker for a build the release pipeline did not produce. That pipeline
27
27
  # empties this line, so a published gem reports a bare version while a local
@@ -51,7 +51,7 @@ DEFAULT_BULLSEYE_LINKER_TOOL = {
51
51
  }
52
52
 
53
53
  DEFAULT_BULLSEYE_FIXTURE_TOOL = {
54
- :executable => '${1}'.freeze,
54
+ :executable => '"${1}"'.freeze, # Test executable, quoted as a path
55
55
  :name => 'default_bullseye_fixture'.freeze,
56
56
  :optional => false.freeze,
57
57
  :arguments => [].freeze
@@ -220,7 +220,7 @@ class Bullseye < Plugin
220
220
  end
221
221
 
222
222
  header = "Untested source files not in the coverage report (:untested_sources is :list):"
223
- @loginator.log_list( untested_sources.sort, header, Verbosity::COMPLAIN, LogLabels::WARNING )
223
+ @loginator.log_list( untested_sources.sort, header, Verbosity::COMPLAIN )
224
224
 
225
225
  when BULLSEYE_UNTESTED_SOURCES_COMPILE
226
226
  untested_sources = collect_untested_sources( sources )
@@ -236,7 +236,7 @@ class Bullseye < Plugin
236
236
  untested_sources.each do |filepath|
237
237
  filename = File.basename(filepath)
238
238
  object = @ceedling[:file_path_utils].form_test_object_filepath( filepath, context: BULLSEYE_SYM )
239
- dependencies = @ceedling[:file_path_utils].form_test_dependencies_filepath( filepath, context: BULLSEYE_SYM )
239
+ dependencies = @ceedling[:file_path_utils].form_test_dependencies_filepath( object, context: BULLSEYE_SYM )
240
240
  search_paths = @configurator.collection_paths_include
241
241
  # Defines and flags resolve as a tested source's do, against this source's filepath
242
242
  flags = @ceedling[:test_build_setup].flags( context: BULLSEYE_SYM, operation: OPERATION_COMPILE_SYM, filepath: filepath )
@@ -263,6 +263,9 @@ class Bullseye < Plugin
263
263
  next
264
264
  end
265
265
 
266
+ @file_wrapper.mkdir( File.dirname( object ) )
267
+ @file_wrapper.mkdir( File.dirname( dependencies ) )
268
+
266
269
  begin
267
270
  @ceedling[:generator].generate_object_file_c(
268
271
  tool: TOOLS_BULLSEYE_COMPILER,
@@ -559,11 +562,10 @@ class Bullseye < Plugin
559
562
  coverage_sources = []
560
563
  @test_invoker.each_test_with_sources { |_, srcs| coverage_sources.concat( srcs ) }
561
564
  coverage_sources.uniq!
562
- # Every configured source extension is a valid ending for a mock/ignored-source name,
563
- # so the two are joined into one regex alternation rather than matching just one.
564
- source_extensions = EXTENSION_SOURCE.to_a.map { |ext| Regexp.escape(ext) }.join('|')
565
- coverage_sources.delete_if {|item| item =~ /#{@configurator.cmock_mock_prefix}.+(?:#{source_extensions})$/}
566
- coverage_sources.delete_if {|item| item =~ /(?:#{BULLSEYE_IGNORE_SOURCES.join('|')})(?:#{source_extensions})$/}
565
+ # Every configured source extension is a valid ending for a mock/ignored-source name
566
+ source_extensions = EXTENSION_SOURCE.pattern
567
+ coverage_sources.delete_if {|item| item =~ /#{@configurator.cmock_mock_prefix}.+#{source_extensions}$/}
568
+ coverage_sources.delete_if {|item| item =~ /(?:#{BULLSEYE_IGNORE_SOURCES.join('|')})#{source_extensions}$/}
567
569
 
568
570
  coverage_sources.each do |source|
569
571
  command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVFN, [], source)
@@ -16,7 +16,7 @@ DEFAULT_CPPCHECK_TOOL = {
16
16
  :optional => true.freeze,
17
17
  :arguments => [
18
18
  '-I"${1}"'.freeze,
19
- '${2}'.freeze
19
+ '"${2}"'.freeze
20
20
  ].freeze
21
21
  }
22
22