ceedling 1.1.0 → 1.1.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 (172) hide show
  1. checksums.yaml +4 -4
  2. data/GIT_COMMIT_SHA +1 -1
  3. data/README.md +10 -7
  4. data/assets/broken_uncovered_file.c +13 -0
  5. data/assets/test_example_file_2.c +22 -0
  6. data/assets/tests_with_partials_coverage/src/blanks.c +10 -0
  7. data/assets/tests_with_partials_coverage/src/blanks.h +1 -0
  8. data/assets/tests_with_partials_coverage/src/counter.c +12 -0
  9. data/assets/tests_with_partials_coverage/src/counter.h +1 -0
  10. data/assets/tests_with_partials_coverage/src/decorators.c +11 -0
  11. data/assets/tests_with_partials_coverage/src/decorators.h +4 -0
  12. data/assets/tests_with_partials_coverage/test/test_blanks.c +8 -0
  13. data/assets/tests_with_partials_coverage/test/test_counter.c +9 -0
  14. data/assets/tests_with_partials_coverage/test/test_decorators.c +8 -0
  15. data/docs/Changelog.md +80 -38
  16. data/docs/KnownIssues.md +9 -0
  17. data/docs/ReleaseNotes.md +5 -1
  18. data/docs/mkdocs/getting-started/installation.md +8 -1
  19. data/docs/mkdocs/getting-started/quick-start.md +20 -2
  20. data/docs/mkdocs/help.md +2 -2
  21. data/docs/mkdocs/index.md +13 -6
  22. data/docs/mkdocs/overview/build-system.md +4 -4
  23. data/docs/mkdocs/plugins/bullseye.md +6 -0
  24. data/docs/mkdocs/plugins/command-hooks.md +20 -15
  25. data/docs/mkdocs/plugins/gcov/gcovr.md +130 -109
  26. data/docs/mkdocs/plugins/gcov/index.md +6 -0
  27. data/docs/mkdocs/plugins/index.md +40 -0
  28. data/docs/mkdocs/plugins/valgrind.md +6 -0
  29. data/docs/mkdocs/testing-guide/partials/index.md +22 -13
  30. data/lib/ceedling/c_extractor/c_extractor_declarations.rb +3 -1
  31. data/lib/ceedling/c_extractor/c_extractor_preprocessing.rb +20 -7
  32. data/lib/ceedling/config/configurator.rb +2 -1
  33. data/lib/ceedling/generators/generator_partials.rb +13 -3
  34. data/lib/ceedling/objects.yml +1 -0
  35. data/lib/ceedling/preprocess/preprocessinator.rb +3 -2
  36. data/lib/ceedling/preprocess/preprocessinator_file_assembler.rb +37 -15
  37. data/lib/ceedling/preprocess/preprocessinator_reconstructor.rb +23 -15
  38. data/lib/ceedling/test_invoker/test_build_executor.rb +3 -4
  39. data/lib/ceedling/test_invoker/test_build_planner.rb +0 -2
  40. data/lib/ceedling/test_invoker/test_invoker_types.rb +1 -1
  41. data/lib/ceedling/tool_executor.rb +5 -0
  42. data/lib/version.rb +1 -1
  43. data/plugins/command_hooks/lib/command_hooks.rb +4 -0
  44. data/plugins/gcov/lib/console_reportinator.rb +3 -1
  45. data/plugins/gcov/lib/gcov.rb +3 -3
  46. data/plugins/gcov/lib/gcov_reportinator.rb +4 -0
  47. data/plugins/gcov/lib/gcovr_reportinator.rb +61 -14
  48. data/plugins/gcov/lib/reportgenerator_reportinator.rb +3 -1
  49. data/site-local/404.html +3 -3
  50. data/site-local/assets/javascripts/{bundle.79ae519e.min.js → bundle.d7400e89.min.js} +2 -2
  51. data/site-local/assets/javascripts/{bundle.79ae519e.min.js.map → bundle.d7400e89.min.js.map} +2 -2
  52. data/site-local/assets/stylesheets/main.ec1eaa64.min.css +1 -0
  53. data/site-local/assets/stylesheets/{main.484c7ddc.min.css.map → main.ec1eaa64.min.css.map} +1 -1
  54. data/site-local/configuration/environment-vars.html +3 -3
  55. data/site-local/configuration/global-collections.html +3 -3
  56. data/site-local/configuration/index.html +3 -3
  57. data/site-local/configuration/loading.html +3 -3
  58. data/site-local/configuration/mixins.html +3 -3
  59. data/site-local/configuration/parallel-builds.html +3 -3
  60. data/site-local/configuration/project-file.html +3 -3
  61. data/site-local/configuration/reference/cexception.html +3 -3
  62. data/site-local/configuration/reference/cmock.html +3 -3
  63. data/site-local/configuration/reference/defines.html +3 -3
  64. data/site-local/configuration/reference/environment.html +3 -3
  65. data/site-local/configuration/reference/extension.html +3 -3
  66. data/site-local/configuration/reference/files.html +3 -3
  67. data/site-local/configuration/reference/flags.html +3 -3
  68. data/site-local/configuration/reference/index.html +3 -3
  69. data/site-local/configuration/reference/libraries.html +3 -3
  70. data/site-local/configuration/reference/mixins.html +3 -3
  71. data/site-local/configuration/reference/paths.html +3 -3
  72. data/site-local/configuration/reference/plugins.html +3 -3
  73. data/site-local/configuration/reference/project.html +3 -3
  74. data/site-local/configuration/reference/release-build.html +3 -3
  75. data/site-local/configuration/reference/test-build.html +3 -3
  76. data/site-local/configuration/reference/test-runner.html +3 -3
  77. data/site-local/configuration/reference/tools.html +3 -3
  78. data/site-local/configuration/reference/unity.html +3 -3
  79. data/site-local/configuration/which-ceedling.html +3 -3
  80. data/site-local/development/index.html +3 -3
  81. data/site-local/development/plugins/configuration.html +3 -3
  82. data/site-local/development/plugins/index.html +3 -3
  83. data/site-local/development/plugins/plugin-subclass.html +3 -3
  84. data/site-local/development/plugins/rake-tasks.html +3 -3
  85. data/site-local/development/workflow.html +3 -3
  86. data/site-local/getting-started/command-line.html +3 -3
  87. data/site-local/getting-started/example-projects/cipher-quest.html +3 -3
  88. data/site-local/getting-started/example-projects/index.html +3 -3
  89. data/site-local/getting-started/example-projects/temp-sensor.html +3 -3
  90. data/site-local/getting-started/example-projects/wondrous-forest.html +3 -3
  91. data/site-local/getting-started/index.html +3 -3
  92. data/site-local/getting-started/installation.html +12 -4
  93. data/site-local/getting-started/quick-start.html +18 -4
  94. data/site-local/help.html +4 -4
  95. data/site-local/index.html +13 -8
  96. data/site-local/overview/build-system.html +6 -6
  97. data/site-local/overview/index.html +3 -3
  98. data/site-local/overview/test-environments.html +3 -3
  99. data/site-local/overview/tools-and-frameworks.html +3 -3
  100. data/site-local/plugins/beep.html +3 -3
  101. data/site-local/plugins/bullseye.html +9 -3
  102. data/site-local/plugins/command-hooks.html +42 -38
  103. data/site-local/plugins/compile-commands-json-db.html +3 -3
  104. data/site-local/plugins/cppcheck.html +3 -3
  105. data/site-local/plugins/dependencies.html +3 -3
  106. data/site-local/plugins/fff.html +3 -3
  107. data/site-local/plugins/gcov/examples.html +3 -3
  108. data/site-local/plugins/gcov/gcovr.html +325 -227
  109. data/site-local/plugins/gcov/index.html +9 -3
  110. data/site-local/plugins/gcov/overview.html +3 -3
  111. data/site-local/plugins/gcov/reportgenerator.html +3 -3
  112. data/site-local/plugins/gcov/reporting.html +3 -3
  113. data/site-local/plugins/gcov/setup.html +3 -3
  114. data/site-local/plugins/gcov/tool-versions.html +3 -3
  115. data/site-local/plugins/gcov/troubleshooting.html +3 -3
  116. data/site-local/plugins/index.html +79 -15
  117. data/site-local/plugins/module-generator.html +3 -3
  118. data/site-local/plugins/report-build-warnings-log.html +3 -3
  119. data/site-local/plugins/report-tests-gtestlike-stdout.html +3 -3
  120. data/site-local/plugins/report-tests-ide-stdout.html +3 -3
  121. data/site-local/plugins/report-tests-log-factory.html +3 -3
  122. data/site-local/plugins/report-tests-pretty-stdout.html +3 -3
  123. data/site-local/plugins/report-tests-raw-output-log.html +3 -3
  124. data/site-local/plugins/report-tests-teamcity-stdout.html +3 -3
  125. data/site-local/plugins/valgrind.html +9 -3
  126. data/site-local/project/release-history.html +3 -3
  127. data/site-local/project/upgrade.html +3 -3
  128. data/site-local/reference/build-directives.html +3 -3
  129. data/site-local/reference/command-line.html +3 -3
  130. data/site-local/reference/environment-vars.html +3 -3
  131. data/site-local/reference/gcov-plugin.html +3 -3
  132. data/site-local/reference/global-collections.html +3 -3
  133. data/site-local/reference/index.html +3 -3
  134. data/site-local/reference/partials-macros.html +3 -3
  135. data/site-local/reference/project-configuration.html +3 -3
  136. data/site-local/sitemap.xml.gz +0 -0
  137. data/site-local/snapshot/examples/cipher_quest/index.html +3 -3
  138. data/site-local/snapshot/examples/temp_sensor/index.html +3 -3
  139. data/site-local/snapshot/examples/wondrous_forest/index.html +3 -3
  140. data/site-local/testing-guide/build-directives.html +3 -3
  141. data/site-local/testing-guide/conventions.html +3 -3
  142. data/site-local/testing-guide/frameworks.html +3 -3
  143. data/site-local/testing-guide/index.html +3 -3
  144. data/site-local/testing-guide/partials/configuration.html +3 -3
  145. data/site-local/testing-guide/partials/conventions.html +3 -3
  146. data/site-local/testing-guide/partials/directives.html +3 -3
  147. data/site-local/testing-guide/partials/example.html +3 -3
  148. data/site-local/testing-guide/partials/index.html +25 -16
  149. data/site-local/testing-guide/partials/overview.html +3 -3
  150. data/site-local/testing-guide/partials/variables.html +3 -3
  151. data/site-local/testing-guide/test-cases.html +3 -3
  152. data/site-local/testing-guide/test-sample.html +3 -3
  153. data/site-local/testing-guide/test-suite-anatomy.html +3 -3
  154. data/spec/support/system/system_context.rb +3 -1
  155. data/spec/system/gcov_deployment_spec.rb +20 -6
  156. data/spec/system/support/gcov_common_test_cases.rb +34 -45
  157. data/spec/system/support/gcov_partials_test_cases.rb +116 -0
  158. data/spec/units/c_extractor/c_extractor_declarations_spec.rb +128 -0
  159. data/spec/units/c_extractor/c_extractor_definitions_spec.rb +7 -0
  160. data/spec/units/c_extractor/c_extractor_integration_spec.rb +17 -0
  161. data/spec/units/c_extractor/c_extractor_preprocessing_spec.rb +46 -0
  162. data/spec/units/generators/generator_partials_spec.rb +32 -6
  163. data/spec/units/preprocess/preprocessinator_file_assembler_spec.rb +250 -1
  164. data/spec/units/preprocess/preprocessinator_reconstructor_spec.rb +151 -1
  165. data/spec/units/test_build_executor_spec.rb +114 -0
  166. data/vendor/unity/auto/generate_test_runner.rb +55 -5
  167. data/vendor/unity/src/unity.h +1 -1
  168. data/vendor/unity/test/testdata/testRunnerGeneratorEmpty.c +13 -0
  169. data/vendor/unity/test/tests/test_generate_test_runner.rb +11 -0
  170. metadata +22 -7
  171. data/site-local/assets/stylesheets/main.484c7ddc.min.css +0 -1
  172. data/vendor/unity/auto/run_test.erb +0 -37
@@ -17,7 +17,7 @@ RSpec.describe PreprocessinatorFileAssembler do
17
17
  # Use real ParsingParcels for _filter_conditionals and collect_file_contents_fallback tests
18
18
  let(:real_parsing_parcels) { ParsingParcels.new }
19
19
  let(:real_reconstructor) do
20
- PreprocessinatorReconstructor.new({ parsing_parcels: real_parsing_parcels })
20
+ PreprocessinatorReconstructor.new({ parsing_parcels: real_parsing_parcels, file_wrapper: @file_wrapper })
21
21
  end
22
22
 
23
23
  before :each do
@@ -260,4 +260,253 @@ RSpec.describe PreprocessinatorFileAssembler do
260
260
 
261
261
  end
262
262
 
263
+
264
+ # ===========================================================================
265
+ describe '#collect_mockable_header_file_contents' do
266
+ # ===========================================================================
267
+
268
+ let(:test) { 'test_module' }
269
+ let(:filepath) { '/src/module.h' }
270
+ let(:directives_only_filepath) { '/build/directives/module.h' }
271
+ let(:preprocessed_filepath) { '/build/full_expansion/module.h' }
272
+ let(:flags) { [] }
273
+ let(:defines) { [] }
274
+ let(:include_paths) { [] }
275
+
276
+ before :each do
277
+ allow(@file_path_utils).to receive(:form_preprocessed_file_full_expansion_filepath)
278
+ .with(filepath, test).and_return(preprocessed_filepath)
279
+ allow(@configurator).to receive(:tools_test_file_full_preprocessor).and_return(:full_preprocessor)
280
+ allow(@tool_executor).to receive(:build_command_line).and_return('gcc -E ...')
281
+ allow(@tool_executor).to receive(:exec)
282
+ stub_file_open(preprocessed_filepath, "# 1 \"#{filepath}\"\nint x;\n", 'r')
283
+ end
284
+
285
+ def call_collect_mockable(fallback:, extras:)
286
+ subject.collect_mockable_header_file_contents(
287
+ test: test,
288
+ filepath: filepath,
289
+ directives_only_filepath: directives_only_filepath,
290
+ fallback: fallback,
291
+ flags: flags,
292
+ defines: defines,
293
+ include_paths: include_paths,
294
+ extras: extras
295
+ )
296
+ end
297
+
298
+ context 'when extras are not requested' do
299
+
300
+ it 'returns an empty extras list and a nil include guard' do
301
+ _contents, extras, include_guard = call_collect_mockable(fallback: true, extras: false)
302
+ expect(extras).to eq([])
303
+ expect(include_guard).to be_nil
304
+ end
305
+
306
+ it 'does not read the original file to look for an include guard' do
307
+ expect(@file_wrapper).not_to receive(:read)
308
+ call_collect_mockable(fallback: true, extras: false)
309
+ end
310
+
311
+ end
312
+
313
+ context 'when extras are requested' do
314
+
315
+ let(:header_with_guard) do
316
+ <<~C
317
+ #ifndef FOO_H
318
+ #define FOO_H
319
+
320
+ void foo(void);
321
+
322
+ #endif
323
+ C
324
+ end
325
+
326
+ it 'extracts the include guard from the original file in fallback mode' do
327
+ allow(@file_wrapper).to receive(:read).with(filepath, 2048).and_return(header_with_guard)
328
+ stub_file_open(filepath, header_with_guard, 'rb')
329
+
330
+ _contents, _extras, include_guard = call_collect_mockable(fallback: true, extras: true)
331
+ expect(include_guard).to eq('FOO_H')
332
+ end
333
+
334
+ it 'extracts the include guard from the original file in directives-only mode' do
335
+ allow(@file_wrapper).to receive(:read).with(filepath, 2048).and_return(header_with_guard)
336
+ stub_file_open(directives_only_filepath, header_with_guard, 'r')
337
+
338
+ _contents, _extras, include_guard = call_collect_mockable(fallback: false, extras: true)
339
+ expect(include_guard).to eq('FOO_H')
340
+ end
341
+
342
+ it 'returns a nil include guard when the original file has no #ifndef/#define guard pair' do
343
+ header_without_guard = "#pragma once\n\nvoid foo(void);\n"
344
+ allow(@file_wrapper).to receive(:read).with(filepath, 2048).and_return(header_without_guard)
345
+ stub_file_open(filepath, header_without_guard, 'rb')
346
+
347
+ _contents, _extras, include_guard = call_collect_mockable(fallback: true, extras: true)
348
+ expect(include_guard).to be_nil
349
+ end
350
+
351
+ end
352
+
353
+ end
354
+
355
+
356
+ # ===========================================================================
357
+ describe '#assemble_preprocessed_header_file' do
358
+ # ===========================================================================
359
+
360
+ let(:preprocessed_filepath) { '/build/mocks/test_module/module.h' }
361
+
362
+ # Binary mode ('wb'): `contents` lines assembled into this file come from
363
+ # an upstream preprocessed file and must reach disk with their line
364
+ # endings unaltered, which text mode would not guarantee.
365
+ def stub_file_write(filepath)
366
+ output = StringIO.new
367
+ allow(@file_wrapper).to receive(:open).with(filepath, 'wb').and_yield(output)
368
+ output
369
+ end
370
+
371
+ it 'writes the given include guard name as the #ifndef/#define/#endif guard' do
372
+ output = stub_file_write(preprocessed_filepath)
373
+
374
+ subject.assemble_preprocessed_header_file(
375
+ filename: 'module.h',
376
+ preprocessed_filepath: preprocessed_filepath,
377
+ contents: ['void foo(void);'],
378
+ extras: [],
379
+ includes: [],
380
+ include_guard: 'FOO_H'
381
+ )
382
+
383
+ expect(output.string).to include("#ifndef FOO_H\n")
384
+ expect(output.string).to include("#define FOO_H\n")
385
+ expect(output.string).to include('#endif // FOO_H')
386
+ end
387
+
388
+ it 'derives a synthetic include guard from the filename when none is given' do
389
+ output = stub_file_write(preprocessed_filepath)
390
+
391
+ subject.assemble_preprocessed_header_file(
392
+ filename: 'module.h',
393
+ preprocessed_filepath: preprocessed_filepath,
394
+ contents: ['void foo(void);'],
395
+ extras: [],
396
+ includes: []
397
+ )
398
+
399
+ expect(output.string).to include("#ifndef __CEEDLING_GENERATED_MODULE_H__\n")
400
+ expect(output.string).to include("#define __CEEDLING_GENERATED_MODULE_H__\n")
401
+ end
402
+
403
+ it 'writes provided includes and contents between the guard lines' do
404
+ output = stub_file_write(preprocessed_filepath)
405
+
406
+ subject.assemble_preprocessed_header_file(
407
+ filename: 'module.h',
408
+ preprocessed_filepath: preprocessed_filepath,
409
+ contents: ['void foo(void);'],
410
+ extras: [],
411
+ includes: ['#include "bar.h"'],
412
+ include_guard: 'FOO_H'
413
+ )
414
+
415
+ expect(output.string).to include('#include "bar.h"')
416
+ expect(output.string).to include('void foo(void);')
417
+ end
418
+
419
+ it 'opens its output file in binary mode' do
420
+ stub_file_write(preprocessed_filepath)
421
+
422
+ subject.assemble_preprocessed_header_file(
423
+ filename: 'module.h',
424
+ preprocessed_filepath: preprocessed_filepath,
425
+ contents: [],
426
+ extras: [],
427
+ includes: []
428
+ )
429
+
430
+ expect(@file_wrapper).to have_received(:open).with(preprocessed_filepath, 'wb')
431
+ end
432
+
433
+ it "passes content lines through to the output file unchanged, including embedded CRLF" do
434
+ output = stub_file_write(preprocessed_filepath)
435
+ content_line_with_crlf = "void foo(void) {\r\n return;\r\n}"
436
+
437
+ subject.assemble_preprocessed_header_file(
438
+ filename: 'module.h',
439
+ preprocessed_filepath: preprocessed_filepath,
440
+ contents: [content_line_with_crlf],
441
+ extras: [],
442
+ includes: []
443
+ )
444
+
445
+ expect(output.string).to include(content_line_with_crlf)
446
+ end
447
+
448
+ end
449
+
450
+
451
+ # ===========================================================================
452
+ describe '#assemble_preprocessed_code_file' do
453
+ # ===========================================================================
454
+
455
+ let(:preprocessed_filepath) { '/build/test/preprocess/module.c' }
456
+
457
+ # Binary mode ('wb'): `contents` lines assembled into this file come from
458
+ # an upstream preprocessed file and must reach disk with their line
459
+ # endings unaltered, which text mode would not guarantee.
460
+ def stub_file_write(filepath)
461
+ output = StringIO.new
462
+ allow(@file_wrapper).to receive(:open).with(filepath, 'wb').and_yield(output)
463
+ output
464
+ end
465
+
466
+ it 'writes provided includes and contents to the output file' do
467
+ output = stub_file_write(preprocessed_filepath)
468
+
469
+ subject.assemble_preprocessed_code_file(
470
+ filename: 'module.c',
471
+ preprocessed_filepath: preprocessed_filepath,
472
+ contents: ['void foo(void) {}'],
473
+ extras: [],
474
+ includes: ['#include "bar.h"']
475
+ )
476
+
477
+ expect(output.string).to include('#include "bar.h"')
478
+ expect(output.string).to include('void foo(void) {}')
479
+ end
480
+
481
+ it 'opens its output file in binary mode' do
482
+ stub_file_write(preprocessed_filepath)
483
+
484
+ subject.assemble_preprocessed_code_file(
485
+ filename: 'module.c',
486
+ preprocessed_filepath: preprocessed_filepath,
487
+ contents: [],
488
+ extras: [],
489
+ includes: []
490
+ )
491
+
492
+ expect(@file_wrapper).to have_received(:open).with(preprocessed_filepath, 'wb')
493
+ end
494
+
495
+ it "passes content lines through to the output file unchanged, including embedded CRLF" do
496
+ output = stub_file_write(preprocessed_filepath)
497
+ content_line_with_crlf = "void foo(void) {\r\n return;\r\n}"
498
+
499
+ subject.assemble_preprocessed_code_file(
500
+ filename: 'module.c',
501
+ preprocessed_filepath: preprocessed_filepath,
502
+ contents: [content_line_with_crlf],
503
+ extras: [],
504
+ includes: []
505
+ )
506
+
507
+ expect(output.string).to include(content_line_with_crlf)
508
+ end
509
+
510
+ end
511
+
263
512
  end
@@ -12,9 +12,11 @@ require 'ceedling/parsing_parcels'
12
12
  describe PreprocessinatorReconstructor do
13
13
  before(:each) do
14
14
  @parsing_parcels = ParsingParcels.new()
15
+ @file_wrapper = double( "FileWrapper" )
15
16
  @extractor = described_class.new(
16
17
  {
17
- :parsing_parcels => @parsing_parcels
18
+ :parsing_parcels => @parsing_parcels,
19
+ :file_wrapper => @file_wrapper,
18
20
  }
19
21
  )
20
22
  end
@@ -75,6 +77,105 @@ describe PreprocessinatorReconstructor do
75
77
  expect( @extractor.extract_file_as_array_from_expansion( input, filepath ) ).to eq expected
76
78
  end
77
79
 
80
+ it "should preserve a run of multiple consecutive blank lines rather than collapsing to one" do
81
+ filepath = "this/path/MY_FILE.C"
82
+
83
+ file_contents = [
84
+ '# 1 "./this/path/MY_FILE.C" 99999',
85
+ 'void some_function(void) {',
86
+ '',
87
+ '',
88
+ '',
89
+ ' return 0;',
90
+ '}'
91
+ ]
92
+
93
+ # All three blank lines must survive -- e.g. a stripped multi-line comment
94
+ # or literal blank lines in the source, either way nothing gets dropped.
95
+ expected = [
96
+ 'void some_function(void) {',
97
+ '',
98
+ '',
99
+ '',
100
+ ' return 0;',
101
+ '}'
102
+ ]
103
+
104
+ input = StringIO.new( file_contents.join( "\n" ) )
105
+
106
+ expect( @extractor.extract_file_as_array_from_expansion( input, filepath ) ).to eq expected
107
+ end
108
+
109
+ it "should preserve independent runs of differing blank-line counts between separate code lines" do
110
+ filepath = "path/multi.c"
111
+
112
+ file_contents = [
113
+ '# 1 "path/multi.c" 1',
114
+ 'int a;',
115
+ '',
116
+ '',
117
+ 'int b;',
118
+ '',
119
+ 'int c;',
120
+ '',
121
+ '',
122
+ '',
123
+ 'int d;'
124
+ ]
125
+
126
+ # Each run's count must stay attached to its own gap -- not merged with a
127
+ # neighboring run, not truncated to a shared count.
128
+ expected = [
129
+ 'int a;',
130
+ '',
131
+ '',
132
+ 'int b;',
133
+ '',
134
+ 'int c;',
135
+ '',
136
+ '',
137
+ '',
138
+ 'int d;'
139
+ ]
140
+
141
+ input = StringIO.new( file_contents.join( "\n" ) )
142
+
143
+ expect( @extractor.extract_file_as_array_from_expansion( input, filepath ) ).to eq expected
144
+ end
145
+
146
+ it "should preserve a following blank-line run after a marker-continuation (dangling semicolon) fragment" do
147
+ filepath = "sys/types_wrapper.c"
148
+
149
+ file_contents = [
150
+ '# 1 "sys/types_wrapper.c" 1',
151
+ 'typedef unsigned long uint32_t', # System typedef expansion, unterminated
152
+ '# 1 "sys/types_wrapper.c" 2', # GCC re-marks the SAME source line...
153
+ ';', # ...to attach a dangling ';' as a continuation, not a new line
154
+ '',
155
+ '',
156
+ 'void some_function(void) {',
157
+ ' return;',
158
+ '}',
159
+ '# 1 "some/useless/file.c"'
160
+ ]
161
+
162
+ # The typedef and its dangling ';' must aggregate onto a single output
163
+ # line (existing behavior), and the two blank lines that follow -- e.g.
164
+ # from a stripped comment after the typedef -- must both still survive.
165
+ expected = [
166
+ 'typedef unsigned long uint32_t;',
167
+ '',
168
+ '',
169
+ 'void some_function(void) {',
170
+ ' return;',
171
+ '}'
172
+ ]
173
+
174
+ input = StringIO.new( file_contents.join( "\n" ) )
175
+
176
+ expect( @extractor.extract_file_as_array_from_expansion( input, filepath ) ).to eq expected
177
+ end
178
+
78
179
  it "should extract text of original file from preprocessed expansion with complex preprocessor line marker sequence" do
79
180
  filepath = "dir/our_file.c"
80
181
 
@@ -207,6 +308,8 @@ describe PreprocessinatorReconstructor do
207
308
  '',
208
309
  'static _Bool ecs_foo__init_structure(void);',
209
310
  '',
311
+ '',
312
+ '',
210
313
  'void ecs_foo_init(void) {',
211
314
  ' var1 = ecs_foo__init_structure();',
212
315
  '}',
@@ -697,4 +800,51 @@ describe PreprocessinatorReconstructor do
697
800
 
698
801
  end
699
802
 
803
+ context "#compact_file_from_expansion" do
804
+ it "should open its input in binary mode and its output in binary mode" do
805
+ # Binary mode on both ends: this content is read again downstream by code
806
+ # that depends on its line count being exact, so nothing here should be
807
+ # subject to platform-specific line ending translation.
808
+ input_handle = StringIO.new( '# 1 "WANT.c" 5' + "\n" + 'text_we_want();' + "\n" )
809
+ output_handle = StringIO.new
810
+
811
+ expect(@file_wrapper).to receive(:open).with( 'input.c', 'rb' ).and_yield( input_handle )
812
+ expect(@file_wrapper).to receive(:open).with( 'output.c', 'wb' ).and_yield( output_handle )
813
+
814
+ @extractor.compact_file_from_expansion(
815
+ input_filepath: 'input.c',
816
+ source_filepath: 'WANT.c',
817
+ output_filepath: 'output.c'
818
+ )
819
+ end
820
+
821
+ it "should extract the same content from CRLF-terminated input as from LF-terminated input" do
822
+ # GCC's preprocessor output on Windows is CRLF-terminated. Extraction must
823
+ # produce identical results regardless of the input's line endings, since
824
+ # the exact line count of what's extracted matters to code downstream.
825
+ lf_input = StringIO.new(
826
+ '# 1 "WANT.c" 5' + "\n" + "line_one();\n" + "\n" + "line_two();\n"
827
+ )
828
+ crlf_input = StringIO.new(
829
+ '# 1 "WANT.c" 5' + "\r\n" + "line_one();\r\n" + "\r\n" + "line_two();\r\n"
830
+ )
831
+ lf_output = StringIO.new
832
+ crlf_output = StringIO.new
833
+
834
+ allow(@file_wrapper).to receive(:open).with( 'lf.c', 'rb' ).and_yield( lf_input )
835
+ allow(@file_wrapper).to receive(:open).with( 'lf_out.c', 'wb' ).and_yield( lf_output )
836
+ allow(@file_wrapper).to receive(:open).with( 'crlf.c', 'rb' ).and_yield( crlf_input )
837
+ allow(@file_wrapper).to receive(:open).with( 'crlf_out.c', 'wb' ).and_yield( crlf_output )
838
+
839
+ @extractor.compact_file_from_expansion(
840
+ input_filepath: 'lf.c', source_filepath: 'WANT.c', output_filepath: 'lf_out.c'
841
+ )
842
+ @extractor.compact_file_from_expansion(
843
+ input_filepath: 'crlf.c', source_filepath: 'WANT.c', output_filepath: 'crlf_out.c'
844
+ )
845
+
846
+ expect( crlf_output.string ).to eq( lf_output.string )
847
+ end
848
+ end
849
+
700
850
  end
@@ -0,0 +1,114 @@
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/test_invoker/test_build_executor'
10
+ require 'ceedling/test_invoker/test_invoker_types'
11
+
12
+ PROJECT_BUILD_VENDOR_UNITY_PATH = 'build/vendor/unity' unless defined?(PROJECT_BUILD_VENDOR_UNITY_PATH)
13
+ UNITY_C_FILE = 'unity.c' unless defined?(UNITY_C_FILE)
14
+
15
+ describe TestBuildExecutor do
16
+ before(:each) do
17
+ @configurator = double( "Configurator" )
18
+ @loginator = double( "Loginator" )
19
+ @reportinator = double( "Reportinator" )
20
+ @batchinator = double( "Batchinator" )
21
+ @preprocessinator = double( "Preprocessinator" )
22
+ @partializer = double( "Partializer" )
23
+ @generator = double( "Generator" )
24
+ @test_context_extractor = double( "TestContextExtractor" )
25
+ @plugin_manager = double( "PluginManager" )
26
+ @file_path_utils = double( "FilePathUtils" )
27
+ @file_finder = double( "FileFinder" )
28
+ @file_wrapper = double( "FileWrapper" )
29
+
30
+ @tools_test_compiler = { name: 'fake compiler' }
31
+ @tools_test_assembler = { name: 'fake assembler' }
32
+
33
+ allow(@configurator).to receive(:extension_assembly).and_return( '.asm' )
34
+ allow(@configurator).to receive(:tools_test_compiler).and_return( @tools_test_compiler )
35
+ allow(@configurator).to receive(:tools_test_assembler).and_return( @tools_test_assembler )
36
+ allow(@configurator).to receive(:project_use_mocks).and_return( false )
37
+ allow(@configurator).to receive(:project_use_exceptions).and_return( false )
38
+ allow(@configurator).to receive(:collection_all_support).and_return( [] )
39
+
40
+ allow(@file_path_utils).to receive(:form_test_build_list_filepath).and_return( 'build/list' )
41
+ allow(@file_path_utils).to receive(:form_test_dependencies_filepath).and_return( 'build/deps' )
42
+
43
+ @executor = described_class.new(
44
+ {
45
+ :configurator => @configurator,
46
+ :loginator => @loginator,
47
+ :reportinator => @reportinator,
48
+ :batchinator => @batchinator,
49
+ :preprocessinator => @preprocessinator,
50
+ :partializer => @partializer,
51
+ :generator => @generator,
52
+ :test_context_extractor => @test_context_extractor,
53
+ :plugin_manager => @plugin_manager,
54
+ :file_path_utils => @file_path_utils,
55
+ :file_finder => @file_finder,
56
+ :file_wrapper => @file_wrapper
57
+ }
58
+ )
59
+
60
+ testable = TestInvokerTypes::Testable.new(
61
+ :compile_defines => [],
62
+ :search_paths => [],
63
+ :compile_flags => [],
64
+ :assembler_flags => []
65
+ )
66
+
67
+ @state = TestInvokerTypes::PipelineState.new( :testables => { :a_test => testable } )
68
+ end
69
+
70
+ context "#compile_test_component" do
71
+ it "compiles a C source file with the configured test compiler tool" do
72
+ allow(@file_wrapper).to receive(:extname).with( 'src/foo.c' ).and_return( '.c' )
73
+ allow(@configurator).to receive(:test_build_use_assembly).and_return( false )
74
+
75
+ expect(@generator).to receive(:generate_object_file_c) do |**args|
76
+ expect( args[:tool] ).to eq( @tools_test_compiler )
77
+ end
78
+ expect(@generator).to_not receive(:generate_object_file_asm)
79
+
80
+ @executor.send(
81
+ :compile_test_component,
82
+ :context => :test, :test => :a_test, :source => 'src/foo.c', :object => 'build/foo.o', :state => @state
83
+ )
84
+ end
85
+
86
+ it "assembles an assembly source file with the configured test assembler tool when assembly support is enabled" do
87
+ allow(@file_wrapper).to receive(:extname).with( 'src/foo.asm' ).and_return( '.asm' )
88
+ allow(@configurator).to receive(:test_build_use_assembly).and_return( true )
89
+
90
+ expect(@generator).to receive(:generate_object_file_asm) do |**args|
91
+ expect( args[:tool] ).to eq( @tools_test_assembler )
92
+ end
93
+ expect(@generator).to_not receive(:generate_object_file_c)
94
+
95
+ @executor.send(
96
+ :compile_test_component,
97
+ :context => :test, :test => :a_test, :source => 'src/foo.asm', :object => 'build/foo.o', :state => @state
98
+ )
99
+ end
100
+
101
+ it "does not compile an assembly source file when assembly support is disabled" do
102
+ allow(@file_wrapper).to receive(:extname).with( 'src/foo.asm' ).and_return( '.asm' )
103
+ allow(@configurator).to receive(:test_build_use_assembly).and_return( false )
104
+
105
+ expect(@generator).to_not receive(:generate_object_file_c)
106
+ expect(@generator).to_not receive(:generate_object_file_asm)
107
+
108
+ @executor.send(
109
+ :compile_test_component,
110
+ :context => :test, :test => :a_test, :source => 'src/foo.asm', :object => 'build/foo.o', :state => @state
111
+ )
112
+ end
113
+ end
114
+ end
@@ -100,9 +100,10 @@ class UnityTestRunnerGenerator
100
100
  create_suite_setup(output)
101
101
  create_suite_teardown(output)
102
102
  create_reset(output)
103
- create_run_test(output) unless tests.empty?
103
+ create_run_test(output)
104
104
  create_args_wrappers(output, tests)
105
105
  create_shuffle_tests(output) if @options[:shuffle_tests]
106
+ tests = create_warning_test(output, input_file, tests)
106
107
  create_main(output, input_file, tests, used_mocks)
107
108
  end
108
109
 
@@ -406,10 +407,43 @@ class UnityTestRunnerGenerator
406
407
  end
407
408
 
408
409
  def create_run_test(output)
409
- require 'erb'
410
- file = File.read(File.join(__dir__, 'run_test.erb'))
411
- template = ERB.new(file, trim_mode: '<>')
412
- output.puts("\n#{template.result(binding)}")
410
+ output.puts("/*=======Test Runner Used To Run Each Test=====*/")
411
+ output.puts("static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num)")
412
+ output.puts("{")
413
+ output.puts(" Unity.CurrentTestName = name;")
414
+ output.puts(" Unity.CurrentTestLineNumber = (UNITY_UINT) line_num;")
415
+ output.puts("#ifdef UNITY_USE_COMMAND_LINE_ARGS")
416
+ output.puts(" if (!UnityTestMatches())")
417
+ output.puts(" return;")
418
+ output.puts("#endif")
419
+ output.puts(" Unity.NumberOfTests++;")
420
+ output.puts(" UNITY_CLR_DETAILS();")
421
+ output.puts(" UNITY_EXEC_TIME_START();")
422
+ output.puts(" CMock_Init();")
423
+ output.puts(" if (TEST_PROTECT())")
424
+ output.puts(" {")
425
+ if @options[:plugins].include?(:cexception)
426
+ output.puts(" volatile CEXCEPTION_T e;")
427
+ output.puts(" Try {")
428
+ output.puts(" #{@options[:setup_name]}();")
429
+ output.puts(" func();")
430
+ output.puts(" } Catch(e) {")
431
+ output.puts(" TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\");")
432
+ output.puts(" }")
433
+ else
434
+ output.puts(" #{@options[:setup_name]}();")
435
+ output.puts(" func();")
436
+ end
437
+ output.puts(" }")
438
+ output.puts(" if (TEST_PROTECT())")
439
+ output.puts(" {")
440
+ output.puts(" #{@options[:teardown_name]}();")
441
+ output.puts(" CMock_Verify();")
442
+ output.puts(" }")
443
+ output.puts(" CMock_Destroy();")
444
+ output.puts(" UNITY_EXEC_TIME_STOP();")
445
+ output.puts(" UnityConcludeTest();")
446
+ output.puts("}")
413
447
  end
414
448
 
415
449
  def create_args_wrappers(output, tests)
@@ -428,6 +462,22 @@ class UnityTestRunnerGenerator
428
462
  end
429
463
  end
430
464
 
465
+ def create_warning_test(output, filename, tests)
466
+ if count_tests(tests) == 0
467
+ warning_test = {
468
+ :test => "test_empty_warning",
469
+ :line_number => 0
470
+ }
471
+ output.puts("\n/*=======Warning Test=====*/")
472
+ output.puts("static void #{warning_test[:test]}(void)")
473
+ output.puts('{')
474
+ output.puts(" TEST_IGNORE_MESSAGE(\"Test file '#{filename.gsub(/\\/, '\\\\\\')}' contains no tests.\");")
475
+ output.puts("}\n")
476
+ tests = [warning_test]
477
+ end
478
+ return tests
479
+ end
480
+
431
481
  def create_shuffle_tests(output)
432
482
  output.puts("\n/*=======Shuffle Test Order=====*/")
433
483
  output.puts('static void shuffleTests(struct UnityRunTestParameters run_test_params_arr[], int num_of_tests)')
@@ -11,7 +11,7 @@
11
11
 
12
12
  #define UNITY_VERSION_MAJOR 2
13
13
  #define UNITY_VERSION_MINOR 7
14
- #define UNITY_VERSION_BUILD 0
14
+ #define UNITY_VERSION_BUILD 1
15
15
  #define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD)
16
16
 
17
17
  #ifdef __cplusplus
@@ -0,0 +1,13 @@
1
+ /* =========================================================================
2
+ Unity - A Test Framework for C
3
+ ThrowTheSwitch.org
4
+ Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
5
+ SPDX-License-Identifier: MIT
6
+ ========================================================================= */
7
+
8
+ /* This Test File Is Used To Verify The Warning When No Tests Are Found */
9
+
10
+ #include "unity.h"
11
+
12
+ void setUp(void) {}
13
+ void tearDown(void) {}
@@ -336,6 +336,17 @@ RUNNER_TESTS = [
336
336
  },
337
337
 
338
338
 
339
+ { :name => 'EmptyFileWarning',
340
+ :testfile => 'testdata/testRunnerGeneratorEmpty.c',
341
+ :testdefines => ['TEST'],
342
+ :options => nil, #defaults
343
+ :expected => {
344
+ :to_pass => [ ],
345
+ :to_fail => [ ],
346
+ :to_ignore => [ 'test_empty_warning' ],
347
+ }
348
+ },
349
+
339
350
  #### WITH MOCKS ##########################################
340
351
 
341
352
  { :name => 'DefaultsThroughOptions',