ceedling 0.28.2 → 0.28.3

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 (253) hide show
  1. checksums.yaml +4 -4
  2. data/assets/ceedling +3 -0
  3. data/assets/ceedling.cmd +1 -0
  4. data/assets/default_gitignore +5 -0
  5. data/assets/project_with_guts.yml +1 -0
  6. data/assets/project_with_guts_gcov.yml +3 -0
  7. data/assets/test_example_file_verbose.c +12 -0
  8. data/bin/ceedling +30 -6
  9. data/docs/CeedlingPacket.md +135 -23
  10. data/docs/CeedlingPacket.odt +0 -0
  11. data/examples/blinky/rakefile.rb +2 -1
  12. data/lib/ceedling/configurator.rb +7 -5
  13. data/lib/ceedling/configurator_builder.rb +10 -7
  14. data/lib/ceedling/configurator_plugins.rb +29 -24
  15. data/lib/ceedling/configurator_setup.rb +0 -1
  16. data/lib/ceedling/defaults.rb +7 -2
  17. data/lib/ceedling/dependinator.rb +10 -2
  18. data/lib/ceedling/file_finder.rb +57 -49
  19. data/lib/ceedling/file_path_utils.rb +12 -4
  20. data/lib/ceedling/file_wrapper.rb +4 -0
  21. data/lib/ceedling/generator.rb +4 -3
  22. data/lib/ceedling/generator_test_results.rb +15 -13
  23. data/lib/ceedling/plugin_manager.rb +18 -18
  24. data/lib/ceedling/plugin_reportinator.rb +3 -2
  25. data/lib/ceedling/plugin_reportinator_helper.rb +2 -3
  26. data/lib/ceedling/preprocessinator_extractor.rb +2 -2
  27. data/lib/ceedling/preprocessinator_includes_handler.rb +5 -0
  28. data/lib/ceedling/rakefile.rb +1 -0
  29. data/lib/ceedling/release_invoker_helper.rb +5 -2
  30. data/lib/ceedling/rules_release.rake +2 -1
  31. data/lib/ceedling/rules_tests.rake +18 -9
  32. data/lib/ceedling/rules_tests_deep_dependencies.rake +2 -2
  33. data/lib/ceedling/task_invoker.rb +15 -3
  34. data/lib/ceedling/tasks_vendor.rake +3 -3
  35. data/lib/ceedling/test_invoker.rb +39 -12
  36. data/lib/ceedling/test_invoker_helper.rb +5 -1
  37. data/lib/ceedling/tool_executor.rb +8 -4
  38. data/lib/ceedling/version.rb +1 -1
  39. data/out.fail +21 -0
  40. data/plugins/beep/README.md +22 -0
  41. data/plugins/beep/lib/beep.rb +40 -0
  42. data/plugins/bullseye/bullseye.rake +43 -36
  43. data/plugins/bullseye/config/defaults.yml +4 -0
  44. data/plugins/bullseye/lib/bullseye.rb +27 -5
  45. data/plugins/command_hooks/lib/command_hooks.rb +3 -0
  46. data/plugins/gcov/README.md +34 -1
  47. data/plugins/gcov/config/defaults.yml +3 -3
  48. data/plugins/gcov/gcov.rake +7 -5
  49. data/plugins/gcov/lib/gcov.rb +3 -1
  50. data/plugins/gcov/lib/gcov_constants.rb +2 -0
  51. data/plugins/junit_tests_report/lib/junit_tests_report.rb +12 -9
  52. data/plugins/module_generator/lib/module_generator.rb +14 -1
  53. data/plugins/module_generator/module_generator.rake +21 -4
  54. data/plugins/raw_output_report/lib/raw_output_report.rb +41 -0
  55. data/spec/gcov/gcov_deployment_spec.rb +1 -1
  56. data/spec/gcov/gcov_test_cases_spec.rb +2 -2
  57. data/spec/generator_test_results_spec.rb +5 -0
  58. data/spec/preprocessinator_includes_handler_spec.rb +1 -0
  59. data/spec/spec_system_helper.rb +178 -4
  60. data/spec/support/test_example.fail +1 -0
  61. data/spec/support/test_example.pass +1 -0
  62. data/spec/support/test_example_empty.pass +1 -0
  63. data/spec/support/test_example_ignore.pass +1 -0
  64. data/spec/support/test_example_mangled.pass +1 -0
  65. data/spec/support/test_example_with_time.pass +22 -0
  66. data/spec/system/deployment_spec.rb +33 -0
  67. data/vendor/cmock/README.md +4 -3
  68. data/vendor/cmock/docs/CMock_Summary.md +1 -1
  69. data/vendor/cmock/lib/cmock_config.rb +4 -0
  70. data/vendor/cmock/lib/cmock_generator.rb +5 -2
  71. data/vendor/cmock/lib/cmock_generator_plugin_array.rb +4 -4
  72. data/vendor/cmock/lib/cmock_generator_plugin_callback.rb +9 -11
  73. data/vendor/cmock/lib/cmock_generator_plugin_cexception.rb +0 -1
  74. data/vendor/cmock/lib/cmock_generator_plugin_ignore.rb +2 -3
  75. data/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb +2 -4
  76. data/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb +0 -2
  77. data/vendor/cmock/lib/cmock_generator_utils.rb +16 -3
  78. data/vendor/cmock/lib/cmock_header_parser.rb +59 -34
  79. data/vendor/cmock/release/build.info +1 -1
  80. data/vendor/cmock/release/version.info +1 -1
  81. data/vendor/cmock/scripts/create_makefile.rb +17 -2
  82. data/vendor/cmock/src/cmock.c +13 -7
  83. data/vendor/cmock/test/test_helper.rb +11 -10
  84. data/vendor/cmock/test/unit/cmock_config_test.rb +4 -2
  85. data/vendor/cmock/test/unit/cmock_generator_main_test.rb +10 -4
  86. data/vendor/cmock/test/unit/cmock_generator_plugin_array_test.rb +20 -12
  87. data/vendor/cmock/test/unit/cmock_generator_plugin_expect_a_test.rb +2 -2
  88. data/vendor/cmock/test/unit/cmock_generator_plugin_expect_b_test.rb +2 -2
  89. data/vendor/cmock/test/unit/cmock_generator_plugin_ignore_arg_test.rb +3 -3
  90. data/vendor/cmock/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb +8 -6
  91. data/vendor/cmock/test/unit/cmock_generator_utils_test.rb +27 -10
  92. data/vendor/cmock/test/unit/cmock_header_parser_test.rb +108 -20
  93. data/vendor/cmock/vendor/c_exception/Gemfile +4 -0
  94. data/vendor/cmock/vendor/c_exception/Gemfile.lock +12 -0
  95. data/vendor/cmock/vendor/c_exception/LICENSE.txt +30 -0
  96. data/vendor/cmock/vendor/c_exception/README.md +162 -0
  97. data/vendor/cmock/vendor/c_exception/Rakefile +42 -0
  98. data/vendor/cmock/vendor/c_exception/docs/CException.md +292 -0
  99. data/vendor/cmock/vendor/c_exception/docs/ThrowTheSwitchCodingStandard.md +207 -0
  100. data/vendor/cmock/vendor/c_exception/lib/CException.c +46 -0
  101. data/vendor/cmock/vendor/c_exception/lib/CException.h +110 -0
  102. data/vendor/cmock/vendor/c_exception/makefile +24 -0
  103. data/vendor/cmock/vendor/c_exception/release/build.info +2 -0
  104. data/vendor/cmock/vendor/c_exception/release/version.info +2 -0
  105. data/vendor/cmock/vendor/c_exception/test/CExceptionConfig.h +46 -0
  106. data/vendor/cmock/vendor/c_exception/test/TestException.c +391 -0
  107. data/vendor/cmock/vendor/c_exception/test/TestException_Runner.c +67 -0
  108. data/vendor/cmock/vendor/unity/README.md +231 -0
  109. data/vendor/cmock/vendor/unity/auto/colour_prompt.rb +118 -0
  110. data/vendor/cmock/vendor/unity/auto/colour_reporter.rb +39 -0
  111. data/vendor/cmock/vendor/unity/auto/generate_config.yml +36 -0
  112. data/vendor/cmock/vendor/unity/auto/generate_module.rb +308 -0
  113. data/vendor/cmock/vendor/unity/auto/generate_test_runner.rb +457 -0
  114. data/vendor/cmock/vendor/unity/auto/parse_output.rb +323 -0
  115. data/vendor/cmock/vendor/unity/auto/stylize_as_junit.rb +252 -0
  116. data/vendor/cmock/vendor/unity/auto/test_file_filter.rb +25 -0
  117. data/vendor/cmock/vendor/unity/auto/type_sanitizer.rb +6 -0
  118. data/vendor/cmock/vendor/unity/auto/unity_test_summary.py +139 -0
  119. data/vendor/cmock/vendor/unity/auto/unity_test_summary.rb +136 -0
  120. data/vendor/cmock/vendor/unity/auto/unity_to_junit.py +146 -0
  121. data/vendor/cmock/vendor/unity/docs/ThrowTheSwitchCodingStandard.md +206 -0
  122. data/vendor/cmock/vendor/unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf +0 -0
  123. data/vendor/cmock/vendor/unity/docs/UnityAssertionsReference.md +779 -0
  124. data/vendor/cmock/vendor/unity/docs/UnityConfigurationGuide.md +433 -0
  125. data/vendor/cmock/vendor/unity/docs/UnityGettingStartedGuide.md +192 -0
  126. data/vendor/cmock/vendor/unity/docs/UnityHelperScriptsGuide.md +260 -0
  127. data/vendor/cmock/vendor/unity/docs/license.txt +21 -0
  128. data/vendor/cmock/vendor/unity/examples/example_1/makefile +71 -0
  129. data/vendor/cmock/vendor/unity/examples/example_1/readme.txt +5 -0
  130. data/vendor/cmock/vendor/unity/examples/example_1/src/ProductionCode.c +24 -0
  131. data/vendor/cmock/vendor/unity/examples/example_1/src/ProductionCode.h +3 -0
  132. data/vendor/cmock/vendor/unity/examples/example_1/src/ProductionCode2.c +11 -0
  133. data/vendor/cmock/vendor/unity/examples/example_1/src/ProductionCode2.h +2 -0
  134. data/vendor/cmock/vendor/unity/examples/example_1/test/TestProductionCode.c +62 -0
  135. data/vendor/cmock/vendor/unity/examples/example_1/test/TestProductionCode2.c +31 -0
  136. data/vendor/cmock/vendor/unity/examples/example_1/test/test_runners/TestProductionCode2_Runner.c +53 -0
  137. data/vendor/cmock/vendor/unity/examples/example_1/test/test_runners/TestProductionCode_Runner.c +57 -0
  138. data/vendor/cmock/vendor/unity/examples/example_2/makefile +70 -0
  139. data/vendor/cmock/vendor/unity/examples/example_2/readme.txt +5 -0
  140. data/vendor/cmock/vendor/unity/examples/example_2/src/ProductionCode.c +24 -0
  141. data/vendor/cmock/vendor/unity/examples/example_2/src/ProductionCode.h +3 -0
  142. data/vendor/cmock/vendor/unity/examples/example_2/src/ProductionCode2.c +11 -0
  143. data/vendor/cmock/vendor/unity/examples/example_2/src/ProductionCode2.h +2 -0
  144. data/vendor/cmock/vendor/unity/examples/example_2/test/TestProductionCode.c +64 -0
  145. data/vendor/cmock/vendor/unity/examples/example_2/test/TestProductionCode2.c +33 -0
  146. data/vendor/cmock/vendor/unity/examples/example_2/test/test_runners/TestProductionCode2_Runner.c +9 -0
  147. data/vendor/cmock/vendor/unity/examples/example_2/test/test_runners/TestProductionCode_Runner.c +11 -0
  148. data/vendor/cmock/vendor/unity/examples/example_2/test/test_runners/all_tests.c +12 -0
  149. data/vendor/cmock/vendor/unity/examples/example_3/helper/UnityHelper.c +10 -0
  150. data/vendor/cmock/vendor/unity/examples/example_3/helper/UnityHelper.h +12 -0
  151. data/vendor/cmock/vendor/unity/examples/example_3/rakefile.rb +43 -0
  152. data/vendor/cmock/vendor/unity/examples/example_3/rakefile_helper.rb +249 -0
  153. data/vendor/cmock/vendor/unity/examples/example_3/readme.txt +13 -0
  154. data/vendor/cmock/vendor/unity/examples/example_3/src/ProductionCode.c +24 -0
  155. data/vendor/cmock/vendor/unity/examples/example_3/src/ProductionCode.h +3 -0
  156. data/vendor/cmock/vendor/unity/examples/example_3/src/ProductionCode2.c +11 -0
  157. data/vendor/cmock/vendor/unity/examples/example_3/src/ProductionCode2.h +2 -0
  158. data/vendor/cmock/vendor/unity/examples/example_3/target_gcc_32.yml +46 -0
  159. data/vendor/cmock/vendor/unity/examples/example_3/test/TestProductionCode.c +62 -0
  160. data/vendor/cmock/vendor/unity/examples/example_3/test/TestProductionCode2.c +31 -0
  161. data/vendor/cmock/vendor/unity/examples/unity_config.h +247 -0
  162. data/vendor/cmock/vendor/unity/extras/eclipse/error_parsers.txt +26 -0
  163. data/vendor/cmock/vendor/unity/extras/fixture/rakefile.rb +48 -0
  164. data/vendor/cmock/vendor/unity/extras/fixture/rakefile_helper.rb +178 -0
  165. data/vendor/cmock/vendor/unity/extras/fixture/readme.txt +9 -0
  166. data/vendor/cmock/vendor/unity/extras/fixture/src/unity_fixture.c +436 -0
  167. data/vendor/cmock/vendor/unity/extras/fixture/src/unity_fixture.h +83 -0
  168. data/vendor/cmock/vendor/unity/extras/fixture/src/unity_fixture_internals.h +51 -0
  169. data/vendor/cmock/vendor/unity/extras/fixture/src/unity_fixture_malloc_overrides.h +47 -0
  170. data/vendor/cmock/vendor/unity/extras/fixture/test/Makefile +75 -0
  171. data/vendor/cmock/vendor/unity/extras/fixture/test/main/AllTests.c +22 -0
  172. data/vendor/cmock/vendor/unity/extras/fixture/test/template_fixture_tests.c +39 -0
  173. data/vendor/cmock/vendor/unity/extras/fixture/test/unity_fixture_Test.c +543 -0
  174. data/vendor/cmock/vendor/unity/extras/fixture/test/unity_fixture_TestRunner.c +57 -0
  175. data/vendor/cmock/vendor/unity/extras/fixture/test/unity_output_Spy.c +57 -0
  176. data/vendor/cmock/vendor/unity/extras/fixture/test/unity_output_Spy.h +17 -0
  177. data/vendor/cmock/vendor/unity/release/build.info +2 -0
  178. data/vendor/cmock/vendor/unity/release/version.info +2 -0
  179. data/vendor/cmock/vendor/unity/src/unity.c +1572 -0
  180. data/vendor/cmock/vendor/unity/src/unity.h +503 -0
  181. data/vendor/cmock/vendor/unity/src/unity_internals.h +924 -0
  182. data/vendor/cmock/vendor/unity/test/Makefile +68 -0
  183. data/vendor/cmock/vendor/unity/test/expectdata/testsample_cmd.c +61 -0
  184. data/vendor/cmock/vendor/unity/test/expectdata/testsample_def.c +57 -0
  185. data/vendor/cmock/vendor/unity/test/expectdata/testsample_head1.c +55 -0
  186. data/vendor/cmock/vendor/unity/test/expectdata/testsample_head1.h +15 -0
  187. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_cmd.c +80 -0
  188. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_def.c +76 -0
  189. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_head1.c +75 -0
  190. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_head1.h +13 -0
  191. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_new1.c +89 -0
  192. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_new2.c +89 -0
  193. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_param.c +77 -0
  194. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_run1.c +89 -0
  195. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_run2.c +89 -0
  196. data/vendor/cmock/vendor/unity/test/expectdata/testsample_mock_yaml.c +90 -0
  197. data/vendor/cmock/vendor/unity/test/expectdata/testsample_new1.c +67 -0
  198. data/vendor/cmock/vendor/unity/test/expectdata/testsample_new2.c +70 -0
  199. data/vendor/cmock/vendor/unity/test/expectdata/testsample_param.c +58 -0
  200. data/vendor/cmock/vendor/unity/test/expectdata/testsample_run1.c +67 -0
  201. data/vendor/cmock/vendor/unity/test/expectdata/testsample_run2.c +70 -0
  202. data/vendor/cmock/vendor/unity/test/expectdata/testsample_yaml.c +71 -0
  203. data/vendor/cmock/vendor/unity/test/rakefile +125 -0
  204. data/vendor/cmock/vendor/unity/test/rakefile_helper.rb +260 -0
  205. data/vendor/cmock/vendor/unity/test/spec/generate_module_existing_file_spec.rb +158 -0
  206. data/vendor/cmock/vendor/unity/test/targets/clang_file.yml +78 -0
  207. data/vendor/cmock/vendor/unity/test/targets/clang_strict.yml +78 -0
  208. data/vendor/cmock/vendor/unity/test/targets/gcc_32.yml +49 -0
  209. data/vendor/cmock/vendor/unity/test/targets/gcc_64.yml +50 -0
  210. data/vendor/cmock/vendor/unity/test/targets/gcc_auto_limits.yml +47 -0
  211. data/vendor/cmock/vendor/unity/test/targets/gcc_auto_stdint.yml +59 -0
  212. data/vendor/cmock/vendor/unity/test/targets/gcc_manual_math.yml +47 -0
  213. data/vendor/cmock/vendor/unity/test/targets/hitech_picc18.yml +101 -0
  214. data/vendor/cmock/vendor/unity/test/targets/iar_arm_v4.yml +90 -0
  215. data/vendor/cmock/vendor/unity/test/targets/iar_arm_v5.yml +80 -0
  216. data/vendor/cmock/vendor/unity/test/targets/iar_arm_v5_3.yml +80 -0
  217. data/vendor/cmock/vendor/unity/test/targets/iar_armcortex_LM3S9B92_v5_4.yml +94 -0
  218. data/vendor/cmock/vendor/unity/test/targets/iar_cortexm3_v5.yml +84 -0
  219. data/vendor/cmock/vendor/unity/test/targets/iar_msp430.yml +95 -0
  220. data/vendor/cmock/vendor/unity/test/targets/iar_sh2a_v6.yml +86 -0
  221. data/vendor/cmock/vendor/unity/test/testdata/CException.h +11 -0
  222. data/vendor/cmock/vendor/unity/test/testdata/Defs.h +8 -0
  223. data/vendor/cmock/vendor/unity/test/testdata/cmock.h +14 -0
  224. data/vendor/cmock/vendor/unity/test/testdata/mockMock.h +13 -0
  225. data/vendor/cmock/vendor/unity/test/testdata/testRunnerGenerator.c +186 -0
  226. data/vendor/cmock/vendor/unity/test/testdata/testRunnerGeneratorSmall.c +70 -0
  227. data/vendor/cmock/vendor/unity/test/testdata/testRunnerGeneratorWithMocks.c +195 -0
  228. data/vendor/cmock/vendor/unity/test/tests/test_generate_test_runner.rb +1252 -0
  229. data/vendor/cmock/vendor/unity/test/tests/testparameterized.c +113 -0
  230. data/vendor/cmock/vendor/unity/test/tests/testunity.c +5371 -0
  231. data/vendor/unity/auto/generate_test_runner.rb +30 -10
  232. data/vendor/unity/auto/parse_output.rb +212 -109
  233. data/vendor/unity/docs/ThrowTheSwitchCodingStandard.md +9 -10
  234. data/vendor/unity/docs/UnityAssertionsReference.md +11 -2
  235. data/vendor/unity/docs/UnityConfigurationGuide.md +90 -55
  236. data/vendor/unity/docs/UnityGettingStartedGuide.md +6 -5
  237. data/vendor/unity/docs/UnityHelperScriptsGuide.md +23 -5
  238. data/vendor/unity/examples/unity_config.h +8 -0
  239. data/vendor/unity/extras/fixture/src/unity_fixture.c +4 -0
  240. data/vendor/unity/extras/fixture/src/unity_fixture.h +1 -1
  241. data/vendor/unity/extras/fixture/src/unity_fixture_internals.h +2 -2
  242. data/vendor/unity/release/build.info +1 -1
  243. data/vendor/unity/release/version.info +1 -1
  244. data/vendor/unity/src/unity.c +64 -57
  245. data/vendor/unity/src/unity.h +111 -7
  246. data/vendor/unity/src/unity_internals.h +173 -73
  247. data/vendor/unity/test/Makefile +5 -1
  248. data/vendor/unity/test/testdata/testRunnerGenerator.c +4 -1
  249. data/vendor/unity/test/testdata/testRunnerGeneratorSmall.c +4 -1
  250. data/vendor/unity/test/testdata/testRunnerGeneratorWithMocks.c +4 -1
  251. data/vendor/unity/test/tests/testparameterized.c +5 -2
  252. data/vendor/unity/test/tests/testunity.c +34 -0
  253. metadata +150 -2
@@ -0,0 +1,36 @@
1
+ #this is a sample configuration file for generate_module
2
+ #you would use it by calling generate_module with the -ygenerate_config.yml option
3
+ #files like this are useful for customizing generate_module to your environment
4
+ :generate_module:
5
+ :defaults:
6
+ #these defaults are used in place of any missing options at the command line
7
+ :path_src: ../src/
8
+ :path_inc: ../src/
9
+ :path_tst: ../test/
10
+ :update_svn: true
11
+ :includes:
12
+ #use [] for no additional includes, otherwise list the includes on separate lines
13
+ :src:
14
+ - Defs.h
15
+ - Board.h
16
+ :inc: []
17
+ :tst:
18
+ - Defs.h
19
+ - Board.h
20
+ - Exception.h
21
+ :boilerplates:
22
+ #these are inserted at the top of generated files.
23
+ #just comment out or remove if not desired.
24
+ #use %1$s where you would like the file name to appear (path/extension not included)
25
+ :src: |
26
+ //-------------------------------------------
27
+ // %1$s.c
28
+ //-------------------------------------------
29
+ :inc: |
30
+ //-------------------------------------------
31
+ // %1$s.h
32
+ //-------------------------------------------
33
+ :tst: |
34
+ //-------------------------------------------
35
+ // Test%1$s.c : Units tests for %1$s.c
36
+ //-------------------------------------------
@@ -0,0 +1,308 @@
1
+ # ==========================================
2
+ # Unity Project - A Test Framework for C
3
+ # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
4
+ # [Released under MIT License. Please refer to license.txt for details]
5
+ # ==========================================
6
+
7
+ # This script creates all the files with start code necessary for a new module.
8
+ # A simple module only requires a source file, header file, and test file.
9
+ # Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware).
10
+
11
+ require 'rubygems'
12
+ require 'fileutils'
13
+ require 'pathname'
14
+
15
+ # TEMPLATE_TST
16
+ TEMPLATE_TST ||= '#include "unity.h"
17
+ %2$s#include "%1$s.h"
18
+
19
+ void setUp(void)
20
+ {
21
+ }
22
+
23
+ void tearDown(void)
24
+ {
25
+ }
26
+
27
+ void test_%1$s_NeedToImplement(void)
28
+ {
29
+ TEST_IGNORE_MESSAGE("Need to Implement %1$s");
30
+ }
31
+ '.freeze
32
+
33
+ # TEMPLATE_SRC
34
+ TEMPLATE_SRC ||= '%2$s#include "%1$s.h"
35
+ '.freeze
36
+
37
+ # TEMPLATE_INC
38
+ TEMPLATE_INC ||= '#ifndef _%3$s_H
39
+ #define _%3$s_H
40
+ %2$s
41
+
42
+ #endif // _%3$s_H
43
+ '.freeze
44
+
45
+ class UnityModuleGenerator
46
+ ############################
47
+ def initialize(options = nil)
48
+ here = File.expand_path(File.dirname(__FILE__)) + '/'
49
+
50
+ @options = UnityModuleGenerator.default_options
51
+ case options
52
+ when NilClass then @options
53
+ when String then @options.merge!(UnityModuleGenerator.grab_config(options))
54
+ when Hash then @options.merge!(options)
55
+ else raise 'If you specify arguments, it should be a filename or a hash of options'
56
+ end
57
+
58
+ # Create default file paths if none were provided
59
+ @options[:path_src] = here + '../src/' if @options[:path_src].nil?
60
+ @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil?
61
+ @options[:path_tst] = here + '../test/' if @options[:path_tst].nil?
62
+ @options[:path_src] += '/' unless @options[:path_src][-1] == 47
63
+ @options[:path_inc] += '/' unless @options[:path_inc][-1] == 47
64
+ @options[:path_tst] += '/' unless @options[:path_tst][-1] == 47
65
+
66
+ # Built in patterns
67
+ @patterns = {
68
+ 'src' => {
69
+ '' => { inc: [] }
70
+ },
71
+ 'test' => {
72
+ '' => { inc: [] }
73
+ },
74
+ 'dh' => {
75
+ 'Driver' => { inc: [create_filename('%1$s', 'Hardware.h')] },
76
+ 'Hardware' => { inc: [] }
77
+ },
78
+ 'dih' => {
79
+ 'Driver' => { inc: [create_filename('%1$s', 'Hardware.h'), create_filename('%1$s', 'Interrupt.h')] },
80
+ 'Interrupt' => { inc: [create_filename('%1$s', 'Hardware.h')] },
81
+ 'Hardware' => { inc: [] }
82
+ },
83
+ 'mch' => {
84
+ 'Model' => { inc: [] },
85
+ 'Conductor' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'Hardware.h')] },
86
+ 'Hardware' => { inc: [] }
87
+ },
88
+ 'mvp' => {
89
+ 'Model' => { inc: [] },
90
+ 'Presenter' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'View.h')] },
91
+ 'View' => { inc: [] }
92
+ }
93
+ }
94
+ end
95
+
96
+ ############################
97
+ def self.default_options
98
+ {
99
+ pattern: 'src',
100
+ includes: {
101
+ src: [],
102
+ inc: [],
103
+ tst: []
104
+ },
105
+ update_svn: false,
106
+ boilerplates: {},
107
+ test_prefix: 'Test',
108
+ mock_prefix: 'Mock'
109
+ }
110
+ end
111
+
112
+ ############################
113
+ def self.grab_config(config_file)
114
+ options = default_options
115
+ unless config_file.nil? || config_file.empty?
116
+ require 'yaml'
117
+ yaml_guts = YAML.load_file(config_file)
118
+ options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
119
+ raise "No :unity or :cmock section found in #{config_file}" unless options
120
+ end
121
+ options
122
+ end
123
+
124
+ ############################
125
+ def files_to_operate_on(module_name, pattern = nil)
126
+ # strip any leading path information from the module name and save for later
127
+ subfolder = File.dirname(module_name)
128
+ module_name = File.basename(module_name)
129
+
130
+ # create triad definition
131
+ prefix = @options[:test_prefix] || 'Test'
132
+ triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] },
133
+ { ext: '.h', path: @options[:path_inc], prefix: '', template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] },
134
+ { ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst] }]
135
+
136
+ # prepare the pattern for use
137
+ pattern = (pattern || @options[:pattern] || 'src').downcase
138
+ patterns = @patterns[pattern]
139
+ raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil?
140
+
141
+ # single file patterns (currently just 'test') can reject the other parts of the triad
142
+ triad.select! { |v| v[:inc] == :tst } if pattern == 'test'
143
+
144
+ # Assemble the path/names of the files we need to work with.
145
+ files = []
146
+ triad.each do |cfg|
147
+ patterns.each_pair do |pattern_file, pattern_traits|
148
+ submodule_name = create_filename(module_name, pattern_file)
149
+ filename = cfg[:prefix] + submodule_name + cfg[:ext]
150
+ files << {
151
+ path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
152
+ name: submodule_name,
153
+ template: cfg[:template],
154
+ boilerplate: cfg[:boilerplate],
155
+ includes: case (cfg[:inc])
156
+ when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) })
157
+ when :inc then (@options[:includes][:inc] || [])
158
+ when :tst then (@options[:includes][:tst] || []) | (pattern_traits[:inc].map { |f| format("#{@options[:mock_prefix]}#{f}", module_name) })
159
+ end
160
+ }
161
+ end
162
+ end
163
+
164
+ files
165
+ end
166
+
167
+ ############################
168
+ def create_filename(part1, part2 = '')
169
+ if part2.empty?
170
+ case (@options[:naming])
171
+ when 'bumpy' then part1
172
+ when 'camel' then part1
173
+ when 'snake' then part1.downcase
174
+ when 'caps' then part1.upcase
175
+ else part1
176
+ end
177
+ else
178
+ case (@options[:naming])
179
+ when 'bumpy' then part1 + part2
180
+ when 'camel' then part1 + part2
181
+ when 'snake' then part1.downcase + '_' + part2.downcase
182
+ when 'caps' then part1.upcase + '_' + part2.upcase
183
+ else part1 + '_' + part2
184
+ end
185
+ end
186
+ end
187
+
188
+ ############################
189
+ def generate(module_name, pattern = nil)
190
+ files = files_to_operate_on(module_name, pattern)
191
+
192
+ # Abort if all of the module files already exist
193
+ all_files_exist = true
194
+ files.each do |file|
195
+ all_files_exist = false unless File.exist?(file[:path])
196
+ end
197
+ raise "ERROR: File #{files[0][:name]} already exists. Exiting." if all_files_exist
198
+
199
+ # Create Source Modules
200
+ files.each_with_index do |file, _i|
201
+ # If this file already exists, don't overwrite it.
202
+ if File.exist?(file[:path])
203
+ puts "File #{file[:path]} already exists!"
204
+ next
205
+ end
206
+ # Create the path first if necessary.
207
+ FileUtils.mkdir_p(File.dirname(file[:path]), verbose: false)
208
+ File.open(file[:path], 'w') do |f|
209
+ f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
210
+ f.write(file[:template] % [file[:name],
211
+ file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
212
+ file[:name].upcase])
213
+ end
214
+ if @options[:update_svn]
215
+ `svn add \"#{file[:path]}\"`
216
+ if $!.exitstatus.zero?
217
+ puts "File #{file[:path]} created and added to source control"
218
+ else
219
+ puts "File #{file[:path]} created but FAILED adding to source control!"
220
+ end
221
+ else
222
+ puts "File #{file[:path]} created"
223
+ end
224
+ end
225
+ puts 'Generate Complete'
226
+ end
227
+
228
+ ############################
229
+ def destroy(module_name, pattern = nil)
230
+ files_to_operate_on(module_name, pattern).each do |filespec|
231
+ file = filespec[:path]
232
+ if File.exist?(file)
233
+ if @options[:update_svn]
234
+ `svn delete \"#{file}\" --force`
235
+ puts "File #{file} deleted and removed from source control"
236
+ else
237
+ FileUtils.remove(file)
238
+ puts "File #{file} deleted"
239
+ end
240
+ else
241
+ puts "File #{file} does not exist so cannot be removed."
242
+ end
243
+ end
244
+ puts 'Destroy Complete'
245
+ end
246
+ end
247
+
248
+ ############################
249
+ # Handle As Command Line If Called That Way
250
+ if $0 == __FILE__
251
+ destroy = false
252
+ options = {}
253
+ module_name = nil
254
+
255
+ # Parse the command line parameters.
256
+ ARGV.each do |arg|
257
+ case arg
258
+ when /^-d/ then destroy = true
259
+ when /^-u/ then options[:update_svn] = true
260
+ when /^-p\"?(\w+)\"?/ then options[:pattern] = Regexp.last_match(1)
261
+ when /^-s\"?(.+)\"?/ then options[:path_src] = Regexp.last_match(1)
262
+ when /^-i\"?(.+)\"?/ then options[:path_inc] = Regexp.last_match(1)
263
+ when /^-t\"?(.+)\"?/ then options[:path_tst] = Regexp.last_match(1)
264
+ when /^-n\"?(.+)\"?/ then options[:naming] = Regexp.last_match(1)
265
+ when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(1))
266
+ when /^(\w+)/
267
+ raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
268
+ module_name = arg
269
+ when /^-(h|-help)/
270
+ ARGV = [].freeze
271
+ else
272
+ raise "ERROR: Unknown option specified '#{arg}'"
273
+ end
274
+ end
275
+
276
+ unless ARGV[0]
277
+ puts ["\nGENERATE MODULE\n-------- ------",
278
+ "\nUsage: ruby generate_module [options] module_name",
279
+ " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
280
+ " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)",
281
+ " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)",
282
+ ' -p"MCH" sets the output pattern to MCH.',
283
+ ' dh - driver hardware.',
284
+ ' dih - driver interrupt hardware.',
285
+ ' mch - model conductor hardware.',
286
+ ' mvp - model view presenter.',
287
+ ' src - just a source module, header and test. (DEFAULT)',
288
+ ' test - just a test file.',
289
+ ' -d destroy module instead of creating it.',
290
+ ' -n"camel" sets the file naming convention.',
291
+ ' bumpy - BumpyCaseFilenames.',
292
+ ' camel - camelCaseFilenames.',
293
+ ' snake - snake_case_filenames.',
294
+ ' caps - CAPS_CASE_FILENAMES.',
295
+ ' -u update subversion too (requires subversion command line)',
296
+ ' -y"my.yml" selects a different yaml config file for module generation',
297
+ ''].join("\n")
298
+ exit
299
+ end
300
+
301
+ raise 'ERROR: You must have a Module name specified! (use option -h for help)' if module_name.nil?
302
+ if destroy
303
+ UnityModuleGenerator.new(options).destroy(module_name)
304
+ else
305
+ UnityModuleGenerator.new(options).generate(module_name)
306
+ end
307
+
308
+ end
@@ -0,0 +1,457 @@
1
+ # ==========================================
2
+ # Unity Project - A Test Framework for C
3
+ # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
4
+ # [Released under MIT License. Please refer to license.txt for details]
5
+ # ==========================================
6
+
7
+ File.expand_path(File.join(File.dirname(__FILE__), 'colour_prompt'))
8
+
9
+ class UnityTestRunnerGenerator
10
+ def initialize(options = nil)
11
+ @options = UnityTestRunnerGenerator.default_options
12
+ case options
13
+ when NilClass then @options
14
+ when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options))
15
+ when Hash then @options.merge!(options)
16
+ else raise 'If you specify arguments, it should be a filename or a hash of options'
17
+ end
18
+ require "#{File.expand_path(File.dirname(__FILE__))}/type_sanitizer"
19
+ end
20
+
21
+ def self.default_options
22
+ {
23
+ includes: [],
24
+ defines: [],
25
+ plugins: [],
26
+ framework: :unity,
27
+ test_prefix: 'test|spec|should',
28
+ mock_prefix: 'Mock',
29
+ mock_suffix: '',
30
+ setup_name: 'setUp',
31
+ teardown_name: 'tearDown',
32
+ main_name: 'main', # set to :auto to automatically generate each time
33
+ main_export_decl: '',
34
+ cmdline_args: false,
35
+ use_param_tests: false
36
+ }
37
+ end
38
+
39
+ def self.grab_config(config_file)
40
+ options = default_options
41
+ unless config_file.nil? || config_file.empty?
42
+ require 'yaml'
43
+ yaml_guts = YAML.load_file(config_file)
44
+ options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
45
+ raise "No :unity or :cmock section found in #{config_file}" unless options
46
+ end
47
+ options
48
+ end
49
+
50
+ def run(input_file, output_file, options = nil)
51
+ @options.merge!(options) unless options.nil?
52
+
53
+ # pull required data from source file
54
+ source = File.read(input_file)
55
+ source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
56
+ tests = find_tests(source)
57
+ headers = find_includes(source)
58
+ testfile_includes = (headers[:local] + headers[:system])
59
+ used_mocks = find_mocks(testfile_includes)
60
+ testfile_includes = (testfile_includes - used_mocks)
61
+ testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
62
+
63
+ # build runner file
64
+ generate(input_file, output_file, tests, used_mocks, testfile_includes)
65
+
66
+ # determine which files were used to return them
67
+ all_files_used = [input_file, output_file]
68
+ all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty?
69
+ all_files_used += @options[:includes] unless @options[:includes].empty?
70
+ all_files_used += headers[:linkonly] unless headers[:linkonly].empty?
71
+ all_files_used.uniq
72
+ end
73
+
74
+ def generate(input_file, output_file, tests, used_mocks, testfile_includes)
75
+ File.open(output_file, 'w') do |output|
76
+ create_header(output, used_mocks, testfile_includes)
77
+ create_externs(output, tests, used_mocks)
78
+ create_mock_management(output, used_mocks)
79
+ create_suite_setup(output)
80
+ create_suite_teardown(output)
81
+ create_reset(output, used_mocks)
82
+ create_main(output, input_file, tests, used_mocks)
83
+ end
84
+
85
+ return unless @options[:header_file] && !@options[:header_file].empty?
86
+
87
+ File.open(@options[:header_file], 'w') do |output|
88
+ create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks)
89
+ end
90
+ end
91
+
92
+ def find_tests(source)
93
+ tests_and_line_numbers = []
94
+
95
+ source_scrubbed = source.clone
96
+ source_scrubbed = source_scrubbed.gsub(/"[^"\n]*"/, '') # remove things in strings
97
+ source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments
98
+ source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments
99
+ lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line
100
+ | (;|\{|\}) /x) # Match ;, {, and } as end of lines
101
+
102
+ lines.each_with_index do |line, _index|
103
+ # find tests
104
+ next unless line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/
105
+ arguments = Regexp.last_match(1)
106
+ name = Regexp.last_match(2)
107
+ call = Regexp.last_match(3)
108
+ params = Regexp.last_match(4)
109
+ args = nil
110
+ if @options[:use_param_tests] && !arguments.empty?
111
+ args = []
112
+ arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] }
113
+ end
114
+ tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 }
115
+ end
116
+ tests_and_line_numbers.uniq! { |v| v[:test] }
117
+
118
+ # determine line numbers and create tests to run
119
+ source_lines = source.split("\n")
120
+ source_index = 0
121
+ tests_and_line_numbers.size.times do |i|
122
+ source_lines[source_index..-1].each_with_index do |line, index|
123
+ next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/
124
+ source_index += index
125
+ tests_and_line_numbers[i][:line_number] = source_index + 1
126
+ break
127
+ end
128
+ end
129
+
130
+ tests_and_line_numbers
131
+ end
132
+
133
+ def find_includes(source)
134
+ # remove comments (block and line, in three steps to ensure correct precedence)
135
+ source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
136
+ source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
137
+ source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
138
+
139
+ # parse out includes
140
+ includes = {
141
+ local: source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten,
142
+ system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" },
143
+ linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+)\.[cC]\w*\s*\"/).flatten
144
+ }
145
+ includes
146
+ end
147
+
148
+ def find_mocks(includes)
149
+ mock_headers = []
150
+ includes.each do |include_path|
151
+ include_file = File.basename(include_path)
152
+ mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}$/i
153
+ end
154
+ mock_headers
155
+ end
156
+
157
+ def create_header(output, mocks, testfile_includes = [])
158
+ output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
159
+ create_runtest(output, mocks)
160
+ output.puts("\n/*=======Automagically Detected Files To Include=====*/")
161
+ output.puts('#ifdef __WIN32__')
162
+ output.puts('#define UNITY_INCLUDE_SETUP_STUBS')
163
+ output.puts('#endif')
164
+ output.puts("#include \"#{@options[:framework]}.h\"")
165
+ output.puts('#include "cmock.h"') unless mocks.empty?
166
+ output.puts('#ifndef UNITY_EXCLUDE_SETJMP_H')
167
+ output.puts('#include <setjmp.h>')
168
+ output.puts("#endif")
169
+ output.puts('#include <stdio.h>')
170
+ if @options[:defines] && !@options[:defines].empty?
171
+ @options[:defines].each { |d| output.puts("#define #{d}") }
172
+ end
173
+ if @options[:header_file] && !@options[:header_file].empty?
174
+ output.puts("#include \"#{File.basename(@options[:header_file])}\"")
175
+ else
176
+ @options[:includes].flatten.uniq.compact.each do |inc|
177
+ output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
178
+ end
179
+ testfile_includes.each do |inc|
180
+ output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
181
+ end
182
+ end
183
+ mocks.each do |mock|
184
+ output.puts("#include \"#{mock.gsub('.h', '')}.h\"")
185
+ end
186
+ output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
187
+
188
+ return unless @options[:enforce_strict_ordering]
189
+
190
+ output.puts('')
191
+ output.puts('int GlobalExpectCount;')
192
+ output.puts('int GlobalVerifyOrder;')
193
+ output.puts('char* GlobalOrderError;')
194
+ end
195
+
196
+ def create_externs(output, tests, _mocks)
197
+ output.puts("\n/*=======External Functions This Runner Calls=====*/")
198
+ output.puts("extern void #{@options[:setup_name]}(void);")
199
+ output.puts("extern void #{@options[:teardown_name]}(void);")
200
+ tests.each do |test|
201
+ output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});")
202
+ end
203
+ output.puts('')
204
+ end
205
+
206
+ def create_mock_management(output, mock_headers)
207
+ return if mock_headers.empty?
208
+
209
+ output.puts("\n/*=======Mock Management=====*/")
210
+ output.puts('static void CMock_Init(void)')
211
+ output.puts('{')
212
+
213
+ if @options[:enforce_strict_ordering]
214
+ output.puts(' GlobalExpectCount = 0;')
215
+ output.puts(' GlobalVerifyOrder = 0;')
216
+ output.puts(' GlobalOrderError = NULL;')
217
+ end
218
+
219
+ mocks = mock_headers.map { |mock| File.basename(mock) }
220
+ mocks.each do |mock|
221
+ mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
222
+ output.puts(" #{mock_clean}_Init();")
223
+ end
224
+ output.puts("}\n")
225
+
226
+ output.puts('static void CMock_Verify(void)')
227
+ output.puts('{')
228
+ mocks.each do |mock|
229
+ mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
230
+ output.puts(" #{mock_clean}_Verify();")
231
+ end
232
+ output.puts("}\n")
233
+
234
+ output.puts('static void CMock_Destroy(void)')
235
+ output.puts('{')
236
+ mocks.each do |mock|
237
+ mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
238
+ output.puts(" #{mock_clean}_Destroy();")
239
+ end
240
+ output.puts("}\n")
241
+ end
242
+
243
+ def create_suite_setup(output)
244
+ output.puts("\n/*=======Suite Setup=====*/")
245
+ output.puts('static void suite_setup(void)')
246
+ output.puts('{')
247
+ if @options[:suite_setup].nil?
248
+ # New style, call suiteSetUp() if we can use weak symbols
249
+ output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)')
250
+ output.puts(' suiteSetUp();')
251
+ output.puts('#endif')
252
+ else
253
+ # Old style, C code embedded in the :suite_setup option
254
+ output.puts(@options[:suite_setup])
255
+ end
256
+ output.puts('}')
257
+ end
258
+
259
+ def create_suite_teardown(output)
260
+ output.puts("\n/*=======Suite Teardown=====*/")
261
+ output.puts('static int suite_teardown(int num_failures)')
262
+ output.puts('{')
263
+ if @options[:suite_teardown].nil?
264
+ # New style, call suiteTearDown() if we can use weak symbols
265
+ output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)')
266
+ output.puts(' return suiteTearDown(num_failures);')
267
+ output.puts('#else')
268
+ output.puts(' return num_failures;')
269
+ output.puts('#endif')
270
+ else
271
+ # Old style, C code embedded in the :suite_teardown option
272
+ output.puts(@options[:suite_teardown])
273
+ end
274
+ output.puts('}')
275
+ end
276
+
277
+ def create_runtest(output, used_mocks)
278
+ cexception = @options[:plugins].include? :cexception
279
+ va_args1 = @options[:use_param_tests] ? ', ...' : ''
280
+ va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : ''
281
+ output.puts("\n/*=======Test Runner Used To Run Each Test Below=====*/")
282
+ output.puts('#define RUN_TEST_NO_ARGS') if @options[:use_param_tests]
283
+ output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\")
284
+ output.puts('{ \\')
285
+ output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\")
286
+ output.puts(' Unity.CurrentTestLineNumber = TestLineNum; \\')
287
+ output.puts(' if (UnityTestMatches()) { \\') if @options[:cmdline_args]
288
+ output.puts(' Unity.NumberOfTests++; \\')
289
+ output.puts(' CMock_Init(); \\') unless used_mocks.empty?
290
+ output.puts(' UNITY_CLR_DETAILS(); \\') unless used_mocks.empty?
291
+ output.puts(' if (TEST_PROTECT()) \\')
292
+ output.puts(' { \\')
293
+ output.puts(' CEXCEPTION_T e; \\') if cexception
294
+ output.puts(' Try { \\') if cexception
295
+ output.puts(" #{@options[:setup_name]}(); \\")
296
+ output.puts(" TestFunc(#{va_args2}); \\")
297
+ output.puts(' } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \\') if cexception
298
+ output.puts(' } \\')
299
+ output.puts(' if (TEST_PROTECT()) \\')
300
+ output.puts(' { \\')
301
+ output.puts(" #{@options[:teardown_name]}(); \\")
302
+ output.puts(' CMock_Verify(); \\') unless used_mocks.empty?
303
+ output.puts(' } \\')
304
+ output.puts(' CMock_Destroy(); \\') unless used_mocks.empty?
305
+ output.puts(' UnityConcludeTest(); \\')
306
+ output.puts(' } \\') if @options[:cmdline_args]
307
+ output.puts("}\n")
308
+ end
309
+
310
+ def create_reset(output, used_mocks)
311
+ output.puts("\n/*=======Test Reset Option=====*/")
312
+ output.puts('void resetTest(void);')
313
+ output.puts('void resetTest(void)')
314
+ output.puts('{')
315
+ output.puts(' CMock_Verify();') unless used_mocks.empty?
316
+ output.puts(' CMock_Destroy();') unless used_mocks.empty?
317
+ output.puts(" #{@options[:teardown_name]}();")
318
+ output.puts(' CMock_Init();') unless used_mocks.empty?
319
+ output.puts(" #{@options[:setup_name]}();")
320
+ output.puts('}')
321
+ end
322
+
323
+ def create_main(output, filename, tests, used_mocks)
324
+ output.puts("\n\n/*=======MAIN=====*/")
325
+ main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
326
+ if @options[:cmdline_args]
327
+ if main_name != 'main'
328
+ output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);")
329
+ end
330
+ output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)")
331
+ output.puts('{')
332
+ output.puts(' int parse_status = UnityParseOptions(argc, argv);')
333
+ output.puts(' if (parse_status != 0)')
334
+ output.puts(' {')
335
+ output.puts(' if (parse_status < 0)')
336
+ output.puts(' {')
337
+ output.puts(" UnityPrint(\"#{filename.gsub('.c', '')}.\");")
338
+ output.puts(' UNITY_PRINT_EOL();')
339
+ if @options[:use_param_tests]
340
+ tests.each do |test|
341
+ if test[:args].nil? || test[:args].empty?
342
+ output.puts(" UnityPrint(\" #{test[:test]}(RUN_TEST_NO_ARGS)\");")
343
+ output.puts(' UNITY_PRINT_EOL();')
344
+ else
345
+ test[:args].each do |args|
346
+ output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");")
347
+ output.puts(' UNITY_PRINT_EOL();')
348
+ end
349
+ end
350
+ end
351
+ else
352
+ tests.each { |test| output.puts(" UnityPrint(\" #{test[:test]}\");\n UNITY_PRINT_EOL();") }
353
+ end
354
+ output.puts(' return 0;')
355
+ output.puts(' }')
356
+ output.puts(' return parse_status;')
357
+ output.puts(' }')
358
+ else
359
+ if main_name != 'main'
360
+ output.puts("#{@options[:main_export_decl]} int #{main_name}(void);")
361
+ end
362
+ output.puts("int #{main_name}(void)")
363
+ output.puts('{')
364
+ end
365
+ output.puts(' suite_setup();')
366
+ output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
367
+ if @options[:use_param_tests]
368
+ tests.each do |test|
369
+ if test[:args].nil? || test[:args].empty?
370
+ output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);")
371
+ else
372
+ test[:args].each { |args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});") }
373
+ end
374
+ end
375
+ else
376
+ tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") }
377
+ end
378
+ output.puts
379
+ output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty?
380
+ output.puts(" return suite_teardown(UnityEnd());")
381
+ output.puts('}')
382
+ end
383
+
384
+ def create_h_file(output, filename, tests, testfile_includes, used_mocks)
385
+ filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase
386
+ output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
387
+ output.puts("#ifndef _#{filename}")
388
+ output.puts("#define _#{filename}\n\n")
389
+ output.puts("#include \"#{@options[:framework]}.h\"")
390
+ output.puts('#include "cmock.h"') unless used_mocks.empty?
391
+ @options[:includes].flatten.uniq.compact.each do |inc|
392
+ output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
393
+ end
394
+ testfile_includes.each do |inc|
395
+ output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
396
+ end
397
+ output.puts "\n"
398
+ tests.each do |test|
399
+ if test[:params].nil? || test[:params].empty?
400
+ output.puts("void #{test[:test]}(void);")
401
+ else
402
+ output.puts("void #{test[:test]}(#{test[:params]});")
403
+ end
404
+ end
405
+ output.puts("#endif\n\n")
406
+ end
407
+ end
408
+
409
+ if $0 == __FILE__
410
+ options = { includes: [] }
411
+
412
+ # parse out all the options first (these will all be removed as we go)
413
+ ARGV.reject! do |arg|
414
+ case arg
415
+ when '-cexception'
416
+ options[:plugins] = [:cexception]
417
+ true
418
+ when /\.*\.ya?ml/
419
+ options = UnityTestRunnerGenerator.grab_config(arg)
420
+ true
421
+ when /--(\w+)=\"?(.*)\"?/
422
+ options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
423
+ true
424
+ when /\.*\.h/
425
+ options[:includes] << arg
426
+ true
427
+ else false
428
+ end
429
+ end
430
+
431
+ # make sure there is at least one parameter left (the input file)
432
+ unless ARGV[0]
433
+ puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)",
434
+ "\n input_test_file - this is the C file you want to create a runner for",
435
+ ' output - this is the name of the runner file to generate',
436
+ ' defaults to (input_test_file)_Runner',
437
+ ' files:',
438
+ ' *.yml / *.yaml - loads configuration from here in :unity or :cmock',
439
+ ' *.h - header files are added as #includes in runner',
440
+ ' options:',
441
+ ' -cexception - include cexception support',
442
+ ' --setup_name="" - redefine setUp func name to something else',
443
+ ' --teardown_name="" - redefine tearDown func name to something else',
444
+ ' --main_name="" - redefine main func name to something else',
445
+ ' --test_prefix="" - redefine test prefix from default test|spec|should',
446
+ ' --suite_setup="" - code to execute for setup of entire suite',
447
+ ' --suite_teardown="" - code to execute for teardown of entire suite',
448
+ ' --use_param_tests=1 - enable parameterized tests (disabled by default)',
449
+ ' --header_file="" - path/name of test header file to generate too'].join("\n")
450
+ exit 1
451
+ end
452
+
453
+ # create the default test runner name if not specified
454
+ ARGV[1] = ARGV[0].gsub('.c', '_Runner.c') unless ARGV[1]
455
+
456
+ UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1])
457
+ end