ceedling 1.1.9 → 1.1.10
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.
- checksums.yaml +4 -4
- data/GIT_COMMIT_SHA +1 -1
- data/README.md +4 -3
- data/docs/Changelog.md +10 -0
- data/docs/KnownIssues.md +11 -2
- data/docs/SECURITY.md +40 -2
- data/docs/mkdocs/development/index.md +11 -0
- data/docs/mkdocs/plugins/fff.md +1 -1
- data/docs/mkdocs/plugins/gcov/gcovr.md +117 -3
- data/docs/mkdocs/plugins/gcov/reportgenerator.md +110 -4
- data/lib/ceedling/generators/generator.rb +11 -6
- data/lib/ceedling/generators/generator_partials.rb +54 -18
- data/lib/ceedling/objects.yml +2 -0
- data/lib/ceedling/partials/partializer.rb +164 -101
- data/lib/ceedling/test_invoker/test_build_executor.rb +21 -7
- data/lib/version.rb +1 -1
- data/site-local/development/index.html +7 -0
- data/site-local/plugins/fff.html +1 -1
- data/site-local/plugins/gcov/gcovr.html +156 -3
- data/site-local/plugins/gcov/reportgenerator.html +201 -14
- data/site-local/sitemap.xml.gz +0 -0
- data/spec/system/partials_types_header_spec.rb +166 -0
- data/spec/units/generators/generator_partials_spec.rb +130 -17
- data/spec/units/partials/partializer_spec.rb +163 -0
- metadata +4 -2
|
@@ -61,6 +61,21 @@ describe GeneratorPartials do
|
|
|
61
61
|
CExtractorTypes::CModule.new()
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# A StringIO standing in for the generated types header, with the filename lookup stubbed.
|
|
65
|
+
# Several examples differ only in what they hand generate_types, not in this plumbing.
|
|
66
|
+
def types_buffer(name, header_filename)
|
|
67
|
+
allow(@file_path_utils).to receive(:form_partial_types_header_filename)
|
|
68
|
+
.with(name)
|
|
69
|
+
.and_return(header_filename)
|
|
70
|
+
|
|
71
|
+
buf = StringIO.new()
|
|
72
|
+
allow(@file_wrapper).to receive(:open)
|
|
73
|
+
.with(File.join('/path/to/output', header_filename), 'wb')
|
|
74
|
+
.and_yield(buf)
|
|
75
|
+
|
|
76
|
+
buf
|
|
77
|
+
end
|
|
78
|
+
|
|
64
79
|
context "#generate_implementation" do
|
|
65
80
|
it "should call generate_header() and generate_source() with correct parameters" do
|
|
66
81
|
# Setup
|
|
@@ -131,7 +146,7 @@ describe GeneratorPartials do
|
|
|
131
146
|
header_includes,
|
|
132
147
|
defns,
|
|
133
148
|
c_module,
|
|
134
|
-
true
|
|
149
|
+
include_variables: true, include_guard: nil
|
|
135
150
|
)
|
|
136
151
|
|
|
137
152
|
# Verify generate_source was called with correct parameters
|
|
@@ -208,7 +223,7 @@ describe GeneratorPartials do
|
|
|
208
223
|
includes,
|
|
209
224
|
decls,
|
|
210
225
|
c_module,
|
|
211
|
-
false
|
|
226
|
+
include_variables: false, include_guard: nil
|
|
212
227
|
)
|
|
213
228
|
|
|
214
229
|
# Verify file path utilities were called
|
|
@@ -447,6 +462,104 @@ describe GeneratorPartials do
|
|
|
447
462
|
|
|
448
463
|
expect( buf.string ).to include( "struct Point { int x; int y; };\nstruct Color { int r; int g; int b; };\n" )
|
|
449
464
|
end
|
|
465
|
+
# The spoof and the carried includes are what make this header compile wherever it lands.
|
|
466
|
+
# Order between them is load-bearing: a carried header can transitively reach the real
|
|
467
|
+
# module header, so the guard has to be satisfied before any include is processed.
|
|
468
|
+
it "states the module's own guard before the includes it carries, then the types" do
|
|
469
|
+
file_contents = <<~CONTENTS
|
|
470
|
+
#ifndef __CEEDLING_GENERATED_MY_MODULE_TYPES_H__
|
|
471
|
+
#define __CEEDLING_GENERATED_MY_MODULE_TYPES_H__
|
|
472
|
+
|
|
473
|
+
#define MY_MODULE_H
|
|
474
|
+
|
|
475
|
+
#include "foundation.h"
|
|
476
|
+
#include <stdint.h>
|
|
477
|
+
|
|
478
|
+
typedef uint8_t Byte;
|
|
479
|
+
|
|
480
|
+
#endif // __CEEDLING_GENERATED_MY_MODULE_TYPES_H__
|
|
481
|
+
|
|
482
|
+
CONTENTS
|
|
483
|
+
|
|
484
|
+
buf = types_buffer( 'my_module', 'my_module_types.h' )
|
|
485
|
+
typedef_stmt = CExtractorTypes::CStatement.new(text: "typedef uint8_t Byte;", line_num: 1)
|
|
486
|
+
|
|
487
|
+
@generator.generate_types(
|
|
488
|
+
name: 'my_module',
|
|
489
|
+
c_module: CExtractorTypes::CModule.new(
|
|
490
|
+
type_definitions: [typedef_stmt],
|
|
491
|
+
element_sequence: [typedef_stmt]
|
|
492
|
+
),
|
|
493
|
+
output_path: '/path/to/output',
|
|
494
|
+
includes: [UserInclude.new('foundation.h'), SystemInclude.new('stdint.h')],
|
|
495
|
+
include_guard: 'MY_MODULE_H'
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it "states no guard when the module's header has none to spoof" do
|
|
502
|
+
buf = types_buffer( 'my_module', 'my_module_types.h' )
|
|
503
|
+
typedef_stmt = CExtractorTypes::CStatement.new(text: "typedef uint8_t Byte;", line_num: 1)
|
|
504
|
+
|
|
505
|
+
@generator.generate_types(
|
|
506
|
+
name: 'my_module',
|
|
507
|
+
c_module: CExtractorTypes::CModule.new(
|
|
508
|
+
type_definitions: [typedef_stmt],
|
|
509
|
+
element_sequence: [typedef_stmt]
|
|
510
|
+
),
|
|
511
|
+
output_path: '/path/to/output',
|
|
512
|
+
includes: [UserInclude.new('foundation.h')],
|
|
513
|
+
include_guard: nil
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
expect( buf.string ).to include('#include "foundation.h"')
|
|
517
|
+
expect( buf.string.scan(/^#define /).length ).to eq(1) # the generated guard alone
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
# The real header's guard also arrives among the extracted macros, since it survives
|
|
521
|
+
# preprocessing. Stating it deliberately and carrying it too would duplicate it.
|
|
522
|
+
it "drops the carried copy of the guard it states itself" do
|
|
523
|
+
buf = types_buffer( 'my_module', 'my_module_types.h' )
|
|
524
|
+
guard_macro = CExtractorTypes::CStatement.new(text: "#define MY_MODULE_H", line_num: 1)
|
|
525
|
+
typedef_stmt = CExtractorTypes::CStatement.new(text: "typedef uint8_t Byte;", line_num: 2)
|
|
526
|
+
|
|
527
|
+
@generator.generate_types(
|
|
528
|
+
name: 'my_module',
|
|
529
|
+
c_module: CExtractorTypes::CModule.new(
|
|
530
|
+
type_definitions: [typedef_stmt],
|
|
531
|
+
macro_definitions: [guard_macro],
|
|
532
|
+
element_sequence: [guard_macro, typedef_stmt]
|
|
533
|
+
),
|
|
534
|
+
output_path: '/path/to/output',
|
|
535
|
+
include_guard: 'MY_MODULE_H'
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
expect( buf.string.scan(/^#define MY_MODULE_H$/).length ).to eq(1)
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# A macro whose name merely begins with the guard's, and a guard-named macro that actually
|
|
542
|
+
# carries a value. Neither is the guard statement.
|
|
543
|
+
it "keeps a macro whose name only resembles the guard" do
|
|
544
|
+
buf = types_buffer( 'my_module', 'my_module_types.h' )
|
|
545
|
+
near_macro = CExtractorTypes::CStatement.new(text: "#define MY_MODULE_H_LIMIT 8", line_num: 1)
|
|
546
|
+
valued_macro = CExtractorTypes::CStatement.new(text: "#define MY_MODULE_H 2", line_num: 2)
|
|
547
|
+
typedef_stmt = CExtractorTypes::CStatement.new(text: "typedef uint8_t Byte;", line_num: 3)
|
|
548
|
+
|
|
549
|
+
@generator.generate_types(
|
|
550
|
+
name: 'my_module',
|
|
551
|
+
c_module: CExtractorTypes::CModule.new(
|
|
552
|
+
type_definitions: [typedef_stmt],
|
|
553
|
+
macro_definitions: [near_macro, valued_macro],
|
|
554
|
+
element_sequence: [near_macro, valued_macro, typedef_stmt]
|
|
555
|
+
),
|
|
556
|
+
output_path: '/path/to/output',
|
|
557
|
+
include_guard: 'MY_MODULE_H'
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
expect( buf.string ).to include('#define MY_MODULE_H_LIMIT 8')
|
|
561
|
+
expect( buf.string ).to include('#define MY_MODULE_H 2')
|
|
562
|
+
end
|
|
450
563
|
end
|
|
451
564
|
|
|
452
565
|
context "#generate_header (private method)" do
|
|
@@ -462,7 +575,7 @@ describe GeneratorPartials do
|
|
|
462
575
|
|
|
463
576
|
CONTENTS
|
|
464
577
|
|
|
465
|
-
@generator.send(:generate_header, buf, 'foo_bar', [], [], empty_module, false)
|
|
578
|
+
@generator.send(:generate_header, buf, 'foo_bar', [], [], empty_module, include_variables: false)
|
|
466
579
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
467
580
|
end
|
|
468
581
|
|
|
@@ -483,7 +596,7 @@ describe GeneratorPartials do
|
|
|
483
596
|
buf,
|
|
484
597
|
'Apples-and-Bananas',
|
|
485
598
|
[UserInclude.new('foo.h'), UserInclude.new('bar.h')],
|
|
486
|
-
[], empty_module, false
|
|
599
|
+
[], empty_module, include_variables: false
|
|
487
600
|
)
|
|
488
601
|
|
|
489
602
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
@@ -505,7 +618,7 @@ describe GeneratorPartials do
|
|
|
505
618
|
make_var(name: 'slices_of_bread', type: 'unsigned int', text: 'unsigned int slices_of_bread = 10;'),
|
|
506
619
|
make_var(name: 'crumbs', type: 'char', text: 'char crumbs[10];')
|
|
507
620
|
)
|
|
508
|
-
@generator.send(:generate_header, buf, 'pb-and-j', [], [], c_module, true)
|
|
621
|
+
@generator.send(:generate_header, buf, 'pb-and-j', [], [], c_module, include_variables: true)
|
|
509
622
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
510
623
|
end
|
|
511
624
|
|
|
@@ -513,7 +626,7 @@ describe GeneratorPartials do
|
|
|
513
626
|
c_module = make_module(
|
|
514
627
|
make_var(name: 'cmd', type: 'cmd_t', text: 'cmd_t cmd = { 0 };', decorators: ['static', 'volatile'])
|
|
515
628
|
)
|
|
516
|
-
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, true)
|
|
629
|
+
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, include_variables: true)
|
|
517
630
|
|
|
518
631
|
expect(buf.string).to include('extern volatile cmd_t cmd;')
|
|
519
632
|
end
|
|
@@ -522,7 +635,7 @@ describe GeneratorPartials do
|
|
|
522
635
|
c_module = make_module(
|
|
523
636
|
make_var(name: 'lookup_table', type: 'uint8_t* const', text: 'uint8_t* const lookup_table;', decorators: ['static', 'const'])
|
|
524
637
|
)
|
|
525
|
-
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, true)
|
|
638
|
+
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, include_variables: true)
|
|
526
639
|
|
|
527
640
|
expect(buf.string).to include('extern const uint8_t* const lookup_table;')
|
|
528
641
|
end
|
|
@@ -576,7 +689,7 @@ describe GeneratorPartials do
|
|
|
576
689
|
[UserInclude.new('Eeny.h'), UserInclude.new('Meeny.h')],
|
|
577
690
|
decls,
|
|
578
691
|
c_module,
|
|
579
|
-
true
|
|
692
|
+
include_variables: true
|
|
580
693
|
)
|
|
581
694
|
|
|
582
695
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
@@ -601,7 +714,7 @@ describe GeneratorPartials do
|
|
|
601
714
|
make_stmt(text: "struct Point { int x; int y; };")
|
|
602
715
|
)
|
|
603
716
|
|
|
604
|
-
@generator.send(:generate_header, buf, 'defs', [], [], c_module, false)
|
|
717
|
+
@generator.send(:generate_header, buf, 'defs', [], [], c_module, include_variables: false)
|
|
605
718
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
606
719
|
end
|
|
607
720
|
|
|
@@ -629,7 +742,7 @@ describe GeneratorPartials do
|
|
|
629
742
|
make_stmt(text: "#define IDX_REF (ADS124S08_REG_ADDR_REF - START_ADDRESS)", line_num: 3)
|
|
630
743
|
)
|
|
631
744
|
|
|
632
|
-
@generator.send(:generate_header, buf, 'regs', [], [], c_module, false)
|
|
745
|
+
@generator.send(:generate_header, buf, 'regs', [], [], c_module, include_variables: false)
|
|
633
746
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
634
747
|
end
|
|
635
748
|
|
|
@@ -644,7 +757,7 @@ describe GeneratorPartials do
|
|
|
644
757
|
make_stmt(text: "#define IDX_REF (ADS124S08_REG_ADDR_REF - START_ADDRESS)", line_num: 3)
|
|
645
758
|
)
|
|
646
759
|
|
|
647
|
-
@generator.send(:generate_header, buf, 'regs', [], [], c_module, false)
|
|
760
|
+
@generator.send(:generate_header, buf, 'regs', [], [], c_module, include_variables: false)
|
|
648
761
|
|
|
649
762
|
expect( buf.string ).to include(
|
|
650
763
|
"#define START_ADDRESS 0x00 // don't change this\n" +
|
|
@@ -694,7 +807,7 @@ describe GeneratorPartials do
|
|
|
694
807
|
element_sequence: [macro_stmt, typedef_stmt, var_decl, aggregate_stmt]
|
|
695
808
|
)
|
|
696
809
|
|
|
697
|
-
@generator.send(:generate_header, buf, 'all_statements', [], [], c_module, true)
|
|
810
|
+
@generator.send(:generate_header, buf, 'all_statements', [], [], c_module, include_variables: true)
|
|
698
811
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
699
812
|
end
|
|
700
813
|
|
|
@@ -718,7 +831,7 @@ describe GeneratorPartials do
|
|
|
718
831
|
make_stmt(text: "typedef uint8_t Byte;", line_num: 3)
|
|
719
832
|
)
|
|
720
833
|
|
|
721
|
-
@generator.send(:generate_header, buf, 'mixed', [], [], c_module, true)
|
|
834
|
+
@generator.send(:generate_header, buf, 'mixed', [], [], c_module, include_variables: true)
|
|
722
835
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
723
836
|
end
|
|
724
837
|
|
|
@@ -738,7 +851,7 @@ describe GeneratorPartials do
|
|
|
738
851
|
make_var( name: 'counter', type: 'int', text: 'int counter;', line_num: 2)
|
|
739
852
|
)
|
|
740
853
|
|
|
741
|
-
@generator.send(:generate_header, buf, 'interface', [], [], c_module, false)
|
|
854
|
+
@generator.send(:generate_header, buf, 'interface', [], [], c_module, include_variables: false)
|
|
742
855
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
743
856
|
end
|
|
744
857
|
|
|
@@ -780,7 +893,7 @@ describe GeneratorPartials do
|
|
|
780
893
|
element_sequence: [typedef_stmt, foo_raw, var_decl, bar_raw]
|
|
781
894
|
)
|
|
782
895
|
|
|
783
|
-
@generator.send(:generate_header, buf, 'interleaved', [], [foo_decl, bar_decl], c_module, true)
|
|
896
|
+
@generator.send(:generate_header, buf, 'interleaved', [], [foo_decl, bar_decl], c_module, include_variables: true)
|
|
784
897
|
expect( buf.string.strip() ).to eq file_contents.strip()
|
|
785
898
|
end
|
|
786
899
|
|
|
@@ -792,7 +905,7 @@ describe GeneratorPartials do
|
|
|
792
905
|
raw = CExtractorTypes::CFunctionDeclaration.new(name: 'exported_func')
|
|
793
906
|
c_module = make_module(raw)
|
|
794
907
|
|
|
795
|
-
@generator.send(:generate_header, buf, 'mymod', [], [decl], c_module, false)
|
|
908
|
+
@generator.send(:generate_header, buf, 'mymod', [], [decl], c_module, include_variables: false)
|
|
796
909
|
|
|
797
910
|
expect(buf.string).to include('__declspec(dllexport) void exported_func(void);')
|
|
798
911
|
end
|
|
@@ -802,7 +915,7 @@ describe GeneratorPartials do
|
|
|
802
915
|
make_var(name: 'counter', type: 'int', text: 'int counter __attribute__((aligned(16)));')
|
|
803
916
|
)
|
|
804
917
|
|
|
805
|
-
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, true)
|
|
918
|
+
@generator.send(:generate_header, buf, 'mymod', [], [], c_module, include_variables: true)
|
|
806
919
|
|
|
807
920
|
expect(buf.string).to include('extern int counter;')
|
|
808
921
|
expect(buf.string).not_to include('__attribute__')
|
|
@@ -23,12 +23,18 @@ describe Partializer do
|
|
|
23
23
|
@reportinator = Reportinator.new
|
|
24
24
|
@loginator = double("Loginator").as_null_object
|
|
25
25
|
|
|
26
|
+
# Guard extraction reads the module's own header text through these two.
|
|
27
|
+
@preprocessinator_reconstructor = double("PreprocessinatorReconstructor")
|
|
28
|
+
@file_wrapper = double("FileWrapper")
|
|
29
|
+
|
|
26
30
|
@partializer = described_class.new(
|
|
27
31
|
{
|
|
28
32
|
:partializer_helper => @partializer_helper,
|
|
29
33
|
:file_finder => @file_finder,
|
|
30
34
|
:c_extractor => @c_extractor,
|
|
31
35
|
:file_path_utils => @file_path_utils,
|
|
36
|
+
:preprocessinator_reconstructor => @preprocessinator_reconstructor,
|
|
37
|
+
:file_wrapper => @file_wrapper,
|
|
32
38
|
:reportinator => @reportinator,
|
|
33
39
|
:loginator => @loginator
|
|
34
40
|
}
|
|
@@ -809,6 +815,40 @@ describe Partializer do
|
|
|
809
815
|
end
|
|
810
816
|
|
|
811
817
|
context "#remap_implementation_source_includes" do
|
|
818
|
+
# A module tested and mocked in one test file splits its own content across two generated
|
|
819
|
+
# headers: the implementation carries the public bodies and the interface declares the
|
|
820
|
+
# private functions those bodies call. The generated source needs both, so this module's own
|
|
821
|
+
# interface header belongs in its own include list.
|
|
822
|
+
it "carries this module's own interface header when it is also mocked" do
|
|
823
|
+
allow(@file_path_utils).to receive(:form_partial_implementation_header_filename)
|
|
824
|
+
.with('module').and_return('ceedling_partial_module_impl.h')
|
|
825
|
+
allow(@file_path_utils).to receive(:form_partial_interface_header_filename)
|
|
826
|
+
.with('module').and_return('ceedling_partial_module_interface.h')
|
|
827
|
+
|
|
828
|
+
result = @partializer.remap_implementation_source_includes(
|
|
829
|
+
name: 'module',
|
|
830
|
+
includes: [UserInclude.new('module.h')],
|
|
831
|
+
partials: { 'module' => make_partial_config(tests_type: :public, mocks_type: :private) }
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
expect( result.map( &:filename ) ).to eq(
|
|
835
|
+
['ceedling_partial_module_impl.h', 'ceedling_partial_module_interface.h']
|
|
836
|
+
)
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
it "carries no interface header for a module that is tested but not mocked" do
|
|
840
|
+
allow(@file_path_utils).to receive(:form_partial_implementation_header_filename)
|
|
841
|
+
.with('module').and_return('ceedling_partial_module_impl.h')
|
|
842
|
+
|
|
843
|
+
result = @partializer.remap_implementation_source_includes(
|
|
844
|
+
name: 'module',
|
|
845
|
+
includes: [UserInclude.new('module.h')],
|
|
846
|
+
partials: { 'module' => make_partial_config(tests_type: :public) }
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
expect( result.map( &:filename ) ).to eq(['ceedling_partial_module_impl.h'])
|
|
850
|
+
end
|
|
851
|
+
|
|
812
852
|
it "returns implementation header when input is empty and no partials" do
|
|
813
853
|
includes = []
|
|
814
854
|
partials = {}
|
|
@@ -1214,6 +1254,129 @@ describe Partializer do
|
|
|
1214
1254
|
### extract_module_contents()
|
|
1215
1255
|
###
|
|
1216
1256
|
|
|
1257
|
+
context "#extract_module_include_guard" do
|
|
1258
|
+
# Read from the original header, not the reconstituted copy: that copy carries a synthetic
|
|
1259
|
+
# guard which #sanitize then strips, so it is not a dependable source for the name to spoof.
|
|
1260
|
+
it "reads a bounded prefix of the module's own header and returns the guard found" do
|
|
1261
|
+
expect(@file_wrapper).to receive(:read)
|
|
1262
|
+
.with('src/Foo.h', Partializer::GUARD_SCAN_BYTES)
|
|
1263
|
+
.and_return("#ifndef FOO_H\n#define FOO_H\n")
|
|
1264
|
+
allow(@preprocessinator_reconstructor).to receive(:extract_include_guard)
|
|
1265
|
+
.with("#ifndef FOO_H\n#define FOO_H\n")
|
|
1266
|
+
.and_return('FOO_H')
|
|
1267
|
+
|
|
1268
|
+
expect( @partializer.extract_module_include_guard('src/Foo.h') ).to eq('FOO_H')
|
|
1269
|
+
end
|
|
1270
|
+
|
|
1271
|
+
# A `#pragma once` header offers no macro any generated file could define, which is what a
|
|
1272
|
+
# nil return means to every caller.
|
|
1273
|
+
it "returns nil when the header carries no guard macro" do
|
|
1274
|
+
allow(@file_wrapper).to receive(:read).and_return("#pragma once\n")
|
|
1275
|
+
allow(@preprocessinator_reconstructor).to receive(:extract_include_guard).and_return(nil)
|
|
1276
|
+
|
|
1277
|
+
expect( @partializer.extract_module_include_guard('src/Foo.h') ).to be_nil
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1280
|
+
it "returns nil for an absent filepath without reading anything" do
|
|
1281
|
+
expect(@file_wrapper).not_to receive(:read)
|
|
1282
|
+
|
|
1283
|
+
expect( @partializer.extract_module_include_guard(nil) ).to be_nil
|
|
1284
|
+
end
|
|
1285
|
+
end
|
|
1286
|
+
|
|
1287
|
+
context "#remap_types_header_includes" do
|
|
1288
|
+
# Nothing replaces this module's own header here. The types header cannot include itself, so
|
|
1289
|
+
# its own entry is simply dropped.
|
|
1290
|
+
it "drops the module's own header without substituting anything" do
|
|
1291
|
+
result = @partializer.remap_types_header_includes(
|
|
1292
|
+
name: 'module',
|
|
1293
|
+
includes: [UserInclude.new('module.h'), UserInclude.new('foundation.h')],
|
|
1294
|
+
partials: {}
|
|
1295
|
+
)
|
|
1296
|
+
|
|
1297
|
+
expect( result ).to eq([UserInclude.new('foundation.h')])
|
|
1298
|
+
end
|
|
1299
|
+
|
|
1300
|
+
it "keeps every other include in its original relative order" do
|
|
1301
|
+
result = @partializer.remap_types_header_includes(
|
|
1302
|
+
name: 'module',
|
|
1303
|
+
includes: [UserInclude.new('first.h'), UserInclude.new('module.h'), UserInclude.new('last.h')],
|
|
1304
|
+
partials: {}
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
expect( result.map( &:filename ) ).to eq(['first.h', 'last.h'])
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
# Another partialized module's real header would reintroduce exactly the content that
|
|
1311
|
+
# module's own Partial replaced, so a mocked one is redirected to its generated interface
|
|
1312
|
+
# header and an unmocked one is dropped.
|
|
1313
|
+
it "redirects a mocked partialized dependency to its interface header" do
|
|
1314
|
+
allow(@file_path_utils).to receive(:form_partial_interface_header_filename)
|
|
1315
|
+
.with('other')
|
|
1316
|
+
.and_return('ceedling_partial_other_interface.h')
|
|
1317
|
+
|
|
1318
|
+
result = @partializer.remap_types_header_includes(
|
|
1319
|
+
name: 'module',
|
|
1320
|
+
includes: [UserInclude.new('module.h'), UserInclude.new('other.h')],
|
|
1321
|
+
partials: { 'other' => make_partial_config(mocks_type: :public) }
|
|
1322
|
+
)
|
|
1323
|
+
|
|
1324
|
+
expect( result.map( &:filename ) ).to eq(['ceedling_partial_other_interface.h'])
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
it "drops a partialized dependency that is not mocked" do
|
|
1328
|
+
result = @partializer.remap_types_header_includes(
|
|
1329
|
+
name: 'module',
|
|
1330
|
+
includes: [UserInclude.new('module.h'), UserInclude.new('other.h')],
|
|
1331
|
+
partials: { 'other' => make_partial_config(tests_type: :public) }
|
|
1332
|
+
)
|
|
1333
|
+
|
|
1334
|
+
expect( result ).to be_empty
|
|
1335
|
+
end
|
|
1336
|
+
|
|
1337
|
+
# Comparing a module name to an include means comparing names. A header whose basename
|
|
1338
|
+
# merely extends the module's is a different file.
|
|
1339
|
+
it "leaves a header whose name only extends a partialized module's name" do
|
|
1340
|
+
result = @partializer.remap_types_header_includes(
|
|
1341
|
+
name: 'module',
|
|
1342
|
+
includes: [UserInclude.new('module.h'), UserInclude.new('other_extra.h'), UserInclude.new('other.h')],
|
|
1343
|
+
partials: { 'other' => make_partial_config(tests_type: :public) }
|
|
1344
|
+
)
|
|
1345
|
+
|
|
1346
|
+
expect( result.map( &:filename ) ).to eq(['other_extra.h'])
|
|
1347
|
+
end
|
|
1348
|
+
|
|
1349
|
+
# The interface header includes the types header, so carrying it back into the types header
|
|
1350
|
+
# would fold that file's function declarations into this one.
|
|
1351
|
+
it "never carries this module's own interface header, even when it is also mocked" do
|
|
1352
|
+
allow(@file_path_utils).to receive(:form_partial_interface_header_filename)
|
|
1353
|
+
.and_return('ceedling_partial_module_interface.h')
|
|
1354
|
+
|
|
1355
|
+
result = @partializer.remap_types_header_includes(
|
|
1356
|
+
name: 'module',
|
|
1357
|
+
includes: [UserInclude.new('module.h'), UserInclude.new('foundation.h')],
|
|
1358
|
+
partials: { 'module' => make_partial_config(tests_type: :public, mocks_type: :private) }
|
|
1359
|
+
)
|
|
1360
|
+
|
|
1361
|
+
expect( result.map( &:filename ) ).to eq(['foundation.h'])
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
it "logs the carried list under its own noun when a test is named" do
|
|
1365
|
+
expect(@loginator).to receive(:log_list).with(
|
|
1366
|
+
anything,
|
|
1367
|
+
'Dependency includes to carry into the shared types header for Partial a_test::module:',
|
|
1368
|
+
Verbosity::OBNOXIOUS
|
|
1369
|
+
)
|
|
1370
|
+
|
|
1371
|
+
@partializer.remap_types_header_includes(
|
|
1372
|
+
name: 'module',
|
|
1373
|
+
includes: [UserInclude.new('foundation.h')],
|
|
1374
|
+
partials: {},
|
|
1375
|
+
test: 'a_test'
|
|
1376
|
+
)
|
|
1377
|
+
end
|
|
1378
|
+
end
|
|
1379
|
+
|
|
1217
1380
|
context "#extract_module_contents" do
|
|
1218
1381
|
before(:each) do
|
|
1219
1382
|
@name = 'TestModule'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ceedling
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mark VanderVoord
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2026-
|
|
13
|
+
date: 2026-10-08 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rake
|
|
@@ -945,6 +945,7 @@ files:
|
|
|
945
945
|
- spec/system/example_wondrous_forest_spec.rb
|
|
946
946
|
- spec/system/gcov_deployment_spec.rb
|
|
947
947
|
- spec/system/mixin_ordering_spec.rb
|
|
948
|
+
- spec/system/partials_types_header_spec.rb
|
|
948
949
|
- spec/system/preprocessing_encoding_spec.rb
|
|
949
950
|
- spec/system/preprocessing_fallback_conditionals_spec.rb
|
|
950
951
|
- spec/system/preprocessing_locale_spec.rb
|
|
@@ -1799,6 +1800,7 @@ test_files:
|
|
|
1799
1800
|
- spec/system/example_wondrous_forest_spec.rb
|
|
1800
1801
|
- spec/system/gcov_deployment_spec.rb
|
|
1801
1802
|
- spec/system/mixin_ordering_spec.rb
|
|
1803
|
+
- spec/system/partials_types_header_spec.rb
|
|
1802
1804
|
- spec/system/preprocessing_encoding_spec.rb
|
|
1803
1805
|
- spec/system/preprocessing_fallback_conditionals_spec.rb
|
|
1804
1806
|
- spec/system/preprocessing_locale_spec.rb
|