defmastership 1.3.2 → 1.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Guardfile +2 -5
  3. data/config/mutant.yml +2 -1
  4. data/config/rubocop.yml +20 -8
  5. data/defmastership.gemspec +4 -14
  6. data/features/changeref.feature +78 -0
  7. data/features/definition_checksum.feature +118 -0
  8. data/features/definition_version.feature +168 -0
  9. data/features/export.feature +67 -22
  10. data/features/external_ref_checksum.feature +169 -0
  11. data/features/external_ref_version.feature +173 -0
  12. data/features/internal_ref_checksum.feature +77 -0
  13. data/features/internal_ref_version.feature +81 -0
  14. data/features/rename_included_files.feature +28 -0
  15. data/lib/defmastership/app.rb +5 -6
  16. data/lib/defmastership/comment_filter.rb +2 -0
  17. data/lib/defmastership/def_type_list.rb +25 -0
  18. data/lib/defmastership/definition_parser.rb +2 -6
  19. data/lib/defmastership/document.rb +6 -9
  20. data/lib/defmastership/modifier/change_ref.rb +11 -34
  21. data/lib/defmastership/modifier/factory.rb +5 -1
  22. data/lib/defmastership/modifier/rename_included_files.rb +9 -0
  23. data/lib/defmastership/modifier/replacement_formatter.rb +37 -0
  24. data/lib/defmastership/modifier/update_def.rb +5 -1
  25. data/lib/defmastership/modifier/update_eref_checksum.rb +46 -0
  26. data/lib/defmastership/modifier/update_eref_common.rb +77 -0
  27. data/lib/defmastership/modifier/update_eref_version.rb +46 -0
  28. data/lib/defmastership/modifier/update_iref_checksum.rb +51 -0
  29. data/lib/defmastership/modifier/update_iref_common.rb +45 -0
  30. data/lib/defmastership/modifier/update_iref_version.rb +58 -0
  31. data/lib/defmastership/version.rb +1 -1
  32. data/spec/spec_helper.rb +11 -10
  33. data/spec/unit/defmastership/app_spec.rb +32 -19
  34. data/spec/unit/defmastership/batch_modifier_spec.rb +9 -7
  35. data/spec/unit/defmastership/def_type_list_spec.rb +22 -0
  36. data/spec/unit/defmastership/definition_spec.rb +8 -51
  37. data/spec/unit/defmastership/document_spec.rb +12 -36
  38. data/spec/unit/defmastership/export/body_formatter_spec.rb +5 -18
  39. data/spec/unit/defmastership/export/csv/formatter_spec.rb +1 -0
  40. data/spec/unit/defmastership/export/header_formatter_spec.rb +2 -6
  41. data/spec/unit/defmastership/hash_spec.rb +2 -0
  42. data/spec/unit/defmastership/modifier/change_ref_spec.rb +33 -70
  43. data/spec/unit/defmastership/modifier/factory_spec.rb +40 -17
  44. data/spec/unit/defmastership/modifier/modifier_common_spec.rb +2 -0
  45. data/spec/unit/defmastership/modifier/rename_included_files_spec.rb +62 -46
  46. data/spec/unit/defmastership/modifier/update_def_checksum_spec.rb +2 -9
  47. data/spec/unit/defmastership/modifier/update_def_spec.rb +76 -21
  48. data/spec/unit/defmastership/modifier/update_def_version_spec.rb +6 -32
  49. data/spec/unit/defmastership/modifier/update_eref_checksum_spec.rb +200 -0
  50. data/spec/unit/defmastership/modifier/update_eref_version_spec.rb +215 -0
  51. data/spec/unit/defmastership/modifier/update_iref_checksum_spec.rb +133 -0
  52. data/spec/unit/defmastership/modifier/update_iref_version_spec.rb +162 -0
  53. data/tasks/code_quality.rake +1 -8
  54. data/tasks/test.rake +15 -0
  55. metadata +34 -3
@@ -20,13 +20,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
20
20
 
21
21
  describe '#do_modifications' do
22
22
  context 'when only one ref document' do
23
- subject(:modifier) do
24
- described_class.new(
25
- ref_document: 'ref_doc.adoc',
26
- def_type: 'req',
27
- first_version: 'a'
28
- )
29
- end
23
+ subject(:modifier) { described_class.new(ref_document: 'ref_doc.adoc', def_type: 'req', first_version: 'a') }
30
24
 
31
25
  let(:document) { instance_double(Defmastership::Document, 'document') }
32
26
  let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
@@ -106,13 +100,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
106
100
  end
107
101
 
108
102
  context 'when ref_tag is provided' do
109
- subject(:modifier) do
110
- described_class.new(
111
- ref_tag: 'THE_TAG',
112
- def_type: 'req',
113
- first_version: 'a'
114
- )
115
- end
103
+ subject(:modifier) { described_class.new(ref_tag: 'THE_TAG', def_type: 'req', first_version: 'a') }
116
104
 
117
105
  let(:document) { instance_double(Defmastership::Document, 'document') }
118
106
  let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
@@ -156,12 +144,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
156
144
 
157
145
  context 'when ref_tag and ref_repo is provided' do
158
146
  subject(:modifier) do
159
- described_class.new(
160
- ref_tag: 'THE_TAG',
161
- ref_repo: 'not dot',
162
- def_type: 'req',
163
- first_version: 'a'
164
- )
147
+ described_class.new(ref_tag: 'THE_TAG', ref_repo: 'not dot', def_type: 'req', first_version: 'a')
165
148
  end
166
149
 
167
150
  let(:document) { instance_double(Defmastership::Document, 'document') }
@@ -254,12 +237,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
254
237
  end
255
238
 
256
239
  describe '#replace_reference' do
257
- subject(:modifier) do
258
- described_class.new(
259
- def_type: 'requirement',
260
- first_version: 'a'
261
- )
262
- end
240
+ subject(:modifier) { described_class.new(def_type: 'requirement', first_version: 'a') }
263
241
 
264
242
  let(:document) { instance_double(Defmastership::Document, 'document') }
265
243
  let(:ref_document) { instance_double(Defmastership::Document, 'ref_document') }
@@ -272,10 +250,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
272
250
  end
273
251
 
274
252
  context 'when definition has not the good type' do
275
- it do
276
- expect(modifier.replace_reference('[define,req,REFERENCE]'))
277
- .to(eq('[define,req,REFERENCE]'))
278
- end
253
+ it { expect(modifier.replace_reference('[define,req,REFERENCE]')).to(eq('[define,req,REFERENCE]')) }
279
254
  end
280
255
 
281
256
  context 'when definition has the good type' do
@@ -292,8 +267,7 @@ RSpec.describe(Defmastership::Modifier::UpdateDefVersion) do
292
267
 
293
268
  it do
294
269
  allow(ref_definition).to(receive(:explicit_version).and_return(nil))
295
- expect(modifier.replace_reference('[define,requirement,REFERENCE]'))
296
- .to(eq('[define,requirement,REFERENCE]'))
270
+ expect(modifier.replace_reference('[define,requirement,REFERENCE]')).to(eq('[define,requirement,REFERENCE]'))
297
271
  end
298
272
 
299
273
  it do
@@ -0,0 +1,200 @@
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 {
113
+ expect(modifier.replace_erefs("defs:eref[type, [THE_REF#{from}]]")).to(eq("defs:eref[type, [THE_REF#{to}]]"))
114
+ }
115
+ end
116
+ end
117
+
118
+ context 'when the definition does not exist' do
119
+ before do
120
+ allow(ref_document).to(receive(:ref_to_def).and_return(nil))
121
+ end
122
+
123
+ it do
124
+ modifier.replace_erefs('defs:eref[type, [BAD_REF(a~abcd1234)]]')
125
+ expect(ref_document).to(have_received(:ref_to_def).with('BAD_REF'))
126
+ end
127
+
128
+ it do
129
+ expect(modifier.replace_erefs('defs:eref[type, [BAD_REF(a~abcd1234)]]'))
130
+ .to(eq('defs:eref[type, [BAD_REF(a~abcd1234)]]'))
131
+ end
132
+
133
+ it { expect(modifier.replace_erefs('defs:eref[type, [BAD_REF]]')).to(eq('defs:eref[type, [BAD_REF]]')) }
134
+ it { expect(modifier.replace_erefs('defs:eref[type, [BAD_REF(a)]]')).to(eq('defs:eref[type, [BAD_REF(a)]]')) }
135
+ end
136
+
137
+ context 'when the line is not a valid eref' do
138
+ it { expect(modifier.replace_erefs('bla bla')).to(eq('bla bla')) }
139
+ end
140
+
141
+ context 'when the line is matching one external ref definition with more refs' do
142
+ let(:other_ref_definition) { instance_double(Defmastership::Definition, 'other_ref_definition') }
143
+
144
+ before do
145
+ allow(ref_document).to(receive(:ref_to_def).with('REF1').and_return(ref_definition))
146
+ allow(ref_document).to(receive(:ref_to_def).with('REF2').and_return(other_ref_definition))
147
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
148
+ allow(other_ref_definition).to(receive(:sha256_short).and_return('~e5f6abcd'))
149
+ modifier.replace_erefs('defs:eref[type, [REF1, REF2]]')
150
+ end
151
+
152
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF1')) }
153
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF2')) }
154
+ it { expect(ref_definition).to(have_received(:sha256_short)) }
155
+ it { expect(other_ref_definition).to(have_received(:sha256_short)) }
156
+
157
+ it do
158
+ expect(modifier.replace_erefs('defs:eref[type, [REF1, REF2]]'))
159
+ .to(eq('defs:eref[type, [REF1(~a1b2c3d4), REF2(~e5f6abcd)]]'))
160
+ end
161
+ end
162
+
163
+ context 'when the modifier modifies only one eref_type' do
164
+ subject(:modifier) { described_class.new({ eref_type: 'implements', ref_document: 'ref_doc.adoc' }) }
165
+
166
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
167
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
168
+
169
+ before do
170
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
171
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
172
+ end
173
+
174
+ it do
175
+ expect(modifier.replace_erefs('defs:eref[implements, [REF]]')).to(eq('defs:eref[implements, [REF(~a1b2c3d4)]]'))
176
+ end
177
+
178
+ it { expect(modifier.replace_erefs('defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF]]')) }
179
+ end
180
+
181
+ context 'when the modifier modifies more than one eref_type' do
182
+ subject(:modifier) { described_class.new({ eref_type: %w[implements covers], ref_document: 'ref_doc.adoc' }) }
183
+
184
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
185
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
186
+
187
+ before do
188
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
189
+ allow(ref_definition).to(receive(:sha256_short).and_return('~a1b2c3d4'))
190
+ end
191
+
192
+ it do
193
+ expect(modifier.replace_erefs('defs:eref[implements, [REF]]')).to(eq('defs:eref[implements, [REF(~a1b2c3d4)]]'))
194
+ end
195
+
196
+ it { expect(modifier.replace_erefs('defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF(~a1b2c3d4)]]')) }
197
+ it { expect(modifier.replace_erefs('defs:eref[covers_not, [REF]]')).to(eq('defs:eref[covers_not, [REF]]')) }
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,215 @@
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 {
113
+ expect(modifier.replace_erefs("defs:eref[type, [THE_REF#{from}]]")).to(eq("defs:eref[type, [THE_REF#{to}]]"))
114
+ }
115
+ end
116
+ end
117
+
118
+ context 'when the line is matching one external ref definition with only one ref withot version' do
119
+ before do
120
+ allow(ref_document).to(receive(:ref_to_def).and_return(ref_definition))
121
+ allow(ref_definition).to(receive(:explicit_version).and_return(nil))
122
+ end
123
+
124
+ [
125
+ ['', ''],
126
+ ['(~abcd1234)', '(~abcd1234)'],
127
+ ['(a)', ''],
128
+ ['(a~abcd1234)', '(~abcd1234)']
129
+ ].each do |from, to|
130
+ it do
131
+ modifier.replace_erefs("defs:eref[type, [THE_REF#{from}]]")
132
+ expect(ref_document).to(have_received(:ref_to_def).with('THE_REF'))
133
+ end
134
+
135
+ it do
136
+ modifier.replace_erefs("defs:eref[type, [THE_REF#{from}]]")
137
+ expect(ref_definition).to(have_received(:explicit_version))
138
+ end
139
+
140
+ it {
141
+ expect(modifier.replace_erefs("defs:eref[type, [THE_REF#{from}]]")).to(eq("defs:eref[type, [THE_REF#{to}]]"))
142
+ }
143
+ end
144
+ end
145
+
146
+ context 'when the definition does not exist' do
147
+ before do
148
+ allow(ref_document).to(receive(:ref_to_def).and_return(nil))
149
+ end
150
+
151
+ it do
152
+ modifier.replace_erefs('defs:eref[type, [BAD_REF(a)]]')
153
+ expect(ref_document).to(have_received(:ref_to_def).with('BAD_REF'))
154
+ end
155
+
156
+ it { expect(modifier.replace_erefs('defs:eref[type, [BAD_REF(a)]]')).to(eq('defs:eref[type, [BAD_REF(a)]]')) }
157
+ end
158
+
159
+ context 'when the line is not a valid eref' do
160
+ it { expect(modifier.replace_erefs('bla bla')).to(eq('bla bla')) }
161
+ end
162
+
163
+ context 'when the line is matching one external ref definition with more refs' do
164
+ let(:other_ref_definition) { instance_double(Defmastership::Definition, 'other_ref_definition') }
165
+
166
+ before do
167
+ allow(ref_document).to(receive(:ref_to_def).with('REF1').and_return(ref_definition))
168
+ allow(ref_document).to(receive(:ref_to_def).with('REF2').and_return(other_ref_definition))
169
+ allow(ref_definition).to(receive(:explicit_version).and_return('a'))
170
+ allow(other_ref_definition).to(receive(:explicit_version).and_return('z'))
171
+ modifier.replace_erefs('defs:eref[type, [REF1, REF2]]')
172
+ end
173
+
174
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF1')) }
175
+ it { expect(ref_document).to(have_received(:ref_to_def).with('REF2')) }
176
+ it { expect(ref_definition).to(have_received(:explicit_version)) }
177
+ it { expect(other_ref_definition).to(have_received(:explicit_version)) }
178
+
179
+ it {
180
+ expect(modifier.replace_erefs('defs:eref[type, [REF1, REF2]]')).to(eq('defs:eref[type, [REF1(a), REF2(z)]]'))
181
+ }
182
+ end
183
+
184
+ context 'when the modifier modifies only one eref_type' do
185
+ subject(:modifier) { described_class.new({ eref_type: 'implements', ref_document: 'ref_doc.adoc' }) }
186
+
187
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
188
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
189
+
190
+ before do
191
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
192
+ allow(ref_definition).to(receive(:explicit_version).and_return('a'))
193
+ end
194
+
195
+ it { expect(modifier.replace_erefs('defs:eref[implements, [REF]]')).to(eq('defs:eref[implements, [REF(a)]]')) }
196
+ it { expect(modifier.replace_erefs('defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF]]')) }
197
+ end
198
+
199
+ context 'when the modifier modifies more than one eref_type' do
200
+ subject(:modifier) { described_class.new({ eref_type: %w[implements covers], ref_document: 'ref_doc.adoc' }) }
201
+
202
+ let(:ref_document) { instance_double(Defmastership::Document, 'document') }
203
+ let(:ref_definition) { instance_double(Defmastership::Definition, 'definition') }
204
+
205
+ before do
206
+ allow(ref_document).to(receive(:ref_to_def).with('REF').and_return(ref_definition))
207
+ allow(ref_definition).to(receive(:explicit_version).and_return('a'))
208
+ end
209
+
210
+ it { expect(modifier.replace_erefs('defs:eref[implements, [REF]]')).to(eq('defs:eref[implements, [REF(a)]]')) }
211
+ it { expect(modifier.replace_erefs('defs:eref[covers, [REF]]')).to(eq('defs:eref[covers, [REF(a)]]')) }
212
+ it { expect(modifier.replace_erefs('defs:eref[covers_not, [REF]]')).to(eq('defs:eref[covers_not, [REF]]')) }
213
+ end
214
+ end
215
+ 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