svg_conform 0.1.4 → 0.1.5

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +182 -21
  3. data/README.adoc +391 -989
  4. data/config/profiles/metanorma.yml +5 -0
  5. data/docs/api_reference.adoc +1355 -0
  6. data/docs/cli_guide.adoc +846 -0
  7. data/docs/reference_manifest.adoc +370 -0
  8. data/docs/requirements.adoc +68 -1
  9. data/examples/document_input_demo.rb +102 -0
  10. data/lib/svg_conform/document.rb +40 -1
  11. data/lib/svg_conform/profile.rb +15 -9
  12. data/lib/svg_conform/references/base_reference.rb +130 -0
  13. data/lib/svg_conform/references/id_definition.rb +38 -0
  14. data/lib/svg_conform/references/reference_classifier.rb +45 -0
  15. data/lib/svg_conform/references/reference_manifest.rb +129 -0
  16. data/lib/svg_conform/references.rb +11 -0
  17. data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +34 -43
  18. data/lib/svg_conform/requirements/id_collection_requirement.rb +38 -0
  19. data/lib/svg_conform/requirements/id_reference_requirement.rb +11 -0
  20. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +3 -0
  21. data/lib/svg_conform/requirements/link_validation_requirement.rb +114 -31
  22. data/lib/svg_conform/requirements/no_external_css_requirement.rb +5 -2
  23. data/lib/svg_conform/requirements.rb +11 -9
  24. data/lib/svg_conform/sax_validation_handler.rb +16 -1
  25. data/lib/svg_conform/validation_context.rb +67 -1
  26. data/lib/svg_conform/validation_result.rb +43 -2
  27. data/lib/svg_conform/validator.rb +56 -16
  28. data/lib/svg_conform/version.rb +1 -1
  29. data/lib/svg_conform.rb +11 -2
  30. data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +1 -0
  31. data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +1 -0
  32. data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +1 -0
  33. data/spec/svg_conform/references/integration_spec.rb +206 -0
  34. data/spec/svg_conform/references/reference_classifier_spec.rb +142 -0
  35. data/spec/svg_conform/references/reference_manifest_spec.rb +307 -0
  36. data/spec/svg_conform/requirements/id_reference_state_spec.rb +93 -0
  37. data/spec/svg_conform/validator_input_types_spec.rb +172 -0
  38. metadata +17 -2
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Reference Manifest Integration" do
6
+ let(:validator) { SvgConform::Validator.new(profile: "metanorma") }
7
+
8
+ describe "complete reference manifest generation" do
9
+ let(:svg_content) do
10
+ <<~SVG
11
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
12
+ <rect id="rect-1" x="0" y="0" width="100" height="100"/>
13
+ <circle id="circle-1" cx="50" cy="50" r="25"/>
14
+ <use href="#rect-1"/>
15
+ <use href="#missing-element"/>
16
+ <a href="urn:ietf:rfc:7996">RFC 7996</a>
17
+ <a href="https://www.example.com">Example</a>
18
+ <image href="data:image/png;base64,iVBORw0KGgo=" x="0" y="0" width="10" height="10"/>
19
+ <image href="./other.svg#fragment" x="0" y="0" width="10" height="10"/>
20
+ </svg>
21
+ SVG
22
+ end
23
+
24
+ it "builds complete manifest with IDs and references" do
25
+ result = validator.validate(svg_content)
26
+ manifest = result.reference_manifest
27
+
28
+ # Check IDs are collected
29
+ expect(manifest.available_ids.size).to eq(2)
30
+ expect(manifest.id_defined?("rect-1")).to be true
31
+ expect(manifest.id_defined?("circle-1")).to be true
32
+
33
+ # Check references are collected
34
+ expect(manifest.internal_references.size).to eq(3) # 2 uses + 1 data URI
35
+ expect(manifest.external_references.size).to eq(3) # 1 urn + 1 https + 1 relative
36
+
37
+ # Check statistics
38
+ stats = manifest.statistics
39
+ expect(stats[:total_ids]).to eq(2)
40
+ expect(stats[:total_references]).to eq(6)
41
+ expect(stats[:unresolved_internal]).to eq(1)
42
+ end
43
+
44
+ it "identifies unresolved internal references" do
45
+ result = validator.validate(svg_content)
46
+ manifest = result.reference_manifest
47
+
48
+ unresolved = manifest.unresolved_internal_references
49
+ expect(unresolved.size).to eq(1)
50
+ expect(unresolved.first.value).to eq("#missing-element")
51
+ end
52
+
53
+ it "groups references by type" do
54
+ result = validator.validate(svg_content)
55
+ manifest = result.reference_manifest
56
+
57
+ by_type = manifest.references_by_type
58
+ expect(by_type["InternalFragmentReference"].size).to eq(2) # 2 uses
59
+ expect(by_type["UrnReference"].size).to eq(1)
60
+ expect(by_type["ExternalUrlReference"].size).to eq(1)
61
+ expect(by_type["DataUriReference"].size).to eq(1)
62
+ expect(by_type["RelativePathReference"].size).to eq(1)
63
+ end
64
+
65
+ it "validates internal references but not external ones" do
66
+ result = validator.validate(svg_content)
67
+
68
+ # Should have errors for unresolved internal reference
69
+ internal_ref_errors = result.errors.select do |e|
70
+ e.message.include?("missing-element")
71
+ end
72
+ expect(internal_ref_errors).not_to be_empty
73
+
74
+ # Should NOT have errors for external references
75
+ external_ref_errors = result.errors.select do |e|
76
+ e.message.include?("urn:") || e.message.include?("https://")
77
+ end
78
+ expect(external_ref_errors).to be_empty
79
+ end
80
+ end
81
+
82
+ describe "ValidationResult convenience methods" do
83
+ let(:svg_content) do
84
+ <<~SVG
85
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
86
+ <rect id="target"/>
87
+ <use href="#target"/>
88
+ <a href="urn:test">Test</a>
89
+ </svg>
90
+ SVG
91
+ end
92
+
93
+ it "provides convenient accessors" do
94
+ result = validator.validate(svg_content)
95
+
96
+ expect(result.available_ids.size).to eq(1)
97
+ expect(result.internal_references.size).to eq(1)
98
+ expect(result.external_references.size).to eq(1)
99
+ expect(result.has_external_references?).to be true
100
+ expect(result.unresolved_internal_references).to be_empty
101
+ end
102
+
103
+ it "exports manifest in different formats" do
104
+ result = validator.validate(svg_content)
105
+
106
+ yaml_export = result.export_manifest(format: :yaml)
107
+ expect(yaml_export).to be_a(String)
108
+ expect(yaml_export).to include("target")
109
+
110
+ json_export = result.export_manifest(format: :json)
111
+ expect(json_export).to be_a(String)
112
+ parsed = JSON.parse(json_export)
113
+ expect(parsed["available_ids"]).to be_an(Array)
114
+ end
115
+ end
116
+
117
+ describe "cross-document reference scenario" do
118
+ let(:svg_with_external_fragment) do
119
+ <<~SVG
120
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
121
+ <rect id="local-element"/>
122
+ <use href="#local-element"/>
123
+ <use href="other-doc.svg#external-element"/>
124
+ </svg>
125
+ SVG
126
+ end
127
+
128
+ it "classifies external fragment references correctly" do
129
+ result = validator.validate(svg_with_external_fragment)
130
+ manifest = result.reference_manifest
131
+
132
+ # Local fragment should be internal
133
+ expect(manifest.internal_references.size).to eq(1)
134
+ expect(manifest.internal_references.first.value).to eq("#local-element")
135
+
136
+ # External fragment should be external (requires consumer validation)
137
+ expect(manifest.external_references.size).to eq(1)
138
+ external_ref = manifest.external_references.first
139
+ expect(external_ref).to be_a(SvgConform::References::RelativePathReference)
140
+ expect(external_ref.has_fragment?).to be true
141
+ expect(external_ref.fragment_component).to eq("external-element")
142
+ end
143
+ end
144
+
145
+ describe "reference statistics and querying" do
146
+ let(:complex_svg) do
147
+ <<~SVG
148
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
149
+ <defs>
150
+ <linearGradient id="grad1">
151
+ <stop offset="0%" stop-color="red"/>
152
+ </linearGradient>
153
+ <clipPath id="clip1">
154
+ <rect x="0" y="0" width="50" height="50"/>
155
+ </clipPath>
156
+ </defs>
157
+ <rect id="rect1" fill="url(#grad1)" clip-path="url(#clip1)"/>
158
+ <use href="#rect1"/>
159
+ <use href="#rect1"/>
160
+ <a href="https://example.com">Link</a>
161
+ </svg>
162
+ SVG
163
+ end
164
+
165
+ it "tracks multiple references to same ID" do
166
+ result = validator.validate(complex_svg)
167
+ manifest = result.reference_manifest
168
+
169
+ rect1_refs = manifest.references_to_id("rect1")
170
+ expect(rect1_refs.size).to eq(2)
171
+ end
172
+
173
+ it "provides accurate statistics" do
174
+ result = validator.validate(complex_svg)
175
+ stats = result.reference_statistics
176
+
177
+ expect(stats[:total_ids]).to eq(3) # grad1, clip1, rect1
178
+ expect(stats[:internal_references]).to eq(2) # 2 uses
179
+ expect(stats[:external_references]).to eq(1) # 1 https
180
+ expect(stats[:unresolved_internal]).to eq(0)
181
+ end
182
+ end
183
+
184
+ describe "to_h includes reference manifest" do
185
+ let(:svg_content) do
186
+ <<~SVG
187
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
188
+ <rect id="test"/>
189
+ <a href="urn:test">Test</a>
190
+ </svg>
191
+ SVG
192
+ end
193
+
194
+ it "includes manifest in hash representation" do
195
+ result = validator.validate(svg_content)
196
+ hash = result.to_h
197
+
198
+ expect(hash).to have_key(:reference_manifest)
199
+ manifest_data = hash[:reference_manifest]
200
+ expect(manifest_data).to have_key(:available_ids)
201
+ expect(manifest_data).to have_key(:internal_references)
202
+ expect(manifest_data).to have_key(:external_references)
203
+ expect(manifest_data).to have_key(:statistics)
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::References::ReferenceClassifier do
6
+ describe ".classify" do
7
+ it "classifies internal fragment references" do
8
+ ref = described_class.classify(
9
+ "#element-id",
10
+ element_name: "use",
11
+ attribute_name: "href",
12
+ line_number: 10,
13
+ )
14
+
15
+ expect(ref).to be_a(SvgConform::References::InternalFragmentReference)
16
+ expect(ref.value).to eq("#element-id")
17
+ expect(ref.internally_validatable?).to be true
18
+ expect(ref.requires_consumer_validation?).to be false
19
+ expect(ref.target_id).to eq("element-id")
20
+ end
21
+
22
+ it "classifies URN references" do
23
+ ref = described_class.classify(
24
+ "urn:ietf:rfc:7996",
25
+ element_name: "a",
26
+ attribute_name: "href",
27
+ line_number: 42,
28
+ )
29
+
30
+ expect(ref).to be_a(SvgConform::References::UrnReference)
31
+ expect(ref.value).to eq("urn:ietf:rfc:7996")
32
+ expect(ref.internally_validatable?).to be false
33
+ expect(ref.requires_consumer_validation?).to be true
34
+ expect(ref.namespace).to eq("ietf")
35
+ end
36
+
37
+ it "classifies external URL references (http)" do
38
+ ref = described_class.classify(
39
+ "http://www.example.com/resource",
40
+ element_name: "a",
41
+ attribute_name: "href",
42
+ )
43
+
44
+ expect(ref).to be_a(SvgConform::References::ExternalUrlReference)
45
+ expect(ref.requires_consumer_validation?).to be true
46
+ expect(ref.protocol).to eq("http")
47
+ end
48
+
49
+ it "classifies external URL references (https)" do
50
+ ref = described_class.classify(
51
+ "https://www.example.com/resource",
52
+ element_name: "a",
53
+ attribute_name: "href",
54
+ )
55
+
56
+ expect(ref).to be_a(SvgConform::References::ExternalUrlReference)
57
+ expect(ref.requires_consumer_validation?).to be true
58
+ expect(ref.protocol).to eq("https")
59
+ end
60
+
61
+ it "classifies data URI references" do
62
+ ref = described_class.classify(
63
+ "data:image/png;base64,iVBORw0KGgo=",
64
+ element_name: "image",
65
+ attribute_name: "href",
66
+ )
67
+
68
+ expect(ref).to be_a(SvgConform::References::DataUriReference)
69
+ expect(ref.internally_validatable?).to be true
70
+ expect(ref.media_type).to eq("image/png")
71
+ end
72
+
73
+ it "classifies relative path references starting with ./" do
74
+ ref = described_class.classify(
75
+ "./other-doc.svg#element",
76
+ element_name: "use",
77
+ attribute_name: "href",
78
+ )
79
+
80
+ expect(ref).to be_a(SvgConform::References::RelativePathReference)
81
+ expect(ref.requires_consumer_validation?).to be true
82
+ expect(ref.has_fragment?).to be true
83
+ expect(ref.path_component).to eq("./other-doc.svg")
84
+ expect(ref.fragment_component).to eq("element")
85
+ end
86
+
87
+ it "classifies relative path references starting with /" do
88
+ ref = described_class.classify(
89
+ "/absolute/path.svg",
90
+ element_name: "use",
91
+ attribute_name: "href",
92
+ )
93
+
94
+ expect(ref).to be_a(SvgConform::References::RelativePathReference)
95
+ expect(ref.requires_consumer_validation?).to be true
96
+ end
97
+
98
+ it "classifies bare paths as relative references" do
99
+ ref = described_class.classify(
100
+ "other-doc.svg",
101
+ element_name: "use",
102
+ attribute_name: "href",
103
+ )
104
+
105
+ expect(ref).to be_a(SvgConform::References::RelativePathReference)
106
+ expect(ref.requires_consumer_validation?).to be true
107
+ end
108
+
109
+ it "returns nil for nil value" do
110
+ ref = described_class.classify(
111
+ nil,
112
+ element_name: "use",
113
+ attribute_name: "href",
114
+ )
115
+
116
+ expect(ref).to be_nil
117
+ end
118
+
119
+ it "returns nil for empty value" do
120
+ ref = described_class.classify(
121
+ "",
122
+ element_name: "use",
123
+ attribute_name: "href",
124
+ )
125
+
126
+ expect(ref).to be_nil
127
+ end
128
+
129
+ it "captures line and column information" do
130
+ ref = described_class.classify(
131
+ "#element-id",
132
+ element_name: "use",
133
+ attribute_name: "href",
134
+ line_number: 42,
135
+ column_number: 15,
136
+ )
137
+
138
+ expect(ref.line_number).to eq(42)
139
+ expect(ref.column_number).to eq(15)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,307 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::References::ReferenceManifest do
6
+ let(:manifest) { described_class.new(source_document: "test.svg") }
7
+
8
+ describe "#initialize" do
9
+ it "creates an empty manifest" do
10
+ expect(manifest.source_document).to eq("test.svg")
11
+ expect(manifest.available_ids).to be_empty
12
+ expect(manifest.internal_references).to be_empty
13
+ expect(manifest.external_references).to be_empty
14
+ end
15
+ end
16
+
17
+ describe "#register_id" do
18
+ it "registers ID definitions" do
19
+ manifest.register_id("element-1", element_name: "rect", line_number: 10)
20
+
21
+ expect(manifest.available_ids.size).to eq(1)
22
+ expect(manifest.available_ids.first.id_value).to eq("element-1")
23
+ expect(manifest.available_ids.first.element_name).to eq("rect")
24
+ expect(manifest.available_ids.first.line_number).to eq(10)
25
+ end
26
+
27
+ it "registers multiple IDs" do
28
+ manifest.register_id("id-1", element_name: "rect")
29
+ manifest.register_id("id-2", element_name: "circle")
30
+
31
+ expect(manifest.available_ids.size).to eq(2)
32
+ end
33
+ end
34
+
35
+ describe "#register_reference" do
36
+ it "separates internal and external references" do
37
+ internal_ref = SvgConform::References::InternalFragmentReference.new(
38
+ value: "#element-1",
39
+ element_name: "use",
40
+ attribute_name: "href",
41
+ )
42
+
43
+ external_ref = SvgConform::References::UrnReference.new(
44
+ value: "urn:test",
45
+ element_name: "a",
46
+ attribute_name: "href",
47
+ )
48
+
49
+ manifest.register_reference(internal_ref)
50
+ manifest.register_reference(external_ref)
51
+
52
+ expect(manifest.internal_references.size).to eq(1)
53
+ expect(manifest.external_references.size).to eq(1)
54
+ end
55
+ end
56
+
57
+ describe "#id_defined?" do
58
+ before do
59
+ manifest.register_id("element-1", element_name: "rect")
60
+ manifest.register_id("element-2", element_name: "circle")
61
+ end
62
+
63
+ it "returns true for defined IDs" do
64
+ expect(manifest.id_defined?("element-1")).to be true
65
+ expect(manifest.id_defined?("element-2")).to be true
66
+ end
67
+
68
+ it "returns false for undefined IDs" do
69
+ expect(manifest.id_defined?("missing-element")).to be false
70
+ end
71
+ end
72
+
73
+ describe "#references_to_id" do
74
+ before do
75
+ manifest.register_id("target-element", element_name: "rect")
76
+
77
+ ref1 = SvgConform::References::InternalFragmentReference.new(
78
+ value: "#target-element",
79
+ element_name: "use",
80
+ attribute_name: "href",
81
+ )
82
+
83
+ ref2 = SvgConform::References::InternalFragmentReference.new(
84
+ value: "#target-element",
85
+ element_name: "a",
86
+ attribute_name: "href",
87
+ )
88
+
89
+ ref3 = SvgConform::References::InternalFragmentReference.new(
90
+ value: "#other-element",
91
+ element_name: "use",
92
+ attribute_name: "href",
93
+ )
94
+
95
+ manifest.register_reference(ref1)
96
+ manifest.register_reference(ref2)
97
+ manifest.register_reference(ref3)
98
+ end
99
+
100
+ it "returns all references to a specific ID" do
101
+ refs = manifest.references_to_id("target-element")
102
+ expect(refs.size).to eq(2)
103
+ expect(refs.all? { |r| r.target_id == "target-element" }).to be true
104
+ end
105
+
106
+ it "returns empty array for ID with no references" do
107
+ refs = manifest.references_to_id("unreferenced-element")
108
+ expect(refs).to be_empty
109
+ end
110
+ end
111
+
112
+ describe "#references_by_type" do
113
+ before do
114
+ manifest.register_reference(
115
+ SvgConform::References::InternalFragmentReference.new(
116
+ value: "#id-1",
117
+ element_name: "use",
118
+ attribute_name: "href",
119
+ ),
120
+ )
121
+
122
+ manifest.register_reference(
123
+ SvgConform::References::UrnReference.new(
124
+ value: "urn:test",
125
+ element_name: "a",
126
+ attribute_name: "href",
127
+ ),
128
+ )
129
+
130
+ manifest.register_reference(
131
+ SvgConform::References::ExternalUrlReference.new(
132
+ value: "https://example.com",
133
+ element_name: "a",
134
+ attribute_name: "href",
135
+ ),
136
+ )
137
+ end
138
+
139
+ it "groups references by type" do
140
+ by_type = manifest.references_by_type
141
+
142
+ expect(by_type.keys).to include(
143
+ "InternalFragmentReference",
144
+ "UrnReference",
145
+ "ExternalUrlReference",
146
+ )
147
+ expect(by_type["InternalFragmentReference"].size).to eq(1)
148
+ expect(by_type["UrnReference"].size).to eq(1)
149
+ expect(by_type["ExternalUrlReference"].size).to eq(1)
150
+ end
151
+ end
152
+
153
+ describe "#unresolved_internal_references" do
154
+ before do
155
+ manifest.register_id("element-1", element_name: "rect")
156
+
157
+ ref1 = SvgConform::References::InternalFragmentReference.new(
158
+ value: "#element-1",
159
+ element_name: "use",
160
+ attribute_name: "href",
161
+ )
162
+
163
+ ref2 = SvgConform::References::InternalFragmentReference.new(
164
+ value: "#missing-element",
165
+ element_name: "use",
166
+ attribute_name: "href",
167
+ )
168
+
169
+ ref3 = SvgConform::References::InternalFragmentReference.new(
170
+ value: "#another-missing",
171
+ element_name: "use",
172
+ attribute_name: "href",
173
+ )
174
+
175
+ manifest.register_reference(ref1)
176
+ manifest.register_reference(ref2)
177
+ manifest.register_reference(ref3)
178
+ end
179
+
180
+ it "identifies references to non-existent IDs" do
181
+ unresolved = manifest.unresolved_internal_references
182
+
183
+ expect(unresolved.size).to eq(2)
184
+ expect(unresolved.map(&:value)).to include("#missing-element",
185
+ "#another-missing")
186
+ expect(unresolved.map(&:value)).not_to include("#element-1")
187
+ end
188
+
189
+ it "returns empty array when all references are resolved" do
190
+ manifest2 = described_class.new
191
+ manifest2.register_id("element-1", element_name: "rect")
192
+
193
+ ref = SvgConform::References::InternalFragmentReference.new(
194
+ value: "#element-1",
195
+ element_name: "use",
196
+ attribute_name: "href",
197
+ )
198
+ manifest2.register_reference(ref)
199
+
200
+ expect(manifest2.unresolved_internal_references).to be_empty
201
+ end
202
+ end
203
+
204
+ describe "#statistics" do
205
+ before do
206
+ manifest.register_id("id-1", element_name: "rect")
207
+ manifest.register_id("id-2", element_name: "circle")
208
+
209
+ manifest.register_reference(
210
+ SvgConform::References::InternalFragmentReference.new(
211
+ value: "#id-1",
212
+ element_name: "use",
213
+ attribute_name: "href",
214
+ ),
215
+ )
216
+
217
+ manifest.register_reference(
218
+ SvgConform::References::InternalFragmentReference.new(
219
+ value: "#missing",
220
+ element_name: "use",
221
+ attribute_name: "href",
222
+ ),
223
+ )
224
+
225
+ manifest.register_reference(
226
+ SvgConform::References::UrnReference.new(
227
+ value: "urn:test",
228
+ element_name: "a",
229
+ attribute_name: "href",
230
+ ),
231
+ )
232
+
233
+ manifest.register_reference(
234
+ SvgConform::References::ExternalUrlReference.new(
235
+ value: "https://example.com",
236
+ element_name: "a",
237
+ attribute_name: "href",
238
+ ),
239
+ )
240
+ end
241
+
242
+ it "provides comprehensive statistics" do
243
+ stats = manifest.statistics
244
+
245
+ expect(stats[:total_ids]).to eq(2)
246
+ expect(stats[:total_references]).to eq(4)
247
+ expect(stats[:internal_references]).to eq(2)
248
+ expect(stats[:external_references]).to eq(2)
249
+ expect(stats[:unresolved_internal]).to eq(1)
250
+ expect(stats[:references_by_type]["InternalFragmentReference"]).to eq(2)
251
+ expect(stats[:references_by_type]["UrnReference"]).to eq(1)
252
+ expect(stats[:references_by_type]["ExternalUrlReference"]).to eq(1)
253
+ end
254
+ end
255
+
256
+ describe "#to_h" do
257
+ before do
258
+ manifest.register_id("test-id", element_name: "rect", line_number: 5)
259
+
260
+ manifest.register_reference(
261
+ SvgConform::References::InternalFragmentReference.new(
262
+ value: "#test-id",
263
+ element_name: "use",
264
+ attribute_name: "href",
265
+ line_number: 10,
266
+ ),
267
+ )
268
+ end
269
+
270
+ it "exports manifest as hash" do
271
+ hash = manifest.to_h
272
+
273
+ expect(hash[:source_document]).to eq("test.svg")
274
+ expect(hash[:available_ids]).to be_an(Array)
275
+ expect(hash[:internal_references]).to be_an(Array)
276
+ expect(hash[:external_references]).to be_an(Array)
277
+ expect(hash[:statistics]).to be_a(Hash)
278
+ end
279
+ end
280
+
281
+ describe "export formats" do
282
+ before do
283
+ manifest.register_id("test-id", element_name: "rect")
284
+ manifest.register_reference(
285
+ SvgConform::References::UrnReference.new(
286
+ value: "urn:test",
287
+ element_name: "a",
288
+ attribute_name: "href",
289
+ ),
290
+ )
291
+ end
292
+
293
+ it "exports as YAML" do
294
+ yaml = manifest.to_yaml
295
+ expect(yaml).to be_a(String)
296
+ expect(yaml).to include("test.svg")
297
+ expect(yaml).to include("test-id")
298
+ end
299
+
300
+ it "exports as JSON" do
301
+ json = manifest.to_json
302
+ expect(json).to be_a(String)
303
+ parsed = JSON.parse(json)
304
+ expect(parsed["source_document"]).to eq("test.svg")
305
+ end
306
+ end
307
+ end