ceedling 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. checksums.yaml +4 -4
  2. data/GIT_COMMIT_SHA +1 -1
  3. data/README.md +11 -9
  4. data/Rakefile +2 -1
  5. data/assets/features/ceedling +1 -1
  6. data/assets/fixtures/test_source_file_duplicate_basenames/test_calc_typo.c +14 -0
  7. data/assets/fixtures/tests_with_duplicate_test_names/test_foo.c +21 -0
  8. data/bin/actionator.rb +6 -12
  9. data/bin/app_cfg.rb +14 -1
  10. data/bin/ceedling +13 -3
  11. data/bin/cli.rb +25 -6
  12. data/bin/cli_handler.rb +113 -73
  13. data/bin/cli_helper.rb +51 -78
  14. data/bin/installation_selector.rb +81 -0
  15. data/bin/launchinator.rb +69 -0
  16. data/bin/mixin_resolvinator.rb +26 -36
  17. data/bin/objects.yml +13 -0
  18. data/bin/path_validator.rb +25 -29
  19. data/bin/versionator.rb +47 -48
  20. data/ceedling.gemspec +19 -15
  21. data/docs/BreakingChanges.md +70 -1
  22. data/docs/Changelog.md +74 -3
  23. data/docs/KnownIssues.md +90 -4
  24. data/docs/ReleaseNotes.md +13 -0
  25. data/lib/ceedling/build_log_writer.rb +33 -0
  26. data/lib/ceedling/config/build_root_policy.rb +70 -0
  27. data/lib/ceedling/config/configurator.rb +14 -16
  28. data/lib/ceedling/config/configurator_builder.rb +58 -28
  29. data/lib/ceedling/config/configurator_paths_validator.rb +179 -0
  30. data/lib/ceedling/config/configurator_plugins.rb +1 -1
  31. data/lib/ceedling/config/configurator_setup.rb +15 -28
  32. data/lib/ceedling/config/configurator_validator.rb +1 -110
  33. data/lib/ceedling/defaults.rb +4 -4
  34. data/lib/ceedling/dependencies/README.md +18 -16
  35. data/lib/ceedling/dependencies/dependency_cache_store.rb +20 -3
  36. data/lib/ceedling/dependencies/dependency_hasher.rb +35 -1
  37. data/lib/ceedling/filename_extension.rb +7 -1
  38. data/lib/ceedling/filesystem/FILE_TREE.md +253 -0
  39. data/lib/ceedling/filesystem/PATH_HANDLING.md +304 -0
  40. data/lib/ceedling/filesystem/README.md +41 -0
  41. data/lib/ceedling/filesystem/build_subpath.rb +102 -0
  42. data/lib/ceedling/filesystem/destination_collision.rb +25 -0
  43. data/lib/ceedling/{file_finder.rb → filesystem/file_finder.rb} +159 -104
  44. data/lib/ceedling/{file_finder_helper.rb → filesystem/file_finder_helper.rb} +36 -31
  45. data/lib/ceedling/filesystem/file_path_collection_utils.rb +183 -0
  46. data/lib/ceedling/{file_path_utils.rb → filesystem/file_path_utils.rb} +108 -97
  47. data/lib/ceedling/{file_system_wrapper.rb → filesystem/file_system_wrapper.rb} +6 -5
  48. data/lib/ceedling/filesystem/file_tree.rb +241 -0
  49. data/lib/ceedling/{file_wrapper.rb → filesystem/file_wrapper.rb} +45 -38
  50. data/lib/ceedling/filesystem/path_exclusions.rb +30 -0
  51. data/lib/ceedling/{path_matcher.rb → filesystem/path_matcher.rb} +27 -23
  52. data/lib/ceedling/{path_mirror.rb → filesystem/path_mirror.rb} +19 -18
  53. data/lib/ceedling/filesystem/path_spellings.rb +55 -0
  54. data/lib/ceedling/filesystem/project_paths.rb +184 -0
  55. data/lib/ceedling/filesystem/working_dir.rb +40 -0
  56. data/lib/ceedling/generators/generator.rb +5 -6
  57. data/lib/ceedling/generators/generator_partials.rb +1 -1
  58. data/lib/ceedling/generators/generator_test_results_backtrace.rb +7 -7
  59. data/lib/ceedling/handoff.rb +121 -0
  60. data/lib/ceedling/includes/include_factory.rb +3 -3
  61. data/lib/ceedling/includes/include_pathinator.rb +67 -10
  62. data/lib/ceedling/includes/includes.rb +1 -1
  63. data/lib/ceedling/installation.rb +92 -0
  64. data/lib/ceedling/library_resolver.rb +99 -0
  65. data/lib/ceedling/objects.yml +23 -2
  66. data/lib/ceedling/partials/partializer.rb +4 -4
  67. data/lib/ceedling/partials/partializer_config.rb +3 -1
  68. data/lib/ceedling/plugins/report_log_writer_plugin.rb +3 -5
  69. data/lib/ceedling/preprocess/preprocessinator_file_assembler.rb +1 -1
  70. data/lib/ceedling/preprocess/preprocessinator_includes_handler.rb +1 -1
  71. data/lib/ceedling/preprocess/preprocessinator_line_marker_includes_extractor.rb +1 -1
  72. data/lib/ceedling/rake_app/rakefile_component_resolver.rb +10 -17
  73. data/lib/ceedling/rakefile.rb +15 -1
  74. data/lib/ceedling/rakefiles/base/tasks_base.rake +1 -1
  75. data/lib/ceedling/rakefiles/release/rules_release.rake +4 -7
  76. data/lib/ceedling/release_invoker/release_build_executor.rb +33 -44
  77. data/lib/ceedling/release_invoker/release_build_planner.rb +14 -6
  78. data/lib/ceedling/reportinator.rb +3 -4
  79. data/lib/ceedling/setupinator.rb +94 -90
  80. data/lib/ceedling/test_context_extractor.rb +5 -1
  81. data/lib/ceedling/test_invoker/PIPELINE.md +9 -7
  82. data/lib/ceedling/test_invoker/mock_locator.rb +60 -2
  83. data/lib/ceedling/test_invoker/partials_manager.rb +12 -0
  84. data/lib/ceedling/test_invoker/standin_headerinator.rb +22 -13
  85. data/lib/ceedling/test_invoker/test_build_executor.rb +24 -40
  86. data/lib/ceedling/test_invoker/test_build_planner.rb +37 -18
  87. data/lib/ceedling/test_invoker/test_build_setup.rb +17 -12
  88. data/lib/ceedling/test_invoker/test_build_validations.rb +16 -31
  89. data/lib/ceedling/test_invoker/test_file_preprocessinator.rb +1 -1
  90. data/lib/ceedling/test_invoker/test_invoker.rb +6 -1
  91. data/lib/ceedling/test_invoker/test_pipeline_helpers.rb +1 -1
  92. data/lib/ceedling/test_invoker/test_source_file_directive_resolver.rb +40 -20
  93. data/lib/ceedling/tool_executor.rb +9 -3
  94. data/lib/ceedling/yaml_wrapper.rb +3 -2
  95. data/lib/version.rb +1 -1
  96. data/plugins/bullseye/config/defaults_bullseye.rb +1 -1
  97. data/plugins/bullseye/lib/bullseye.rb +9 -7
  98. data/plugins/cppcheck/config/defaults_cppcheck.rb +1 -1
  99. data/plugins/dependencies/config/defaults.yml +6 -6
  100. data/plugins/dependencies/dependencies.rake +4 -1
  101. data/plugins/dependencies/lib/dependencies.rb +18 -8
  102. data/plugins/dependencies/lib/dependency_spec.rb +17 -5
  103. data/plugins/fff/lib/fff.rb +45 -39
  104. data/plugins/fff/spec/fff_cmock_wrapper_spec.rb +128 -0
  105. data/plugins/gcov/config/defaults_gcov.rb +1 -1
  106. data/plugins/gcov/lib/console_reportinator.rb +4 -18
  107. data/plugins/gcov/lib/gcov.rb +9 -2
  108. data/plugins/gcov/lib/gcovr_reportinator.rb +8 -40
  109. data/plugins/gcov/lib/gcovr_thresholds.rb +74 -0
  110. data/plugins/gcov/lib/reportgenerator_reportinator.rb +1 -1
  111. data/plugins/module_generator/lib/module_generator.rb +3 -3
  112. data/plugins/report_tests_teamcity_stdout/lib/report_tests_teamcity_stdout.rb +53 -80
  113. data/plugins/sanitize/lib/sanitize_records.rb +3 -6
  114. data/plugins/valgrind/lib/valgrind.rb +14 -7
  115. data/site-local/configuration/reference/cmock.html +2 -1
  116. data/site-local/configuration/reference/files.html +9 -3
  117. data/site-local/configuration/reference/libraries.html +21 -3
  118. data/site-local/configuration/reference/paths.html +29 -6
  119. data/site-local/configuration/reference/project.html +17 -7
  120. data/site-local/configuration/reference/release-build.html +2 -0
  121. data/site-local/configuration/reference/tools.html +9 -0
  122. data/site-local/configuration/which-ceedling.html +377 -17
  123. data/site-local/development/releases.html +5 -1
  124. data/site-local/development/workflow.html +48 -43
  125. data/site-local/getting-started/builds.html +2 -0
  126. data/site-local/getting-started/command-line.html +56 -4
  127. data/site-local/plugins/dependencies.html +6 -3
  128. data/site-local/plugins/fff.html +42 -11
  129. data/site-local/plugins/gcov/gcovr.html +15 -12
  130. data/site-local/plugins/gcov/setup.html +2 -1
  131. data/site-local/plugins/report-tests-raw-output-log.html +3 -1
  132. data/site-local/plugins/report-tests-teamcity-stdout.html +6 -3
  133. data/site-local/plugins/sanitize.html +7 -6
  134. data/site-local/plugins/valgrind.html +8 -7
  135. data/site-local/project/upgrade.html +3 -0
  136. data/site-local/reference/command-line.html +9 -2
  137. data/site-local/sitemap.xml.gz +0 -0
  138. data/site-local/snapshot/plugins/bullseye/config/defaults_bullseye.rb +1 -1
  139. data/site-local/snapshot/plugins/gcov/config/defaults_gcov.rb +1 -1
  140. data/site-local/testing-guide/conventions.html +53 -0
  141. data/spec/integration/actionator_file_operations_spec.rb +91 -1
  142. data/spec/integration/compile_commands_json_db_spec.rb +1 -1
  143. data/spec/integration/configurator_validation_spec.rb +1 -1
  144. data/spec/integration/dependencies/dependency_tracker_cache_hardening_spec.rb +26 -0
  145. data/spec/integration/dependencies/dependency_tracker_core_spec.rb +22 -0
  146. data/spec/integration/launcher_handoff_spec.rb +297 -0
  147. data/spec/integration/mixin_loading_spec.rb +1 -1
  148. data/spec/integration/module_generator_spec.rb +3 -3
  149. data/spec/integration/nested_test_artifacts_spec.rb +99 -0
  150. data/spec/integration/partials_module_resolution_spec.rb +7 -4
  151. data/spec/integration/path_intake_scenarios_spec.rb +101 -0
  152. data/spec/integration/path_scenarios_spec.rb +322 -0
  153. data/spec/integration/quote_include_isolator_spec.rb +1 -1
  154. data/spec/integration/report_build_warnings_log_spec.rb +1 -1
  155. data/spec/integration/report_tests_log_factory_spec.rb +1 -1
  156. data/spec/integration/test_executable_manifest_spec.rb +1 -1
  157. data/spec/integration/test_includes_extractinator_spec.rb +2 -1
  158. data/spec/integration/test_naming_spec.rb +198 -0
  159. data/spec/integration/test_source_file_checks_spec.rb +166 -0
  160. data/spec/integration/tool_validator_spec.rb +1 -1
  161. data/spec/integration/upgrade_docs_spec.rb +84 -0
  162. data/spec/integration/vendor_copy_transient_io_retry_spec.rb +74 -5
  163. data/spec/support/file_tree_helper.rb +88 -0
  164. data/spec/support/integration/configurator_integration_helper.rb +6 -6
  165. data/spec/support/integration/dependency_tracker_integration_helper.rb +1 -1
  166. data/spec/support/integration/partials_generation_integration_helper.rb +2 -2
  167. data/spec/support/integration/path_scenario_harness.rb +173 -0
  168. data/spec/support/integration/spec_integration_helper.rb +1 -1
  169. data/spec/support/integration/test_includes_harness.rb +13 -2
  170. data/spec/support/spec_helper.rb +2 -0
  171. data/spec/support/system/spec_system_helper.rb +7 -6
  172. data/spec/support/system/system_context.rb +21 -3
  173. data/spec/support/working_dir_tracking.rb +49 -0
  174. data/spec/system/build_output_mirroring_spec.rb +2 -2
  175. data/spec/system/conditional_mock_includes_spec.rb +1 -1
  176. data/spec/system/delta_builds_spec.rb +137 -11
  177. data/spec/system/gcov_deployment_spec.rb +1 -0
  178. data/spec/system/header_include_path_validation_spec.rb +4 -4
  179. data/spec/system/launcher_handoff_spec.rb +82 -0
  180. data/spec/system/mock_include_folders_spec.rb +91 -0
  181. data/spec/system/parent_directory_reference_spec.rb +5 -3
  182. data/spec/system/path_handling_probes_spec.rb +192 -0
  183. data/spec/system/preprocessing_parameterized_tests_spec.rb +1 -1
  184. data/spec/system/rake_release_task_path_disambiguation_spec.rb +6 -6
  185. data/spec/system/rake_test_task_path_disambiguation_spec.rb +85 -0
  186. data/spec/system/special_path_characters_spec.rb +86 -0
  187. data/spec/system/support/common_test_cases.rb +23 -21
  188. data/spec/system/support/gcov_common_test_cases.rb +37 -9
  189. data/spec/system/support/sanitize_common_test_cases.rb +2 -2
  190. data/spec/system/support/valgrind_common_test_cases.rb +12 -12
  191. data/spec/system/test_pipeline_stop_points_spec.rb +4 -4
  192. data/spec/system/test_runner_system_include_spec.rb +1 -1
  193. data/spec/system/test_source_file_directive_spec.rb +34 -5
  194. data/spec/units/bin/actionator_spec.rb +14 -17
  195. data/spec/units/bin/app_cfg_spec.rb +37 -0
  196. data/spec/units/bin/cli_handler_spec.rb +282 -6
  197. data/spec/units/bin/cli_helper_spec.rb +116 -45
  198. data/spec/units/bin/installation_selector_spec.rb +114 -0
  199. data/spec/units/bin/launchinator_spec.rb +171 -0
  200. data/spec/units/bin/path_validator_spec.rb +10 -0
  201. data/spec/units/bin/versionator_spec.rb +38 -6
  202. data/spec/units/build_log_writer_spec.rb +57 -0
  203. data/spec/units/config/build_root_policy_spec.rb +61 -0
  204. data/spec/units/config/configurator_builder_spec.rb +37 -6
  205. data/spec/units/config/configurator_paths_validator_spec.rb +292 -0
  206. data/spec/units/config/configurator_setup_spec.rb +9 -65
  207. data/spec/units/config/configurator_spec.rb +27 -5
  208. data/spec/units/config/configurator_validator_spec.rb +1 -172
  209. data/spec/units/default_tools_quoting_spec.rb +83 -0
  210. data/spec/units/dependencies/dependency_cache_store_spec.rb +33 -2
  211. data/spec/units/dependencies/dependency_debug_tree_spec.rb +1 -1
  212. data/spec/units/dependencies/dependency_hasher_spec.rb +42 -1
  213. data/spec/units/dependencies/dependency_path_normalizer_spec.rb +1 -1
  214. data/spec/units/dependencies/dependency_tracker_spec.rb +3 -1
  215. data/spec/units/filename_extension_spec.rb +11 -0
  216. data/spec/units/filesystem/build_subpath_spec.rb +122 -0
  217. data/spec/units/filesystem/destination_collision_spec.rb +30 -0
  218. data/spec/units/{file_finder_helper_spec.rb → filesystem/file_finder_helper_spec.rb} +46 -1
  219. data/spec/units/{file_finder_spec.rb → filesystem/file_finder_spec.rb} +188 -22
  220. data/spec/units/{file_path_collection_utils_spec.rb → filesystem/file_path_collection_utils_spec.rb} +181 -1
  221. data/spec/units/{file_path_utils_spec.rb → filesystem/file_path_utils_spec.rb} +204 -87
  222. data/spec/units/filesystem/file_system_wrapper_spec.rb +33 -0
  223. data/spec/units/filesystem/file_tree_spec.rb +511 -0
  224. data/spec/units/filesystem/file_tree_windows_spec.rb +78 -0
  225. data/spec/units/{file_wrapper_spec.rb → filesystem/file_wrapper_spec.rb} +95 -12
  226. data/spec/units/{path_matcher_spec.rb → filesystem/path_matcher_spec.rb} +12 -1
  227. data/spec/units/{path_mirror_spec.rb → filesystem/path_mirror_spec.rb} +32 -4
  228. data/spec/units/filesystem/project_paths_spec.rb +147 -0
  229. data/spec/units/filesystem/working_dir_spec.rb +71 -0
  230. data/spec/units/generators/generator_spec.rb +12 -6
  231. data/spec/units/generators/generator_test_results_backtrace_spec.rb +50 -46
  232. data/spec/units/generators/generator_test_results_spec.rb +1 -1
  233. data/spec/units/handoff_spec.rb +205 -0
  234. data/spec/units/includes/include_factory_spec.rb +3 -3
  235. data/spec/units/includes/include_pathinator_spec.rb +46 -0
  236. data/spec/units/installation_spec.rb +228 -0
  237. data/spec/units/library_resolver_spec.rb +157 -0
  238. data/spec/units/mock_locator_spec.rb +76 -1
  239. data/spec/units/partials/partializer_config_spec.rb +7 -0
  240. data/spec/units/partials/partializer_spec.rb +1 -0
  241. data/spec/units/partials_manager_spec.rb +17 -0
  242. data/spec/units/plugins/bullseye_spec.rb +15 -2
  243. data/spec/units/plugins/console_reportinator_spec.rb +18 -20
  244. data/spec/units/plugins/dependencies_spec.rb +33 -7
  245. data/spec/units/plugins/dependency_spec_spec.rb +17 -0
  246. data/spec/units/plugins/gcov_spec.rb +28 -3
  247. data/spec/units/plugins/gcovr_reportinator_spec.rb +19 -47
  248. data/spec/units/plugins/gcovr_thresholds_spec.rb +95 -0
  249. data/spec/units/plugins/module_generator_spec.rb +5 -5
  250. data/spec/units/plugins/report_build_warnings_log_spec.rb +3 -3
  251. data/spec/units/plugins/report_log_writer_plugin_spec.rb +10 -1
  252. data/spec/units/plugins/report_tests_raw_output_log_spec.rb +13 -2
  253. data/spec/units/plugins/report_tests_teamcity_stdout_spec.rb +77 -3
  254. data/spec/units/plugins/reportgenerator_reportinator_spec.rb +1 -1
  255. data/spec/units/plugins/sanitize_records_spec.rb +3 -1
  256. data/spec/units/plugins/sanitize_spec.rb +1 -1
  257. data/spec/units/plugins/valgrind_spec.rb +23 -8
  258. data/spec/units/preprocess/preprocessinator_comment_stripper_spec.rb +1 -1
  259. data/spec/units/rake_app/rakefile_component_resolver_spec.rb +21 -0
  260. data/spec/units/release_build_executor_spec.rb +53 -14
  261. data/spec/units/release_build_planner_spec.rb +15 -3
  262. data/spec/units/reportinator_spec.rb +5 -5
  263. data/spec/units/standin_headerinator_spec.rb +31 -1
  264. data/spec/units/test_build_executor_spec.rb +65 -3
  265. data/spec/units/test_build_planner_spec.rb +104 -2
  266. data/spec/units/test_build_setup_spec.rb +96 -12
  267. data/spec/units/test_context_extractor_spec.rb +25 -0
  268. data/spec/units/test_file_preprocessinator_spec.rb +17 -1
  269. data/spec/units/test_includes_extractinator_spec.rb +5 -1
  270. data/spec/units/test_invoker/objects_wiring_spec.rb +6 -3
  271. data/spec/units/test_invoker_spec.rb +14 -1
  272. data/spec/units/test_source_file_directive_resolver_spec.rb +38 -7
  273. data/spec/units/tool_executor_spec.rb +26 -0
  274. data/spec/units/yaml_wrapper_spec.rb +11 -0
  275. metadata +109 -25
  276. data/lib/ceedling/file_path_collection_utils.rb +0 -164
@@ -0,0 +1,83 @@
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 'shellwords'
10
+ require 'yaml'
11
+ require 'ceedling/defaults'
12
+ require 'ceedling/tool_executor'
13
+ require 'ceedling/ruby_expandinator'
14
+
15
+ load File.expand_path( '../../plugins/gcov/config/defaults_gcov.rb', __dir__ )
16
+ load File.expand_path( '../../plugins/bullseye/config/defaults_bullseye.rb', __dir__ )
17
+ load File.expand_path( '../../plugins/cppcheck/config/defaults_cppcheck.rb', __dir__ )
18
+
19
+ # GH #1373: the default tools that run a test executable named it unquoted, so a path holding
20
+ # an apostrophe or a space broke the shell command. Each command here is split as a POSIX
21
+ # shell splits it, and every path must come back as one word, exactly as given.
22
+ describe 'Default tools' do
23
+ SPECIAL_PATH = "build/test/out/test/o'neil dir/test_q/test_q.out"
24
+ OTHER_PATH = "src/my dir/o'neil.c"
25
+
26
+ DEPENDENCIES_TOOLS = YAML.load_file(
27
+ File.expand_path( '../../plugins/dependencies/config/defaults.yml', __dir__ ), symbolize_names: true
28
+ )[:tools]
29
+
30
+ before(:each) do
31
+ helper = double('tool_executor_helper').as_null_object
32
+ allow(helper).to receive(:osify_path_separators) { |path| path }
33
+ system_wrapper = double('system_wrapper').as_null_object
34
+ allow(system_wrapper).to receive(:constants_include?).and_return( false )
35
+
36
+ @tool_executor = ToolExecutor.new(
37
+ {
38
+ :tool_executor_helper => helper,
39
+ :loginator => double('loginator').as_null_object,
40
+ :verbosinator => double('verbosinator').as_null_object,
41
+ :system_wrapper => system_wrapper,
42
+ :ruby_expandinator => RubyExpandinator.new
43
+ }
44
+ )
45
+ end
46
+
47
+ # Configuration hands Ceedling an unfrozen copy of each default tool
48
+ def words(tool, *args)
49
+ Shellwords.split( @tool_executor.build_command_line( Marshal.load( Marshal.dump( tool ) ), [], *args )[:line] )
50
+ end
51
+
52
+ {
53
+ 'test fixture' => DEFAULT_TEST_FIXTURE_TOOL,
54
+ 'gcov fixture' => DEFAULT_GCOV_FIXTURE_TOOL,
55
+ 'Bullseye fixture' => DEFAULT_BULLSEYE_FIXTURE_TOOL,
56
+ }.each do |name, tool|
57
+ it "names the test executable as one word in the #{name}" do
58
+ expect( words( tool, SPECIAL_PATH ) ).to eq( [SPECIAL_PATH] )
59
+ end
60
+ end
61
+
62
+ it 'names the test executable as one word in a simple backtrace rerun' do
63
+ expect( words( DEFAULT_TEST_FIXTURE_SIMPLE_BACKTRACE_TOOL, SPECIAL_PATH, '-n "test_a"' ) ).to eq( [SPECIAL_PATH, '-n', 'test_a'] )
64
+ end
65
+
66
+ it 'names the test executable as one word in a gdb backtrace' do
67
+ expect( words( DEFAULT_TEST_BACKTRACE_GDB_TOOL, 'build/gdb.txt', SPECIAL_PATH, '-n "test_a"' ).last( 3 ) ).to eq( [SPECIAL_PATH, '-n', 'test_a'] )
68
+ end
69
+
70
+ it 'names each source file as one word for cppcheck' do
71
+ expect( words( DEFAULT_CPPCHECK_TOOL, ['src'], [OTHER_PATH, 'src/b.c'] ).last( 2 ) ).to eq( [OTHER_PATH, 'src/b.c'] )
72
+ end
73
+
74
+ it 'names the library and each object as one word for the Dependencies archiver' do
75
+ expect( words( DEPENDENCIES_TOOLS[:deps_linker], [OTHER_PATH, 'b.o'], 'build/my dir/libx.a' ) ).to eq(
76
+ ['ar', 'rcs', 'build/my dir/libx.a', OTHER_PATH, 'b.o']
77
+ )
78
+ end
79
+
80
+ it 'names the archive as one word for the Dependencies zip unarchiver' do
81
+ expect( words( DEPENDENCIES_TOOLS[:deps_zip], 'vendor/my dir/x.zip' ) ).to eq( ['unzip', '-o', 'vendor/my dir/x.zip'] )
82
+ end
83
+ end
@@ -7,7 +7,7 @@
7
7
 
8
8
  require 'spec_helper'
9
9
  require 'json'
10
- require 'ceedling/file_wrapper'
10
+ require 'ceedling/filesystem/file_wrapper'
11
11
  require 'ceedling/loginator'
12
12
  require 'ceedling/dependencies/dependency_cache_store'
13
13
 
@@ -124,6 +124,37 @@ describe DependencyCacheStore do
124
124
  expect( @store.load('cache.json')['entries'] ).to eq( {} )
125
125
  end
126
126
 
127
+ # GH #1364: version 2 places per-test build output by the test's path from the project root
128
+ it 'marks the 1.2.2 build layout as schema version 2' do
129
+ expect( DependencyCacheStore::CACHE_SCHEMA_VERSION ).to eq( 2 )
130
+ end
131
+
132
+ it 'rebuilds once from an older build layout, advising clobber for what that layout left' do
133
+ payload = JSON.generate(
134
+ 'schema_version' => 1, 'hash_algorithm' => DependencyHasher::HASH_ALGORITHM, 'entries' => { 'foo.o' => valid_entry }
135
+ )
136
+ stub_file( 'build/cache/.test.dep_cache.json', payload )
137
+
138
+ expect(@loginator).to receive(:log).with(
139
+ 'Dependency cache build/cache/.test.dep_cache.json comes from an earlier Ceedling build layout -- rebuilding ' \
140
+ 'everything once. Run `ceedling clobber` to remove any orphaned build output left in the old layout.',
141
+ Verbosity::COMPLAIN
142
+ )
143
+
144
+ expect( @store.load('build/cache/.test.dep_cache.json')['entries'] ).to eq( {} )
145
+ end
146
+
147
+ it 'keeps its usual warning for a schema_version it never wrote' do
148
+ payload = JSON.generate(
149
+ 'schema_version' => DependencyCacheStore::CACHE_SCHEMA_VERSION + 1, 'hash_algorithm' => DependencyHasher::HASH_ALGORITHM, 'entries' => {}
150
+ )
151
+ stub_file( 'cache.json', payload )
152
+
153
+ expect(@loginator).to receive(:log).with( /cache\.json has an incompatible or missing schema_version/, Verbosity::COMPLAIN )
154
+
155
+ @store.load('cache.json')
156
+ end
157
+
127
158
  it 'treats a mismatched hash_algorithm as an absent cache' do
128
159
  payload = JSON.generate(
129
160
  'schema_version' => DependencyCacheStore::CACHE_SCHEMA_VERSION,
@@ -153,7 +184,7 @@ describe DependencyCacheStore do
153
184
  result = @store.load('cache.json')
154
185
 
155
186
  expect( result['entries'].keys ).to eq( ['good.o'] )
156
- expect( @loginator ).to have_received(:log)
187
+ expect( @loginator ).to have_received(:log).with( /'bad\.o' in cache\.json is malformed/, Verbosity::COMPLAIN )
157
188
  end
158
189
 
159
190
  it 'drops an entry with a self_hash of the wrong length' do
@@ -7,7 +7,7 @@
7
7
 
8
8
  require 'spec_helper'
9
9
  require 'yaml'
10
- require 'ceedling/file_wrapper'
10
+ require 'ceedling/filesystem/file_wrapper'
11
11
  require 'ceedling/yaml_wrapper'
12
12
  require 'ceedling/dependencies/dependency_debug_tree'
13
13
 
@@ -7,16 +7,57 @@
7
7
 
8
8
  require 'spec_helper'
9
9
  require 'digest'
10
- require 'ceedling/file_wrapper'
10
+ require 'ceedling/filesystem/file_wrapper'
11
11
  require 'ceedling/dependencies/dependency_hasher'
12
12
 
13
13
  describe DependencyHasher do
14
14
 
15
15
  before(:each) do
16
16
  @file_wrapper = instance_double('FileWrapper')
17
+ # No file status by default, so every read below hashes afresh
18
+ allow( @file_wrapper ).to receive(:stat).and_return( nil )
17
19
  @hasher = described_class.new( { :file_wrapper => @file_wrapper } )
18
20
  end
19
21
 
22
+ # GH #1368: every test link hashes the libraries it links, so a large library was read
23
+ # once per test executable on every build
24
+ describe '#hash_of_file memo' do
25
+ def status(size, mtime)
26
+ return double( %q(File::Stat), size: size, mtime: mtime )
27
+ end
28
+
29
+ before(:each) do
30
+ allow( @file_wrapper ).to receive(:read_binary).with('libx.a').and_return('library')
31
+ end
32
+
33
+ it 'hashes a file left unchanged since before the build began only once' do
34
+ allow( @file_wrapper ).to receive(:stat).with('libx.a').and_return( status( 7, Time.now - 60 ) )
35
+
36
+ 2.times { expect( @hasher.hash_of_file('libx.a') ).to eq( Digest::SHA256.hexdigest('library') ) }
37
+
38
+ expect( @file_wrapper ).to have_received(:read_binary).once
39
+ end
40
+
41
+ it 'hashes again a file whose size or modification time changed' do
42
+ allow( @file_wrapper ).to receive(:stat).with('libx.a').and_return(
43
+ status( 7, Time.now - 60 ), status( 8, Time.now - 60 ), status( 8, Time.now - 50 )
44
+ )
45
+
46
+ 3.times { @hasher.hash_of_file('libx.a') }
47
+
48
+ expect( @file_wrapper ).to have_received(:read_binary).exactly(3).times
49
+ end
50
+
51
+ # A file the build writes can change within one timestamp tick, unseen by its status
52
+ it 'hashes afresh, every time, a file modified as the build began or since' do
53
+ allow( @file_wrapper ).to receive(:stat).with('libx.a').and_return( status( 7, Time.now ) )
54
+
55
+ 2.times { @hasher.hash_of_file('libx.a') }
56
+
57
+ expect( @file_wrapper ).to have_received(:read_binary).twice
58
+ end
59
+ end
60
+
20
61
  describe '#hash_of_file' do
21
62
  it 'returns the SHA-256 hex digest of the file content read via FileWrapper' do
22
63
  allow( @file_wrapper ).to receive(:read_binary).with('foo.c').and_return('int main(void) {}')
@@ -6,7 +6,7 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'spec_helper'
9
- require 'ceedling/file_wrapper'
9
+ require 'ceedling/filesystem/file_wrapper'
10
10
  require 'ceedling/dependencies/dependency_path_normalizer'
11
11
 
12
12
  describe DependencyPathNormalizer do
@@ -7,7 +7,7 @@
7
7
 
8
8
  require 'spec_helper'
9
9
  require 'ceedling/exceptions'
10
- require 'ceedling/file_wrapper'
10
+ require 'ceedling/filesystem/file_wrapper'
11
11
  require 'ceedling/system_wrapper'
12
12
  require 'ceedling/loginator'
13
13
  require 'ceedling/yaml_wrapper'
@@ -52,6 +52,8 @@ describe DependencyTracker do
52
52
  allow( @file_wrapper ).to receive(:mkdir)
53
53
  allow( @file_wrapper ).to receive(:write)
54
54
  allow( @file_wrapper ).to receive(:mv)
55
+ # No file status, so every hash reads its file afresh
56
+ allow( @file_wrapper ).to receive(:stat).and_return(nil)
55
57
  allow( @system_wrapper ).to receive(:env_get).with('CEEDLING_DEP_DEBUG').and_return(nil)
56
58
 
57
59
  hasher = DependencyHasher.new( { :file_wrapper => @file_wrapper } )
@@ -51,6 +51,17 @@ describe FilenameExtension do
51
51
  end
52
52
  end
53
53
 
54
+ describe '#pattern' do
55
+ it 'matches any one of its extensions, escaped, as a group' do
56
+ pattern = FilenameExtension.new( ['.c', '.c++'] ).pattern
57
+
58
+ expect('a.c++').to match( /#{pattern}\z/ )
59
+ expect('a.c').to match( /#{pattern}\z/ )
60
+ expect('a.cxx').to_not match( /#{pattern}\z/ )
61
+ expect('a_c').to_not match( /#{pattern}\z/ )
62
+ end
63
+ end
64
+
54
65
  describe '#candidates' do
55
66
  it 'produces one candidate filename per configured extension' do
56
67
  extension = FilenameExtension.new(['.s', '.S'])
@@ -0,0 +1,122 @@
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/build_subpath'
12
+
13
+ # GH #1370 and the path handling audit around it: a build file placed by text could land
14
+ # outside the build directory
15
+ describe BuildSubpath do
16
+ WINDOWS_ONLY_BUILD = { if: Gem.win_platform? }.freeze
17
+
18
+ around(:each) do |example|
19
+ Dir.mktmpdir do |dir|
20
+ @ws = File.realpath( dir )
21
+ FileUtils.mkdir_p( File.join( @ws, 'app' ) )
22
+ Dir.chdir( File.join( @ws, 'app' ) ) { example.run }
23
+ end
24
+ end
25
+
26
+ # Every other example reads INSTALLATION_ROOT itself, so only this one shows it names the
27
+ # running installation
28
+ it 'names the running installation, which holds what Ceedling ships' do
29
+ expect(File.file?( File.join( BuildSubpath::INSTALLATION_ROOT, 'lib', 'ceedling', 'filesystem', 'build_subpath.rb' ) )).to be( true )
30
+ BuildSubpath::INSTALLED_DIRS.each { |dir| expect(File.directory?( dir )).to be( true ), dir }
31
+ end
32
+
33
+ describe '.encode and .decode' do
34
+ {
35
+ 'a file in the project' => ['src/drv/uart', 'src/drv/uart'],
36
+ 'a sibling of the project' => ['../shared/src', '_up_/shared/src'],
37
+ 'the working directory' => ['.', '']
38
+ }.each do |label, (path, encoded)|
39
+ it "places #{label} by its path from the project root, and reads it back" do
40
+ expect(BuildSubpath.encode( path )).to eq( encoded )
41
+ expect(BuildSubpath.decode( encoded )).to eq( path == '.' ? '' : path )
42
+ end
43
+ end
44
+
45
+ # A project's own directory may carry a marker's name, which must read back as itself
46
+ it 'places a directory named like a marker apart from the marker, and reads it back' do
47
+ ['_up_/x', 'src/a/_up_', '_ceedling_/src', '_abs_/C/x', '_unc_/srv', 'src/__up_/x'].each do |path|
48
+ encoded = BuildSubpath.encode( path )
49
+
50
+ expect(BuildSubpath.decode( encoded )).to eq( path ), "#{path} => #{encoded}"
51
+ end
52
+ expect(BuildSubpath.encode( '_up_/x' )).to_not eq( BuildSubpath.encode( '../x' ) )
53
+ # macOS and Windows file systems fold case
54
+ expect(BuildSubpath.encode( '_UP_/x' ).downcase).to_not eq( BuildSubpath.encode( '../x' ).downcase )
55
+ expect(BuildSubpath.decode( BuildSubpath.encode( '_UP_/x' ) )).to eq( '_UP_/x' )
56
+ end
57
+
58
+ # Windows has no relative path from one drive to another
59
+ it 'places a file of the running Ceedling on another drive below `_ceedling_` too' do
60
+ file = File.join( BuildSubpath::INSTALLATION_ROOT, 'plugins/fff/src' )
61
+ allow(ProjectPaths).to receive(:relative).and_call_original
62
+ allow(ProjectPaths).to receive(:relative).with( file ).and_return( file )
63
+
64
+ expect(BuildSubpath.encode( file )).to eq( '_ceedling_/plugins/fff/src' )
65
+ end
66
+
67
+ it 'places an absolute path below the project as a relative one' do
68
+ expect(BuildSubpath.encode( File.join( @ws, 'app/src/x' ) )).to eq( 'src/x' )
69
+ end
70
+
71
+ it 'places a file of the running Ceedling outside the project below `_ceedling_`, and reads it back' do
72
+ file = File.join( BuildSubpath::INSTALLATION_ROOT, 'plugins/fff/src' )
73
+
74
+ expect(BuildSubpath.encode( file )).to eq( '_ceedling_/plugins/fff/src' )
75
+ expect(File.expand_path( BuildSubpath.decode( '_ceedling_/plugins/fff/src' ) )).to eq( file )
76
+ end
77
+
78
+ # A project may itself sit inside a Ceedling checkout, as the system specs' projects do.
79
+ # Only what Ceedling ships places below `_ceedling_`.
80
+ it 'places a directory beside a project inside the installation by its path from the project root' do
81
+ root = BuildSubpath::INSTALLATION_ROOT
82
+ allow(ProjectPaths).to receive(:working_dir).and_return( File.join( root, 'specout/proj/app' ) )
83
+
84
+ expect(BuildSubpath.encode( File.join( root, 'specout/proj/shared/src' ) )).to eq( '_up_/shared/src' )
85
+ expect(BuildSubpath.encode( File.join( root, 'plugins/fff/src' ) )).to eq( '_ceedling_/plugins/fff/src' )
86
+ end
87
+
88
+ it 'places a file of the running Ceedling inside the project by its path from the project root' do
89
+ Dir.chdir( BuildSubpath::INSTALLATION_ROOT ) do
90
+ expect(BuildSubpath.encode( 'plugins/fff/src' )).to eq( 'plugins/fff/src' )
91
+ end
92
+ end
93
+
94
+ it 'places a path on another drive below `_abs_`, and reads it back', **WINDOWS_ONLY_BUILD do
95
+ other = Dir.pwd.start_with?( 'C' ) ? 'D' : 'C'
96
+
97
+ expect(BuildSubpath.encode( "#{other}:/x/inc" )).to eq( "_abs_/#{other}/x/inc" )
98
+ expect(BuildSubpath.decode( "_abs_/#{other}/x/inc" )).to eq( "#{other}:/x/inc" )
99
+ end
100
+
101
+ it 'places a UNC path below `_unc_`, and reads it back', **WINDOWS_ONLY_BUILD do
102
+ expect(BuildSubpath.encode( '//server/share/inc' )).to eq( '_unc_/server/share/inc' )
103
+ expect(BuildSubpath.decode( '_unc_/server/share/inc' )).to eq( '//server/share/inc' )
104
+ end
105
+
106
+ it 'never places a file outside the build subpath it names' do
107
+ ['../../far/x', '/opt/x', '../shared', File.join( @ws, 'app/../../x' )].each do |path|
108
+ encoded = BuildSubpath.encode( path )
109
+
110
+ expect(encoded.split( '/' )).to_not include( '..' ), "#{path}: #{encoded}"
111
+ expect(encoded).to_not start_with( '/' ), "#{path}: #{encoded}"
112
+ end
113
+ end
114
+ end
115
+
116
+ describe '.of_directory' do
117
+ it 'is the encoding of a directory, with the working directory as empty' do
118
+ expect(BuildSubpath.of_directory( 'src/drv' )).to eq( 'src/drv' )
119
+ expect(BuildSubpath.of_directory( '.' )).to eq( '' )
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,30 @@
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 'ceedling/filesystem/destination_collision'
10
+
11
+ describe DestinationCollision do
12
+ describe '.find' do
13
+ it 'gives each output more than one input maps to, with those inputs' do
14
+ shared = DestinationCollision.find( ['a/x.c', 'b/x.c', 'c/y.c', 'a/x.c'] ) { |input| File.basename( input ) }
15
+
16
+ expect(shared).to eq( 'x.c' => ['a/x.c', 'b/x.c'] )
17
+ end
18
+
19
+ it 'gives nothing when every input has an output of its own' do
20
+ expect(DestinationCollision.find( ['a.c', 'b.c'] ) { |input| input }).to be_empty
21
+ end
22
+ end
23
+
24
+ describe '.raise_for' do
25
+ it 'names every input and the output they share, with a fix' do
26
+ expect { DestinationCollision.raise_for( 'out/x.o', ['a/x.c', 'b/x.c'], 'would build to the same file' ) }
27
+ .to raise_error( CeedlingException, '`a/x.c` and `b/x.c` would build to the same file `out/x.o`. Rename one, or move it to its own directory.' )
28
+ end
29
+ end
30
+ end
@@ -6,7 +6,7 @@
6
6
  # =========================================================================
7
7
 
8
8
  require 'spec_helper'
9
- require 'ceedling/file_finder_helper'
9
+ require 'ceedling/filesystem/file_finder_helper'
10
10
  require 'ceedling/constants'
11
11
  require 'ceedling/loginator'
12
12
 
@@ -124,6 +124,22 @@ describe FileFinderHelper do
124
124
  @ff_helper.resolve_file_in_collection('c.cpp', FILE_LIST, :ignore)
125
125
  end
126
126
 
127
+ # Every test that names an ambiguous file looks it up, and each lookup makes the same choice
128
+ it 'logs a given choice once, however many lookups make it' do
129
+ expect(@loginator).to receive(:log).once
130
+
131
+ 3.times { @ff_helper.resolve_file_in_collection('c.cpp', FILE_LIST, :ignore) }
132
+ end
133
+
134
+ it 'logs each different choice' do
135
+ expect(@loginator).to receive(:log).twice
136
+
137
+ 2.times do
138
+ @ff_helper.resolve_file_in_collection('c.cpp', FILE_LIST, :ignore)
139
+ @ff_helper.resolve_file_in_collection('c.hpp', FILE_LIST, :ignore)
140
+ end
141
+ end
142
+
127
143
  it 'logs nothing when a bare basename resolves uniquely' do
128
144
  expect(@loginator).to_not receive(:log)
129
145
  @ff_helper.resolve_file_in_collection('a.c', FILE_LIST, :ignore)
@@ -154,4 +170,33 @@ describe FileFinderHelper do
154
170
  end
155
171
  end
156
172
  end
173
+ # A module generator path hint is matched to the configured path it resembles most
174
+ describe '#find_best_path_in_collection' do
175
+ PATHS = ['src', 'src/lab', 'src/lab/x', 'test/lab'].freeze
176
+
177
+ it 'gives a path the collection holds itself' do
178
+ expect(@ff_helper.find_best_path_in_collection( 'src/lab/x', PATHS, :error, 'module' )).to eq( 'src/lab/x' )
179
+ end
180
+
181
+ it 'prefers the first path ending as the hint does over one merely holding its segments' do
182
+ expect(@ff_helper.find_best_path_in_collection( 'lab', PATHS, :error, 'module' )).to eq( 'src/lab' )
183
+ expect(@ff_helper.find_best_path_in_collection( 'test/lab', ['src/lab', 'test/lab/x', 'test/lab'], :error, 'module' )).to eq( 'test/lab' )
184
+ end
185
+
186
+ it 'raises for a hint matching nothing when told to' do
187
+ expect { @ff_helper.find_best_path_in_collection( 'nowhere', PATHS, :error, 'module' ) }
188
+ .to raise_error( CeedlingException, 'Found no path `nowhere` in module search paths.' )
189
+ end
190
+
191
+ it 'warns of a hint matching nothing, or keeps quiet, and gives the first path' do
192
+ expect(@ff_helper.find_best_path_in_collection( 'nowhere', PATHS, :warn, 'module' )).to eq( 'src' )
193
+ expect(@loginator).to have_received(:log).with( 'Found no path `nowhere` in module search paths.', Verbosity::COMPLAIN )
194
+
195
+ expect(@ff_helper.find_best_path_in_collection( 'nowhere', PATHS, :ignore, 'module' )).to eq( 'src' )
196
+ end
197
+
198
+ it 'raises without a collection' do
199
+ expect { @ff_helper.find_best_path_in_collection( 'lab', nil, :error, 'module' ) }.to raise_error( /No path list provided for module search/ )
200
+ end
201
+ end
157
202
  end