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
@@ -24,11 +24,11 @@ require 'ceedling/constants'
24
24
  require 'ceedling/defaults'
25
25
  require 'ceedling/system_utils'
26
26
  require 'ceedling/system_wrapper'
27
- require 'ceedling/file_wrapper'
27
+ require 'ceedling/filesystem/file_wrapper'
28
28
  require 'ceedling/yaml_wrapper'
29
29
  require 'ceedling/reportinator'
30
30
  require 'ceedling/ruby_expandinator'
31
- require 'ceedling/file_path_collection_utils'
31
+ require 'ceedling/filesystem/file_path_collection_utils'
32
32
  require 'ceedling/tool_validator'
33
33
  require 'ceedling/tool_executor'
34
34
  require 'ceedling/tool_executor_helper'
@@ -39,6 +39,7 @@ require 'ceedling/config/configurator_setup'
39
39
  require 'ceedling/config/configurator_builder'
40
40
  require 'ceedling/config/configurator_plugins'
41
41
  require 'ceedling/config/configurator_validator'
42
+ require 'ceedling/config/configurator_paths_validator'
42
43
 
43
44
  module ConfiguratorIntegrationHelpers
44
45
 
@@ -58,11 +59,10 @@ module ConfiguratorIntegrationHelpers
58
59
 
59
60
  o[:configurator_plugins] = ConfiguratorPlugins.new( o.slice( :file_wrapper, :system_wrapper ) )
60
61
  o[:configurator_builder] = ConfiguratorBuilder.new( o.slice( :file_path_collection_utils, :loginator, :file_wrapper, :system_wrapper ) )
61
- o[:configurator_validator] = ConfiguratorValidator.new(
62
- o.slice( :config_walkinator, :file_wrapper, :loginator, :reportinator, :tool_validator )
63
- )
62
+ o[:configurator_validator] = ConfiguratorValidator.new( o.slice( :config_walkinator, :loginator, :reportinator, :tool_validator ) )
63
+ o[:configurator_paths_validator] = ConfiguratorPathsValidator.new( o.slice( :config_walkinator, :file_wrapper, :loginator, :reportinator ) )
64
64
  o[:configurator_setup] = ConfiguratorSetup.new(
65
- o.slice( :configurator_builder, :configurator_validator, :loginator, :reportinator,
65
+ o.slice( :configurator_builder, :configurator_validator, :configurator_paths_validator, :loginator, :reportinator,
66
66
  :file_wrapper, :system_wrapper, :tool_executor )
67
67
  )
68
68
  o[:configurator] = Configurator.new(
@@ -18,7 +18,7 @@
18
18
 
19
19
  require 'fileutils'
20
20
  require 'tmpdir'
21
- require 'ceedling/file_wrapper'
21
+ require 'ceedling/filesystem/file_wrapper'
22
22
  require 'ceedling/system_wrapper'
23
23
  require 'ceedling/yaml_wrapper'
24
24
  require 'ceedling/dependencies/dependency_hasher'
@@ -56,8 +56,8 @@ require 'ceedling/preprocess/preprocessinator_comment_stripper'
56
56
  require 'ceedling/preprocess/c_comment_scanner'
57
57
  require 'ceedling/preprocess/preprocessinator_file_assembler'
58
58
  require 'ceedling/parsing_parcels'
59
- require 'ceedling/file_path_utils'
60
- require 'ceedling/file_wrapper'
59
+ require 'ceedling/filesystem/file_path_utils'
60
+ require 'ceedling/filesystem/file_wrapper'
61
61
  require 'ceedling/includes/includes'
62
62
 
63
63
 
@@ -0,0 +1,173 @@
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
+ # Runs a project layout through configuration, collection, build-path mapping, and the
9
+ # lookups that invert that mapping, without compiling anything.
10
+ #
11
+ # A scenario is a workspace: the project in `app/`, with siblings beside it (`shared/`,
12
+ # `vendor/`) for paths that reach outside the project, and a separate directory elsewhere
13
+ # for paths far outside it, as a vendor SDK installed at a drive's root is. YAML may name
14
+ # absolute paths with `%{ws}`, `%{app}` and `%{far}`. The workspace is resolved through File.realpath first, so a
15
+ # system temp directory behind a symlink (macOS's /tmp) doesn't add a second spelling.
16
+ #
17
+ # Test preprocessing is off, so no preprocessor is probed, and nothing is built.
18
+
19
+ require 'tmpdir'
20
+ require 'fileutils'
21
+ require 'configurator_integration_helper'
22
+ require 'ceedling/filesystem/file_path_utils'
23
+ require 'ceedling/filesystem/file_finder'
24
+ require 'ceedling/filesystem/file_finder_helper'
25
+ require 'ceedling/test_invoker/test_build_setup'
26
+ require 'ceedling/test_invoker/test_invoker_types'
27
+
28
+ module PathScenarioHarness
29
+ include ConfiguratorIntegrationHelpers
30
+
31
+ # Runs each test of a batch in turn, in place of the thread pool
32
+ class SerialBatchinator
33
+ def exec(things:, **_options)
34
+ things.each { |thing| yield thing }
35
+ end
36
+ end
37
+
38
+ # A root spelled each way a project file might, for one place in the workspace
39
+ ROOT_SPELLINGS = {
40
+ plain: ->(root, **) { root },
41
+ dot_slash: ->(root, **) { "./#{root}" },
42
+ absolute: ->(root, app:, **) { File.join( app, root ) },
43
+ backslash: ->(root, **) { root.tr( '/', '\\' ) },
44
+ symlink: ->(root, ws:, **) { File.join( ws, 'link', root ) }
45
+ }.freeze
46
+
47
+ # Runs the block in a workspace holding `files` (paths relative to the workspace), from
48
+ # `cwd` within it, with `far` files in a directory outside the workspace. A `link`
49
+ # symlink to `app/` is made when `symlink` is set.
50
+ def in_workspace(files, cwd: 'app', symlink: false, far: {})
51
+ Dir.mktmpdir do |dir|
52
+ Dir.mktmpdir do |far_dir|
53
+ ws = File.realpath( dir )
54
+ @far = File.join( File.realpath( far_dir ), 'deep', 'sdk' )
55
+ write_files( ws, files )
56
+ write_files( @far, far )
57
+ FileUtils.mkdir_p( File.join( ws, 'app' ) )
58
+ File.symlink( File.join( ws, 'app' ), File.join( ws, 'link' ) ) if symlink
59
+
60
+ Dir.chdir( File.join( ws, cwd ) ) { yield ws, File.join( ws, 'app' ) }
61
+ end
62
+ end
63
+ end
64
+
65
+ def write_files(root, files)
66
+ files.each do |path, content|
67
+ FileUtils.mkdir_p( File.join( root, File.dirname( path ) ) )
68
+ File.write( File.join( root, path ), content )
69
+ end
70
+ end
71
+
72
+ # A project file for a scenario. `paths` and `files` are the :paths and :files sections.
73
+ def scenario_yaml(ws:, app:, paths:, files: {}, project: {})
74
+ config = {
75
+ project: { build_root: 'build', use_test_preprocessor: :none, use_mocks: true, release_build: true }.merge( project ),
76
+ paths: paths,
77
+ files: files
78
+ }
79
+ # Psych writes Symbol keys and values in the `:key:` form a project file uses
80
+ return YAML.dump( placed( config, ws: ws, app: app ) )
81
+ end
82
+
83
+ # Fills `%{ws}`, `%{app}` and `%{far}` in every string with the workspace's absolute paths
84
+ def placed(value, ws:, app:)
85
+ case value
86
+ when Hash then value.transform_values { |item| placed( item, ws: ws, app: app ) }
87
+ when Array then value.map { |item| placed( item, ws: ws, app: app ) }
88
+ when String then value.gsub( '%{ws}', ws ).gsub( '%{app}', app ).gsub( '%{far}', @far.to_s )
89
+ else value
90
+ end
91
+ end
92
+
93
+ # Configures the project, and prepares every test's build paths, as stage 1 of a build does
94
+ def scenario(yaml)
95
+ configurator = configure( yaml )[:configurator]
96
+
97
+ file_wrapper = FileWrapper.new( loginator: double( 'loginator', log: nil ), verbosinator: double( 'verbosinator', should_output?: false ) )
98
+ file_path_utils = FilePathUtils.new( configurator: configurator, file_wrapper: file_wrapper )
99
+
100
+ collaborators = TestBuildSetup.constructor_keys.to_h { |key| [key, double( key.to_s )] }
101
+ setup = TestBuildSetup.new( collaborators.merge(
102
+ configurator: configurator, file_wrapper: file_wrapper, file_path_utils: file_path_utils, batchinator: SerialBatchinator.new
103
+ ) )
104
+ state = TestInvokerTypes::PipelineState.new( tests: configurator.collection_all_tests, testables: {}, context: :test, options: [], lock: Mutex.new )
105
+ setup.stage_prepare_build_paths( state )
106
+
107
+ finder = FileFinder.new(
108
+ configurator: configurator, file_finder_helper: FileFinderHelper.new( loginator: double( 'loginator', log: nil ) ),
109
+ file_path_utils: file_path_utils, file_wrapper: file_wrapper, yaml_wrapper: nil
110
+ )
111
+
112
+ return { configurator: configurator, state: state, paths: file_path_utils, finder: finder }
113
+ end
114
+
115
+ # Every build file a scenario's sources and headers map to, by kind
116
+ def placements(scene)
117
+ configurator, state, paths = scene.values_at( :configurator, :state, :paths )
118
+ testable = state.testables.values.first
119
+ sources = configurator.collection_all_source
120
+
121
+ return {
122
+ test_objects: paths.form_test_build_objects_filelist( testable.paths[:build], sources ),
123
+ release_objects: paths.form_release_build_objects_filelist( sources ),
124
+ preprocessed: configurator.collection_all_headers.map { |header| paths.form_preprocessed_file_filepath( header, testable.name ) },
125
+ mocks: configurator.collection_all_headers.map { |header| mock_output_path( scene, testable, header ) }
126
+ }
127
+ end
128
+
129
+ # Where a mock of `header` is generated, through the lookup a build's mock stage makes
130
+ def mock_output_path(scene, testable, header)
131
+ mock = "#{scene[:configurator].cmock_mock_prefix}#{File.basename( header )}"
132
+ _source, subdir = scene[:finder].resolve_mock( mock, complain: :ignore )
133
+ return nil if subdir.nil?
134
+
135
+ return scene[:paths].form_mock_output_path( testable.paths[:mocks], subdir )
136
+ end
137
+
138
+ # Every path lies within the build root, by real containment
139
+ def expect_inside_build(paths, build: File.expand_path( 'build' ))
140
+ paths.compact.each do |path|
141
+ expanded = File.expand_path( path )
142
+ expect(expanded).to start_with( build + '/' ), "#{path} lies outside #{build}/"
143
+ expect(path.split( %r{[\\/]} )).to_not include( '..' ), "#{path} holds `..`"
144
+ end
145
+ end
146
+
147
+ # Distinct inputs map to distinct build files
148
+ def expect_distinct(paths, label)
149
+ duplicates = paths.compact.group_by { |path| File.expand_path( path ) }.select { |_, group| group.size > 1 }.keys
150
+ expect(duplicates).to be_empty, "#{label} collide: #{duplicates.join( ', ' )}"
151
+ end
152
+
153
+ # No collection holds a file under the build root
154
+ def expect_collections_outside_build(configurator, build: File.expand_path( 'build' ))
155
+ entries = configurator.collection_all_source + configurator.collection_all_headers + configurator.collection_all_tests
156
+ inside = entries.select { |entry| File.expand_path( entry ).start_with?( build + '/' ) }
157
+ expect(inside).to be_empty, "collected from the build root: #{inside.join( ', ' )}"
158
+ end
159
+
160
+ # No file is collected twice, under two spellings
161
+ def expect_one_spelling_each(configurator)
162
+ entries = configurator.collection_all_source + configurator.collection_all_headers
163
+ twice = entries.group_by { |entry| File.realpath( entry ) rescue File.expand_path( entry ) }.select { |_, group| group.size > 1 }
164
+ expect(twice).to be_empty, "collected twice: #{twice.values.map { |group| group.join( ' and ' ) }.join( '; ' )}"
165
+ end
166
+
167
+ # Build placements relative to the build root, comparable across spellings
168
+ def relative_placements(scene, build: File.expand_path( 'build' ))
169
+ return placements( scene ).transform_values do |paths|
170
+ paths.compact.map { |path| File.expand_path( path ).delete_prefix( build + '/' ) }.sort
171
+ end
172
+ end
173
+ end
@@ -25,7 +25,7 @@ require 'fileutils'
25
25
 
26
26
  require 'ceedling/constants'
27
27
  require 'ceedling/defaults'
28
- require 'ceedling/file_wrapper'
28
+ require 'ceedling/filesystem/file_wrapper'
29
29
  require 'ceedling/yaml_wrapper'
30
30
  require 'ceedling/parsing_parcels'
31
31
  require 'ceedling/includes/includes'
@@ -21,8 +21,8 @@
21
21
 
22
22
  require 'spec_integration_helper'
23
23
  require 'ceedling/filename_extension'
24
- require 'ceedling/file_finder'
25
- require 'ceedling/file_finder_helper'
24
+ require 'ceedling/filesystem/file_finder'
25
+ require 'ceedling/filesystem/file_finder_helper'
26
26
  require 'ceedling/test_context_extractor'
27
27
  require 'ceedling/test_invoker/test_invoker_types'
28
28
  require 'ceedling/test_invoker/test_search_paths'
@@ -52,6 +52,10 @@ module IntegrationSpecHelpers
52
52
  def get_cmock_config
53
53
  {}
54
54
  end
55
+
56
+ def cmock_mock_name_include_folder
57
+ true
58
+ end
55
59
  def project_use_mocks
56
60
  true
57
61
  end
@@ -86,6 +90,13 @@ module IntegrationSpecHelpers
86
90
  def paths_include
87
91
  ['src']
88
92
  end
93
+ # The canonical roots configuration computes from the three above
94
+ def collection_mirror_roots_headers
95
+ ['test', 'src']
96
+ end
97
+ def collection_mirror_roots_include
98
+ ['src']
99
+ end
89
100
  def collection_paths_support
90
101
  []
91
102
  end
@@ -59,3 +59,5 @@ $: << File.join(here, '../../bin')
59
59
  $: << File.join(here, '../../lib')
60
60
  $: << File.join(here, '../../vendor/cmock/lib')
61
61
  $: << File.join(here, '../../vendor/unity/auto')
62
+
63
+ require 'working_dir_tracking'
@@ -5,6 +5,7 @@
5
5
  # SPDX-License-Identifier: MIT
6
6
  # =========================================================================
7
7
 
8
+ require 'digest'
8
9
  require 'fileutils'
9
10
  require 'tmpdir'
10
11
  require 'open3'
@@ -142,6 +143,7 @@ RSpec.configure do |config|
142
143
  $stderr.puts "\n" + ("=" * 72)
143
144
  $stderr.puts "FAILED: #{format_description.call(example)}"
144
145
  $stderr.puts "Temp dir: #{@c.dir}"
146
+ $stderr.puts "Project: #{@proj_name}" if defined?(@proj_name) && @proj_name
145
147
  $stderr.puts "Log file: #{log_path}"
146
148
  if @c.respond_to?(:console_summary) && !@c.console_summary.nil?
147
149
  $stderr.puts "-" * 72
@@ -259,13 +261,12 @@ def html_docs_bundle_available?
259
261
  Dir.exist?(File.join(File.dirname(__FILE__), '..', '..', '..', 'site-local'))
260
262
  end
261
263
 
264
+ # A project directory name unique to the current example, kept short because Windows
265
+ # paths stop at 260 characters and a project's deepest build file sits well over 100
266
+ # below it. The full description, nested groups and all, tells apart same-named examples
267
+ # sharing one spec file's temp dir. Failure reports print the name beside the example.
262
268
  def unique_proj_name(prefix)
263
- safe = RSpec.current_example.description
264
- .downcase
265
- .gsub(/[^a-z0-9]+/, '_')
266
- .gsub(/\A_+|_+\z/, '')
267
- .slice(0, 60)
268
- "#{prefix}_#{safe}"
269
+ "#{prefix}_#{Digest::SHA256.hexdigest( RSpec.current_example.full_description )[0, 8]}"
269
270
  end
270
271
 
271
272
  def convert_slashes(path)
@@ -6,9 +6,11 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'fileutils'
9
+ require 'securerandom'
10
+ require 'tmpdir'
9
11
  require 'bundler'
10
12
  require 'ceedling/encodinator'
11
- require 'ceedling/file_wrapper'
13
+ require 'ceedling/filesystem/file_wrapper'
12
14
  require 'ceedling/verbosinator'
13
15
  require 'ceedling/yaml_wrapper'
14
16
  require_relative 'gem_dir_layout'
@@ -145,13 +147,29 @@ class SystemContext
145
147
  # or fail/) is determined by done!.
146
148
  base = File.join(Dir.pwd, ARTIFACTS_DIR, 'proj')
147
149
  FileUtils.mkdir_p(base)
148
- @dir = Dir.mktmpdir(nil, base)
150
+ @dir = self.class.brief_tmpdir(base)
149
151
  else
150
- @dir = Dir.mktmpdir
152
+ @dir = self.class.brief_tmpdir(Dir.tmpdir)
151
153
  end
152
154
  @gem = GemDirLayout.new(@dir)
153
155
  end
154
156
 
157
+ # A new directory below `base` with a 7-character name, where Dir.mktmpdir's runs to
158
+ # 22. Windows paths stop at 260 characters, and a project's deepest build file sits
159
+ # well over 100 below this directory. Dir.mkdir is atomic, so concurrent runs never
160
+ # share one.
161
+ def self.brief_tmpdir(base)
162
+ loop do
163
+ dir = File.join(base, "s#{SecureRandom.hex(3)}")
164
+ begin
165
+ Dir.mkdir(dir)
166
+ return dir
167
+ rescue Errno::EEXIST
168
+ next
169
+ end
170
+ end
171
+ end
172
+
155
173
  def done!
156
174
  if keep_all? || (keep_failures_only? && @failed)
157
175
  # 'all' mode: preserve pass and fail artifacts for post-run inspection.
@@ -0,0 +1,49 @@
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/filesystem/working_dir'
9
+
10
+ # WorkingDir reads the working directory once, and Ceedling changes directory only through
11
+ # WorkingDir.chdir. Specs change directory in-process with Dir.chdir all the time, so here
12
+ # every Dir.chdir forgets the working directory too, and each spec's paths resolve against
13
+ # the directory it is in. `untracked` suspends that, so a spec can show what Ceedling
14
+ # itself does.
15
+ module WorkingDirTracking
16
+
17
+ @paused = false
18
+
19
+ def self.untracked
20
+ previous = @paused
21
+ @paused = true
22
+ yield
23
+ ensure
24
+ @paused = previous
25
+ end
26
+
27
+ def self.forget
28
+ WorkingDir.forget unless @paused
29
+ end
30
+
31
+ module DirChdir
32
+ def chdir(*args)
33
+ WorkingDirTracking.forget
34
+ return super unless block_given?
35
+
36
+ super( *args ) do |*yielded|
37
+ WorkingDirTracking.forget
38
+ yield( *yielded )
39
+ ensure
40
+ WorkingDirTracking.forget
41
+ end
42
+ ensure
43
+ WorkingDirTracking.forget
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ Dir.singleton_class.prepend( WorkingDirTracking::DirChdir )
@@ -62,8 +62,8 @@ ceedling_system_tests do
62
62
  expect(output).to_not match(/Ambiguous/)
63
63
  expect(output).to match(/^Linking /)
64
64
 
65
- expect(File.exist?('build/release/out/foo/bar.o')).to be true
66
- expect(File.exist?('build/release/out/baz/bar.o')).to be true
65
+ expect(File.exist?('build/release/out/src/foo/bar.o')).to be true
66
+ expect(File.exist?('build/release/out/src/baz/bar.o')).to be true
67
67
 
68
68
  binary = Dir.glob('build/artifacts/release/*.out').first
69
69
  run_output = `#{binary}`
@@ -128,7 +128,7 @@ ceedling_system_tests do
128
128
 
129
129
  # The runner initializes and verifies the newly enabled module's mock
130
130
  in_project do
131
- expect(File.read( 'build/test/runners/test_Case_02_runner.c' )).to include( 'mock_MyModulePart2' )
131
+ expect(File.read( 'build/test/runners/test/test_Case_02_runner.c' )).to include( 'mock_MyModulePart2' )
132
132
  end
133
133
  end
134
134
 
@@ -123,9 +123,9 @@ ceedling_system_tests do
123
123
  # so none of this test's mocks are considered stale purely from that
124
124
  # unrelated cache miss. Only a change to the header a mock actually
125
125
  # mocks, or to the mock's own config meta, can make it regenerate.
126
- expect(rebuild).to_not match(/Generating mock for TestAdcModel::TaskScheduler\.h/)
127
- expect(rebuild).to_not match(/Generating mock for TestAdcModel::TemperatureCalculator\.h/)
128
- expect(rebuild).to_not match(/Generating mock for TestAdcModel::TemperatureFilter\.h/)
126
+ expect(rebuild).to_not match(/Generating mock for test\/adc\/TestAdcModel::TaskScheduler\.h/)
127
+ expect(rebuild).to_not match(/Generating mock for test\/adc\/TestAdcModel::TemperatureCalculator\.h/)
128
+ expect(rebuild).to_not match(/Generating mock for test\/adc\/TestAdcModel::TemperatureFilter\.h/)
129
129
 
130
130
  expect(rebuild).to match(/^Compiling TestAdcModel\.c/)
131
131
  expect(rebuild).to match(/^Linking TestAdcModel\.out/)
@@ -147,7 +147,7 @@ ceedling_system_tests do
147
147
  expect(rebuild).to_not match(/^Compiling .*TimerModel/)
148
148
  expect(rebuild).to_not match(/^Linking .*Usart/)
149
149
  expect(rebuild).to_not match(/^Linking .*Timer/)
150
- expect(rebuild).to_not match(/Generating mock for TestUsartConductor/)
150
+ expect(rebuild).to_not match(/Generating mock for test\/TestUsartConductor/)
151
151
  end
152
152
  end
153
153
  end
@@ -220,6 +220,24 @@ ceedling_system_tests do
220
220
  end
221
221
  end
222
222
 
223
+ # Every remaining object is unchanged, so only the list of objects shows the change. A
224
+ # stale executable would still hold the source's code and report its cached pass.
225
+ it "relinks a test whose source leaves the build, failing at link without it" do
226
+ @c.with_context do
227
+ Dir.chdir "temp_sensor" do
228
+ @c.ceedling_build_exec("test:all")
229
+
230
+ @c.merge_project_yml_for_test({ :files => { :source => ['-:src/TemperatureFilter.c'] } })
231
+ rebuild = @c.ceedling_build_exec("test:TestTemperatureFilter.c")
232
+
233
+ expect(@c.last_exit_status).to_not eq(0)
234
+ expect(rebuild).to_not match(/^Compiling /)
235
+ expect(rebuild).to match(/^Linking TestTemperatureFilter\.out/)
236
+ expect(rebuild).to match(/undefined reference|Undefined symbols/)
237
+ end
238
+ end
239
+ end
240
+
223
241
  it "clobber removes the dependency cache and forces a full rebuild afterward" do
224
242
  @c.with_context do
225
243
  Dir.chdir "temp_sensor" do
@@ -429,6 +447,95 @@ ceedling_system_tests do
429
447
  end
430
448
  end
431
449
 
450
+ # GH #1368: a link tracked its libraries only by their -l and -L arguments, so a library
451
+ # rebuilt under the same name relinked nothing. A test kept its cached result against the
452
+ # old library, and a release kept the old library's code. `m` is on no library path the
453
+ # project configures, so it is never tracked, and never relinks an unchanged build.
454
+ describe "Delta builds: linked libraries" do
455
+ before { @proj_name = unique_proj_name("delta_libs") }
456
+
457
+ def build_library!(value)
458
+ FileUtils.mkdir_p( ['vendor/lib', 'vendor/obj'] )
459
+ File.write( 'vendor/obj/x.c', "int lib_value(void) { return #{value}; }\n" )
460
+ FileUtils.rm_f( 'vendor/lib/libx.a' )
461
+ system( 'gcc', '-c', 'vendor/obj/x.c', '-o', 'vendor/obj/x.o' ) or raise 'Could not compile the library'
462
+ system( 'ar', 'rcs', 'vendor/lib/libx.a', 'vendor/obj/x.o' ) or raise 'Could not archive the library'
463
+ end
464
+
465
+ def deploy_library_project!
466
+ @c.ceedling_appcmd_exec("new #{@proj_name}")
467
+
468
+ Dir.chdir @proj_name do
469
+ build_library!( 1 )
470
+ File.write( 'src/x.h', "int lib_value(void);\n" )
471
+ File.write( 'src/main.c', "#include \"x.h\"\nint main(void) { return lib_value(); }\n" )
472
+ File.write( 'test/test_lib.c', <<~C )
473
+ #include "unity.h"
474
+ #include "x.h"
475
+ void setUp(void) {}
476
+ void tearDown(void) {}
477
+ void test_value(void) { TEST_ASSERT_EQUAL_INT(1, lib_value()); }
478
+ C
479
+ @c.merge_project_yml_for_test( {
480
+ :project => { :release_build => true },
481
+ :paths => { :libraries => ['vendor/lib'] },
482
+ :libraries => { :test => ['x', 'm'], :release => ['x', 'm'] }
483
+ } )
484
+ end
485
+ end
486
+
487
+ it "relinks a test when a library it links is rebuilt under the same name" do
488
+ @c.with_context do
489
+ deploy_library_project!
490
+
491
+ Dir.chdir @proj_name do
492
+ baseline = @c.ceedling_build_exec("test:all")
493
+ expect(baseline).to match(/PASSED:\s+1/)
494
+
495
+ build_library!( 2 )
496
+ rebuild = @c.ceedling_build_exec("test:all")
497
+
498
+ expect(rebuild).to_not match(/^Compiling /)
499
+ expect(rebuild).to match(/^Linking test_lib\.out/)
500
+ expect(rebuild).to match(/FAILED:\s+1/)
501
+ end
502
+ end
503
+ end
504
+
505
+ it "relinks a release when a library it links is rebuilt under the same name" do
506
+ @c.with_context do
507
+ deploy_library_project!
508
+
509
+ Dir.chdir @proj_name do
510
+ @c.ceedling_build_exec("release")
511
+
512
+ build_library!( 2 )
513
+ rebuild = @c.ceedling_build_exec("release")
514
+
515
+ expect(rebuild).to_not match(/^Compiling /)
516
+ expect(rebuild).to match(/^Linking /)
517
+ end
518
+ end
519
+ end
520
+
521
+ it "relinks nothing when no library changed, whatever libraries it can't find" do
522
+ @c.with_context do
523
+ deploy_library_project!
524
+
525
+ Dir.chdir @proj_name do
526
+ @c.ceedling_build_exec("test:all")
527
+ @c.ceedling_build_exec("release")
528
+
529
+ tests = @c.ceedling_build_exec("test:all")
530
+ release = @c.ceedling_build_exec("release")
531
+
532
+ expect(tests).to_not match(/^Linking /)
533
+ expect(release).to_not match(/^Linking /)
534
+ end
535
+ end
536
+ end
537
+ end
538
+
432
539
  # :unity ↳ :shuffle_tests decides test-case execution order at runtime, inside
433
540
  # the compiled executable's own main() -- not at compile or link time. So an
434
541
  # executable delta builds correctly judge unchanged (same source, same flags,
@@ -528,7 +635,7 @@ ceedling_system_tests do
528
635
 
529
636
  rebuild = @c.ceedling_build_exec("test:all")
530
637
 
531
- expect(rebuild).to match(/^Compiling TestSoilMoisture::SoilMoisture\.c/)
638
+ expect(rebuild).to match(/^Compiling test\/TestSoilMoisture::SoilMoisture\.c/)
532
639
  expect(rebuild).to match(/^Linking TestSoilMoisture\.out/)
533
640
  expect(rebuild).to match(/^Running TestSoilMoisture\.out/)
534
641
 
@@ -563,7 +670,7 @@ ceedling_system_tests do
563
670
 
564
671
  rebuild = @c.ceedling_build_exec("test:all")
565
672
 
566
- expect(rebuild).to match(/^Compiling TestForestMonitor::ForestMonitor\.c/)
673
+ expect(rebuild).to match(/^Compiling test\/TestForestMonitor::ForestMonitor\.c/)
567
674
 
568
675
  expect(rebuild).to_not match(/^Compiling.*SoilMoisture/)
569
676
  expect(rebuild).to_not match(/^Compiling.*TemperatureSensor/)
@@ -631,11 +738,11 @@ ceedling_system_tests do
631
738
 
632
739
  rebuild = @c.ceedling_build_exec("test:all")
633
740
 
634
- expect(rebuild).to match(/Preprocessing partial (header|source) for TestSoilMoisture/)
635
- expect(rebuild).to match(/Preprocessing partial (header|source) for TestForestMonitor/)
636
- expect(rebuild).to match(/Generating Partial implementation for TestSoilMoisture/)
637
- expect(rebuild).to match(/Generating Partial implementation for TestForestMonitor/)
638
- expect(rebuild).to match(/Generating Partial mockable interface for TestForestMonitor/)
741
+ expect(rebuild).to match(/Preprocessing partial (header|source) for test\/TestSoilMoisture/)
742
+ expect(rebuild).to match(/Preprocessing partial (header|source) for test\/TestForestMonitor/)
743
+ expect(rebuild).to match(/Generating Partial implementation for test\/TestSoilMoisture/)
744
+ expect(rebuild).to match(/Generating Partial implementation for test\/TestForestMonitor/)
745
+ expect(rebuild).to match(/Generating Partial mockable interface for test\/TestForestMonitor/)
639
746
 
640
747
  expect(rebuild).to match(/TESTED:\s+71/)
641
748
  expect(rebuild).to match(/PASSED:\s+71/)
@@ -704,6 +811,25 @@ ceedling_system_tests do
704
811
  end
705
812
  end
706
813
 
814
+ # main.c is unchanged, so only the list of objects shows the change. A stale artifact
815
+ # would still hold the analyzer's code.
816
+ it "relinks when a source leaves the build, failing at link without it" do
817
+ @c.with_context do
818
+ Dir.chdir "cipher_quest" do
819
+ enable_release_features!
820
+ @c.ceedling_build_exec("release")
821
+
822
+ @c.merge_project_yml_for_test({ :files => { :source => ['-:src/analyzer.c'] } })
823
+ rebuild = @c.ceedling_build_exec("release")
824
+
825
+ expect(@c.last_exit_status).to_not eq(0)
826
+ expect(rebuild).to_not match(/^Compiling main\.c/)
827
+ expect(rebuild).to match(/^Linking /)
828
+ expect(rebuild).to match(/undefined reference|Undefined symbols/)
829
+ end
830
+ end
831
+ end
832
+
707
833
  it "recompiles every object whose source #includes a changed header, via .d-file-derived transitive tracking, leaving unrelated objects untouched" do
708
834
  @c.with_context do
709
835
  Dir.chdir "cipher_quest" do
@@ -53,6 +53,7 @@ ceedling_system_tests do
53
53
  test_case :project_with_gcov_untested_sources_compile_failure
54
54
  test_case :project_with_gcov_untested_sources_standalone_task
55
55
  test_case :project_with_gcov_untested_sources_compiled_with_matched_defines
56
+ test_case :project_with_gcov_untested_sources_sharing_a_name
56
57
  test_case :help_tasks_include_gcov
57
58
  test_case :create_html_report
58
59
  test_case :create_html_report_with_gcovr_custom_args