ceedling 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. checksums.yaml +4 -4
  2. data/GIT_COMMIT_SHA +1 -1
  3. data/README.md +57 -58
  4. data/Rakefile +5 -3
  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 +35 -1
  10. data/bin/ceedling +13 -3
  11. data/bin/cli.rb +25 -6
  12. data/bin/cli_handler.rb +119 -73
  13. data/bin/cli_helper.rb +56 -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 +84 -3
  23. data/docs/KnownIssues.md +90 -4
  24. data/docs/ReleaseNotes.md +13 -0
  25. data/docs/overrides/main.html +11 -8
  26. data/lib/ceedling/build_log_writer.rb +33 -0
  27. data/lib/ceedling/config/build_root_policy.rb +70 -0
  28. data/lib/ceedling/config/configurator.rb +19 -18
  29. data/lib/ceedling/config/configurator_builder.rb +58 -28
  30. data/lib/ceedling/config/configurator_paths_validator.rb +179 -0
  31. data/lib/ceedling/config/configurator_plugins.rb +1 -1
  32. data/lib/ceedling/config/configurator_setup.rb +39 -41
  33. data/lib/ceedling/config/configurator_validator.rb +1 -110
  34. data/lib/ceedling/defaults.rb +4 -4
  35. data/lib/ceedling/dependencies/README.md +18 -16
  36. data/lib/ceedling/dependencies/dependency_cache_store.rb +20 -3
  37. data/lib/ceedling/dependencies/dependency_hasher.rb +35 -1
  38. data/lib/ceedling/filename_extension.rb +7 -1
  39. data/lib/ceedling/filesystem/FILE_TREE.md +253 -0
  40. data/lib/ceedling/filesystem/PATH_HANDLING.md +304 -0
  41. data/lib/ceedling/filesystem/README.md +41 -0
  42. data/lib/ceedling/filesystem/build_subpath.rb +102 -0
  43. data/lib/ceedling/filesystem/destination_collision.rb +25 -0
  44. data/lib/ceedling/{file_finder.rb → filesystem/file_finder.rb} +159 -104
  45. data/lib/ceedling/{file_finder_helper.rb → filesystem/file_finder_helper.rb} +36 -31
  46. data/lib/ceedling/filesystem/file_path_collection_utils.rb +183 -0
  47. data/lib/ceedling/{file_path_utils.rb → filesystem/file_path_utils.rb} +108 -97
  48. data/lib/ceedling/{file_system_wrapper.rb → filesystem/file_system_wrapper.rb} +6 -5
  49. data/lib/ceedling/filesystem/file_tree.rb +241 -0
  50. data/lib/ceedling/{file_wrapper.rb → filesystem/file_wrapper.rb} +65 -28
  51. data/lib/ceedling/filesystem/path_exclusions.rb +30 -0
  52. data/lib/ceedling/{path_matcher.rb → filesystem/path_matcher.rb} +27 -23
  53. data/lib/ceedling/{path_mirror.rb → filesystem/path_mirror.rb} +19 -18
  54. data/lib/ceedling/filesystem/path_spellings.rb +55 -0
  55. data/lib/ceedling/filesystem/project_paths.rb +184 -0
  56. data/lib/ceedling/filesystem/working_dir.rb +40 -0
  57. data/lib/ceedling/generators/generator.rb +5 -6
  58. data/lib/ceedling/generators/generator_partials.rb +1 -1
  59. data/lib/ceedling/generators/generator_test_results_backtrace.rb +7 -7
  60. data/lib/ceedling/handoff.rb +121 -0
  61. data/lib/ceedling/includes/include_factory.rb +3 -3
  62. data/lib/ceedling/includes/include_pathinator.rb +67 -10
  63. data/lib/ceedling/includes/includes.rb +1 -1
  64. data/lib/ceedling/installation.rb +92 -0
  65. data/lib/ceedling/library_resolver.rb +99 -0
  66. data/lib/ceedling/objects.yml +23 -2
  67. data/lib/ceedling/partials/partializer.rb +4 -4
  68. data/lib/ceedling/partials/partializer_config.rb +3 -1
  69. data/lib/ceedling/plugins/report_log_writer_plugin.rb +3 -5
  70. data/lib/ceedling/preprocess/preprocessinator_file_assembler.rb +1 -1
  71. data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +1 -1
  72. data/lib/ceedling/preprocess/preprocessinator_line_marker_includes_extractor.rb +1 -1
  73. data/lib/ceedling/rake_app/rakefile_component_resolver.rb +10 -17
  74. data/lib/ceedling/rake_app/test_task_name.rb +29 -0
  75. data/lib/ceedling/rakefile.rb +16 -1
  76. data/lib/ceedling/rakefiles/base/tasks_base.rake +1 -1
  77. data/lib/ceedling/rakefiles/release/rules_release.rake +4 -7
  78. data/lib/ceedling/rakefiles/tests/rules_tests.rake +3 -20
  79. data/lib/ceedling/rakefiles/tests/rules_tests_generate.rake +4 -30
  80. data/lib/ceedling/release_invoker/release_build_executor.rb +33 -44
  81. data/lib/ceedling/release_invoker/release_build_planner.rb +14 -6
  82. data/lib/ceedling/reportinator.rb +3 -4
  83. data/lib/ceedling/setupinator.rb +95 -87
  84. data/lib/ceedling/test_context_extractor.rb +5 -1
  85. data/lib/ceedling/test_invoker/PIPELINE.md +9 -7
  86. data/lib/ceedling/test_invoker/mock_locator.rb +60 -2
  87. data/lib/ceedling/test_invoker/partials_manager.rb +12 -0
  88. data/lib/ceedling/test_invoker/standin_headerinator.rb +22 -13
  89. data/lib/ceedling/test_invoker/test_build_executor.rb +42 -41
  90. data/lib/ceedling/test_invoker/test_build_planner.rb +37 -18
  91. data/lib/ceedling/test_invoker/test_build_setup.rb +17 -12
  92. data/lib/ceedling/test_invoker/test_build_validations.rb +16 -31
  93. data/lib/ceedling/test_invoker/test_file_preprocessinator.rb +1 -1
  94. data/lib/ceedling/test_invoker/test_invoker.rb +6 -1
  95. data/lib/ceedling/test_invoker/test_pipeline_helpers.rb +1 -1
  96. data/lib/ceedling/test_invoker/test_source_file_directive_resolver.rb +40 -20
  97. data/lib/ceedling/tool_executor.rb +9 -3
  98. data/lib/ceedling/yaml_wrapper.rb +3 -2
  99. data/lib/version.rb +1 -1
  100. data/plugins/bullseye/bullseye.rake +6 -9
  101. data/plugins/bullseye/config/defaults_bullseye.rb +1 -1
  102. data/plugins/bullseye/lib/bullseye.rb +9 -7
  103. data/plugins/cppcheck/config/defaults_cppcheck.rb +1 -1
  104. data/plugins/dependencies/config/defaults.yml +6 -6
  105. data/plugins/dependencies/dependencies.rake +4 -1
  106. data/plugins/dependencies/lib/dependencies.rb +18 -8
  107. data/plugins/dependencies/lib/dependency_spec.rb +17 -5
  108. data/plugins/fff/lib/fff.rb +45 -39
  109. data/plugins/fff/spec/fff_cmock_wrapper_spec.rb +128 -0
  110. data/plugins/gcov/config/defaults_gcov.rb +1 -1
  111. data/plugins/gcov/gcov.rake +6 -9
  112. data/plugins/gcov/lib/console_reportinator.rb +4 -18
  113. data/plugins/gcov/lib/gcov.rb +9 -2
  114. data/plugins/gcov/lib/gcovr_reportinator.rb +8 -40
  115. data/plugins/gcov/lib/gcovr_thresholds.rb +74 -0
  116. data/plugins/gcov/lib/reportgenerator_reportinator.rb +1 -1
  117. data/plugins/module_generator/lib/module_generator.rb +3 -3
  118. data/plugins/report_tests_teamcity_stdout/lib/report_tests_teamcity_stdout.rb +53 -80
  119. data/plugins/sanitize/lib/sanitize_records.rb +3 -6
  120. data/plugins/sanitize/sanitize.rake +6 -6
  121. data/plugins/valgrind/lib/valgrind.rb +14 -7
  122. data/plugins/valgrind/valgrind.rake +6 -6
  123. data/site-local/404.html +6 -20
  124. data/site-local/assets/javascripts/{bundle.d7400e89.min.js → bundle.c21346df.min.js} +3 -3
  125. data/site-local/assets/javascripts/{bundle.d7400e89.min.js.map → bundle.c21346df.min.js.map} +2 -2
  126. data/site-local/assets/javascripts/workers/{search.2c215733.min.js → search.a7633da7.min.js} +2 -2
  127. data/site-local/assets/javascripts/workers/{search.2c215733.min.js.map → search.a7633da7.min.js.map} +1 -1
  128. data/site-local/assets/stylesheets/main.57a0d79d.min.css +6 -0
  129. data/site-local/assets/stylesheets/main.57a0d79d.min.css.map +1 -0
  130. data/site-local/assets/stylesheets/palette.fb2fffe2.min.css +4 -0
  131. data/site-local/assets/stylesheets/palette.fb2fffe2.min.css.map +1 -0
  132. data/site-local/configuration/environment-vars.html +6 -20
  133. data/site-local/configuration/global-collections.html +6 -20
  134. data/site-local/configuration/index.html +6 -20
  135. data/site-local/configuration/loading.html +6 -20
  136. data/site-local/configuration/mixins.html +10 -24
  137. data/site-local/configuration/parallel-builds.html +6 -20
  138. data/site-local/configuration/project-file.html +8 -22
  139. data/site-local/configuration/reference/cexception.html +6 -20
  140. data/site-local/configuration/reference/cmock.html +8 -21
  141. data/site-local/configuration/reference/defines.html +16 -30
  142. data/site-local/configuration/reference/environment.html +10 -24
  143. data/site-local/configuration/reference/extension.html +6 -20
  144. data/site-local/configuration/reference/files.html +22 -30
  145. data/site-local/configuration/reference/flags.html +13 -27
  146. data/site-local/configuration/reference/index.html +6 -20
  147. data/site-local/configuration/reference/libraries.html +27 -23
  148. data/site-local/configuration/reference/mixins.html +6 -20
  149. data/site-local/configuration/reference/partials.html +6 -20
  150. data/site-local/configuration/reference/paths.html +38 -29
  151. data/site-local/configuration/reference/plugins.html +6 -20
  152. data/site-local/configuration/reference/project.html +32 -36
  153. data/site-local/configuration/reference/release-build.html +8 -20
  154. data/site-local/configuration/reference/test-build.html +6 -20
  155. data/site-local/configuration/reference/test-runner.html +6 -20
  156. data/site-local/configuration/reference/tools.html +27 -32
  157. data/site-local/configuration/reference/unity.html +6 -20
  158. data/site-local/configuration/which-ceedling.html +383 -37
  159. data/site-local/development/index.html +6 -20
  160. data/site-local/development/plugins/configuration.html +6 -20
  161. data/site-local/development/plugins/index.html +6 -20
  162. data/site-local/development/plugins/plugin-subclass.html +54 -68
  163. data/site-local/development/plugins/rake-tasks.html +8 -22
  164. data/site-local/development/releases.html +84 -29
  165. data/site-local/development/workflow.html +62 -71
  166. data/site-local/getting-started/builds.html +8 -20
  167. data/site-local/getting-started/command-line.html +62 -24
  168. data/site-local/getting-started/example-projects/cipher-quest.html +6 -20
  169. data/site-local/getting-started/example-projects/index.html +6 -20
  170. data/site-local/getting-started/example-projects/temp-sensor.html +6 -20
  171. data/site-local/getting-started/example-projects/wondrous-forest.html +6 -20
  172. data/site-local/getting-started/index.html +6 -20
  173. data/site-local/getting-started/installation.html +6 -20
  174. data/site-local/getting-started/quick-start.html +6 -20
  175. data/site-local/help.html +6 -20
  176. data/site-local/index.html +11 -24
  177. data/site-local/overview/build-system.html +6 -20
  178. data/site-local/overview/index.html +6 -20
  179. data/site-local/overview/test-environments.html +6 -20
  180. data/site-local/overview/tools-and-frameworks.html +6 -20
  181. data/site-local/plugins/beep.html +6 -20
  182. data/site-local/plugins/bullseye/index.html +13 -24
  183. data/site-local/plugins/bullseye/licensing.html +14 -28
  184. data/site-local/plugins/command-hooks.html +8 -22
  185. data/site-local/plugins/compile-commands-json-db.html +6 -20
  186. data/site-local/plugins/cppcheck.html +8 -22
  187. data/site-local/plugins/dependencies.html +16 -27
  188. data/site-local/plugins/fff.html +49 -32
  189. data/site-local/plugins/gcov/examples.html +7 -21
  190. data/site-local/plugins/gcov/gcovr.html +22 -33
  191. data/site-local/plugins/gcov/index.html +6 -20
  192. data/site-local/plugins/gcov/overview.html +9 -20
  193. data/site-local/plugins/gcov/reportgenerator.html +9 -23
  194. data/site-local/plugins/gcov/reporting.html +6 -20
  195. data/site-local/plugins/gcov/setup.html +8 -21
  196. data/site-local/plugins/gcov/tool-versions.html +6 -20
  197. data/site-local/plugins/gcov/troubleshooting.html +10 -24
  198. data/site-local/plugins/index.html +6 -20
  199. data/site-local/plugins/module-generator.html +21 -35
  200. data/site-local/plugins/report-build-warnings-log.html +53 -67
  201. data/site-local/plugins/report-tests-gtestlike-stdout.html +6 -20
  202. data/site-local/plugins/report-tests-ide-stdout.html +43 -57
  203. data/site-local/plugins/report-tests-log-factory.html +50 -64
  204. data/site-local/plugins/report-tests-pretty-stdout.html +7 -21
  205. data/site-local/plugins/report-tests-raw-output-log.html +9 -21
  206. data/site-local/plugins/report-tests-teamcity-stdout.html +20 -31
  207. data/site-local/plugins/sanitize.html +56 -65
  208. data/site-local/plugins/valgrind.html +49 -58
  209. data/site-local/project/index.html +6 -20
  210. data/site-local/project/release-history.html +6 -20
  211. data/site-local/project/sbom.html +6 -20
  212. data/site-local/project/upgrade.html +9 -20
  213. data/site-local/reference/build-directives.html +6 -20
  214. data/site-local/reference/command-line.html +15 -22
  215. data/site-local/reference/environment-vars.html +6 -20
  216. data/site-local/reference/gcov-plugin.html +6 -20
  217. data/site-local/reference/global-collections.html +6 -20
  218. data/site-local/reference/index.html +6 -20
  219. data/site-local/reference/partials-macros.html +6 -20
  220. data/site-local/reference/project-configuration.html +6 -20
  221. data/site-local/sitemap.xml.gz +0 -0
  222. data/site-local/snapshot/examples/cipher_quest/index.html +16 -30
  223. data/site-local/snapshot/examples/temp_sensor/index.html +8 -22
  224. data/site-local/snapshot/examples/wondrous_forest/index.html +6 -20
  225. data/site-local/snapshot/plugins/bullseye/config/defaults_bullseye.rb +1 -1
  226. data/site-local/snapshot/plugins/gcov/config/defaults_gcov.rb +1 -1
  227. data/site-local/testing-guide/build-directives.html +14 -28
  228. data/site-local/testing-guide/conventions.html +66 -27
  229. data/site-local/testing-guide/frameworks.html +11 -25
  230. data/site-local/testing-guide/index.html +6 -20
  231. data/site-local/testing-guide/partials/configuration.html +8 -22
  232. data/site-local/testing-guide/partials/conventions.html +8 -22
  233. data/site-local/testing-guide/partials/directives.html +16 -30
  234. data/site-local/testing-guide/partials/example.html +14 -28
  235. data/site-local/testing-guide/partials/index.html +6 -20
  236. data/site-local/testing-guide/partials/overview.html +6 -20
  237. data/site-local/testing-guide/partials/variables.html +11 -25
  238. data/site-local/testing-guide/test-cases.html +13 -27
  239. data/site-local/testing-guide/test-sample.html +12 -26
  240. data/site-local/testing-guide/test-suite-anatomy.html +6 -20
  241. data/spec/integration/actionator_file_operations_spec.rb +91 -1
  242. data/spec/integration/compile_commands_json_db_spec.rb +1 -1
  243. data/spec/integration/configurator_pipeline_spec.rb +10 -0
  244. data/spec/integration/configurator_validation_spec.rb +1 -1
  245. data/spec/integration/dependencies/dependency_tracker_cache_hardening_spec.rb +26 -0
  246. data/spec/integration/dependencies/dependency_tracker_core_spec.rb +62 -0
  247. data/spec/integration/launcher_handoff_spec.rb +297 -0
  248. data/spec/integration/mixin_loading_spec.rb +1 -1
  249. data/spec/integration/module_generator_spec.rb +3 -3
  250. data/spec/integration/nested_test_artifacts_spec.rb +99 -0
  251. data/spec/integration/partials_module_resolution_spec.rb +7 -4
  252. data/spec/integration/path_intake_scenarios_spec.rb +101 -0
  253. data/spec/integration/path_scenarios_spec.rb +322 -0
  254. data/spec/integration/quote_include_isolator_spec.rb +1 -1
  255. data/spec/integration/rake_task_registry_plugins_spec.rb +95 -0
  256. data/spec/integration/report_build_warnings_log_spec.rb +1 -1
  257. data/spec/integration/report_tests_log_factory_spec.rb +1 -1
  258. data/spec/integration/test_executable_manifest_spec.rb +1 -1
  259. data/spec/integration/test_includes_extractinator_spec.rb +2 -1
  260. data/spec/integration/test_naming_spec.rb +198 -0
  261. data/spec/integration/test_source_file_checks_spec.rb +166 -0
  262. data/spec/integration/tool_validator_spec.rb +1 -1
  263. data/spec/integration/upgrade_docs_spec.rb +84 -0
  264. data/spec/integration/vendor_copy_transient_io_retry_spec.rb +192 -75
  265. data/spec/support/file_tree_helper.rb +88 -0
  266. data/spec/support/integration/configurator_integration_helper.rb +10 -7
  267. data/spec/support/integration/dependency_tracker_integration_helper.rb +1 -1
  268. data/spec/support/integration/partials_generation_integration_helper.rb +2 -2
  269. data/spec/support/integration/path_scenario_harness.rb +173 -0
  270. data/spec/support/integration/spec_integration_helper.rb +1 -1
  271. data/spec/support/integration/test_includes_harness.rb +13 -2
  272. data/spec/support/spec_helper.rb +2 -0
  273. data/spec/support/system/spec_system_helper.rb +7 -6
  274. data/spec/support/system/system_context.rb +21 -3
  275. data/spec/support/working_dir_tracking.rb +49 -0
  276. data/spec/system/build_output_mirroring_spec.rb +2 -2
  277. data/spec/system/conditional_mock_includes_spec.rb +1 -1
  278. data/spec/system/delta_builds_spec.rb +137 -11
  279. data/spec/system/gcov_deployment_spec.rb +1 -0
  280. data/spec/system/header_include_path_validation_spec.rb +4 -4
  281. data/spec/system/launcher_handoff_spec.rb +82 -0
  282. data/spec/system/mock_include_folders_spec.rb +91 -0
  283. data/spec/system/parent_directory_reference_spec.rb +5 -3
  284. data/spec/system/path_handling_probes_spec.rb +192 -0
  285. data/spec/system/preprocessing_parameterized_tests_spec.rb +1 -1
  286. data/spec/system/rake_release_task_path_disambiguation_spec.rb +6 -6
  287. data/spec/system/rake_test_task_path_disambiguation_spec.rb +85 -0
  288. data/spec/system/special_path_characters_spec.rb +86 -0
  289. data/spec/system/support/common_test_cases.rb +23 -21
  290. data/spec/system/support/gcov_common_test_cases.rb +37 -9
  291. data/spec/system/support/sanitize_common_test_cases.rb +2 -2
  292. data/spec/system/support/valgrind_common_test_cases.rb +12 -12
  293. data/spec/system/test_pipeline_stop_points_spec.rb +4 -4
  294. data/spec/system/test_runner_system_include_spec.rb +1 -1
  295. data/spec/system/test_source_file_directive_spec.rb +34 -5
  296. data/spec/units/bin/actionator_spec.rb +14 -17
  297. data/spec/units/bin/app_cfg_spec.rb +47 -0
  298. data/spec/units/bin/cli_handler_spec.rb +284 -7
  299. data/spec/units/bin/cli_helper_spec.rb +126 -45
  300. data/spec/units/bin/installation_selector_spec.rb +114 -0
  301. data/spec/units/bin/launchinator_spec.rb +171 -0
  302. data/spec/units/bin/path_validator_spec.rb +10 -0
  303. data/spec/units/bin/versionator_spec.rb +38 -6
  304. data/spec/units/build_log_writer_spec.rb +57 -0
  305. data/spec/units/config/build_root_policy_spec.rb +61 -0
  306. data/spec/units/config/configurator_builder_spec.rb +37 -6
  307. data/spec/units/config/configurator_paths_validator_spec.rb +292 -0
  308. data/spec/units/config/configurator_setup_spec.rb +65 -103
  309. data/spec/units/config/configurator_spec.rb +37 -6
  310. data/spec/units/config/configurator_validator_spec.rb +1 -172
  311. data/spec/units/default_tools_quoting_spec.rb +83 -0
  312. data/spec/units/dependencies/dependency_cache_store_spec.rb +33 -2
  313. data/spec/units/dependencies/dependency_debug_tree_spec.rb +1 -1
  314. data/spec/units/dependencies/dependency_hasher_spec.rb +42 -1
  315. data/spec/units/dependencies/dependency_path_normalizer_spec.rb +1 -1
  316. data/spec/units/dependencies/dependency_tracker_spec.rb +3 -1
  317. data/spec/units/filename_extension_spec.rb +11 -0
  318. data/spec/units/filesystem/build_subpath_spec.rb +122 -0
  319. data/spec/units/filesystem/destination_collision_spec.rb +30 -0
  320. data/spec/units/{file_finder_helper_spec.rb → filesystem/file_finder_helper_spec.rb} +46 -1
  321. data/spec/units/{file_finder_spec.rb → filesystem/file_finder_spec.rb} +188 -22
  322. data/spec/units/{file_path_collection_utils_spec.rb → filesystem/file_path_collection_utils_spec.rb} +181 -1
  323. data/spec/units/{file_path_utils_spec.rb → filesystem/file_path_utils_spec.rb} +204 -87
  324. data/spec/units/filesystem/file_system_wrapper_spec.rb +33 -0
  325. data/spec/units/filesystem/file_tree_spec.rb +511 -0
  326. data/spec/units/filesystem/file_tree_windows_spec.rb +78 -0
  327. data/spec/units/{file_wrapper_spec.rb → filesystem/file_wrapper_spec.rb} +154 -32
  328. data/spec/units/{path_matcher_spec.rb → filesystem/path_matcher_spec.rb} +12 -1
  329. data/spec/units/{path_mirror_spec.rb → filesystem/path_mirror_spec.rb} +32 -4
  330. data/spec/units/filesystem/project_paths_spec.rb +147 -0
  331. data/spec/units/filesystem/working_dir_spec.rb +71 -0
  332. data/spec/units/generators/generator_spec.rb +12 -6
  333. data/spec/units/generators/generator_test_results_backtrace_spec.rb +50 -46
  334. data/spec/units/generators/generator_test_results_spec.rb +1 -1
  335. data/spec/units/handoff_spec.rb +205 -0
  336. data/spec/units/includes/include_factory_spec.rb +3 -3
  337. data/spec/units/includes/include_pathinator_spec.rb +46 -0
  338. data/spec/units/installation_spec.rb +228 -0
  339. data/spec/units/library_resolver_spec.rb +157 -0
  340. data/spec/units/mock_locator_spec.rb +76 -1
  341. data/spec/units/partials/partializer_config_spec.rb +7 -0
  342. data/spec/units/partials/partializer_spec.rb +1 -0
  343. data/spec/units/partials_manager_spec.rb +17 -0
  344. data/spec/units/plugins/bullseye_spec.rb +15 -2
  345. data/spec/units/plugins/console_reportinator_spec.rb +18 -20
  346. data/spec/units/plugins/dependencies_spec.rb +33 -7
  347. data/spec/units/plugins/dependency_spec_spec.rb +17 -0
  348. data/spec/units/plugins/gcov_spec.rb +28 -3
  349. data/spec/units/plugins/gcovr_reportinator_spec.rb +19 -47
  350. data/spec/units/plugins/gcovr_thresholds_spec.rb +95 -0
  351. data/spec/units/plugins/module_generator_spec.rb +5 -5
  352. data/spec/units/plugins/report_build_warnings_log_spec.rb +3 -3
  353. data/spec/units/plugins/report_log_writer_plugin_spec.rb +10 -1
  354. data/spec/units/plugins/report_tests_raw_output_log_spec.rb +13 -2
  355. data/spec/units/plugins/report_tests_teamcity_stdout_spec.rb +77 -3
  356. data/spec/units/plugins/reportgenerator_reportinator_spec.rb +1 -1
  357. data/spec/units/plugins/sanitize_records_spec.rb +3 -1
  358. data/spec/units/plugins/sanitize_spec.rb +1 -1
  359. data/spec/units/plugins/valgrind_spec.rb +23 -8
  360. data/spec/units/preprocess/preprocessinator_comment_stripper_spec.rb +1 -1
  361. data/spec/units/rake_app/rakefile_component_resolver_spec.rb +21 -0
  362. data/spec/units/rake_app/test_task_name_spec.rb +47 -0
  363. data/spec/units/release_build_executor_spec.rb +53 -14
  364. data/spec/units/release_build_planner_spec.rb +15 -3
  365. data/spec/units/reportinator_spec.rb +5 -5
  366. data/spec/units/standin_headerinator_spec.rb +31 -1
  367. data/spec/units/test_build_executor_spec.rb +107 -5
  368. data/spec/units/test_build_planner_spec.rb +104 -2
  369. data/spec/units/test_build_setup_spec.rb +96 -12
  370. data/spec/units/test_context_extractor_spec.rb +25 -0
  371. data/spec/units/test_file_preprocessinator_spec.rb +17 -1
  372. data/spec/units/test_includes_extractinator_spec.rb +5 -1
  373. data/spec/units/test_invoker/objects_wiring_spec.rb +6 -3
  374. data/spec/units/test_invoker_spec.rb +14 -1
  375. data/spec/units/test_source_file_directive_resolver_spec.rb +38 -7
  376. data/spec/units/tool_executor_spec.rb +26 -0
  377. data/spec/units/yaml_wrapper_spec.rb +11 -0
  378. metadata +122 -33
  379. data/lib/ceedling/file_path_collection_utils.rb +0 -164
  380. data/site-local/assets/stylesheets/main.ec1eaa64.min.css +0 -1
  381. data/site-local/assets/stylesheets/main.ec1eaa64.min.css.map +0 -1
  382. data/site-local/assets/stylesheets/palette.ab4e12ef.min.css +0 -1
  383. data/site-local/assets/stylesheets/palette.ab4e12ef.min.css.map +0 -1
@@ -269,6 +269,8 @@ class PartialsManager
269
269
  end
270
270
  end
271
271
 
272
+ order_partials( partials.map { |partial| partial[:testable] }.uniq )
273
+
272
274
  log_skip_summary( task: "Partial types generation", count: skipped_types, noun: "types headers" )
273
275
  log_skip_summary( task: "Partial implementation generation", count: skipped_impl, noun: "implementations" )
274
276
  log_skip_summary( task: "Partial interface generation", count: skipped_interface, noun: "interfaces" )
@@ -296,6 +298,16 @@ class PartialsManager
296
298
  # and `config.includes` is recalled from the on-disk list a prior stale run wrote
297
299
  # -- so `config` ends up populated identically either way, and stage 8 (which
298
300
  # reads only `config`) needs no knowledge of which path produced it.
301
+ # Build threads finish in any order. Each test's Partial modules return to its configuration
302
+ # order, which its link and mock lists follow, so an unchanged build sees unchanged lists.
303
+ def order_partials(testables)
304
+ testables.each do |testable|
305
+ order = testable.partials.configs.values.map( &:module )
306
+ testable.partials.tests.sort_by! { |_module| order.index( _module ) }
307
+ testable.partials.mocks.sort_by! { |_module| order.index( _module ) }
308
+ end
309
+ end
310
+
299
311
  def preprocess_partials(items:, kind:, noun:, preserve_macros_method:, expand_macros_method:)
300
312
  directives_only = @configurator.test_build_preprocess_directives_only_available
301
313
  skipped = 0
@@ -8,6 +8,7 @@
8
8
  require 'ceedling/constants'
9
9
  require 'ceedling/includes/includes'
10
10
  require 'ceedling/test_invoker/test_pipeline_helpers'
11
+ require 'ceedling/filesystem/project_paths'
11
12
 
12
13
  # Stand-in headers: files placed where a test's mocks and Partials will be generated, so
13
14
  # the preprocessor finds something at each of their #includes before stage 8 or stage 10
@@ -46,7 +47,7 @@ class StandinHeaderinator
46
47
  mock_dirs = place_mocks( testable, mocks, complain )
47
48
  place_partials( testable, Includes.filter( includes, /^#{PARTIAL_FILENAME_PREFIX}/ ) )
48
49
 
49
- return mock_dirs.uniq
50
+ return mock_dirs.flatten.uniq
50
51
  end
51
52
 
52
53
  private
@@ -67,18 +68,25 @@ class StandinHeaderinator
67
68
  end
68
69
  end
69
70
 
70
- # Gives the mock's mirrored directory, or nil when its missing header is tolerated or
71
- # the test has no mock root
71
+ # Gives the search paths that reach the mock, or nil when its missing header is tolerated
72
+ # or the test has no mock root
72
73
  def place_mock(testable, include, collection, complain)
74
+ return nil if testable.paths[:mocks].nil?
75
+
73
76
  source, subdir = @mock_locator.locate( include, collection: collection, complain: complain )
74
77
  return nil if source.nil?
75
78
 
76
- mock_dir = subdir.empty? ? testable.name : File.join( testable.name, subdir )
77
- write_mock( testable.name, @file_path_utils.form_mock_header_filepath( mock_dir, include.filename ), include, source )
79
+ placement = @mock_locator.placement( mocks_root: testable.paths[:mocks], subdir: subdir, include_path: include.filepath )
80
+ write_placed_mock( testable.name, placement, include, source )
78
81
 
79
- return nil if testable.paths[:mocks].nil?
82
+ return @mock_locator.search_directories( placement )
83
+ end
80
84
 
81
- return @file_path_utils.form_mock_output_path( testable.paths[:mocks], subdir )
85
+ # The test's #include reaches a climbing folder's mock only from the directory it climbs
86
+ # from, so that is made too
87
+ def write_placed_mock(test, placement, include, source)
88
+ @file_wrapper.mkdir( placement.reach ) unless ProjectPaths.contains?( placement.reach, placement.directory )
89
+ write_mock( test, File.join( placement.directory, include.filename.ext( EXTENSION_CORE_HEADER ) ), include, source, placement.folder )
82
90
  end
83
91
 
84
92
  # A Partial's generated #include names whatever directory its module was named by, and
@@ -97,8 +105,8 @@ class StandinHeaderinator
97
105
  @file_wrapper.write_blank_file( filepath )
98
106
  end
99
107
 
100
- def write_mock(test, filepath, include, header)
101
- contents = "#{MARKER}\n#{header_include( header )}\n"
108
+ def write_mock(test, filepath, include, header, folder)
109
+ contents = "#{MARKER}\n#{header_include( header, folder )}\n"
102
110
  return if current?( filepath, contents )
103
111
 
104
112
  log_placement( test, include )
@@ -106,11 +114,12 @@ class StandinHeaderinator
106
114
  @file_wrapper.write( filepath, contents )
107
115
  end
108
116
 
109
- # The line CMock opens a mock with: its :orig_header_include_fmt around the header's name.
110
- # Ceedling hands CMock no folder, so the name is the header's own.
111
- def header_include( header )
117
+ # The line CMock opens a mock with: its :orig_header_include_fmt around the header's name,
118
+ # below the folder CMock is given, if any
119
+ def header_include( header, folder )
112
120
  format = @configurator.get_cmock_config[:orig_header_include_fmt] || '#include "%s"'
113
- return format.gsub( '%s', File.basename( header ) )
121
+ name = folder.nil? ? File.basename( header ) : File.join( folder, File.basename( header ) )
122
+ return format.gsub( '%s', name )
114
123
  end
115
124
 
116
125
  # A file that is not a stand-in, such as a real mock, counts as current. Only its first
@@ -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
 
@@ -350,6 +359,11 @@ class TestBuildExecutor
350
359
  # (not reusing it) so a tool-only change reruns the fixture without also
351
360
  # marking the executable itself stale and forcing an unnecessary relink.
352
361
  #
362
+ # The command line test case filters (--test-case, --exclude_test_case) are a fourth.
363
+ # When :test_runner ↳ :cmdline_args is on, as any :use_backtrace other than :none makes
364
+ # it, a filtered and an unfiltered executable are identical, and only the filter tells
365
+ # one run's results from another's. See fixture_meta.
366
+ #
353
367
  # The target itself is a dedicated marker file, not either outcome-dependent
354
368
  # results file (.pass/.fail) -- which of those two actually gets written
355
369
  # depends on whether the test passes, so neither is guaranteed to exist after
@@ -375,11 +389,9 @@ class TestBuildExecutor
375
389
 
376
390
  @batchinator.exec(workload: :test, things: state.testables) do |_, testable|
377
391
  begin
378
- # `paths[:results]` is only per-test-unique for a test mirrored into its own
379
- # subdirectory -- a test with no mirrored subdir shares that directory with
380
- # every other such test, so the marker's own filename (not just its directory)
381
- # must be test-specific too, matching clean_test_results' own `test + '.*'`
382
- # 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.
383
395
  fixture_target = File.join( testable.paths[:results], "#{File.basename( testable.name )}.fixture_run" )
384
396
 
385
397
  fixture_tool = resolve_fixture_tool( context: state.context, tool: @configurator.tools_test_fixture, test_name: testable.name, target: fixture_target )
@@ -404,7 +416,7 @@ class TestBuildExecutor
404
416
 
405
417
  @dependinator.register(
406
418
  fixture_target, files: [testable.executable],
407
- meta: { tools: [fixture_tool], use_backtrace: use_backtrace, backtrace_tools: backtrace_tools }
419
+ meta: fixture_meta( fixture_tool: fixture_tool, use_backtrace: use_backtrace, backtrace_tools: backtrace_tools )
408
420
  )
409
421
 
410
422
  run_now = testable.executable_rebuilt || force_rerun || @dependinator.stale?( fixture_target )
@@ -466,6 +478,18 @@ class TestBuildExecutor
466
478
  # Helper methods
467
479
  # -----------------------------------------------------------------------
468
480
 
481
+ # What a test fixture's run depends on besides its executable. An unset filter, nil or
482
+ # empty, is one value, so an unfiltered run keeps a stable key.
483
+ def fixture_meta(fixture_tool:, use_backtrace:, backtrace_tools:)
484
+ return {
485
+ tools: [fixture_tool],
486
+ use_backtrace: use_backtrace,
487
+ backtrace_tools: backtrace_tools,
488
+ include_test_case: @configurator.include_test_case.to_s,
489
+ exclude_test_case: @configurator.exclude_test_case.to_s
490
+ }
491
+ end
492
+
469
493
  def generate_executable(context:, build_path:, executable:, objects:, flags:, lib_args:, lib_paths:, tool:)
470
494
  begin
471
495
  @generator.generate_executable_file(
@@ -529,41 +553,18 @@ class TestBuildExecutor
529
553
  end
530
554
 
531
555
  def convert_libraries_to_arguments()
532
- args = ((@configurator.project_config_hash[:libraries_test] || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten
556
+ args = test_library_entries()
533
557
  if (defined? LIBRARIES_FLAG)
534
558
  args.map! { |v| LIBRARIES_FLAG.gsub( /\$\{1\}/, v ) }
535
559
  end
536
560
  return args
537
561
  end
538
562
 
539
- def get_library_paths_to_arguments()
540
- paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : []
541
- if (defined? LIBRARIES_PATH_FLAG)
542
- paths.map! { |v| LIBRARIES_PATH_FLAG.gsub( /\$\{1\}/, v ) }
543
- end
544
- return paths
545
- end
546
-
547
563
  private
548
564
 
549
- # Finds the folder a mock's #include names and the directory the mock is written to.
550
- #
551
- # CMock names a mock's guard and lifecycle functions by that folder, and the runner names
552
- # its calls by the same #include. Two same-named mocks stay distinct only if the folder
553
- # reaches CMock. CMock writes below its own root at that folder, so the folder must end the
554
- # mock's directory. A folder trailing the mirrored location keeps that location. An #include
555
- # spelling more path than the mirror holds moves its mock below the per-test root at the
556
- # written path, which the root search path still reaches. A bare #include has no folder.
557
- # Without :mock_name_include_folder no folder is passed, and CMock names by filename alone.
558
- def mock_folder_and_path(mocks_root, output_path, include_path)
559
- return [nil, output_path] unless @configurator.cmock_mock_name_include_folder
560
-
561
- folder = File.dirname( include_path.to_s ).sub( %r{\A(?:\./)+}, '' )
562
-
563
- return [nil, output_path] if folder.empty? || folder == '.'
564
- return [folder, output_path] if output_path.end_with?( File.join( '', folder ) )
565
-
566
- 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
567
568
  end
568
569
 
569
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