defmastership 1.3.2 → 1.3.4

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -9
  3. data/Guardfile +2 -5
  4. data/Rakefile +1 -1
  5. data/config/mutant.yml +2 -1
  6. data/config/rubocop.yml +20 -8
  7. data/defmastership.gemspec +6 -15
  8. data/features/changeref.feature +108 -0
  9. data/features/definition_checksum.feature +118 -0
  10. data/features/definition_version.feature +168 -0
  11. data/features/export.feature +122 -22
  12. data/features/external_ref_checksum.feature +169 -0
  13. data/features/external_ref_version.feature +173 -0
  14. data/features/internal_ref_checksum.feature +77 -0
  15. data/features/internal_ref_version.feature +81 -0
  16. data/features/rename_included_files.feature +55 -0
  17. data/features/step_definitions/git_steps.rb +3 -0
  18. data/lib/defmastership/app.rb +35 -8
  19. data/lib/defmastership/comment_filter.rb +2 -0
  20. data/lib/defmastership/def_type_list.rb +25 -0
  21. data/lib/defmastership/definition_parser.rb +2 -6
  22. data/lib/defmastership/document.rb +6 -9
  23. data/lib/defmastership/export/csv/formatter.rb +8 -60
  24. data/lib/defmastership/export/formatter.rb +88 -0
  25. data/lib/defmastership/export/json/formatter.rb +34 -0
  26. data/lib/defmastership/export/xlsx/formatter.rb +87 -0
  27. data/lib/defmastership/export/yaml/formatter.rb +34 -0
  28. data/lib/defmastership/modifier/change_ref.rb +24 -39
  29. data/lib/defmastership/modifier/factory.rb +5 -1
  30. data/lib/defmastership/modifier/modifier_common.rb +4 -4
  31. data/lib/defmastership/modifier/rename_included_files.rb +16 -5
  32. data/lib/defmastership/modifier/replacement_formatter.rb +37 -0
  33. data/lib/defmastership/modifier/update_def.rb +7 -2
  34. data/lib/defmastership/modifier/update_eref_checksum.rb +46 -0
  35. data/lib/defmastership/modifier/update_eref_common.rb +78 -0
  36. data/lib/defmastership/modifier/update_eref_version.rb +46 -0
  37. data/lib/defmastership/modifier/update_iref_checksum.rb +52 -0
  38. data/lib/defmastership/modifier/update_iref_common.rb +45 -0
  39. data/lib/defmastership/modifier/update_iref_version.rb +59 -0
  40. data/lib/defmastership/version.rb +1 -1
  41. data/spec/spec_helper.rb +11 -10
  42. data/spec/unit/defmastership/app_spec.rb +57 -20
  43. data/spec/unit/defmastership/batch_modifier_spec.rb +9 -7
  44. data/spec/unit/defmastership/def_type_list_spec.rb +22 -0
  45. data/spec/unit/defmastership/definition_spec.rb +8 -51
  46. data/spec/unit/defmastership/document_spec.rb +12 -36
  47. data/spec/unit/defmastership/export/body_formatter_spec.rb +5 -18
  48. data/spec/unit/defmastership/export/csv/formatter_spec.rb +45 -231
  49. data/spec/unit/defmastership/export/formatter_spec.rb +97 -0
  50. data/spec/unit/defmastership/export/header_formatter_spec.rb +2 -6
  51. data/spec/unit/defmastership/export/json/formatter_spec.rb +85 -0
  52. data/spec/unit/defmastership/export/xlsx/formatter_spec.rb +82 -0
  53. data/spec/unit/defmastership/export/yaml/formatter_spec.rb +85 -0
  54. data/spec/unit/defmastership/hash_spec.rb +2 -0
  55. data/spec/unit/defmastership/modifier/change_ref_spec.rb +66 -97
  56. data/spec/unit/defmastership/modifier/factory_spec.rb +40 -17
  57. data/spec/unit/defmastership/modifier/modifier_common_spec.rb +7 -5
  58. data/spec/unit/defmastership/modifier/rename_included_files_spec.rb +105 -85
  59. data/spec/unit/defmastership/modifier/update_def_checksum_spec.rb +6 -13
  60. data/spec/unit/defmastership/modifier/update_def_spec.rb +79 -22
  61. data/spec/unit/defmastership/modifier/update_def_version_spec.rb +13 -37
  62. data/spec/unit/defmastership/modifier/update_eref_checksum_spec.rb +209 -0
  63. data/spec/unit/defmastership/modifier/update_eref_version_spec.rb +227 -0
  64. data/spec/unit/defmastership/modifier/update_iref_checksum_spec.rb +133 -0
  65. data/spec/unit/defmastership/modifier/update_iref_version_spec.rb +162 -0
  66. data/tasks/code_quality.rake +1 -8
  67. data/tasks/test.rake +15 -0
  68. metadata +59 -6
@@ -0,0 +1,209 @@
1
+ # Copyright (c) 2025 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/document')
5
+ require('defmastership/modifier/update_eref_checksum')
6
+
7
+ RSpec.describe(Defmastership::Modifier::UpdateErefChecksum) do
8
+ describe '.new' do
9
+ context 'when default config' do
10
+ subject(:modifier) { described_class.new({}) }
11
+
12
+ it { is_expected.not_to(be_nil) }
13
+ it { expect(described_class.ancestors).to(include(Defmastership::Modifier::ModifierCommon)) }
14
+ it { is_expected.to(have_attributes(config: { eref_type: '', ref_document: '' })) }
15
+ end
16
+
17
+ context 'when config with simple options' do
18
+ subject(:modifier) { described_class.new({ eref_type: 'type', ref_document: 'ref.adoc' }) }
19
+
20
+ it { is_expected.to(have_attributes(config: { eref_type: 'type', ref_document: 'ref.adoc' })) }
21
+ end
22
+ end
23
+
24
+ describe '.replacement_methods' do
25
+ it { expect(described_class.replacement_methods).to(eq(%i[replace_erefs])) }
26
+ end
27
+
28
+ describe '#do_modifications' do
29
+ context 'when only one ref doc' do
30
+ subject(:modifier) { described_class.new({ ref_document: 'ref_doc.adoc' }) }
31
+
32
+ let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
33
+ let(:adoc_sources) do
34
+ {
35
+ 'file1.adoc' => 'pouet',
36
+ 'file2.adoc' => 'tagada'
37
+ }
38
+ end
39
+
40
+ before do
41
+ allow(Defmastership::Document).to(receive(:new).once.and_return(ref_document))
42
+ allow(ref_document).to(receive(:parse_file_with_preprocessor))
43
+ allow_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).and_return(adoc_sources))
44
+
45
+ modifier.do_modifications(adoc_sources)
46
+ end
47
+
48
+ it { expect(Defmastership::Document).to(have_received(:new).once) }
49
+ it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('ref_doc.adoc')) }
50
+
51
+ it 'call the parent method' do
52
+ expect_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).with(adoc_sources))
53
+ modifier.do_modifications(adoc_sources)
54
+ end
55
+ end
56
+
57
+ context 'when more ref docs' do
58
+ subject(:modifier) { described_class.new({ ref_document: ['ref_doc1.adoc', 'ref_doc2.adoc'] }) }
59
+
60
+ let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
61
+ let(:adoc_sources) do
62
+ {
63
+ 'file1.adoc' => 'pouet',
64
+ 'file2.adoc' => 'tagada'
65
+ }
66
+ end
67
+
68
+ before do
69
+ allow(Defmastership::Document).to(receive(:new).once.and_return(ref_document))
70
+ allow(ref_document).to(receive(:parse_file_with_preprocessor))
71
+
72
+ modifier.do_modifications(adoc_sources)
73
+ end
74
+
75
+ it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('ref_doc1.adoc')) }
76
+ it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('ref_doc2.adoc')) }
77
+ end
78
+ end
79
+
80
+ describe '#replace_erefs' do
81
+ subject(:modifier) { described_class.new({ ref_document: 'ref_doc.adoc' }) }
82
+
83
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
84
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
85
+
86
+ before do
87
+ allow(Defmastership::Document).to(receive(:new).and_return(ref_document))
88
+ end
89
+
90
+ context 'when the line is matching one external ref definition with only one ref' do
91
+ before do
92
+ allow(ref_document).to(receive(:ref_to_def).and_return(ref_definition))
93
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
94
+ end
95
+
96
+ [
97
+ ['', '(~a1b2c3d4)'],
98
+ ['(~abcd1234)', '(~a1b2c3d4)'],
99
+ ['(a)', '(a~a1b2c3d4)'],
100
+ ['(a~abcd1234)', '(a~a1b2c3d4)']
101
+ ].each do |from, to|
102
+ it do
103
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
104
+ expect(ref_document).to(have_received(:ref_to_def).with('THE_REF'))
105
+ end
106
+
107
+ it do
108
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
109
+ expect(ref_definition).to(have_received(:sha256_short))
110
+ end
111
+
112
+ it do
113
+ expect(
114
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
115
+ ).to(eq("defs:eref[type, [THE_REF#{to}]]"))
116
+ end
117
+ end
118
+ end
119
+
120
+ context 'when the definition does not exist' do
121
+ before do
122
+ allow(ref_document).to(receive(:ref_to_def).and_return(nil))
123
+ end
124
+
125
+ it do
126
+ modifier.replace_erefs('', 'defs:eref[type, [BAD_REF(a~abcd1234)]]')
127
+ expect(ref_document).to(have_received(:ref_to_def).with('BAD_REF'))
128
+ end
129
+
130
+ it do
131
+ expect(modifier.replace_erefs('', 'defs:eref[type, [BAD_REF(a~abcd1234)]]'))
132
+ .to(eq('defs:eref[type, [BAD_REF(a~abcd1234)]]'))
133
+ end
134
+
135
+ it { expect(modifier.replace_erefs('', 'defs:eref[type, [BAD_REF]]')).to(eq('defs:eref[type, [BAD_REF]]')) }
136
+ it { expect(modifier.replace_erefs('', 'defs:eref[type, [BAD_REF(a)]]')).to(eq('defs:eref[type, [BAD_REF(a)]]')) }
137
+ end
138
+
139
+ context 'when the line is not a valid eref' do
140
+ it { expect(modifier.replace_erefs('', 'bla bla')).to(eq('bla bla')) }
141
+ end
142
+
143
+ context 'when the line is matching one external ref definition with more refs' do
144
+ let(:other_ref_definition) { instance_double(Defmastership::Definition, 'other_ref_definition') }
145
+
146
+ before do
147
+ allow(ref_document).to(receive(:ref_to_def).with('REF1').and_return(ref_definition))
148
+ allow(ref_document).to(receive(:ref_to_def).with('REF2').and_return(other_ref_definition))
149
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
150
+ allow(other_ref_definition).to(receive(:sha256_short).and_return('~e5f6abcd'))
151
+ modifier.replace_erefs('', 'defs:eref[type, [REF1, REF2]]')
152
+ end
153
+
154
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF1')) }
155
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF2')) }
156
+ it { expect(ref_definition).to(have_received(:sha256_short)) }
157
+ it { expect(other_ref_definition).to(have_received(:sha256_short)) }
158
+
159
+ it do
160
+ expect(modifier.replace_erefs('', 'defs:eref[type, [REF1, REF2]]'))
161
+ .to(eq('defs:eref[type, [REF1(~a1b2c3d4), REF2(~e5f6abcd)]]'))
162
+ end
163
+ end
164
+
165
+ context 'when the modifier modifies only one eref_type' do
166
+ subject(:modifier) { described_class.new({ eref_type: 'implements', ref_document: 'ref_doc.adoc' }) }
167
+
168
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
169
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
170
+
171
+ before do
172
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
173
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
174
+ end
175
+
176
+ it do
177
+ expect(
178
+ modifier.replace_erefs('', 'defs:eref[implements, [REF]]')
179
+ ).to(eq('defs:eref[implements, [REF(~a1b2c3d4)]]'))
180
+ end
181
+
182
+ it { expect(modifier.replace_erefs('', 'defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF]]')) }
183
+ end
184
+
185
+ context 'when the modifier modifies more than one eref_type' do
186
+ subject(:modifier) { described_class.new({ eref_type: %w[implements covers], ref_document: 'ref_doc.adoc' }) }
187
+
188
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
189
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
190
+
191
+ before do
192
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
193
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
194
+ end
195
+
196
+ it do
197
+ expect(
198
+ modifier.replace_erefs('', 'defs:eref[implements, [REF]]')
199
+ ).to(eq('defs:eref[implements, [REF(~a1b2c3d4)]]'))
200
+ end
201
+
202
+ it do
203
+ expect(modifier.replace_erefs('', 'defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF(~a1b2c3d4)]]'))
204
+ end
205
+
206
+ it { expect(modifier.replace_erefs('', 'defs:eref[covers_not, [REF]]')).to(eq('defs:eref[covers_not, [REF]]')) }
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,227 @@
1
+ # Copyright (c) 2025 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/document')
5
+ require('defmastership/modifier/update_eref_version')
6
+
7
+ RSpec.describe(Defmastership::Modifier::UpdateErefVersion) do
8
+ describe '.new' do
9
+ context 'when default config' do
10
+ subject(:modifier) { described_class.new({}) }
11
+
12
+ it { is_expected.not_to(be_nil) }
13
+ it { expect(described_class.ancestors).to(include(Defmastership::Modifier::ModifierCommon)) }
14
+ it { is_expected.to(have_attributes(config: { eref_type: '', ref_document: '' })) }
15
+ end
16
+
17
+ context 'when config with simple options' do
18
+ subject(:modifier) { described_class.new({ eref_type: 'type', ref_document: 'ref.adoc' }) }
19
+
20
+ it { is_expected.to(have_attributes(config: { eref_type: 'type', ref_document: 'ref.adoc' })) }
21
+ end
22
+ end
23
+
24
+ describe '.replacement_methods' do
25
+ it { expect(described_class.replacement_methods).to(eq(%i[replace_erefs])) }
26
+ end
27
+
28
+ describe '#do_modifications' do
29
+ context 'when only one ref doc' do
30
+ subject(:modifier) { described_class.new({ ref_document: 'ref_doc.adoc' }) }
31
+
32
+ let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
33
+ let(:adoc_sources) do
34
+ {
35
+ 'file1.adoc' => 'pouet',
36
+ 'file2.adoc' => 'tagada'
37
+ }
38
+ end
39
+
40
+ before do
41
+ allow(Defmastership::Document).to(receive(:new).once.and_return(ref_document))
42
+ allow(ref_document).to(receive(:parse_file_with_preprocessor))
43
+ allow_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).and_return(adoc_sources))
44
+
45
+ modifier.do_modifications(adoc_sources)
46
+ end
47
+
48
+ it { expect(Defmastership::Document).to(have_received(:new).once) }
49
+ it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('ref_doc.adoc')) }
50
+
51
+ it 'call the parent method' do
52
+ expect_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).with(adoc_sources))
53
+ modifier.do_modifications(adoc_sources)
54
+ end
55
+ end
56
+
57
+ context 'when more ref docs' do
58
+ subject(:modifier) { described_class.new({ ref_document: ['ref_doc1.adoc', 'ref_doc2.adoc'] }) }
59
+
60
+ let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
61
+ let(:adoc_sources) do
62
+ {
63
+ 'file1.adoc' => 'pouet',
64
+ 'file2.adoc' => 'tagada'
65
+ }
66
+ end
67
+
68
+ before do
69
+ allow(Defmastership::Document).to(receive(:new).once.and_return(ref_document))
70
+ allow(ref_document).to(receive(:parse_file_with_preprocessor))
71
+
72
+ modifier.do_modifications(adoc_sources)
73
+ end
74
+
75
+ it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('ref_doc1.adoc')) }
76
+ it { expect(ref_document).to(have_received(:parse_file_with_preprocessor).with('ref_doc2.adoc')) }
77
+ end
78
+ end
79
+
80
+ describe '#replace_erefs' do
81
+ subject(:modifier) { described_class.new({ ref_document: 'ref_doc.adoc' }) }
82
+
83
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
84
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
85
+
86
+ before do
87
+ allow(Defmastership::Document).to(receive(:new).and_return(ref_document))
88
+ end
89
+
90
+ context 'when the line is matching one external ref definition with only one ref' do
91
+ before do
92
+ allow(ref_document).to(receive(:ref_to_def).and_return(ref_definition))
93
+ allow(ref_definition).to(receive(:explicit_version).and_return('z'))
94
+ end
95
+
96
+ [
97
+ ['', '(z)'],
98
+ ['(~abcd1234)', '(z~abcd1234)'],
99
+ ['(a)', '(z)'],
100
+ ['(a~abcd1234)', '(z~abcd1234)']
101
+ ].each do |from, to|
102
+ it do
103
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
104
+ expect(ref_document).to(have_received(:ref_to_def).with('THE_REF'))
105
+ end
106
+
107
+ it do
108
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
109
+ expect(ref_definition).to(have_received(:explicit_version))
110
+ end
111
+
112
+ it do
113
+ expect(
114
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
115
+ ).to(eq("defs:eref[type, [THE_REF#{to}]]"))
116
+ end
117
+ end
118
+ end
119
+
120
+ context 'when the line is matching one external ref definition with only one ref withot version' do
121
+ before do
122
+ allow(ref_document).to(receive(:ref_to_def).and_return(ref_definition))
123
+ allow(ref_definition).to(receive(:explicit_version).and_return(nil))
124
+ end
125
+
126
+ [
127
+ ['', ''],
128
+ ['(~abcd1234)', '(~abcd1234)'],
129
+ ['(a)', ''],
130
+ ['(a~abcd1234)', '(~abcd1234)']
131
+ ].each do |from, to|
132
+ it do
133
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
134
+ expect(ref_document).to(have_received(:ref_to_def).with('THE_REF'))
135
+ end
136
+
137
+ it do
138
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
139
+ expect(ref_definition).to(have_received(:explicit_version))
140
+ end
141
+
142
+ it do
143
+ expect(
144
+ modifier.replace_erefs('', "defs:eref[type, [THE_REF#{from}]]")
145
+ ).to(eq("defs:eref[type, [THE_REF#{to}]]"))
146
+ end
147
+ end
148
+ end
149
+
150
+ context 'when the definition does not exist' do
151
+ before do
152
+ allow(ref_document).to(receive(:ref_to_def).and_return(nil))
153
+ end
154
+
155
+ it do
156
+ modifier.replace_erefs('', 'defs:eref[type, [BAD_REF(a)]]')
157
+ expect(ref_document).to(have_received(:ref_to_def).with('BAD_REF'))
158
+ end
159
+
160
+ it { expect(modifier.replace_erefs('', 'defs:eref[type, [BAD_REF(a)]]')).to(eq('defs:eref[type, [BAD_REF(a)]]')) }
161
+ end
162
+
163
+ context 'when the line is not a valid eref' do
164
+ it { expect(modifier.replace_erefs('', 'bla bla')).to(eq('bla bla')) }
165
+ end
166
+
167
+ context 'when the line is matching one external ref definition with more refs' do
168
+ let(:other_ref_definition) { instance_double(Defmastership::Definition, 'other_ref_definition') }
169
+
170
+ before do
171
+ allow(ref_document).to(receive(:ref_to_def).with('REF1').and_return(ref_definition))
172
+ allow(ref_document).to(receive(:ref_to_def).with('REF2').and_return(other_ref_definition))
173
+ allow(ref_definition).to(receive(:explicit_version).and_return('a'))
174
+ allow(other_ref_definition).to(receive(:explicit_version).and_return('z'))
175
+ modifier.replace_erefs('', 'defs:eref[type, [REF1, REF2]]')
176
+ end
177
+
178
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF1')) }
179
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF2')) }
180
+ it { expect(ref_definition).to(have_received(:explicit_version)) }
181
+ it { expect(other_ref_definition).to(have_received(:explicit_version)) }
182
+
183
+ it do
184
+ expect(
185
+ modifier.replace_erefs('', 'defs:eref[type, [REF1, REF2]]')
186
+ ).to(eq('defs:eref[type, [REF1(a), REF2(z)]]'))
187
+ end
188
+ end
189
+
190
+ context 'when the modifier modifies only one eref_type' do
191
+ subject(:modifier) { described_class.new({ eref_type: 'implements', ref_document: 'ref_doc.adoc' }) }
192
+
193
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
194
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
195
+
196
+ before do
197
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
198
+ allow(ref_definition).to(receive(:explicit_version).and_return('a'))
199
+ end
200
+
201
+ it do
202
+ expect(modifier.replace_erefs('', 'defs:eref[implements, [REF]]')).to(eq('defs:eref[implements, [REF(a)]]'))
203
+ end
204
+
205
+ it { expect(modifier.replace_erefs('', 'defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF]]')) }
206
+ end
207
+
208
+ context 'when the modifier modifies more than one eref_type' do
209
+ subject(:modifier) { described_class.new({ eref_type: %w[implements covers], ref_document: 'ref_doc.adoc' }) }
210
+
211
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
212
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
213
+
214
+ before do
215
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
216
+ allow(ref_definition).to(receive(:explicit_version).and_return('a'))
217
+ end
218
+
219
+ it do
220
+ expect(modifier.replace_erefs('', 'defs:eref[implements, [REF]]')).to(eq('defs:eref[implements, [REF(a)]]'))
221
+ end
222
+
223
+ it { expect(modifier.replace_erefs('', 'defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF(a)]]')) }
224
+ it { expect(modifier.replace_erefs('', 'defs:eref[covers_not, [REF]]')).to(eq('defs:eref[covers_not, [REF]]')) }
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,133 @@
1
+ # Copyright (c) 2025 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/modifier/update_iref_checksum')
5
+
6
+ RSpec.describe(Defmastership::Modifier::UpdateIrefChecksum) do
7
+ subject(:modifier) { described_class.new({}) }
8
+
9
+ describe '.new' do
10
+ it { is_expected.not_to(be_nil) }
11
+ it { expect(described_class.ancestors).to(include(Defmastership::Modifier::ModifierCommon)) }
12
+ it { is_expected.to(have_attributes(config: {})) }
13
+ end
14
+
15
+ describe '.replacement_methods' do
16
+ it { expect(described_class.replacement_methods).to(eq(%i[replace_irefs])) }
17
+ end
18
+
19
+ describe '#do_modifications' do
20
+ let(:document) { instance_double(Defmastership::Document, 'document') }
21
+ let(:adoc_sources) do
22
+ {
23
+ 'file1.adoc' => 'pouet',
24
+ 'file2.adoc' => 'tagada'
25
+ }
26
+ end
27
+
28
+ before do
29
+ allow(Defmastership::Document).to(receive(:new).and_return(document))
30
+ allow(document).to(receive(:parse_file_with_preprocessor))
31
+ allow_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).and_return(adoc_sources))
32
+
33
+ modifier.do_modifications(adoc_sources)
34
+ end
35
+
36
+ it { expect(Defmastership::Document).to(have_received(:new)) }
37
+
38
+ it do
39
+ expect(document).to(
40
+ have_received(:parse_file_with_preprocessor)
41
+ .once.with('file1.adoc')
42
+ .once.with('file2.adoc')
43
+ )
44
+ end
45
+
46
+ it { expect(modifier.do_modifications(adoc_sources)).to(eq(adoc_sources)) }
47
+
48
+ it 'call the parent method' do
49
+ expect_any_instance_of(Defmastership::Modifier::ModifierCommon).to(receive(:do_modifications).with(adoc_sources))
50
+ modifier.do_modifications(adoc_sources)
51
+ end
52
+ end
53
+
54
+ describe '#replace_irefs' do
55
+ let(:document) { instance_double(Defmastership::Document, 'document') }
56
+ let(:definition) { instance_double(Defmastership::Definition, 'definition') }
57
+
58
+ before do
59
+ allow(Defmastership::Document).to(receive(:new).and_return(document))
60
+ end
61
+
62
+ context 'when the line is matching a good internal ref definition' do
63
+ before do
64
+ allow(document).to(receive(:ref_to_def).and_return(definition))
65
+ allow(definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
66
+ end
67
+
68
+ [
69
+ ['', '(~a1b2c3d4)'],
70
+ ['(~abcd1234)', '(~a1b2c3d4)'],
71
+ ['(a)', '(a~a1b2c3d4)'],
72
+ ['(a~abcd1234)', '(a~a1b2c3d4)']
73
+ ].each do |from, to|
74
+ it do
75
+ modifier.replace_irefs('', "whatever defs:iref[THE_REF#{from}] whatever")
76
+ expect(document).to(have_received(:ref_to_def).with('THE_REF'))
77
+ end
78
+
79
+ it do
80
+ modifier.replace_irefs('', "whatever defs:iref[THE_REF#{from}] whatever")
81
+ expect(definition).to(have_received(:sha256_short))
82
+ end
83
+
84
+ it {
85
+ expect(modifier.replace_irefs('', "whatever defs:iref[THE_REF#{from}] whatever"))
86
+ .to(eq("whatever defs:iref[THE_REF#{to}] whatever"))
87
+ }
88
+ end
89
+ end
90
+
91
+ context 'when the definition does not exist' do
92
+ before do
93
+ allow(document).to(receive(:ref_to_def).and_return(nil))
94
+ end
95
+
96
+ it do
97
+ modifier.replace_irefs('', 'whatever defs:iref[BAD_REF(a~abcd1234)] whatever')
98
+ expect(document).to(have_received(:ref_to_def).with('BAD_REF'))
99
+ end
100
+
101
+ it {
102
+ expect(modifier.replace_irefs('', 'whatever defs:iref[BAD_REF(a~abcd1234)] whatever'))
103
+ .to(eq('whatever defs:iref[BAD_REF(a~abcd1234)] whatever'))
104
+ }
105
+ end
106
+
107
+ context 'when the line is not a valid iref' do
108
+ it { expect(modifier.replace_irefs('', 'bla bla')).to(eq('bla bla')) }
109
+ end
110
+
111
+ context 'when the line is matching more than one iref' do
112
+ let(:other_definition) { instance_double(Defmastership::Definition, 'other_definition') }
113
+
114
+ before do
115
+ allow(document).to(receive(:ref_to_def).with('REF1').and_return(definition))
116
+ allow(document).to(receive(:ref_to_def).with('REF2').and_return(other_definition))
117
+ allow(definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
118
+ allow(other_definition).to(receive(:sha256_short).and_return('~e5f6abcd'))
119
+ modifier.replace_irefs('', 'defs:iref[REF1], defs:iref[REF2]')
120
+ end
121
+
122
+ it { expect(document).to(have_received(:ref_to_def).with('REF1')) }
123
+ it { expect(document).to(have_received(:ref_to_def).with('REF2')) }
124
+ it { expect(definition).to(have_received(:sha256_short)) }
125
+ it { expect(other_definition).to(have_received(:sha256_short)) }
126
+
127
+ it {
128
+ expect(modifier.replace_irefs('', 'defs:iref[REF1], defs:iref[REF2]'))
129
+ .to(eq('defs:iref[REF1(~a1b2c3d4)], defs:iref[REF2(~e5f6abcd)]'))
130
+ }
131
+ end
132
+ end
133
+ end