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
@@ -0,0 +1,322 @@
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
+ # Path handling across project layouts and the spellings a project file may use for one
9
+ # place: through configuration, collection, build-path mapping, and the lookups that invert
10
+ # it. Every build file must land inside the build root, distinct inputs must stay distinct,
11
+ # and every spelling of one layout must place files alike.
12
+ #
13
+ # Each example names the gap it probes (GH #1370 and the path handling audit around it).
14
+
15
+ require 'spec_helper'
16
+ require 'path_scenario_harness'
17
+
18
+ describe 'Path scenarios (integration)' do
19
+ include PathScenarioHarness
20
+
21
+ TEST_C = "#include \"unity.h\"\nvoid setUp(void) {}\nvoid tearDown(void) {}\nvoid test_it(void) {}\n"
22
+
23
+ def c(name)
24
+ "int #{name}(void) { return 0; }\n"
25
+ end
26
+
27
+ def h(name)
28
+ "int #{name}(void);\n"
29
+ end
30
+
31
+ # --- Baseline -------------------------------------------------------------------------
32
+
33
+ it 'baseline: mirrors same-named files below one plain root, inside the build root' do
34
+ files = {
35
+ 'app/src/a/util.c' => c( 'a' ), 'app/src/b/util.c' => c( 'b' ),
36
+ 'app/src/a/util.h' => h( 'a' ), 'app/src/b/util.h' => h( 'b' ),
37
+ 'app/test/test_u.c' => TEST_C
38
+ }
39
+ in_workspace( files ) do |ws, app|
40
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: ['src/**'] } ) )
41
+ placed = placements( scene )
42
+
43
+ placed.each_value { |paths| expect_inside_build( paths ) }
44
+ expect_distinct( placed[:test_objects], 'test objects' )
45
+ expect_distinct( placed[:release_objects], 'release objects' )
46
+ expect_distinct( placed[:preprocessed], 'preprocessed headers' )
47
+ end
48
+ end
49
+
50
+ # --- G1 (#1370): a `..` root beside a header outside the project ------------------------
51
+
52
+ # The report's vendor SDK sat at its drive's root, far above the project, so its headers'
53
+ # paths climb past the `..` root. A sibling one level up is truly below `..` and mirrors.
54
+ context 'G1 (#1370): a `..` root beside an include path far outside the project' do
55
+ def files
56
+ {
57
+ 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ),
58
+ 'app/test/test_m.c' => TEST_C,
59
+ 'vendor/inc/cmsis.h' => h( 'cmsis' )
60
+ }
61
+ end
62
+
63
+ [
64
+ ['an absolute vendor path far outside', '%{far}/inc'],
65
+ ['a sibling vendor path', '../vendor/inc']
66
+ ].each do |label, vendor|
67
+ it "places a mock of the vendor header inside the build root, with #{label}" do
68
+ in_workspace( files, far: { 'inc/sdk.h' => h( 'sdk' ) } ) do |ws, app|
69
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: ['../**', vendor] } ) )
70
+ placed = placements( scene )
71
+
72
+ expect_inside_build( placed[:mocks] )
73
+ expect_inside_build( placed[:preprocessed] )
74
+ expect_inside_build( placed[:test_objects] )
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ # --- G2: equivalent spellings of one root ------------------------------------------------
81
+
82
+ context 'G2: one layout under each spelling of its roots' do
83
+ def files
84
+ {
85
+ 'app/src/a/util.c' => c( 'a' ), 'app/src/b/util.c' => c( 'b' ),
86
+ 'app/src/a/util.h' => h( 'a' ), 'app/src/b/util.h' => h( 'b' ),
87
+ 'app/test/test_u.c' => TEST_C
88
+ }
89
+ end
90
+
91
+ def placed_with(spelling, ws, app)
92
+ spell = PathScenarioHarness::ROOT_SPELLINGS[spelling]
93
+ roots = ->(root) { [spell.call( root, ws: ws, app: app )] }
94
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: roots.( 'test/**' ), source: roots.( 'src/**' ), include: roots.( 'src/**' ) } ) )
95
+ return [scene, relative_placements( scene )]
96
+ end
97
+
98
+ (PathScenarioHarness::ROOT_SPELLINGS.keys - [:plain]).each do |spelling|
99
+ it "places every build file as the plain spelling does, with #{spelling} roots" do
100
+ in_workspace( files, symlink: spelling == :symlink ) do |ws, app|
101
+ _, plain = placed_with( :plain, ws, app )
102
+ scene, spelled = placed_with( spelling, ws, app )
103
+
104
+ expect_one_spelling_each( scene[:configurator] )
105
+ expect(spelled).to eq( plain )
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # --- G3 and G13: exclusions ---------------------------------------------------------------
112
+
113
+ context 'G3 and G13: a `-:` exclusion' do
114
+ def files
115
+ {
116
+ 'app/src/sub/x.c' => c( 'x1' ), 'app/src/exp/sub/x.c' => c( 'x2' ), 'app/src/exp/deep/y.c' => c( 'y' ),
117
+ 'app/src/main.h' => h( 'main' ), 'app/test/test_m.c' => TEST_C
118
+ }
119
+ end
120
+
121
+ it 'G13: excludes the whole subtree it names' do
122
+ in_workspace( files ) do |ws, app|
123
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['+:src/**', '-:src/exp'], include: ['src/**'] } ) )
124
+
125
+ expect(scene[:configurator].collection_all_source).to match_array( %w[src/sub/x.c] )
126
+ end
127
+ end
128
+
129
+ # A file the exclusion fails to drop (G13) must not mirror below the exclusion itself
130
+ it 'G3: is never a root that kept files mirror below' do
131
+ in_workspace( files ) do |ws, app|
132
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['+:src/**', '-:src/exp'], include: ['src/**'] } ) )
133
+ placed = placements( scene )
134
+
135
+ expect_distinct( placed[:release_objects], 'release objects' )
136
+ end
137
+ end
138
+ end
139
+
140
+ # --- G4: header-to-source correlation ---------------------------------------------------
141
+
142
+ context 'G4: a header found beside its source by convention' do
143
+ def files
144
+ {
145
+ 'app/include/drv/x.h' => h( 'x' ), 'app/src/drv/x.c' => c( 'x' ),
146
+ 'app/components/foo/include/foo.h' => h( 'foo' ), 'app/components/foo/src/foo.c' => c( 'foo' ),
147
+ 'app/test/test_x.c' => TEST_C
148
+ }
149
+ end
150
+
151
+ {
152
+ 'a plain include root' => ['include/**'],
153
+ 'a `./` include root' => ['./include/**'],
154
+ 'an absolute include root' => ['%{app}/include/**']
155
+ }.each do |label, include|
156
+ it "finds the source of a header below #{label}" do
157
+ in_workspace( files ) do |ws, app|
158
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: include } ) )
159
+
160
+ expect(scene[:finder].find_build_input_file( filepath: 'include/drv/x.h', complain: :ignore, context: :test )).to eq( 'src/drv/x.c' )
161
+ end
162
+ end
163
+ end
164
+
165
+ it 'finds the source of a header below a glob-middle include root' do
166
+ in_workspace( files ) do |ws, app|
167
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['components/*/src'], include: ['components/*/include'] } ) )
168
+
169
+ expect(scene[:finder].find_build_input_file( filepath: 'components/foo/include/foo.h', complain: :ignore, context: :test )).to eq( 'components/foo/src/foo.c' )
170
+ end
171
+ end
172
+ end
173
+
174
+ # --- G5 and G6: collisions --------------------------------------------------------------
175
+
176
+ context 'G5: the same relative path below two roots' do
177
+ it 'gives each source its own release object' do
178
+ files = { 'app/src/foo.c' => c( 'a' ), 'app/lib/foo.c' => c( 'b' ), 'app/src/foo.h' => h( 'a' ), 'app/test/test_f.c' => TEST_C }
179
+ in_workspace( files ) do |ws, app|
180
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**', 'lib/**'], include: ['src/**'] } ) )
181
+
182
+ expect_distinct( placements( scene )[:release_objects], 'release objects' )
183
+ end
184
+ end
185
+ end
186
+
187
+ context 'G6: nested roots' do
188
+ it 'gives a file in the inner root and one in the outer root their own objects' do
189
+ files = { 'app/src/util.c' => c( 'a' ), 'app/src/legacy/util.c' => c( 'b' ), 'app/src/util.h' => h( 'a' ), 'app/test/test_u.c' => TEST_C }
190
+ in_workspace( files ) do |ws, app|
191
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**', 'src/legacy/**'], include: ['src/**'] } ) )
192
+ placed = placements( scene )
193
+
194
+ expect_distinct( placed[:test_objects], 'test objects' )
195
+ expect_distinct( placed[:release_objects], 'release objects' )
196
+ end
197
+ end
198
+ end
199
+
200
+ # --- G8: outside every root -------------------------------------------------------------
201
+
202
+ context 'G8: sources reached only through :files' do
203
+ it 'gives same-named files outside every root their own objects' do
204
+ files = { 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/a/util.c' => c( 'a' ), 'app/b/util.c' => c( 'b' ), 'app/test/test_m.c' => TEST_C }
205
+ in_workspace( files ) do |ws, app|
206
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: ['src/**'] }, files: { source: ['a/util.c', 'b/util.c'] } ) )
207
+
208
+ expect_distinct( placements( scene )[:release_objects], 'release objects' )
209
+ end
210
+ end
211
+ end
212
+
213
+ # --- Sources outside the project --------------------------------------------------------
214
+
215
+ context 'sources and headers in a sibling directory' do
216
+ it 'places their build files inside the build root, each its own' do
217
+ files = {
218
+ 'shared/src/a/util.c' => c( 'a' ), 'shared/src/b/util.c' => c( 'b' ),
219
+ 'shared/src/a/util.h' => h( 'a' ), 'shared/src/b/util.h' => h( 'b' ),
220
+ 'app/test/test_u.c' => TEST_C
221
+ }
222
+ in_workspace( files ) do |ws, app|
223
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['../shared/src/**'], include: ['../shared/src/**'] } ) )
224
+ placed = placements( scene )
225
+
226
+ placed.each_value { |paths| expect_inside_build( paths ) }
227
+ expect_distinct( placed[:release_objects], 'release objects' )
228
+ end
229
+ end
230
+ end
231
+
232
+ # --- G15: a root above the build root --------------------------------------------------
233
+
234
+ context 'G15: a root that holds the build root' do
235
+ it 'collects nothing from an existing build directory' do
236
+ files = {
237
+ 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/test/test_m.c' => TEST_C,
238
+ 'app/build/test/mocks/test/test_m/mock_main.h' => h( 'mock' ), 'app/build/test/runners/test/test_m/test_m_runner.c' => c( 'r' )
239
+ }
240
+ in_workspace( files ) do |ws, app|
241
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: ['../**'] } ) )
242
+
243
+ expect_collections_outside_build( scene[:configurator] )
244
+ end
245
+ end
246
+
247
+ # A release compiles every collected source, so generated mocks and runners broke it
248
+ it 'collects nothing from an existing build directory through a `:files` glob' do
249
+ files = {
250
+ 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/test/test_m.c' => TEST_C,
251
+ 'app/build/test/mocks/test/test_m/mock_main.c' => c( 'mock' ), 'app/build/vendor/unity/src/unity.c' => c( 'unity' )
252
+ }
253
+ in_workspace( files ) do |ws, app|
254
+ yaml = scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: ['src/**'] }, files: { source: ['+:**/*.c'] } )
255
+ scene = scenario( yaml )
256
+
257
+ expect_collections_outside_build( scene[:configurator] )
258
+ expect(scene[:configurator].collection_release_build_input.to_a.grep( %r{\Abuild/} )).to be_empty
259
+ expect(scene[:configurator].collection_existing_test_build_input.to_a.grep( %r{\Abuild/test/} )).to be_empty
260
+ end
261
+ end
262
+
263
+ # Generated code may sit in the build root, beside the directories Ceedling creates there
264
+ it 'collects generated code an entry names in the build root, but nothing Ceedling created there' do
265
+ files = {
266
+ 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/test/test_m.c' => TEST_C,
267
+ 'app/build/gen/table.c' => c( 'table' ), 'app/build/gen/table.h' => h( 'table' ),
268
+ 'app/build/test/mocks/test/test_m/mock_main.c' => c( 'mock' ), 'app/build/test/mocks/test/test_m/mock_main.h' => h( 'mock' )
269
+ }
270
+ in_workspace( files ) do |ws, app|
271
+ paths = { test: ['test/**'], source: ['src/**', 'build/**'], include: ['src/**', 'build/gen'] }
272
+ yaml = scenario_yaml( ws: ws, app: app, paths: paths, files: { source: ['+:build/**/*.c'] } )
273
+ scene = scenario( yaml )
274
+
275
+ expect(scene[:configurator].collection_all_source.to_a).to contain_exactly( 'src/main.c', 'build/gen/table.c' )
276
+ expect(scene[:configurator].collection_all_headers.to_a).to include( 'build/gen/table.h' )
277
+ expect(scene[:configurator].collection_all_headers.to_a.grep( %r{\Abuild/test/} )).to be_empty
278
+ end
279
+ end
280
+ end
281
+
282
+ # --- Test files kept out of the sources and the release --------------------------------
283
+
284
+ context 'test files among the sources' do
285
+ # A release compiles every source it collects, and a test file holds a second main()
286
+ it 'collects no test file into the sources or the release through a `:files` glob' do
287
+ files = { 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/test/test_m.c' => TEST_C }
288
+ in_workspace( files ) do |ws, app|
289
+ yaml = scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**'], include: ['src/**'] }, files: { source: ['+:**/*.c'] } )
290
+ scene = scenario( yaml )
291
+
292
+ expect(scene[:configurator].collection_all_tests.to_a).to eq( ['test/test_m.c'] )
293
+ expect(scene[:configurator].collection_all_source.to_a).to eq( ['src/main.c'] )
294
+ expect(scene[:configurator].collection_release_build_input.to_a).to eq( ['src/main.c'] )
295
+ end
296
+ end
297
+
298
+ # A test root beside the sources reaches the release through :paths as well
299
+ it 'collects no test file into the release from a source root that holds the tests' do
300
+ files = { 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/src/test/test_m.c' => TEST_C }
301
+ in_workspace( files ) do |ws, app|
302
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['src/test/**'], source: ['src/**'], include: ['src/**'] } ) )
303
+
304
+ expect(scene[:configurator].collection_release_build_input.to_a).to eq( ['src/main.c'] )
305
+ end
306
+ end
307
+
308
+ end
309
+
310
+ # --- G12: the working directory reached through a symlink -------------------------------
311
+
312
+ context 'G12: absolute roots spelled through a symlink to the project' do
313
+ it 'collects each file once' do
314
+ files = { 'app/src/main.c' => c( 'main' ), 'app/src/main.h' => h( 'main' ), 'app/test/test_m.c' => TEST_C }
315
+ in_workspace( files, symlink: true ) do |ws, app|
316
+ scene = scenario( scenario_yaml( ws: ws, app: app, paths: { test: ['test/**'], source: ['src/**', '%{ws}/link/src/**'], include: ['src/**'] } ) )
317
+
318
+ expect_one_spelling_each( scene[:configurator] )
319
+ end
320
+ end
321
+ end
322
+ end
@@ -24,7 +24,7 @@ require 'spec_integration_helper'
24
24
  require 'fileutils'
25
25
  require 'tmpdir'
26
26
  require 'open3'
27
- require 'ceedling/file_wrapper'
27
+ require 'ceedling/filesystem/file_wrapper'
28
28
  require 'ceedling/quote_include_isolator'
29
29
  require 'ceedling/constants'
30
30
 
@@ -0,0 +1,95 @@
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
+ # The task registry decides from the requested task names whether a command builds tests or a
9
+ # release, and so whether build/vendor/ is populated (GH #1361). It reads that from the real
10
+ # .rake files. The first pass runs before plugin constants are loaded, so a plugin namespace
11
+ # such as `namespace GCOV_SYM do` is resolved by its NAME_SYM naming convention. The second
12
+ # pass resolves the constants themselves. Both must agree.
13
+
14
+ require 'spec_helper'
15
+ require 'ceedling/constants'
16
+ require 'ceedling/rake_app/rake_task_registry'
17
+
18
+ describe 'RakeTaskRegistry against the real rakefiles (integration)' do
19
+ REGISTRY_SPEC_ROOT = File.expand_path( '../..', __dir__ )
20
+
21
+ REGISTRY_SPEC_RAKEFILES = Dir.glob( File.join( REGISTRY_SPEC_ROOT, 'lib/ceedling/rakefiles/**/*.rake' ) ) +
22
+ %w[gcov valgrind sanitize bullseye].map { |plugin| File.join( REGISTRY_SPEC_ROOT, "plugins/#{plugin}/#{plugin}.rake" ) }
23
+
24
+ REGISTRY_SPEC_PLUGIN_CONSTANTS = {
25
+ 'GCOV_SYM' => :gcov,
26
+ 'VALGRIND_SYM' => :valgrind,
27
+ 'SANITIZE_SYM' => :sanitize,
28
+ 'BULLSEYE_SYM' => :bullseye
29
+ }.freeze
30
+
31
+ REGISTRY_SPEC_TEST_BUILDS = %w[
32
+ test test:all test:test_foo.c test:unit/test_foo.c
33
+ gen:mocks:test_foo.c
34
+ gcov:all gcov:test_foo.c gcov:test/test_foo.c
35
+ valgrind:all valgrind:test/test_foo.c
36
+ sanitize:all sanitize:test/test_foo.c
37
+ bullseye:all bullseye:test/test_foo.c
38
+ ].freeze
39
+
40
+ REGISTRY_SPEC_NOT_BUILDS = %w[files:test dumpconfig clobber clean utils:gcov report:gcov module:create].freeze
41
+
42
+ def registry
43
+ registry = RakeTaskRegistry.new
44
+ registry.register_test_tasks( REGISTRY_SPEC_RAKEFILES )
45
+ registry.register_release_tasks( REGISTRY_SPEC_RAKEFILES )
46
+ return registry
47
+ end
48
+
49
+ def expect_classified(registry)
50
+ REGISTRY_SPEC_TEST_BUILDS.each do |task|
51
+ expect( registry.task_is?( task, RakeTaskRegistry::TAG_TEST ) ).to be(true), "#{task} should be a test build"
52
+ expect( registry.task_is?( task, RakeTaskRegistry::TAG_BUILD ) ).to be(true), "#{task} should be a build"
53
+ end
54
+
55
+ expect( registry.task_is?( 'release', RakeTaskRegistry::TAG_RELEASE ) ).to be(true)
56
+ expect( registry.task_is?( 'release', RakeTaskRegistry::TAG_TEST ) ).to be(false)
57
+
58
+ REGISTRY_SPEC_NOT_BUILDS.each do |task|
59
+ expect( registry.task_is?( task, RakeTaskRegistry::TAG_BUILD ) ).to be(false), "#{task} should not be a build"
60
+ end
61
+ end
62
+
63
+ it 'finds every test-building plugin namespace before plugin constants are loaded' do
64
+ REGISTRY_SPEC_PLUGIN_CONSTANTS.each_key { |name| hide_const( name ) }
65
+ expect_classified( registry )
66
+ end
67
+
68
+ # A build reached through a call the registry can't place would leave build/vendor
69
+ # unpopulated. Each call sits in a namespace, or in a top-level task (`task RELEASE_SYM`)
70
+ # named for a namespace the registry knows.
71
+ it 'places every test and release pipeline call where the registry finds it' do
72
+ registered = registry
73
+ markers = [RakeTaskRegistry::MARKER_TEST_TASKS_SETUP_AND_INVOKE, RakeTaskRegistry::MARKER_RELEASE_TASKS]
74
+
75
+ REGISTRY_SPEC_RAKEFILES.each do |rakefile|
76
+ lines = File.readlines( rakefile, encoding: 'bom|utf-8' )
77
+ lines.each_with_index do |line, index|
78
+ next unless markers.any? { |marker| line.match?( marker ) }
79
+
80
+ namespace = registered.send( :find_enclosing_namespace, lines, index )
81
+ task_line = lines[0...index].reverse.find { |prior| prior.match?( /\Atask\s/ ) }
82
+ task_name = task_line && task_line[/\Atask\s*\(?\s*:?([A-Za-z_]+)/, 1]
83
+ task_name = Object.const_get( task_name ).to_s if task_name&.match?( /\A[A-Z_]+\z/ )
84
+ found = !namespace.nil? || !registered.tags_for( task_name.to_s ).empty?
85
+
86
+ expect( found ).to be(true), "#{File.basename( rakefile )}:#{index + 1} runs a pipeline the registry cannot place"
87
+ end
88
+ end
89
+ end
90
+
91
+ it 'finds every test-building plugin namespace once plugin constants are loaded' do
92
+ REGISTRY_SPEC_PLUGIN_CONSTANTS.each { |name, value| stub_const( name, value ) }
93
+ expect_classified( registry )
94
+ end
95
+ end
@@ -16,7 +16,7 @@ require 'open3'
16
16
  require 'json'
17
17
  require 'ceedling/constants'
18
18
  require 'ceedling/plugins/plugin'
19
- require 'ceedling/file_wrapper'
19
+ require 'ceedling/filesystem/file_wrapper'
20
20
 
21
21
  $LOAD_PATH.unshift( File.expand_path( '../../plugins/report_build_warnings_log/lib', __dir__ ) )
22
22
 
@@ -16,7 +16,7 @@ require 'spec_helper'
16
16
  require 'json'
17
17
  require 'tmpdir'
18
18
  require 'rexml/document'
19
- require 'ceedling/file_wrapper'
19
+ require 'ceedling/filesystem/file_wrapper'
20
20
  require 'ceedling/config/config_walkinator'
21
21
 
22
22
  $: << File.expand_path('../../../plugins/report_tests_log_factory/lib', __FILE__)
@@ -14,7 +14,7 @@ require 'spec_integration_helper'
14
14
  require 'open3'
15
15
  require 'tmpdir'
16
16
  require 'ceedling/constants'
17
- require 'ceedling/file_wrapper'
17
+ require 'ceedling/filesystem/file_wrapper'
18
18
  require 'ceedling/generators/generator'
19
19
  require 'ceedling/system_wrapper'
20
20
  require 'fileutils'
@@ -140,7 +140,8 @@ describe 'Test file #include extraction (integration)' do
140
140
 
141
141
  extract_in_mode( tree, 'test_reader.c' ) do |harness, testable|
142
142
  expect(harness.mocks( 'test/test_reader.c' )).to eq( ['mock_widget.h'] )
143
- expect(testable.mock_search_paths).to eq( ['build/mocks/test_reader/drivers'] )
143
+ # The macro's #include resolves as `drivers/mock_widget.h`, reached from the mock root
144
+ expect(testable.mock_search_paths).to eq( ['build/mocks/test_reader/drivers', 'build/mocks/test_reader'] )
144
145
  end
145
146
  end
146
147
 
@@ -0,0 +1,198 @@
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
+ # How tests are named, across project layouts with same-named tests (GH #1364). A project's YAML runs through the real
9
+ # configuration pipeline in a temporary project, so test paths and collections come from
10
+ # real globs. A real FilePathUtils names each test, and a real TestBuildSetup prepares its
11
+ # directories, as stage 1 of a build does.
12
+
13
+ require 'spec_helper'
14
+ require 'configurator_integration_helper'
15
+ require 'ceedling/filesystem/file_path_utils'
16
+ require 'ceedling/filesystem/file_finder'
17
+ require 'ceedling/filesystem/file_finder_helper'
18
+ require 'ceedling/test_invoker/test_build_setup'
19
+ require 'ceedling/test_invoker/test_invoker_types'
20
+
21
+ describe 'Test naming (integration)' do
22
+ include ConfiguratorIntegrationHelpers
23
+
24
+ # Runs each test of a batch in turn, in place of the thread pool
25
+ class TestNamingBatchinator
26
+ def exec(things:, **_options)
27
+ things.each { |thing| yield thing }
28
+ end
29
+ end
30
+
31
+ # name => [test paths, `:paths ↳ :test` entries, `:files ↳ :test` entries]
32
+ TEST_NAMING_LAYOUTS = {
33
+ 'flat and nested under one root' => [%w[test/test_calc.c test/unit/test_calc.c], %w[test/**], []],
34
+ 'the same subdirectory under two roots' => [%w[test/unit/test_calc.c extra/unit/test_calc.c], %w[test/unit/** extra/**], []],
35
+ 'overlapping roots' => [%w[test/test_calc.c test/unit/test_calc.c], %w[test/** test/unit/**], []],
36
+ 'the same layout under two roots' => [%w[test/foo/test_x.c extra/foo/test_x.c], %w[test/** extra/**], []],
37
+ 'a :files test outside every root' => [%w[test/test_calc.c other/test_calc.c], %w[test/**], %w[other/test_calc.c]]
38
+ }.freeze
39
+
40
+ def project_yaml(test_paths, test_files)
41
+ return <<~YAML
42
+ :project:
43
+ :build_root: build
44
+ :paths:
45
+ :test: #{test_paths.inspect}
46
+ :source: [src/**]
47
+ :include: [src/**]
48
+ :files:
49
+ :test: #{test_files.inspect}
50
+ YAML
51
+ end
52
+
53
+ def project_files(tests)
54
+ files = { 'src/calc.c' => "int calc(void) { return 1; }\n", 'src/calc.h' => "int calc(void);\n" }
55
+ tests.each { |test| files[test] = "#include \"unity.h\"\nvoid test_it(void) {}\n" }
56
+ return files
57
+ end
58
+
59
+ # Stage 1 of a build of `tests`, with real naming and real directories
60
+ def prepare(configurator, tests)
61
+ file_wrapper = FileWrapper.new( loginator: double( 'loginator', log: nil ), verbosinator: double( 'verbosinator', should_output?: false ) )
62
+ file_path_utils = FilePathUtils.new( configurator: configurator, file_wrapper: file_wrapper )
63
+
64
+ collaborators = TestBuildSetup.constructor_keys.to_h { |key| [key, double( key.to_s )] }
65
+ setup = TestBuildSetup.new( collaborators.merge(
66
+ configurator: configurator, file_wrapper: file_wrapper, file_path_utils: file_path_utils, batchinator: TestNamingBatchinator.new
67
+ ) )
68
+
69
+ state = TestInvokerTypes::PipelineState.new( tests: tests, testables: {}, context: :test, options: [], lock: Mutex.new )
70
+ setup.stage_prepare_build_paths( state )
71
+ return [state, file_path_utils]
72
+ end
73
+
74
+ def finder(configurator, file_path_utils)
75
+ loginator = double( 'loginator', log: nil )
76
+ return FileFinder.new(
77
+ configurator: configurator, file_finder_helper: FileFinderHelper.new( loginator: loginator ), file_path_utils: file_path_utils,
78
+ file_wrapper: FileWrapper.new( loginator: loginator, verbosinator: double( 'verbosinator', should_output?: false ) ), yaml_wrapper: nil
79
+ )
80
+ end
81
+
82
+ # Each test's own object resolves to that test, by name and from its object path alone
83
+ def expect_own_objects_resolve(configurator, state, file_path_utils)
84
+ finder = finder( configurator, file_path_utils )
85
+ state.testables.each_value do |testable|
86
+ object = File.join( testable.paths[:build], File.basename( testable.filepath ).ext( '.o' ) )
87
+ expect(finder.find_build_input_file( filepath: object, context: :test, test: testable.name )).to eq( testable.filepath )
88
+ expect(finder.find_build_input_file( filepath: object, context: :test )).to eq( testable.filepath )
89
+ end
90
+ end
91
+
92
+ TEST_NAMING_LAYOUTS.each do |layout, (tests, test_paths, test_files)|
93
+ context "with #{layout}" do
94
+ it 'names each test by its path, inside the build directory, with results where summaries look' do
95
+ in_temp_project( project_files( tests ) ) do
96
+ configurator = configure( project_yaml( test_paths, test_files ) )[:configurator]
97
+ expect(configurator.collection_all_tests).to match_array( tests )
98
+
99
+ state, file_path_utils = prepare( configurator, configurator.collection_all_tests )
100
+
101
+ expect(state.testables.keys.map( &:to_s )).to match_array( tests.map { |test| test.ext( '' ) } )
102
+
103
+ build = File.expand_path( 'build' ) + '/'
104
+ state.testables.each_value do |testable|
105
+ testable.paths.each_value { |path| expect(File.expand_path( path )).to start_with( build ) }
106
+ end
107
+
108
+ expected = state.testables.values.map { |testable| file_path_utils.form_pass_results_filepath( testable.paths[:results], testable.filepath ) }
109
+ expect(file_path_utils.form_pass_results_filelist( configurator.project_test_results_path, tests )).to match_array( expected )
110
+ expect(expected.uniq.size).to eq( tests.size )
111
+
112
+ expect_own_objects_resolve( configurator, state, file_path_utils )
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ # One test's name continues another's, so its directories nest inside the other's
119
+ context 'with a test directory named like a test beside it' do
120
+ it "keeps each test's mocks its own" do
121
+ tests = %w[test/test_foo.c test/test_foo/test_bar.c]
122
+ in_temp_project( project_files( tests ) ) do
123
+ configurator = configure( project_yaml( %w[test/**], [] ) )[:configurator]
124
+ state, file_path_utils = prepare( configurator, configurator.collection_all_tests )
125
+ expect_own_objects_resolve( configurator, state, file_path_utils )
126
+
127
+ mock = "#{configurator.cmock_mock_prefix}widget"
128
+ state.testables.each_value do |testable|
129
+ FileUtils.mkdir_p( testable.paths[:mocks] )
130
+ File.write( File.join( testable.paths[:mocks], "#{mock}.c" ), "\n" )
131
+ end
132
+
133
+ finder = finder( configurator, file_path_utils )
134
+ state.testables.each_value do |testable|
135
+ object = File.join( testable.paths[:build], "#{mock}.o" )
136
+ expect(finder.find_build_input_file( filepath: object, context: :test, test: testable.name )).to eq( File.join( testable.paths[:mocks], "#{mock}.c" ) )
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ context 'with tests outside the project' do
143
+ def outside_files
144
+ return project_files( [] ).transform_keys { |path| File.join( 'app', path ) }.merge(
145
+ 'shared/test/unit/test_s.c' => "void test_it(void) {}\n",
146
+ 'other/test_o.c' => "void test_it(void) {}\n"
147
+ )
148
+ end
149
+
150
+ it 'keeps their names and directories inside the build directory' do
151
+ in_temp_project( outside_files ) do
152
+ Dir.chdir( 'app' ) do
153
+ configurator = configure( project_yaml( %w[../shared/test/**], %w[../other/test_o.c] ) )[:configurator]
154
+
155
+ state, file_path_utils = prepare( configurator, configurator.collection_all_tests )
156
+
157
+ expect(state.testables.keys.map( &:to_s )).to match_array( %w[_up_/shared/test/unit/test_s _up_/other/test_o] )
158
+ expect_own_objects_resolve( configurator, state, file_path_utils )
159
+ build = File.expand_path( 'build' ) + '/'
160
+ state.testables.each_value do |testable|
161
+ testable.paths.each_value { |path| expect(File.expand_path( path )).to start_with( build ) }
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ # A project directory named like the marker a test outside the project is named by keeps
168
+ # a name of its own
169
+ it 'names a test below a project directory called `_up_` apart from one above the project' do
170
+ files = outside_files.merge( 'app/_up_/other/test_o.c' => "void test_it(void) {}\n" )
171
+
172
+ in_temp_project( files ) do
173
+ Dir.chdir( 'app' ) do
174
+ configurator = configure( project_yaml( %w[../shared/test/** _up_/**], %w[../other/test_o.c] ) )[:configurator]
175
+
176
+ state, _file_path_utils = prepare( configurator, ['_up_/other/test_o.c', '../other/test_o.c'] )
177
+
178
+ expect(state.testables.keys.map( &:to_s )).to match_array( %w[__up_/other/test_o _up_/other/test_o] )
179
+ end
180
+ end
181
+ end
182
+
183
+ it 'stops a build that has two tests sharing one name, naming both' do
184
+ files = outside_files.merge( 'app/test/test_d.c' => "void test_it(void) {}\n", 'app/test/test_d.cpp' => "void test_it(void) {}\n" )
185
+
186
+ in_temp_project( files ) do
187
+ Dir.chdir( 'app' ) do
188
+ yaml = project_yaml( %w[test/**], [] ) + ":extension:\n :source: ['.c', '.cpp']\n"
189
+ configurator = configure( yaml )[:configurator]
190
+
191
+ expect { prepare( configurator, ['test/test_d.c'] ) }.to raise_error( CeedlingException ) { |error|
192
+ expect(error.message).to include( 'test/test_d.c', 'test/test_d.cpp', '`test/test_d`' )
193
+ }
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end