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
@@ -6,7 +6,8 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'spec_helper'
9
- require 'ceedling/file_wrapper'
9
+ require 'tmpdir'
10
+ require 'ceedling/filesystem/file_wrapper'
10
11
  require 'ceedling/system_wrapper'
11
12
  require 'ceedling/exceptions'
12
13
 
@@ -210,54 +211,175 @@ describe FileWrapper do
210
211
  end
211
212
  end
212
213
 
213
- # Same transient-visibility race as #open_with_retry, here hitting FileUtils.cp_r's
214
- # own internal stat-then-open sequence instead of a bare File.open (Issue #1292:
215
- # a vendor destination briefly reporting the wrong file/directory type mid-copy).
216
- # Stub-based, matching #open_with_retry's own spec above -- no real filesystem or
217
- # timing involved.
218
- describe '#cp_r_with_retry' do
214
+ # A transient error mid-copy, such as a file another process holds open on Windows, is
215
+ # retried; one that never clears names the file. An error retrying cannot clear fails at
216
+ # once (GH #1376). FileTree's own specs cover the walk and the healing.
217
+ describe '#sync_tree retries' do
219
218
  before(:each) do
220
219
  allow(@file_wrapper).to receive(:sleep)
221
220
  end
222
221
 
223
- it 'behaves identically to #cp_r when nothing fails' do
224
- allow(FileUtils).to receive(:cp_r)
222
+ def with_tree
223
+ Dir.mktmpdir do |dir|
224
+ source = File.join( dir, 'src' )
225
+ FileUtils.mkdir_p( source )
226
+ File.write( File.join( source, 'unity.c' ), "int x;\n" )
227
+ yield source, File.join( dir, 'dest' )
228
+ end
229
+ end
225
230
 
226
- @file_wrapper.cp_r_with_retry('/src/.', '/dest')
231
+ it 'copies without retrying when nothing fails' do
232
+ with_tree do |source, dest|
233
+ @file_wrapper.sync_tree( source, dest )
227
234
 
228
- expect(FileUtils).to have_received(:cp_r).with('/src/.', '/dest')
229
- expect(@file_wrapper).not_to have_received(:sleep)
235
+ expect( File.read( File.join( dest, 'unity.c' ) ) ).to eq( "int x;\n" )
236
+ expect(@file_wrapper).not_to have_received(:sleep)
237
+ end
230
238
  end
231
239
 
232
- it 'retries past a SystemCallError and succeeds once the underlying copy stops raising' do
233
- call_count = 0
234
- allow(FileUtils).to receive(:cp_r) do
235
- call_count += 1
236
- raise Errno::EISDIR, 'transient' if call_count < 3
240
+ it 'retries past a transient error and succeeds once the copy stops raising' do
241
+ with_tree do |source, dest|
242
+ calls = 0
243
+ allow(@file_wrapper).to receive(:replace_file).and_wrap_original do |original, *args|
244
+ calls += 1
245
+ raise Errno::EACCES, 'transient' if calls < 3
246
+ original.call( *args )
247
+ end
248
+
249
+ @file_wrapper.sync_tree( source, dest )
250
+
251
+ expect( calls ).to eq( 3 )
252
+ expect(@file_wrapper).to have_received(:sleep).twice
253
+ expect( File.exist?( File.join( dest, 'unity.c' ) ) ).to be(true)
237
254
  end
255
+ end
238
256
 
239
- @file_wrapper.cp_r_with_retry('/src/.', '/dest')
257
+ it 'raises a CeedlingException naming the destination once every retry is exhausted, and logs it' do
258
+ with_tree do |source, dest|
259
+ allow(@file_wrapper).to receive(:replace_file).and_raise( Errno::EACCES, 'still held open' )
240
260
 
241
- expect(call_count).to eq(3)
242
- expect(@file_wrapper).to have_received(:sleep).twice
261
+ expect { @file_wrapper.sync_tree( source, dest ) }.to raise_error( CeedlingException, /#{Regexp.escape( dest )}/ )
262
+ expect(@loginator).to have_received(:log).with( a_string_including( dest ), Verbosity::ERRORS, LogLabels::AUTO )
263
+ # Initial attempt plus one retry for each configured delay
264
+ expect(@file_wrapper).to have_received(:replace_file).exactly( FileWrapper::TRANSIENT_IO_RETRY_DELAYS.size + 1 ).times
265
+ end
243
266
  end
244
267
 
245
- it 'raises a CeedlingException naming the destination and retry count once every retry is exhausted, and logs it' do
246
- allow(FileUtils).to receive(:cp_r).and_raise(Errno::ENOTDIR, 'still wrong type')
268
+ it 'fails at once on an error retrying cannot clear' do
269
+ with_tree do |source, dest|
270
+ allow(@file_wrapper).to receive(:replace_file).and_raise( Errno::ENOTDIR, 'wrong type' )
247
271
 
248
- expect { @file_wrapper.cp_r_with_retry('/src/.', '/dest') }.to raise_error(CeedlingException, /\/dest/)
249
- expect(@loginator).to have_received(:log).with(a_string_including('/dest'), Verbosity::ERRORS)
250
- # Initial attempt + one retry per configured delay.
251
- expect(FileUtils).to have_received(:cp_r).exactly(FileWrapper::TRANSIENT_IO_RETRY_DELAYS.size + 1).times
272
+ expect { @file_wrapper.sync_tree( source, dest ) }.to raise_error( Errno::ENOTDIR )
273
+ expect(@file_wrapper).not_to have_received(:sleep)
274
+ end
252
275
  end
253
276
 
254
- it 'does not retry a non-SystemCallError -- propagates immediately' do
255
- allow(FileUtils).to receive(:cp_r).and_raise(ArgumentError, 'not transient')
277
+ it 'propagates an error that is not a SystemCallError without retrying' do
278
+ with_tree do |source, dest|
279
+ allow(@file_wrapper).to receive(:replace_file).and_raise( ArgumentError, 'not transient' )
256
280
 
257
- expect {
258
- @file_wrapper.cp_r_with_retry('/src/.', '/dest')
259
- }.to raise_error(ArgumentError, 'not transient')
260
- expect(@file_wrapper).not_to have_received(:sleep)
281
+ expect { @file_wrapper.sync_tree( source, dest ) }.to raise_error( ArgumentError, 'not transient' )
282
+ expect(@file_wrapper).not_to have_received(:sleep)
283
+ end
284
+ end
285
+ end
286
+
287
+ describe '#tree_files' do
288
+ it 'lists every regular file below a directory as full paths in sorted path order' do
289
+ Dir.mktmpdir do |dir|
290
+ ['a/b.c', 'a.c', '.hidden', 'dir[1]/x.c'].each do |name|
291
+ FileUtils.mkdir_p( File.dirname( File.join( dir, name ) ) )
292
+ File.write( File.join( dir, name ), name )
293
+ end
294
+
295
+ expect( @file_wrapper.tree_files( dir ) ).to eq( ['.hidden', 'a.c', 'a/b.c', 'dir[1]/x.c'].map { |name| File.join( dir, name ) } )
296
+ end
297
+ end
298
+ end
299
+
300
+ # The temporary copy beside the destination is the longest path replace_file writes
301
+ describe '#replace_file' do
302
+ it 'checks the length of its temporary path, then leaves only the destination' do
303
+ Dir.mktmpdir do |dir|
304
+ source = File.join( dir, 'unity.h' )
305
+ destination = File.join( dir, 'out', 'unity.h' )
306
+ File.write( source, "int x;\n" )
307
+ FileUtils.mkdir_p( File.dirname( destination ) )
308
+ checked = []
309
+ allow(@file_wrapper).to receive(:check_path_length) { |path, **| checked << path }
310
+
311
+ @file_wrapper.replace_file( source, destination )
312
+
313
+ expect( checked.size ).to eq( 1 )
314
+ expect( File.dirname( checked.first ) ).to eq( File.dirname( destination ) )
315
+ expect( checked.first.length ).to be > destination.length
316
+ expect( Dir.children( File.dirname( destination ) ) ).to eq( ['unity.h'] )
317
+ end
318
+ end
319
+
320
+ # Windows refuses to rename over a read-only file
321
+ it 'leaves the destination owner-writable, from a read-only source over a read-only destination' do
322
+ Dir.mktmpdir do |dir|
323
+ source = File.join( dir, 'unity.h' )
324
+ destination = File.join( dir, 'out', 'unity.h' )
325
+ File.write( source, "new\n" )
326
+ FileUtils.mkdir_p( File.dirname( destination ) )
327
+ File.write( destination, "old\n" )
328
+ File.chmod( 0o444, source )
329
+ File.chmod( 0o444, destination )
330
+ allow(@file_wrapper).to receive(:check_path_length)
331
+
332
+ @file_wrapper.replace_file( source, destination )
333
+
334
+ expect( File.read( destination ) ).to eq( "new\n" )
335
+ expect( File.stat( destination ).mode & 0o200 ).to eq( 0o200 )
336
+ end
337
+ end
338
+
339
+ it 'replaces a destination link without changing the mode of the file it names' do
340
+ Dir.mktmpdir do |dir|
341
+ source = File.join( dir, 'unity.h' )
342
+ outside = File.join( dir, 'outside.h' )
343
+ destination = File.join( dir, 'out', 'unity.h' )
344
+ File.write( source, "new\n" )
345
+ File.write( outside, "outside\n" )
346
+ File.chmod( 0o444, outside )
347
+ FileUtils.mkdir_p( File.dirname( destination ) )
348
+ begin
349
+ File.symlink( outside, destination )
350
+ rescue NotImplementedError, SystemCallError => e
351
+ skip "symlinks are unavailable here (#{e.class})"
352
+ end
353
+ allow(@file_wrapper).to receive(:check_path_length)
354
+
355
+ @file_wrapper.replace_file( source, destination )
356
+
357
+ expect( File.read( destination ) ).to eq( "new\n" )
358
+ expect( File.stat( outside ).mode & 0o777 ).to eq( 0o444 )
359
+ end
360
+ end
361
+ end
362
+
363
+ describe '#mkdir_for' do
364
+ it 'makes every directory above a file and returns the filepath' do
365
+ Dir.mktmpdir do |dir|
366
+ filepath = File.join( dir, 'artifacts', 'test', 'unit', 'test_foo.log' )
367
+
368
+ expect( @file_wrapper.mkdir_for( filepath ) ).to eq( filepath )
369
+ expect( File.directory?( File.dirname( filepath ) ) ).to be true
370
+ expect( File.exist?( filepath ) ).to be false
371
+ end
372
+ end
373
+
374
+ it 'tolerates threads making the same directory at once' do
375
+ Dir.mktmpdir do |dir|
376
+ filepath = File.join( dir, 'a', 'b', 'c', 'test_foo.log' )
377
+
378
+ threads = Array.new( 8 ) { Thread.new { @file_wrapper.mkdir_for( filepath ) } }
379
+
380
+ expect { threads.each( &:join ) }.to_not raise_error
381
+ expect( File.directory?( File.dirname( filepath ) ) ).to be true
382
+ end
261
383
  end
262
384
  end
263
385
 
@@ -6,7 +6,7 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'spec_helper'
9
- require 'ceedling/path_matcher'
9
+ require 'ceedling/filesystem/path_matcher'
10
10
  require 'ceedling/exceptions'
11
11
 
12
12
  describe PathMatcher do
@@ -190,4 +190,15 @@ describe PathMatcher do
190
190
  end
191
191
  end
192
192
 
193
+
194
+ # A `.` segment names nothing (the path handling audit around GH #1370)
195
+ describe 'G9: `.` segments' do
196
+ it 'matches a query with a leading `./`' do
197
+ expect(PathMatcher.candidates( './foo.h', ['inc/foo.h'] )).to eq( ['inc/foo.h'] )
198
+ end
199
+
200
+ it 'matches a query with a `.` segment within it' do
201
+ expect(PathMatcher.candidates( 'sub/./bar.h', ['inc/sub/bar.h'] )).to eq( ['inc/sub/bar.h'] )
202
+ end
203
+ end
193
204
  end
@@ -6,7 +6,7 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'spec_helper'
9
- require 'ceedling/path_mirror'
9
+ require 'ceedling/filesystem/path_mirror'
10
10
 
11
11
  describe PathMirror do
12
12
 
@@ -20,9 +20,9 @@ describe PathMirror do
20
20
  expect(described_class.relative_subdir('src/drivers/sensors/foo.c', ['src/**'])).to eq('drivers/sensors')
21
21
  end
22
22
 
23
- it 'strips +:/-: aggregation decorators from configured roots before comparing' do
23
+ it 'strips a +: decorator, and never treats a -: exclusion as a root' do
24
24
  expect(described_class.relative_subdir('src/drivers/foo.c', ['+:src/**'])).to eq('drivers')
25
- expect(described_class.relative_subdir('src/drivers/foo.c', ['-:src/**'])).to eq('drivers')
25
+ expect(described_class.relative_subdir('src/drivers/foo.c', ['-:src/**'])).to eq('')
26
26
  end
27
27
 
28
28
  it 'picks the most specific (longest) matching root when configured roots are nested' do
@@ -49,7 +49,7 @@ describe PathMirror do
49
49
  it 'produces the same result as .relative_subdir when roots are cleaned once upfront' do
50
50
  clean = described_class.clean_roots(['+:src/**', '-:src/legacy/**'])
51
51
  expect(described_class.relative_subdir_from_clean_roots('src/drivers/foo.c', clean)).to eq('drivers')
52
- expect(described_class.relative_subdir_from_clean_roots('src/legacy/vendor/foo.c', clean)).to eq('vendor')
52
+ expect(described_class.relative_subdir_from_clean_roots('src/legacy/vendor/foo.c', clean)).to eq('legacy/vendor')
53
53
  end
54
54
 
55
55
  it 'drops decorated roots that clean to nothing' do
@@ -100,4 +100,32 @@ describe PathMirror do
100
100
  expect( PathMirror.path_segments('drivers//uart/') ).to eq(['drivers', 'uart'])
101
101
  end
102
102
  end
103
+
104
+ # Root matching across spellings of one place (GH #1370 and the path handling audit)
105
+ describe 'root containment' do
106
+ it 'G1 (#1370): never answers a subdirectory that climbs out, below a `..` root' do
107
+ subdir = PathMirror.relative_subdir( '../../../opt/vendor/inc/x.h', ['../**'] )
108
+
109
+ expect(subdir.split( '/' )).to_not include( '..' )
110
+ end
111
+
112
+ it 'G2: mirrors below a `./`-spelled root as below the plain one' do
113
+ expect(PathMirror.relative_subdir( 'src/a/x.c', ['./src/**'] )).to eq( 'a' )
114
+ end
115
+
116
+ it 'G2: mirrors below an absolute root spelling of a relative file\'s directory' do
117
+ expect(PathMirror.relative_subdir( 'src/a/x.c', [File.join( Dir.pwd, 'src/**' )] )).to eq( 'a' )
118
+ end
119
+
120
+ it 'G2: mirrors a file spelled relatively below an absolute root outside the working directory' do
121
+ file = File.join( '..', '..', 'opt', 'x', 'a', 'f.c' )
122
+ root = File.join( File.expand_path( '../..' ), 'opt', 'x', '**' )
123
+
124
+ expect(PathMirror.relative_subdir( file, [root] )).to eq( 'a' )
125
+ end
126
+
127
+ it 'G3: never treats a `-:` exclusion as a root' do
128
+ expect(PathMirror.relative_subdir( 'src/exp/sub/x.c', ['+:src/**', '-:src/exp'] )).to eq( 'exp/sub' )
129
+ end
130
+ end
103
131
  end
@@ -0,0 +1,147 @@
1
+ # =========================================================================
2
+ # Ceedling - Test-Centered Build System for C
3
+ # ThrowTheSwitch.org
4
+ # Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ # SPDX-License-Identifier: MIT
6
+ # =========================================================================
7
+
8
+ require 'spec_helper'
9
+ require 'tmpdir'
10
+ require 'fileutils'
11
+ require 'ceedling/filesystem/project_paths'
12
+
13
+ # GH #1370 and the path handling audit around it: one place spelled many ways compared
14
+ # as text, so `..` "contained" paths above it and build files escaped the build directory
15
+ describe ProjectPaths do
16
+ WINDOWS_ONLY = { if: Gem.win_platform? }.freeze
17
+ POSIX_ONLY = { unless: Gem.win_platform? }.freeze
18
+
19
+ around(:each) do |example|
20
+ Dir.mktmpdir do |dir|
21
+ @ws = File.realpath( dir )
22
+ FileUtils.mkdir_p( File.join( @ws, 'app' ) )
23
+ Dir.chdir( File.join( @ws, 'app' ) ) { example.run }
24
+ end
25
+ end
26
+
27
+ describe '.standardize' do
28
+ it 'writes a path with forward slashes and no trailing separator' do
29
+ expect(ProjectPaths.standardize( " src\\drv\\ " )).to eq( 'src/drv' )
30
+ end
31
+
32
+ it 'reads `~` as the home directory, after any decorator' do
33
+ expect(ProjectPaths.standardize( '~/inc' )).to eq( File.join( Dir.home, 'inc' ) )
34
+ expect(ProjectPaths.standardize( '-:~/inc' )).to eq( "-:#{File.join( Dir.home, 'inc' )}" )
35
+ end
36
+
37
+ it 'leaves `~user` as written' do
38
+ expect(ProjectPaths.standardize( '~someone/inc' )).to eq( '~someone/inc' )
39
+ end
40
+
41
+ it 'keeps a filesystem root' do
42
+ expect(ProjectPaths.standardize( '/' )).to eq( '/' )
43
+ end
44
+
45
+ it 'reads `~` after a decorator and a space, and drops every trailing separator' do
46
+ expect(ProjectPaths.standardize( '+: ~/inc' )).to eq( "+:#{File.join( Dir.home, 'inc' )}" )
47
+ expect(ProjectPaths.standardize( 'src//' )).to eq( 'src' )
48
+ end
49
+ end
50
+
51
+ describe '.absolute' do
52
+ # Spelled as the full computation spells it, whatever the shortcut for a clean path
53
+ it 'spells a rooted path with a trailing separator or surrounding space without either' do
54
+ expect(ProjectPaths.absolute( '/a/' )).to eq( '/a' ) unless Gem.win_platform?
55
+ expect(ProjectPaths.absolute( " #{@ws}/x " )).to eq( "#{@ws}/x" )
56
+ end
57
+
58
+ it 'reads `~user` as a directory of that name, never the user\'s home' do
59
+ expect(ProjectPaths.absolute( '~nosuchuser/inc' )).to eq( File.join( @ws, 'app', '~nosuchuser/inc' ) )
60
+ end
61
+
62
+ it 'reads a doubled leading separator as the filesystem root', **POSIX_ONLY do
63
+ expect(ProjectPaths.absolute( '//usr/include' )).to eq( '/usr/include' )
64
+ expect(ProjectPaths.contains?( '/usr', '//usr/include' )).to be true
65
+ end
66
+
67
+ it 'keeps a UNC path\'s `..` below its share', **WINDOWS_ONLY do
68
+ expect(ProjectPaths.absolute( '//srv/sh/a/../../../x' )).to eq( '//srv/sh/x' )
69
+ end
70
+ end
71
+
72
+ describe '.canonical' do
73
+ it 'spells every form of one place alike' do
74
+ FileUtils.mkdir_p( 'src/drv' )
75
+ spellings = ['src/drv', './src/drv', 'src/drv/', 'src\\drv', File.join( @ws, 'app/src/drv' ), 'src/../src/drv']
76
+
77
+ expect(spellings.map { |spelling| ProjectPaths.canonical( spelling ) }.uniq).to eq( ['src/drv'] )
78
+ end
79
+
80
+ it 'resolves a symlink along the existing part of a path', **POSIX_ONLY do
81
+ FileUtils.mkdir_p( 'src' )
82
+ File.symlink( File.join( @ws, 'app' ), File.join( @ws, 'link' ) )
83
+
84
+ expect(ProjectPaths.canonical( File.join( @ws, 'link/src/not_yet' ) )).to eq( 'src/not_yet' )
85
+ end
86
+
87
+ it 'climbs to a place outside the project' do
88
+ expect(ProjectPaths.canonical( File.join( @ws, 'shared/src' ) )).to eq( '../shared/src' )
89
+ end
90
+ end
91
+
92
+ describe '.subdir_below' do
93
+ it 'names the directories from a root down to a path below it' do
94
+ expect(ProjectPaths.subdir_below( 'src', 'src/drv/uart' )).to eq( 'drv/uart' )
95
+ expect(ProjectPaths.subdir_below( 'src', 'src' )).to eq( '' )
96
+ end
97
+
98
+ it 'finds nothing below a root that only shares a path\'s leading text' do
99
+ expect(ProjectPaths.subdir_below( 'src', 'src2/x' )).to be_nil
100
+ end
101
+
102
+ it 'finds nothing below `..` for a path climbing past it' do
103
+ expect(ProjectPaths.subdir_below( '..', '../../vendor/inc' )).to be_nil
104
+ expect(ProjectPaths.subdir_below( '..', '../vendor/inc' )).to eq( 'vendor/inc' )
105
+ end
106
+
107
+ it 'compares every spelling of a root and a path' do
108
+ expect(ProjectPaths.subdir_below( './src', File.join( @ws, 'app/src/a' ) )).to eq( 'a' )
109
+ expect(ProjectPaths.subdir_below( File.join( @ws, 'app/src' ), 'src/a' )).to eq( 'a' )
110
+ end
111
+
112
+ it 'never answers a subdirectory that climbs or is absolute' do
113
+ roots = ['..', '../..', '.', 'src', File.join( @ws, 'vendor' ), '/']
114
+ paths = ['../../far/x', '../vendor/inc', 'src/a', '/opt/x', File.join( @ws, 'vendor/inc' )]
115
+
116
+ roots.product( paths ).each do |root, path|
117
+ subdir = ProjectPaths.subdir_below( root, path )
118
+ next if subdir.nil?
119
+
120
+ expect(subdir.split( '/' )).to_not include( '..' ), "#{root} below #{path}: #{subdir}"
121
+ expect(subdir).to_not start_with( '/' ), "#{root} below #{path}: #{subdir}"
122
+ end
123
+ end
124
+
125
+ it 'compares Windows paths without regard to case', **WINDOWS_ONLY do
126
+ expect(ProjectPaths.subdir_below( 'C:/Proj/Src', 'c:/proj/src/a' )).to eq( 'a' )
127
+ end
128
+ end
129
+
130
+ # A build asks for the working directory tens of thousands of times, and asking the
131
+ # operating system costs tens of microseconds on macOS
132
+ describe '.working_dir' do
133
+ it 'reads the working directory once, however often it is asked' do
134
+ ProjectPaths.working_dir
135
+ expect(Dir).not_to receive(:pwd)
136
+
137
+ 3.times { expect(ProjectPaths.working_dir).to eq( File.join( @ws, 'app' ) ) }
138
+ end
139
+
140
+ it 'answers a remembered path without reading the working directory' do
141
+ ProjectPaths.absolute( 'src/drv' )
142
+ expect(Dir).not_to receive(:pwd)
143
+
144
+ expect(ProjectPaths.absolute( 'src/drv' )).to eq( File.join( @ws, 'app/src/drv' ) )
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,71 @@
1
+ # =========================================================================
2
+ # Ceedling - Test-Centered Build System for C
3
+ # ThrowTheSwitch.org
4
+ # Copyright (c) 2010-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ # SPDX-License-Identifier: MIT
6
+ # =========================================================================
7
+
8
+ require 'spec_helper'
9
+ require 'tmpdir'
10
+ require 'fileutils'
11
+ require 'ceedling/filesystem/working_dir'
12
+ require 'ceedling/filesystem/project_paths'
13
+
14
+ describe WorkingDir do
15
+ around(:each) do |example|
16
+ Dir.mktmpdir do |dir|
17
+ @ws = File.realpath( dir )
18
+ FileUtils.mkdir_p( File.join( @ws, 'app/dep' ) )
19
+ Dir.chdir( File.join( @ws, 'app' ) ) { example.run }
20
+ end
21
+ end
22
+
23
+ describe '.path' do
24
+ it 'reads the working directory once, however often it is asked' do
25
+ WorkingDir.path
26
+ expect(Dir).not_to receive(:pwd)
27
+
28
+ 3.times { expect(WorkingDir.path).to eq( File.join( @ws, 'app' ) ) }
29
+ end
30
+
31
+ it 'keeps answering for the directory Ceedling started in across a plain Dir.chdir' do
32
+ WorkingDir.path
33
+
34
+ answer = WorkingDirTracking.untracked { Dir.chdir( 'dep' ) { WorkingDir.path } }
35
+ expect(answer).to eq( File.join( @ws, 'app' ) )
36
+ end
37
+
38
+ # The spec suite's own Dir.chdir hook, which every in-process spec relies on
39
+ it 'answers for a directory a spec changes to' do
40
+ WorkingDir.path
41
+
42
+ expect(Dir.chdir( 'dep' ) { WorkingDir.path }).to eq( File.join( @ws, 'app/dep' ) )
43
+ expect(WorkingDir.path).to eq( File.join( @ws, 'app' ) )
44
+ end
45
+ end
46
+
47
+ # Untracked, so the spec suite's Dir.chdir hook can't do WorkingDir.chdir's work for it
48
+ describe '.chdir' do
49
+ around(:each) { |example| WorkingDirTracking.untracked { example.run } }
50
+
51
+ before(:each) do
52
+ WorkingDir.path
53
+ end
54
+
55
+ it 'answers for the directory it changes to, then for the one it left' do
56
+ inside = WorkingDir.chdir( 'dep' ) { [WorkingDir.path, ProjectPaths.canonical( File.join( @ws, 'app/dep/x' ) )] }
57
+
58
+ expect(inside).to eq( [File.join( @ws, 'app/dep' ), 'x'] )
59
+ expect(WorkingDir.path).to eq( File.join( @ws, 'app' ) )
60
+ expect(ProjectPaths.canonical( File.join( @ws, 'app/dep/x' ) )).to eq( 'dep/x' )
61
+ end
62
+
63
+ it 'answers for the directory it left after a block that raises' do
64
+ inside = nil
65
+ expect { WorkingDir.chdir( 'dep' ) { inside = WorkingDir.path; raise 'failed' } }.to raise_error( 'failed' )
66
+
67
+ expect(inside).to eq( File.join( @ws, 'app/dep' ) )
68
+ expect(WorkingDir.path).to eq( File.join( @ws, 'app' ) )
69
+ end
70
+ end
71
+ end
@@ -155,7 +155,13 @@ describe Generator do
155
155
 
156
156
  it 'has each simple backtrace rerun explained by the plugins' do
157
157
  run( use_backtrace: :simple )
158
- expect(backtrace).to have_received(:do_simple).with( 'test_a.c', 'build/test_a.out', anything, [], context: :test, tool: :fixture, explain: kind_of(Proc) )
158
+ expect(backtrace).to have_received(:do_simple).with( 'test_a.c', 'build/test_a.out', anything, [], tool: :fixture, explain: kind_of(Proc) )
159
+ end
160
+
161
+ # GH #1364: same-named tests keep separate gdb logs
162
+ it 'places gdb backtraces by the test name' do
163
+ run( use_backtrace: :gdb )
164
+ expect(backtrace).to have_received(:do_gdb).with( 'test_a.c', 'build/test_a.out', anything, [], context: :test, test_name: 'test_a' )
159
165
  end
160
166
 
161
167
  # A tool that runs the reruns itself can't run under gdb
@@ -235,7 +241,7 @@ describe Generator do
235
241
  def generate(**extra)
236
242
  @generator.generate_mock(
237
243
  context: :test, mock: :mock_config, test: 'test_both', input_filepath: 'src/drivers/uart/config.h',
238
- output_path: 'build/test/mocks/test_both/drivers/uart', **extra
244
+ output_path: 'build/test/mocks/test_both/drivers/uart', mock_root: 'build/test/mocks/test_both/drivers/uart', **extra
239
245
  )
240
246
  end
241
247
 
@@ -246,16 +252,16 @@ describe Generator do
246
252
  expect(@cmock).to have_received(:setup_mocks).with( 'src/drivers/uart/config.h', nil )
247
253
  end
248
254
 
249
- # CMock writes below its root at the folder, so the root is the directory less the folder
250
- it 'roots CMock above the folder and hands it the folder, which names the mock' do
251
- generate( folder: 'drivers/uart' )
255
+ # CMock writes below its root at the folder
256
+ it 'roots CMock where it is told and hands it the folder, which names the mock' do
257
+ generate( folder: 'drivers/uart', mock_root: 'build/test/mocks/test_both' )
252
258
 
253
259
  expect(@generator_mocks).to have_received(:build_configuration).with( 'build/test/mocks/test_both', overrides: {} )
254
260
  expect(@cmock).to have_received(:setup_mocks).with( 'src/drivers/uart/config.h', 'drivers/uart' )
255
261
  end
256
262
 
257
263
  it 'still reports the mock\'s own directory to plugins' do
258
- generate( folder: 'drivers/uart' )
264
+ generate( folder: 'drivers/uart', mock_root: 'build/test/mocks/test_both' )
259
265
 
260
266
  expect(@plugin_manager).to have_received(:pre_mock_generate).with( hash_including( output_path: 'build/test/mocks/test_both/drivers/uart' ) )
261
267
  end