svg_conform 0.1.10 → 0.1.11
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 +32 -14
- data/lib/svg_conform/classification_cache.rb +36 -0
- data/lib/svg_conform/profile.rb +3 -0
- data/lib/svg_conform/requirements/base_requirement.rb +83 -0
- data/lib/svg_conform/requirements/id_reference_requirement.rb +29 -28
- data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +41 -21
- data/lib/svg_conform/requirements/no_external_css_requirement.rb +16 -9
- data/lib/svg_conform/sax_validation_handler.rb +52 -68
- data/lib/svg_conform/validation_context.rb +51 -16
- data/lib/svg_conform/version.rb +1 -1
- data/spec/fixtures/svg_1_2_rfc/expected_errors/ietf_test_violations.yml +47 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/ietf_test_violations.svg +28 -0
- data/spec/spec_helper.rb +0 -5
- data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +150 -0
- data/spec/svg_conform/validation_context_spec.rb +305 -0
- data/spec/svg_conform_spec.rb +156 -0
- metadata +6 -2
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe SvgConform::ValidationContext do
|
|
4
|
+
let(:document) { nil }
|
|
5
|
+
let(:profile) { instance_double(SvgConform::Profile) }
|
|
6
|
+
let(:context) { described_class.new(document, profile) }
|
|
7
|
+
|
|
8
|
+
describe "#state_for" do
|
|
9
|
+
# Create test requirement with nested State class
|
|
10
|
+
let(:requirement_with_state) do
|
|
11
|
+
req_class = Class.new(SvgConform::Requirements::BaseRequirement) do
|
|
12
|
+
def id
|
|
13
|
+
"test_requirement"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Define State class as a proper constant
|
|
18
|
+
req_class.const_set(:State, Class.new do
|
|
19
|
+
attr_accessor :collected_items
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
@collected_items = []
|
|
23
|
+
end
|
|
24
|
+
end)
|
|
25
|
+
|
|
26
|
+
req_class.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "creates a fresh State instance on first access" do
|
|
30
|
+
state = context.state_for(requirement_with_state)
|
|
31
|
+
expect(state).to be_a(requirement_with_state.class::State)
|
|
32
|
+
expect(state.collected_items).to eq([])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "returns the same State instance on subsequent accesses for same requirement class" do
|
|
36
|
+
state1 = context.state_for(requirement_with_state)
|
|
37
|
+
state1.collected_items << "item1"
|
|
38
|
+
state2 = context.state_for(requirement_with_state)
|
|
39
|
+
expect(state2).to be(state1)
|
|
40
|
+
expect(state2.collected_items).to eq(["item1"])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "creates separate State instances for different requirement classes" do
|
|
44
|
+
req1_class = Class.new(SvgConform::Requirements::BaseRequirement) do
|
|
45
|
+
def id
|
|
46
|
+
"req1"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
req1_class.const_set(:State, Class.new do
|
|
50
|
+
attr_accessor :data
|
|
51
|
+
|
|
52
|
+
def initialize
|
|
53
|
+
@data = []
|
|
54
|
+
end
|
|
55
|
+
end)
|
|
56
|
+
|
|
57
|
+
req2_class = Class.new(SvgConform::Requirements::BaseRequirement) do
|
|
58
|
+
def id
|
|
59
|
+
"req2"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
req2_class.const_set(:State, Class.new do
|
|
63
|
+
attr_accessor :items
|
|
64
|
+
|
|
65
|
+
def initialize
|
|
66
|
+
@items = []
|
|
67
|
+
end
|
|
68
|
+
end)
|
|
69
|
+
|
|
70
|
+
req1 = req1_class.new
|
|
71
|
+
req2 = req2_class.new
|
|
72
|
+
|
|
73
|
+
state1 = context.state_for(req1)
|
|
74
|
+
state2 = context.state_for(req1)
|
|
75
|
+
state3 = context.state_for(req2)
|
|
76
|
+
|
|
77
|
+
expect(state1).to be(state2)
|
|
78
|
+
expect(state1).not_to be(state3)
|
|
79
|
+
expect(state2).not_to be(state3)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "uses requirement class as key, not instance" do
|
|
83
|
+
req1_instance1 = requirement_with_state
|
|
84
|
+
req1_instance2 = requirement_with_state.class.new
|
|
85
|
+
|
|
86
|
+
state1 = context.state_for(req1_instance1)
|
|
87
|
+
state1.collected_items << "from_instance1"
|
|
88
|
+
|
|
89
|
+
state2 = context.state_for(req1_instance2)
|
|
90
|
+
|
|
91
|
+
# Both instances of the same requirement class should share state
|
|
92
|
+
expect(state1).to be(state2)
|
|
93
|
+
expect(state2.collected_items).to eq(["from_instance1"])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "with requirement that lacks nested State class" do
|
|
97
|
+
let(:requirement_without_state) do
|
|
98
|
+
Class.new(SvgConform::Requirements::BaseRequirement) do
|
|
99
|
+
def id
|
|
100
|
+
"no_state_requirement"
|
|
101
|
+
end
|
|
102
|
+
end.new
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "raises an error when State class is not defined" do
|
|
106
|
+
expect do
|
|
107
|
+
context.state_for(requirement_without_state)
|
|
108
|
+
end.to raise_error(NameError, /uninitialized constant.*State/)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "state lifecycle" do
|
|
114
|
+
let(:requirement_class) do
|
|
115
|
+
req_class = Class.new(SvgConform::Requirements::BaseRequirement) do
|
|
116
|
+
def id
|
|
117
|
+
"counter_requirement"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
req_class.const_set(:State, Class.new do
|
|
122
|
+
attr_accessor :counter
|
|
123
|
+
|
|
124
|
+
def initialize
|
|
125
|
+
@counter = 0
|
|
126
|
+
end
|
|
127
|
+
end)
|
|
128
|
+
|
|
129
|
+
req_class
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "creates fresh state for each validation context instance" do
|
|
133
|
+
requirement = requirement_class.new
|
|
134
|
+
|
|
135
|
+
context1 = described_class.new(nil, profile)
|
|
136
|
+
state1 = context1.state_for(requirement)
|
|
137
|
+
state1.counter = 42
|
|
138
|
+
|
|
139
|
+
context2 = described_class.new(nil, profile)
|
|
140
|
+
state2 = context2.state_for(requirement)
|
|
141
|
+
|
|
142
|
+
# Different contexts should have different state instances
|
|
143
|
+
expect(state1).not_to be(state2)
|
|
144
|
+
expect(state2.counter).to eq(0)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "prevents state pollution across validations" do
|
|
148
|
+
requirement = requirement_class.new
|
|
149
|
+
|
|
150
|
+
# First validation
|
|
151
|
+
context1 = described_class.new(nil, profile)
|
|
152
|
+
state1 = context1.state_for(requirement)
|
|
153
|
+
state1.counter = 100
|
|
154
|
+
|
|
155
|
+
# Second validation with same profile
|
|
156
|
+
context2 = described_class.new(nil, profile)
|
|
157
|
+
state2 = context2.state_for(requirement)
|
|
158
|
+
|
|
159
|
+
# State should be fresh, not polluted by first validation
|
|
160
|
+
expect(state2.counter).to eq(0)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe "#node_structurally_invalid?" do
|
|
165
|
+
it "returns false for nodes not marked as structurally invalid" do
|
|
166
|
+
# In SAX mode (document = nil), simple objects return nil from node_id generator
|
|
167
|
+
node = Object.new
|
|
168
|
+
expect(context.node_structurally_invalid?(node)).to be false
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
describe "#mark_node_structurally_invalid" do
|
|
173
|
+
it "marks a node as structurally invalid" do
|
|
174
|
+
# Use a node-like object with a stable path_id for tracking
|
|
175
|
+
node = Object.new
|
|
176
|
+
def node.path_id
|
|
177
|
+
"test_node_1"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context.mark_node_structurally_invalid(node)
|
|
181
|
+
# After marking, the node should be tracked as structurally invalid
|
|
182
|
+
expect(context.node_structurally_invalid?(node)).to be true
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
describe "#register_id" do
|
|
187
|
+
it "registers an ID in the reference manifest" do
|
|
188
|
+
context.register_id("test_id", element_name: "svg", line_number: 1,
|
|
189
|
+
column_number: 1)
|
|
190
|
+
expect(context.id_defined?("test_id")).to be true
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
describe "#register_reference" do
|
|
195
|
+
it "registers a reference in the manifest" do
|
|
196
|
+
# Use a concrete reference type
|
|
197
|
+
reference = SvgConform::References::InternalFragmentReference.new(
|
|
198
|
+
value: "#target",
|
|
199
|
+
element_name: "use",
|
|
200
|
+
attribute_name: "href",
|
|
201
|
+
line_number: 1,
|
|
202
|
+
column_number: 1,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
context.register_reference(reference)
|
|
206
|
+
# Verify reference was added - the manifest should now track this reference
|
|
207
|
+
expect(context.reference_manifest).to be_a(SvgConform::References::ReferenceManifest)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
describe "#id_defined?" do
|
|
212
|
+
it "returns false for undefined IDs" do
|
|
213
|
+
expect(context.id_defined?("nonexistent")).to be false
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "returns true for registered IDs" do
|
|
217
|
+
context.register_id("test_id", element_name: "svg")
|
|
218
|
+
expect(context.id_defined?("test_id")).to be true
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
describe "#add_error" do
|
|
223
|
+
it "adds an error to the context" do
|
|
224
|
+
node = Object.new
|
|
225
|
+
context.add_error(
|
|
226
|
+
node: node,
|
|
227
|
+
message: "test error",
|
|
228
|
+
requirement_id: "test",
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
expect(context.has_errors?).to be true
|
|
232
|
+
expect(context.errors.first.message).to eq("test error")
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
describe "#add_warning" do
|
|
237
|
+
it "adds a warning to the context" do
|
|
238
|
+
node = Object.new
|
|
239
|
+
context.add_warning(
|
|
240
|
+
rule: "test_rule",
|
|
241
|
+
node: node,
|
|
242
|
+
message: "test warning",
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
expect(context.has_warnings?).to be true
|
|
246
|
+
expect(context.warnings.first.message).to eq("test warning")
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
describe "#add_notice" do
|
|
251
|
+
it "adds a notice to the context" do
|
|
252
|
+
node = Object.new
|
|
253
|
+
context.add_notice(
|
|
254
|
+
rule: "test_rule",
|
|
255
|
+
node: node,
|
|
256
|
+
message: "test notice",
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
expect(context.infos.first.message).to eq("test notice")
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
describe "#has_errors?" do
|
|
264
|
+
it "returns false when no errors" do
|
|
265
|
+
expect(context.has_errors?).to be false
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it "returns true when errors are added" do
|
|
269
|
+
node = Object.new
|
|
270
|
+
context.add_error(node: node, message: "error", requirement_id: "test")
|
|
271
|
+
expect(context.has_errors?).to be true
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
describe "#has_warnings?" do
|
|
276
|
+
it "returns false when no warnings" do
|
|
277
|
+
expect(context.has_warnings?).to be false
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "returns true when warnings are added" do
|
|
281
|
+
node = Object.new
|
|
282
|
+
context.add_warning(rule: "test", node: node, message: "warning")
|
|
283
|
+
expect(context.has_warnings?).to be true
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
describe "#add_fix" do
|
|
288
|
+
it "stores fix in fixes array" do
|
|
289
|
+
fix = -> { "some action" }
|
|
290
|
+
context.add_fix(fix)
|
|
291
|
+
expect(context.fixes).to eq([fix])
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
describe "#has_fixes?" do
|
|
296
|
+
it "returns false when no fixes" do
|
|
297
|
+
expect(context.has_fixes?).to be false
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
it "returns true when fixes are added" do
|
|
301
|
+
context.add_fix(-> { "action" })
|
|
302
|
+
expect(context.has_fixes?).to be true
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
data/spec/svg_conform_spec.rb
CHANGED
|
@@ -29,4 +29,160 @@ RSpec.describe SvgConform do
|
|
|
29
29
|
expect(css_profile).not_to be_nil
|
|
30
30
|
expect(css_profile.requirements).not_to be_empty
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
describe "profile switching without state leakage" do
|
|
34
|
+
let(:svg_with_invalid_ref) do
|
|
35
|
+
<<~SVG
|
|
36
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
37
|
+
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 100 100">
|
|
38
|
+
<defs>
|
|
39
|
+
<rect id="valid-rect" width="10" height="10"/>
|
|
40
|
+
</defs>
|
|
41
|
+
<use href="#valid-rect" x="10" y="10"/>
|
|
42
|
+
<use href="#invalid-rect" x="20" y="20"/>
|
|
43
|
+
</svg>
|
|
44
|
+
SVG
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "maintains consistent validation results when switching between profiles" do
|
|
48
|
+
validator = SvgConform::Validator.new(mode: :sax)
|
|
49
|
+
|
|
50
|
+
# First validation with metanorma profile
|
|
51
|
+
profile_meta = SvgConform::Profiles.get("metanorma")
|
|
52
|
+
result_meta1 = validator.validate(svg_with_invalid_ref,
|
|
53
|
+
profile: profile_meta)
|
|
54
|
+
first_meta_count = result_meta1.errors.count
|
|
55
|
+
|
|
56
|
+
# Validation with svg_1_2_rfc profile
|
|
57
|
+
profile_rfc = SvgConform::Profiles.get("svg_1_2_rfc")
|
|
58
|
+
result_rfc1 = validator.validate(svg_with_invalid_ref,
|
|
59
|
+
profile: profile_rfc)
|
|
60
|
+
first_rfc_count = result_rfc1.errors.count
|
|
61
|
+
|
|
62
|
+
# Second validation with metanorma profile (should match first)
|
|
63
|
+
result_meta2 = validator.validate(svg_with_invalid_ref,
|
|
64
|
+
profile: profile_meta)
|
|
65
|
+
second_meta_count = result_meta2.errors.count
|
|
66
|
+
|
|
67
|
+
# Second validation with svg_1_2_rfc profile (should match first)
|
|
68
|
+
result_rfc2 = validator.validate(svg_with_invalid_ref,
|
|
69
|
+
profile: profile_rfc)
|
|
70
|
+
second_rfc_count = result_rfc2.errors.count
|
|
71
|
+
|
|
72
|
+
# Verify consistency - no state leakage between profiles
|
|
73
|
+
expect(first_meta_count).to eq(second_meta_count),
|
|
74
|
+
"metanorma profile should return consistent results (#{first_meta_count} vs #{second_meta_count})"
|
|
75
|
+
|
|
76
|
+
expect(first_rfc_count).to eq(second_rfc_count),
|
|
77
|
+
"svg_1_2_rfc profile should return consistent results (#{first_rfc_count} vs #{second_rfc_count})"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "properly resets requirement state between validations" do
|
|
81
|
+
# This test specifically verifies that requirement state is reset
|
|
82
|
+
# by validating the same content multiple times
|
|
83
|
+
validator = SvgConform::Validator.new(mode: :sax)
|
|
84
|
+
profile = SvgConform::Profiles.get("svg_1_2_rfc")
|
|
85
|
+
|
|
86
|
+
results = []
|
|
87
|
+
3.times do
|
|
88
|
+
result = validator.validate(svg_with_invalid_ref, profile: profile)
|
|
89
|
+
results << result.errors.count
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# All runs should produce the same error count
|
|
93
|
+
expect(results.uniq.size).to eq(1),
|
|
94
|
+
"All validation runs should produce identical results: #{results.inspect}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "handles interleaved profile validations correctly" do
|
|
98
|
+
validator = SvgConform::Validator.new(mode: :sax)
|
|
99
|
+
|
|
100
|
+
profile_meta = SvgConform::Profiles.get("metanorma")
|
|
101
|
+
profile_rfc = SvgConform::Profiles.get("svg_1_2_rfc")
|
|
102
|
+
|
|
103
|
+
# Interleave validations
|
|
104
|
+
results = []
|
|
105
|
+
results << [:meta,
|
|
106
|
+
validator.validate(svg_with_invalid_ref,
|
|
107
|
+
profile: profile_meta).errors.count]
|
|
108
|
+
results << [:rfc,
|
|
109
|
+
validator.validate(svg_with_invalid_ref,
|
|
110
|
+
profile: profile_rfc).errors.count]
|
|
111
|
+
results << [:meta,
|
|
112
|
+
validator.validate(svg_with_invalid_ref,
|
|
113
|
+
profile: profile_meta).errors.count]
|
|
114
|
+
results << [:rfc,
|
|
115
|
+
validator.validate(svg_with_invalid_ref,
|
|
116
|
+
profile: profile_rfc).errors.count]
|
|
117
|
+
results << [:meta,
|
|
118
|
+
validator.validate(svg_with_invalid_ref,
|
|
119
|
+
profile: profile_meta).errors.count]
|
|
120
|
+
|
|
121
|
+
# Extract counts by profile
|
|
122
|
+
meta_counts = results.select { |type, _| type == :meta }.map(&:last)
|
|
123
|
+
rfc_counts = results.select { |type, _| type == :rfc }.map(&:last)
|
|
124
|
+
|
|
125
|
+
# Each profile should produce consistent results
|
|
126
|
+
expect(meta_counts.uniq.size).to eq(1),
|
|
127
|
+
"metanorma validations should be consistent: #{meta_counts.inspect}"
|
|
128
|
+
expect(rfc_counts.uniq.size).to eq(1),
|
|
129
|
+
"svg_1_2_rfc validations should be consistent: #{rfc_counts.inspect}"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "returns different error counts for profiles with different requirements" do
|
|
133
|
+
# Real-world SVG with style attributes that violate svg_1_2_rfc but not metanorma
|
|
134
|
+
svg_with_styles = <<~SVG
|
|
135
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" preserveAspectRatio="xMidYMid" version="1.1" viewBox="0 0 28000 21000">
|
|
136
|
+
<g class="Drawing" id="Straight_Connector_42">
|
|
137
|
+
<g>
|
|
138
|
+
<g style="stroke:rgb(0,0,0);stroke-width:88;fill:none">
|
|
139
|
+
<path d="M 4264,13886 L 4264,17273" style="fill:none" />
|
|
140
|
+
</g></g></g>
|
|
141
|
+
<g class="Drawing" id="Straight_Connector_33">
|
|
142
|
+
<g>
|
|
143
|
+
<g style="stroke:rgb(0,0,0);stroke-width:88;fill:none">
|
|
144
|
+
<path d="M 20355,10711 L 20351,13886" style="fill:none" />
|
|
145
|
+
</g></g></g>
|
|
146
|
+
<g class="Drawing">
|
|
147
|
+
<g>
|
|
148
|
+
<g style="stroke:none;fill:none">
|
|
149
|
+
<rect height="3490" width="25184" x="1512" y="340" />
|
|
150
|
+
</g>
|
|
151
|
+
<g style="font-family:Arial embedded;font-size:1552px;font-weight:400">
|
|
152
|
+
<g style="stroke:none;fill:rgb(0,0,0)">
|
|
153
|
+
<text>
|
|
154
|
+
<tspan x="4733 5855 6718 7582 8446 8877 9741 10605 11036 12074 12853 13716 14580 15443 15960 16307 17171 17602 18724 19071 19935 20799 21315 22179 " y="2482">
|
|
155
|
+
Updated Scenario Diagram
|
|
156
|
+
</tspan>
|
|
157
|
+
</text>
|
|
158
|
+
</g>
|
|
159
|
+
</g>
|
|
160
|
+
</g>
|
|
161
|
+
</g>
|
|
162
|
+
</svg>
|
|
163
|
+
SVG
|
|
164
|
+
|
|
165
|
+
validator = SvgConform::Validator.new(mode: :sax)
|
|
166
|
+
|
|
167
|
+
# Validate with metanorma (should have 0 errors - more permissive)
|
|
168
|
+
profile_meta = SvgConform::Profiles.get("metanorma")
|
|
169
|
+
result_meta = validator.validate(svg_with_styles, profile: profile_meta)
|
|
170
|
+
meta_errors = result_meta.errors.count
|
|
171
|
+
|
|
172
|
+
# Validate with svg_1_2_rfc (should have errors - stricter requirements)
|
|
173
|
+
profile_rfc = SvgConform::Profiles.get("svg_1_2_rfc")
|
|
174
|
+
result_rfc = validator.validate(svg_with_styles, profile: profile_rfc)
|
|
175
|
+
rfc_errors = result_rfc.errors.count
|
|
176
|
+
|
|
177
|
+
# Profiles should return different results
|
|
178
|
+
expect(meta_errors).to eq(0), "metanorma profile should allow this SVG"
|
|
179
|
+
expect(rfc_errors).to be > 0,
|
|
180
|
+
"svg_1_2_rfc profile should detect violations"
|
|
181
|
+
|
|
182
|
+
# Verify consistency when repeating
|
|
183
|
+
result_rfc2 = validator.validate(svg_with_styles, profile: profile_rfc)
|
|
184
|
+
expect(result_rfc2.errors.count).to eq(rfc_errors),
|
|
185
|
+
"svg_1_2_rfc should return same error count on repeat (no state leakage)"
|
|
186
|
+
end
|
|
187
|
+
end
|
|
32
188
|
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.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|
|
@@ -115,6 +115,7 @@ files:
|
|
|
115
115
|
- exe/svg_conform
|
|
116
116
|
- lib/svg_conform.rb
|
|
117
117
|
- lib/svg_conform/batch_report.rb
|
|
118
|
+
- lib/svg_conform/classification_cache.rb
|
|
118
119
|
- lib/svg_conform/cli.rb
|
|
119
120
|
- lib/svg_conform/commands/check.rb
|
|
120
121
|
- lib/svg_conform/commands/profiles.rb
|
|
@@ -241,8 +242,10 @@ files:
|
|
|
241
242
|
- spec/fixtures/style/repair/basic_violations.svg
|
|
242
243
|
- spec/fixtures/style_promotion/inputs/basic_test.svg
|
|
243
244
|
- spec/fixtures/style_promotion/repair/basic_test.svg
|
|
245
|
+
- spec/fixtures/svg_1_2_rfc/expected_errors/ietf_test_violations.yml
|
|
244
246
|
- spec/fixtures/svg_1_2_rfc/inputs/allowed_elements_violations.svg
|
|
245
247
|
- spec/fixtures/svg_1_2_rfc/inputs/color_restrictions_violations.svg
|
|
248
|
+
- spec/fixtures/svg_1_2_rfc/inputs/ietf_test_violations.svg
|
|
246
249
|
- spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.code
|
|
247
250
|
- spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.err
|
|
248
251
|
- spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.out
|
|
@@ -445,6 +448,7 @@ files:
|
|
|
445
448
|
- spec/svg_conform/requirements/style_promotion_requirement_spec.rb
|
|
446
449
|
- spec/svg_conform/requirements/style_requirement_spec.rb
|
|
447
450
|
- spec/svg_conform/requirements/viewbox_required_requirement_spec.rb
|
|
451
|
+
- spec/svg_conform/validation_context_spec.rb
|
|
448
452
|
- spec/svg_conform/validator_input_types_spec.rb
|
|
449
453
|
- spec/svg_conform_spec.rb
|
|
450
454
|
- spec/svgcheck_compatibility_spec.rb
|