svg_conform 0.1.4 → 0.1.6
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/.rubocop_todo.yml +18 -40
- data/README.adoc +111 -1171
- data/config/profiles/metanorma.yml +5 -0
- data/docs/api_reference.adoc +1355 -0
- data/docs/cli_guide.adoc +846 -0
- data/docs/reference_manifest.adoc +371 -0
- data/docs/requirements.adoc +68 -1
- data/examples/document_input_demo.rb +102 -0
- data/lib/svg_conform/document.rb +40 -1
- data/lib/svg_conform/profile.rb +15 -9
- data/lib/svg_conform/references/base_reference.rb +130 -0
- data/lib/svg_conform/references/id_definition.rb +38 -0
- data/lib/svg_conform/references/reference_classifier.rb +45 -0
- data/lib/svg_conform/references/reference_manifest.rb +129 -0
- data/lib/svg_conform/references.rb +11 -0
- data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +34 -43
- data/lib/svg_conform/requirements/id_collection_requirement.rb +38 -0
- data/lib/svg_conform/requirements/id_reference_requirement.rb +11 -0
- data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +3 -0
- data/lib/svg_conform/requirements/link_validation_requirement.rb +114 -31
- data/lib/svg_conform/requirements/no_external_css_requirement.rb +5 -2
- data/lib/svg_conform/requirements.rb +11 -9
- data/lib/svg_conform/sax_validation_handler.rb +16 -1
- data/lib/svg_conform/validation_context.rb +67 -1
- data/lib/svg_conform/validation_result.rb +43 -2
- data/lib/svg_conform/validator.rb +56 -16
- data/lib/svg_conform/version.rb +1 -1
- data/lib/svg_conform.rb +11 -2
- data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +1 -0
- data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +1 -0
- data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +1 -0
- data/spec/svg_conform/references/integration_spec.rb +206 -0
- data/spec/svg_conform/references/reference_classifier_spec.rb +142 -0
- data/spec/svg_conform/references/reference_manifest_spec.rb +307 -0
- data/spec/svg_conform/requirements/id_reference_state_spec.rb +93 -0
- data/spec/svg_conform/validator_input_types_spec.rb +172 -0
- data/svg_conform.gemspec +1 -1
- metadata +25 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "IdReferenceRequirement" do
|
|
6
|
+
let(:validator) { SvgConform::Validator.new(mode: :sax) }
|
|
7
|
+
|
|
8
|
+
# SVG with a reference to undefined ID 'missing_id'
|
|
9
|
+
let(:svg_with_error) do
|
|
10
|
+
<<~SVG
|
|
11
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
12
|
+
<a href="#missing_id">
|
|
13
|
+
<rect x="10" y="10" width="80" height="80"/>
|
|
14
|
+
</a>
|
|
15
|
+
</svg>
|
|
16
|
+
SVG
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# SVG with valid references only
|
|
20
|
+
let(:svg_without_error) do
|
|
21
|
+
<<~SVG
|
|
22
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
23
|
+
<rect id="valid_id" x="10" y="10" width="80" height="80"/>
|
|
24
|
+
<a href="#valid_id">
|
|
25
|
+
<text x="50" y="50">Link</text>
|
|
26
|
+
</a>
|
|
27
|
+
</svg>
|
|
28
|
+
SVG
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "does not leak state from first validation to second validation" do
|
|
32
|
+
# First validation: SVG with reference error
|
|
33
|
+
result1 = validator.validate(svg_with_error, profile: :metanorma)
|
|
34
|
+
|
|
35
|
+
# Verify first validation caught the error
|
|
36
|
+
expect(result1.errors.map(&:message)).to include(
|
|
37
|
+
match(/Reference to undefined ID 'missing_id'/),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Second validation: SVG without reference errors
|
|
41
|
+
result2 = validator.validate(svg_without_error, profile: :metanorma)
|
|
42
|
+
|
|
43
|
+
# Verify second validation does NOT report errors from first validation
|
|
44
|
+
error_messages = result2.errors.map(&:message).join("\n")
|
|
45
|
+
expect(error_messages).not_to include("missing_id"),
|
|
46
|
+
"State leaked from first validation! Second validation should not mention 'missing_id'"
|
|
47
|
+
|
|
48
|
+
# Second validation should have no errors (or at least no reference errors)
|
|
49
|
+
reference_errors = result2.errors.select do |e|
|
|
50
|
+
e.message.include?("Reference to undefined")
|
|
51
|
+
end
|
|
52
|
+
expect(reference_errors).to be_empty,
|
|
53
|
+
"Second validation should have no reference errors, but got: #{reference_errors.map(&:message)}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "handles multiple sequential validations correctly" do
|
|
57
|
+
# Run multiple validations to ensure state resets each time
|
|
58
|
+
results = []
|
|
59
|
+
|
|
60
|
+
# Alternate between error and no-error SVGs
|
|
61
|
+
3.times do
|
|
62
|
+
results << validator.validate(svg_with_error, profile: :metanorma)
|
|
63
|
+
results << validator.validate(svg_without_error, profile: :metanorma)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Check that error pattern is consistent
|
|
67
|
+
results.each_with_index do |result, i|
|
|
68
|
+
if i.even?
|
|
69
|
+
# Should have error (svg_with_error)
|
|
70
|
+
expect(result.errors.map(&:message)).to include(
|
|
71
|
+
match(/Reference to undefined ID 'missing_id'/),
|
|
72
|
+
)
|
|
73
|
+
else
|
|
74
|
+
# Should NOT have error about missing_id (svg_without_error)
|
|
75
|
+
error_messages = result.errors.map(&:message).join("\n")
|
|
76
|
+
expect(error_messages).not_to include("missing_id")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "resets state when using the same profile instance" do
|
|
82
|
+
# Get profile instance
|
|
83
|
+
profile = SvgConform::Profiles.get(:metanorma)
|
|
84
|
+
|
|
85
|
+
# Run two validations using the same profile
|
|
86
|
+
validator.validate(svg_with_error, profile: profile)
|
|
87
|
+
result2 = validator.validate(svg_without_error, profile: profile)
|
|
88
|
+
|
|
89
|
+
# Second validation should not have first validation's errors
|
|
90
|
+
error_messages = result2.errors.map(&:message).join("\n")
|
|
91
|
+
expect(error_messages).not_to include("missing_id")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe SvgConform::Validator do
|
|
6
|
+
let(:validator) { described_class.new(mode: :sax) }
|
|
7
|
+
let(:simple_svg) do
|
|
8
|
+
<<~SVG
|
|
9
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
10
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
11
|
+
<rect id="box" x="10" y="10" width="80" height="80" fill="black"/>
|
|
12
|
+
</svg>
|
|
13
|
+
SVG
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "#validate with different input types" do
|
|
17
|
+
context "with String input (backward compatibility)" do
|
|
18
|
+
it "validates XML string successfully" do
|
|
19
|
+
result = validator.validate(simple_svg, profile: :metanorma)
|
|
20
|
+
|
|
21
|
+
expect(result).to be_a(SvgConform::ValidationResult)
|
|
22
|
+
expect(result.valid?).to be true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "processes errors correctly" do
|
|
26
|
+
invalid_svg = '<svg><rect fill="red"/></svg>'
|
|
27
|
+
result = validator.validate(invalid_svg, profile: :svg_1_2_rfc)
|
|
28
|
+
|
|
29
|
+
expect(result).to be_a(SvgConform::ValidationResult)
|
|
30
|
+
# Will have errors due to missing viewBox and invalid color
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "with Moxml::Document input" do
|
|
35
|
+
it "validates Moxml document without re-parsing" do
|
|
36
|
+
# Parse once into Moxml
|
|
37
|
+
moxml_doc = Moxml.new.parse(simple_svg)
|
|
38
|
+
|
|
39
|
+
# Validate using the document object
|
|
40
|
+
result = validator.validate(moxml_doc, profile: :metanorma)
|
|
41
|
+
|
|
42
|
+
expect(result).to be_a(SvgConform::ValidationResult)
|
|
43
|
+
expect(result.valid?).to be true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "serializes document once for SAX validation (safe for large files)" do
|
|
47
|
+
moxml_doc = Moxml.new.parse(simple_svg)
|
|
48
|
+
|
|
49
|
+
# Should call to_xml once for SAX validation
|
|
50
|
+
# (SAX mode is safe for large files, unlike DOM)
|
|
51
|
+
expect(moxml_doc).to receive(:to_xml).once.and_call_original
|
|
52
|
+
|
|
53
|
+
validator.validate(moxml_doc, profile: :metanorma)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context "with Moxml::Element input" do
|
|
58
|
+
it "validates Moxml element node" do
|
|
59
|
+
moxml_doc = Moxml.new.parse(simple_svg)
|
|
60
|
+
svg_element = moxml_doc.root
|
|
61
|
+
|
|
62
|
+
result = validator.validate(svg_element, profile: :metanorma)
|
|
63
|
+
|
|
64
|
+
expect(result).to be_a(SvgConform::ValidationResult)
|
|
65
|
+
expect(result.valid?).to be true
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "with Nokogiri input (metanorm use case)" do
|
|
70
|
+
it "validates Nokogiri::XML::Document" do
|
|
71
|
+
nokogiri_doc = Nokogiri::XML(simple_svg)
|
|
72
|
+
|
|
73
|
+
result = validator.validate(nokogiri_doc, profile: :metanorma)
|
|
74
|
+
|
|
75
|
+
expect(result).to be_a(SvgConform::ValidationResult)
|
|
76
|
+
expect(result.valid?).to be true
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "validates Nokogiri::XML::Element" do
|
|
80
|
+
nokogiri_doc = Nokogiri::XML(simple_svg)
|
|
81
|
+
svg_element = nokogiri_doc.root
|
|
82
|
+
|
|
83
|
+
# This is the metanorma use case - passing element directly
|
|
84
|
+
result = validator.validate(svg_element, profile: :metanorma)
|
|
85
|
+
|
|
86
|
+
expect(result).to be_a(SvgConform::ValidationResult)
|
|
87
|
+
expect(result.valid?).to be true
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "serializes Nokogiri element once for SAX validation" do
|
|
91
|
+
nokogiri_doc = Nokogiri::XML(simple_svg)
|
|
92
|
+
svg_element = nokogiri_doc.root
|
|
93
|
+
|
|
94
|
+
# Should call to_xml once for SAX validation
|
|
95
|
+
# (SAX mode is memory-safe for large SVGs)
|
|
96
|
+
expect(svg_element).to receive(:to_xml).once.and_call_original
|
|
97
|
+
|
|
98
|
+
validator.validate(svg_element, profile: :metanorma)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "with invalid input" do
|
|
103
|
+
it "raises ArgumentError for unsupported input type" do
|
|
104
|
+
expect do
|
|
105
|
+
validator.validate(12345, profile: :metanorma)
|
|
106
|
+
end.to raise_error(ArgumentError, /Invalid input type/)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "raises ArgumentError for nil input" do
|
|
110
|
+
expect do
|
|
111
|
+
validator.validate(nil, profile: :metanorma)
|
|
112
|
+
end.to raise_error(ArgumentError, /Invalid input type/)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context "with reference manifest" do
|
|
117
|
+
let(:svg_with_refs) do
|
|
118
|
+
<<~SVG
|
|
119
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
120
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
121
|
+
<defs>
|
|
122
|
+
<rect id="box" width="10" height="10"/>
|
|
123
|
+
</defs>
|
|
124
|
+
<use href="#box" x="20" y="20"/>
|
|
125
|
+
</svg>
|
|
126
|
+
SVG
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "builds reference manifest from Nokogiri element" do
|
|
130
|
+
nokogiri_doc = Nokogiri::XML(svg_with_refs)
|
|
131
|
+
svg_element = nokogiri_doc.root
|
|
132
|
+
|
|
133
|
+
result = validator.validate(svg_element, profile: :metanorma)
|
|
134
|
+
|
|
135
|
+
expect(result.reference_manifest).not_to be_nil
|
|
136
|
+
expect(result.available_ids.map(&:id_value)).to include("box")
|
|
137
|
+
expect(result.internal_references.size).to be > 0
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "builds reference manifest from Moxml document" do
|
|
141
|
+
moxml_doc = Moxml.new.parse(svg_with_refs)
|
|
142
|
+
|
|
143
|
+
result = validator.validate(moxml_doc, profile: :metanorma)
|
|
144
|
+
|
|
145
|
+
expect(result.reference_manifest).not_to be_nil
|
|
146
|
+
expect(result.available_ids.map(&:id_value)).to include("box")
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe "integration with remediation" do
|
|
152
|
+
let(:invalid_svg) do
|
|
153
|
+
<<~SVG
|
|
154
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
155
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
156
|
+
<rect fill="red" width="10" height="10"/>
|
|
157
|
+
</svg>
|
|
158
|
+
SVG
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "applies remediation when using document object input" do
|
|
162
|
+
nokogiri_doc = Nokogiri::XML(invalid_svg)
|
|
163
|
+
svg_element = nokogiri_doc.root
|
|
164
|
+
|
|
165
|
+
result = validator.validate(svg_element, profile: :svg_1_2_rfc, fix: true)
|
|
166
|
+
|
|
167
|
+
# Should have validation errors initially
|
|
168
|
+
expect(result.has_errors?).to be true
|
|
169
|
+
# Remediation should have been attempted
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
data/svg_conform.gemspec
CHANGED
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
spec.require_paths = ["lib"]
|
|
30
30
|
|
|
31
31
|
spec.add_dependency "lutaml-model", "~> 0.7"
|
|
32
|
-
spec.add_dependency "moxml"
|
|
32
|
+
spec.add_dependency "moxml", "~> 0.1", ">= 0.1.10"
|
|
33
33
|
spec.add_dependency "table_tennis"
|
|
34
34
|
spec.add_dependency "thor"
|
|
35
35
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: svg_conform
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|
|
@@ -28,16 +28,22 @@ dependencies:
|
|
|
28
28
|
name: moxml
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.1'
|
|
31
34
|
- - ">="
|
|
32
35
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
36
|
+
version: 0.1.10
|
|
34
37
|
type: :runtime
|
|
35
38
|
prerelease: false
|
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
40
|
requirements:
|
|
41
|
+
- - "~>"
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0.1'
|
|
38
44
|
- - ">="
|
|
39
45
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
46
|
+
version: 0.1.10
|
|
41
47
|
- !ruby/object:Gem::Dependency
|
|
42
48
|
name: table_tennis
|
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -92,11 +98,15 @@ files:
|
|
|
92
98
|
- config/profiles/svg_1_2_rfc.yml
|
|
93
99
|
- config/profiles/svg_1_2_rfc_with_rdf.yml
|
|
94
100
|
- config/svgcheck_mapping.yml
|
|
101
|
+
- docs/api_reference.adoc
|
|
102
|
+
- docs/cli_guide.adoc
|
|
95
103
|
- docs/profiles.adoc
|
|
96
104
|
- docs/rdf_metadata_support.adoc
|
|
105
|
+
- docs/reference_manifest.adoc
|
|
97
106
|
- docs/remediation.adoc
|
|
98
107
|
- docs/requirements.adoc
|
|
99
108
|
- examples/demo.rb
|
|
109
|
+
- examples/document_input_demo.rb
|
|
100
110
|
- examples/readme_usage.rb
|
|
101
111
|
- examples/requirements_demo.rb
|
|
102
112
|
- exe/svg_conform
|
|
@@ -137,6 +147,11 @@ files:
|
|
|
137
147
|
- lib/svg_conform/node_index_builder.rb
|
|
138
148
|
- lib/svg_conform/profile.rb
|
|
139
149
|
- lib/svg_conform/profiles.rb
|
|
150
|
+
- lib/svg_conform/references.rb
|
|
151
|
+
- lib/svg_conform/references/base_reference.rb
|
|
152
|
+
- lib/svg_conform/references/id_definition.rb
|
|
153
|
+
- lib/svg_conform/references/reference_classifier.rb
|
|
154
|
+
- lib/svg_conform/references/reference_manifest.rb
|
|
140
155
|
- lib/svg_conform/remediation_engine.rb
|
|
141
156
|
- lib/svg_conform/remediation_result.rb
|
|
142
157
|
- lib/svg_conform/remediation_runner.rb
|
|
@@ -160,6 +175,7 @@ files:
|
|
|
160
175
|
- lib/svg_conform/requirements/element_requirement_config.rb
|
|
161
176
|
- lib/svg_conform/requirements/font_family_requirement.rb
|
|
162
177
|
- lib/svg_conform/requirements/forbidden_content_requirement.rb
|
|
178
|
+
- lib/svg_conform/requirements/id_collection_requirement.rb
|
|
163
179
|
- lib/svg_conform/requirements/id_reference_requirement.rb
|
|
164
180
|
- lib/svg_conform/requirements/invalid_id_references_requirement.rb
|
|
165
181
|
- lib/svg_conform/requirements/link_validation_requirement.rb
|
|
@@ -386,6 +402,9 @@ files:
|
|
|
386
402
|
- spec/svg_conform/profiles/no_external_css_profile_spec.rb
|
|
387
403
|
- spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb
|
|
388
404
|
- spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb
|
|
405
|
+
- spec/svg_conform/references/integration_spec.rb
|
|
406
|
+
- spec/svg_conform/references/reference_classifier_spec.rb
|
|
407
|
+
- spec/svg_conform/references/reference_manifest_spec.rb
|
|
389
408
|
- spec/svg_conform/remediations/color_remediation_spec.rb
|
|
390
409
|
- spec/svg_conform/remediations/font_embedding_remediation_spec.rb
|
|
391
410
|
- spec/svg_conform/remediations/font_remediation_spec.rb
|
|
@@ -401,6 +420,7 @@ files:
|
|
|
401
420
|
- spec/svg_conform/requirements/font_family_requirement_spec.rb
|
|
402
421
|
- spec/svg_conform/requirements/forbidden_content_requirement_spec.rb
|
|
403
422
|
- spec/svg_conform/requirements/id_reference_requirement_spec.rb
|
|
423
|
+
- spec/svg_conform/requirements/id_reference_state_spec.rb
|
|
404
424
|
- spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb
|
|
405
425
|
- spec/svg_conform/requirements/link_validation_requirement_spec.rb
|
|
406
426
|
- spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb
|
|
@@ -411,6 +431,7 @@ files:
|
|
|
411
431
|
- spec/svg_conform/requirements/style_promotion_requirement_spec.rb
|
|
412
432
|
- spec/svg_conform/requirements/style_requirement_spec.rb
|
|
413
433
|
- spec/svg_conform/requirements/viewbox_required_requirement_spec.rb
|
|
434
|
+
- spec/svg_conform/validator_input_types_spec.rb
|
|
414
435
|
- spec/svg_conform_spec.rb
|
|
415
436
|
- spec/svgcheck_compatibility_spec.rb
|
|
416
437
|
- svg_conform.gemspec
|