svg_conform 0.1.0
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 +7 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +23 -0
- data/.github/workflows/svgcheck-compatibility.yml +135 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +183 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Gemfile +14 -0
- data/README.adoc +1384 -0
- data/Rakefile +15 -0
- data/config/profiles/base.yml +34 -0
- data/config/profiles/lucid_fix.yml +37 -0
- data/config/profiles/metanorma.yml +212 -0
- data/config/profiles/no_external_css.yml +20 -0
- data/config/profiles/svg_1_2_rfc.yml +284 -0
- data/config/profiles/svg_1_2_rfc_with_rdf.yml +145 -0
- data/config/svgcheck_mapping.yml +180 -0
- data/docs/profiles.adoc +547 -0
- data/docs/rdf_metadata_support.adoc +212 -0
- data/docs/remediation.adoc +732 -0
- data/docs/requirements.adoc +709 -0
- data/examples/demo.rb +116 -0
- data/examples/requirements_demo.rb +240 -0
- data/exe/svg_conform +7 -0
- data/lib/svg_conform/batch_report.rb +70 -0
- data/lib/svg_conform/cli.rb +107 -0
- data/lib/svg_conform/commands/check.rb +390 -0
- data/lib/svg_conform/commands/profiles.rb +118 -0
- data/lib/svg_conform/commands/svgcheck.rb +90 -0
- data/lib/svg_conform/commands/svgcheck_compare.rb +92 -0
- data/lib/svg_conform/commands/svgcheck_compatibility.rb +43 -0
- data/lib/svg_conform/commands/svgcheck_generate.rb +262 -0
- data/lib/svg_conform/compatibility/analysis_context.rb +68 -0
- data/lib/svg_conform/compatibility/comparison_result.rb +147 -0
- data/lib/svg_conform/compatibility/compatibility_analyzer.rb +85 -0
- data/lib/svg_conform/compatibility/file_processor.rb +109 -0
- data/lib/svg_conform/compatibility/pattern_discovery.rb +319 -0
- data/lib/svg_conform/compatibility/report_formatter.rb +359 -0
- data/lib/svg_conform/compatibility/svg_analysis_engine.rb +316 -0
- data/lib/svg_conform/compatibility/validity_analysis.rb +252 -0
- data/lib/svg_conform/compatibility/xml_analysis_engine.rb +198 -0
- data/lib/svg_conform/compatibility_analyzer.rb +285 -0
- data/lib/svg_conform/conformance_report.rb +267 -0
- data/lib/svg_conform/constants.rb +199 -0
- data/lib/svg_conform/css_color.rb +262 -0
- data/lib/svg_conform/document.rb +203 -0
- data/lib/svg_conform/external_checkers/svgcheck/compatibility_engine.rb +166 -0
- data/lib/svg_conform/external_checkers/svgcheck/output_generator.rb +101 -0
- data/lib/svg_conform/external_checkers/svgcheck/parser.rb +200 -0
- data/lib/svg_conform/external_checkers/svgcheck/report_comparator.rb +175 -0
- data/lib/svg_conform/external_checkers/svgcheck/report_generator.rb +82 -0
- data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +249 -0
- data/lib/svg_conform/external_checkers/svgcheck.rb +56 -0
- data/lib/svg_conform/external_checkers.rb +34 -0
- data/lib/svg_conform/fixer.rb +56 -0
- data/lib/svg_conform/profile.rb +164 -0
- data/lib/svg_conform/profiles.rb +60 -0
- data/lib/svg_conform/remediation_engine.rb +92 -0
- data/lib/svg_conform/remediation_result.rb +36 -0
- data/lib/svg_conform/remediation_runner.rb +225 -0
- data/lib/svg_conform/remediations/base_remediation.rb +165 -0
- data/lib/svg_conform/remediations/color_remediation.rb +226 -0
- data/lib/svg_conform/remediations/font_embedding_remediation.rb +145 -0
- data/lib/svg_conform/remediations/font_remediation.rb +122 -0
- data/lib/svg_conform/remediations/image_embedding_remediation.rb +154 -0
- data/lib/svg_conform/remediations/invalid_id_references_remediation.rb +129 -0
- data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +244 -0
- data/lib/svg_conform/remediations/namespace_remediation.rb +151 -0
- data/lib/svg_conform/remediations/no_external_css_remediation.rb +192 -0
- data/lib/svg_conform/remediations/style_promotion_remediation.rb +93 -0
- data/lib/svg_conform/remediations/viewbox_remediation.rb +127 -0
- data/lib/svg_conform/remediations.rb +40 -0
- data/lib/svg_conform/report_comparator.rb +772 -0
- data/lib/svg_conform/requirements/allowed_elements_requirement.rb +367 -0
- data/lib/svg_conform/requirements/base_requirement.rb +98 -0
- data/lib/svg_conform/requirements/color_restrictions_requirement.rb +126 -0
- data/lib/svg_conform/requirements/element_requirement_config.rb +75 -0
- data/lib/svg_conform/requirements/font_family_requirement.rb +133 -0
- data/lib/svg_conform/requirements/forbidden_content_requirement.rb +60 -0
- data/lib/svg_conform/requirements/id_reference_requirement.rb +133 -0
- data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +132 -0
- data/lib/svg_conform/requirements/link_validation_requirement.rb +55 -0
- data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +211 -0
- data/lib/svg_conform/requirements/namespace_requirement.rb +294 -0
- data/lib/svg_conform/requirements/no_external_css_requirement.rb +132 -0
- data/lib/svg_conform/requirements/no_external_fonts_requirement.rb +121 -0
- data/lib/svg_conform/requirements/no_external_images_requirement.rb +91 -0
- data/lib/svg_conform/requirements/style_promotion_requirement.rb +72 -0
- data/lib/svg_conform/requirements/style_requirement.rb +226 -0
- data/lib/svg_conform/requirements/viewbox_required_requirement.rb +96 -0
- data/lib/svg_conform/requirements.rb +49 -0
- data/lib/svg_conform/semantic_comparator.rb +829 -0
- data/lib/svg_conform/validation_context.rb +408 -0
- data/lib/svg_conform/validation_result.rb +146 -0
- data/lib/svg_conform/validator.rb +91 -0
- data/lib/svg_conform/version.rb +5 -0
- data/lib/svg_conform.rb +68 -0
- data/lib/tasks/fixtures.rake +321 -0
- data/lib/tasks/svgcheck.rake +111 -0
- data/reference-docs/SVG-1.2-RFC.rnc.txt +1676 -0
- data/reference-docs/Scalable Vector Graphics (SVG) 1.1 (Second Edition).html +40764 -0
- data/reference-docs/Scalable Vector Graphics (SVG) Tiny 1.2 Specification.html +44591 -0
- data/reference-docs/rfc7996.txt +2971 -0
- data/sig/svg_conform.rbs +4 -0
- data/spec/fixtures/allowed_elements/inputs/basic_violations.svg +21 -0
- data/spec/fixtures/allowed_elements/repair/basic_violations.svg +18 -0
- data/spec/fixtures/color_restrictions/inputs/basic_violations.svg +23 -0
- data/spec/fixtures/color_restrictions/repair/basic_violations.svg +23 -0
- data/spec/fixtures/comprehensive/inputs/multiple_violations.svg +21 -0
- data/spec/fixtures/comprehensive/repair/multiple_violations.svg +16 -0
- data/spec/fixtures/font_family/inputs/basic_violations.svg +17 -0
- data/spec/fixtures/font_family/repair/basic_violations.svg +17 -0
- data/spec/fixtures/forbidden_content/inputs/basic_violations.svg +27 -0
- data/spec/fixtures/forbidden_content/repair/basic_violations.svg +19 -0
- data/spec/fixtures/id_reference/inputs/basic_violations.svg +17 -0
- data/spec/fixtures/id_reference/repair/basic_violations.svg +15 -0
- data/spec/fixtures/link_validation/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/link_validation/repair/basic_violations.svg +16 -0
- data/spec/fixtures/lucid/inputs/simple.svg +67 -0
- data/spec/fixtures/lucid/repair/simple.svg +63 -0
- data/spec/fixtures/namespace/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/namespace/repair/basic_violations.svg +17 -0
- data/spec/fixtures/namespace_attributes/inputs/basic_violations.svg +16 -0
- data/spec/fixtures/namespace_attributes/repair/basic_violations.svg +15 -0
- data/spec/fixtures/no_external_css/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/no_external_css/repair/basic_violations.svg +18 -0
- data/spec/fixtures/style/inputs/basic_violations.svg +22 -0
- data/spec/fixtures/style/repair/basic_violations.svg +22 -0
- data/spec/fixtures/style_promotion/inputs/basic_test.svg +15 -0
- data/spec/fixtures/style_promotion/repair/basic_test.svg +15 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/allowed_elements_violations.svg +18 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/color_restrictions_violations.svg +23 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.out +23 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.out +20 -0
- data/spec/fixtures/svgcheck/check/circle.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/circle.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/circle.svg.out +2 -0
- data/spec/fixtures/svgcheck/check/colors.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/colors.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/colors.svg.out +13 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.out +76 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.out +11 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.out +5835 -0
- data/spec/fixtures/svgcheck/check/good.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/good.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/good.svg.out +1 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.out +5 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.out +8 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.out +1 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.code +1 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.err +0 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.out +2 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.out +9 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.out +508 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.out +20 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.out +162 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.out +4 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.out +3 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.out +3 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.out +3 -0
- data/spec/fixtures/svgcheck/inputs/DrawBerry-sample-2.svg +28 -0
- data/spec/fixtures/svgcheck/inputs/IETF-test.svg +28 -0
- data/spec/fixtures/svgcheck/inputs/circle.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/colors.svg +18 -0
- data/spec/fixtures/svgcheck/inputs/dia-sample-svg.svg +47 -0
- data/spec/fixtures/svgcheck/inputs/example-dot.svg +75 -0
- data/spec/fixtures/svgcheck/inputs/full-tiny.svg +16194 -0
- data/spec/fixtures/svgcheck/inputs/good.svg +19 -0
- data/spec/fixtures/svgcheck/inputs/httpbis-proxy20-fig6.svg +2 -0
- data/spec/fixtures/svgcheck/inputs/malformed.svg +11 -0
- data/spec/fixtures/svgcheck/inputs/rfc-svg.svg +1028 -0
- data/spec/fixtures/svgcheck/inputs/rfc.xml +37 -0
- data/spec/fixtures/svgcheck/inputs/rgb.svg +9 -0
- data/spec/fixtures/svgcheck/inputs/svg-wordle.svg +330 -0
- data/spec/fixtures/svgcheck/inputs/threshold.svg +26 -0
- data/spec/fixtures/svgcheck/inputs/utf8.svg +448 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-both.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-height.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-none.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-width.svg +3 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.out +23 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.file +29 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.out +20 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.out +2 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.file +19 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.out +13 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.file +47 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.out +76 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.file +69 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.out +11 -0
- data/spec/fixtures/svgcheck/repair/good.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/good.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/good.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/good.svg.out +1 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.file +73 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.out +5 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.file +9 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.out +8 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.out +1 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.code +1 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.err +0 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.file +37 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.out +2 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.file +10 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.out +9 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.file +112 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.out +508 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.file +27 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.out +20 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.file +381 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.out +162 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.out +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.out +3 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.out +3 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.out +3 -0
- data/spec/fixtures/viewbox_required/inputs/missing_viewbox.svg +10 -0
- data/spec/fixtures/viewbox_required/repair/missing_viewbox.svg +10 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/svg_conform/batch_report_spec.rb +99 -0
- data/spec/svg_conform/commands/check_command_spec.rb +90 -0
- data/spec/svg_conform/commands/profiles_command_spec.rb +20 -0
- data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +13 -0
- data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +13 -0
- data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +14 -0
- data/spec/svg_conform/profiles/base_profile_spec.rb +42 -0
- data/spec/svg_conform/profiles/lucid_fix_profile_spec.rb +46 -0
- data/spec/svg_conform/profiles/lucid_profile_spec.rb +84 -0
- data/spec/svg_conform/profiles/metanorma_profile_spec.rb +62 -0
- data/spec/svg_conform/profiles/no_external_css_profile_spec.rb +66 -0
- data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +200 -0
- data/spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb +81 -0
- data/spec/svg_conform/remediations/color_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/font_embedding_remediation_spec.rb +20 -0
- data/spec/svg_conform/remediations/font_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/image_embedding_remediation_spec.rb +20 -0
- data/spec/svg_conform/remediations/invalid_id_references_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/namespace_attribute_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/namespace_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/no_external_css_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/style_promotion_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/viewbox_remediation_spec.rb +95 -0
- data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +118 -0
- data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +168 -0
- data/spec/svg_conform/requirements/font_family_requirement_spec.rb +188 -0
- data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +195 -0
- data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +86 -0
- data/spec/svg_conform/requirements/namespace_requirement_spec.rb +184 -0
- data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/no_external_fonts_requirement_spec.rb +20 -0
- data/spec/svg_conform/requirements/no_external_images_requirement_spec.rb +20 -0
- data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/style_requirement_spec.rb +76 -0
- data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +165 -0
- data/spec/svg_conform_spec.rb +32 -0
- data/spec/svgcheck_compatibility_spec.rb +355 -0
- data/svg_conform.gemspec +35 -0
- metadata +436 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "paint"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Compatibility
|
|
7
|
+
# Handles formatting and display of compatibility analysis results
|
|
8
|
+
class ReportFormatter
|
|
9
|
+
def initialize(context)
|
|
10
|
+
@context = context
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def display_single_file_result(result)
|
|
14
|
+
if @context.semantic_analysis?
|
|
15
|
+
display_semantic_single_result(result)
|
|
16
|
+
else
|
|
17
|
+
display_basic_single_result(result)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def display_batch_results(results)
|
|
22
|
+
if @context.semantic_analysis?
|
|
23
|
+
display_semantic_batch_results(results)
|
|
24
|
+
else
|
|
25
|
+
display_basic_batch_results(results)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def write_output_file(results)
|
|
30
|
+
return unless @context.file_output?
|
|
31
|
+
|
|
32
|
+
content = generate_output_content(results)
|
|
33
|
+
File.write(@context.output_file, content)
|
|
34
|
+
puts "📄 Results written to: #{@context.output_file}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def display_semantic_single_result(result)
|
|
40
|
+
display_file_header(result.filename)
|
|
41
|
+
display_semantic_validation_section(result)
|
|
42
|
+
display_semantic_repair_section(result) if @context.repair_mode?
|
|
43
|
+
display_xml_equivalence_section(result) if result.xml_equivalence
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def display_basic_single_result(result)
|
|
47
|
+
display_file_header(result.filename)
|
|
48
|
+
display_basic_validation_section(result)
|
|
49
|
+
display_basic_repair_section(result) if @context.repair_mode?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def display_semantic_batch_results(results)
|
|
53
|
+
display_batch_header(results.length)
|
|
54
|
+
display_semantic_summary_table(results)
|
|
55
|
+
display_semantic_batch_statistics(results)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def display_basic_batch_results(results)
|
|
59
|
+
display_batch_header(results.length)
|
|
60
|
+
display_basic_summary_table(results)
|
|
61
|
+
display_basic_batch_statistics(results)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def display_file_header(filename)
|
|
65
|
+
mode_icon = @context.repair_mode? ? "🔧" : "📋"
|
|
66
|
+
mode_text = @context.repair_mode? ? "Repair Analysis" : "Analysis"
|
|
67
|
+
analysis_type = @context.semantic_analysis? ? "Semantic" : "Basic"
|
|
68
|
+
|
|
69
|
+
puts Paint["#{mode_icon} #{analysis_type} #{mode_text}: #{filename}",
|
|
70
|
+
:cyan, :bold]
|
|
71
|
+
puts "=" * 60
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def display_batch_header(file_count)
|
|
75
|
+
mode_icon = @context.repair_mode? ? "🔧" : "📋"
|
|
76
|
+
mode_text = @context.repair_mode? ? "Repair Analysis" : "Analysis"
|
|
77
|
+
analysis_type = @context.semantic_analysis? ? "Semantic" : "Basic"
|
|
78
|
+
|
|
79
|
+
puts Paint["#{mode_icon} #{analysis_type} Batch #{mode_text} (#{file_count} files)",
|
|
80
|
+
:cyan, :bold]
|
|
81
|
+
puts "=" * 80
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def display_semantic_validation_section(result)
|
|
85
|
+
return unless result.validation_comparison
|
|
86
|
+
|
|
87
|
+
puts Paint["📊 Validation Comparison:", :blue, :bold]
|
|
88
|
+
|
|
89
|
+
score = result.compatibility_score
|
|
90
|
+
score_color = if score >= 90
|
|
91
|
+
:green
|
|
92
|
+
else
|
|
93
|
+
score >= 70 ? :yellow : :red
|
|
94
|
+
end
|
|
95
|
+
puts " Compatibility Score: #{Paint[format('%.1f%%', score),
|
|
96
|
+
score_color, :bold]}"
|
|
97
|
+
|
|
98
|
+
validity_status = result.validity_match? ? "✅ Match" : "❌ Mismatch"
|
|
99
|
+
puts " Validity Match: #{validity_status}"
|
|
100
|
+
puts " SvgConform Valid: #{result.svg_conform_valid? ? '✅' : '❌'}"
|
|
101
|
+
puts " Svgcheck Valid: #{result.svgcheck_valid? ? '✅' : '❌'}"
|
|
102
|
+
puts
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def display_semantic_repair_section(result)
|
|
106
|
+
return unless result.validation_comparison
|
|
107
|
+
|
|
108
|
+
puts Paint["🔧 Repair Results:", :blue, :bold]
|
|
109
|
+
|
|
110
|
+
if result.successful_remediation?
|
|
111
|
+
puts " Remediation: #{Paint['✅ Successful', :green, :bold]}"
|
|
112
|
+
else
|
|
113
|
+
puts " Remediation: #{Paint['❌ Failed', :red, :bold]}"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if result.content_comparison
|
|
117
|
+
equivalence = result.content_equivalence_score
|
|
118
|
+
equiv_color = if equivalence >= 90
|
|
119
|
+
:green
|
|
120
|
+
else
|
|
121
|
+
equivalence >= 70 ? :yellow : :red
|
|
122
|
+
end
|
|
123
|
+
puts " Content Equivalence: #{Paint[format('%.1f%%', equivalence),
|
|
124
|
+
equiv_color, :bold]}"
|
|
125
|
+
end
|
|
126
|
+
puts
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def display_xml_equivalence_section(result)
|
|
130
|
+
puts Paint["🔍 XML Equivalence:", :blue, :bold]
|
|
131
|
+
|
|
132
|
+
if result.xml_error
|
|
133
|
+
puts " Status: #{Paint['❌ Error', :red, :bold]}"
|
|
134
|
+
puts " Error: #{result.xml_error}"
|
|
135
|
+
elsif result.xml_equivalent?
|
|
136
|
+
puts " Status: #{Paint['✅ Equivalent', :green, :bold]}"
|
|
137
|
+
else
|
|
138
|
+
puts " Status: #{Paint['❌ Different', :red, :bold]}"
|
|
139
|
+
puts " Differences: #{result.xml_differences.length}"
|
|
140
|
+
end
|
|
141
|
+
puts
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def display_basic_validation_section(result)
|
|
145
|
+
puts Paint["📊 Validation Results:", :blue, :bold]
|
|
146
|
+
puts " SvgConform Valid: #{result.svg_conform_valid? ? '✅' : '❌'}"
|
|
147
|
+
puts " Svgcheck Valid: #{result.svgcheck_valid? ? '✅' : '❌'}"
|
|
148
|
+
puts " Validity Match: #{result.validity_match? ? '✅' : '❌'}"
|
|
149
|
+
puts
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def display_basic_repair_section(result)
|
|
153
|
+
puts Paint["🔧 Repair Results:", :blue, :bold]
|
|
154
|
+
|
|
155
|
+
if result.successful_remediation?
|
|
156
|
+
puts " Remediation: #{Paint['✅ Successful', :green, :bold]}"
|
|
157
|
+
puts " Issues Fixed: #{result.issues_fixed}"
|
|
158
|
+
puts " Remediations Applied: #{result.remediations_applied}"
|
|
159
|
+
else
|
|
160
|
+
puts " Remediation: #{Paint['❌ Failed', :red, :bold]}"
|
|
161
|
+
end
|
|
162
|
+
puts
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def display_semantic_summary_table(results)
|
|
166
|
+
puts Paint["📊 Summary Table:", :blue, :bold]
|
|
167
|
+
puts
|
|
168
|
+
|
|
169
|
+
header = format("%-25s %12s %8s %12s %12s",
|
|
170
|
+
"File", "Compatibility", "Valid", "SvgConform", "Svgcheck")
|
|
171
|
+
puts Paint[header, :white, :bold]
|
|
172
|
+
puts "-" * 70
|
|
173
|
+
|
|
174
|
+
results.each do |result|
|
|
175
|
+
score = format("%.1f%%", result.compatibility_score)
|
|
176
|
+
score_color = if result.compatibility_score >= 90
|
|
177
|
+
:green
|
|
178
|
+
else
|
|
179
|
+
result.compatibility_score >= 70 ? :yellow : :red
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
validity = result.validity_match? ? "✅" : "❌"
|
|
183
|
+
svg_conform = result.svg_conform_valid? ? "✅" : "❌"
|
|
184
|
+
svgcheck = result.svgcheck_valid? ? "✅" : "❌"
|
|
185
|
+
|
|
186
|
+
row = format("%-25s %12s %8s %12s %12s",
|
|
187
|
+
result.filename.truncate(23),
|
|
188
|
+
Paint[score, score_color],
|
|
189
|
+
validity,
|
|
190
|
+
svg_conform,
|
|
191
|
+
svgcheck)
|
|
192
|
+
puts row
|
|
193
|
+
end
|
|
194
|
+
puts
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def display_basic_summary_table(results)
|
|
198
|
+
puts Paint["📊 Summary Table:", :blue, :bold]
|
|
199
|
+
puts
|
|
200
|
+
|
|
201
|
+
header = format("%-25s %8s %12s %12s %8s",
|
|
202
|
+
"File", "Valid", "SvgConform", "Svgcheck", "Errors")
|
|
203
|
+
puts Paint[header, :white, :bold]
|
|
204
|
+
puts "-" * 66
|
|
205
|
+
|
|
206
|
+
results.each do |result|
|
|
207
|
+
validity = result.validity_match? ? "✅" : "❌"
|
|
208
|
+
svg_conform = result.svg_conform_valid? ? "✅" : "❌"
|
|
209
|
+
svgcheck = result.svgcheck_valid? ? "✅" : "❌"
|
|
210
|
+
errors = result.error_count
|
|
211
|
+
|
|
212
|
+
row = format("%-25s %8s %12s %12s %8d",
|
|
213
|
+
result.filename.truncate(23),
|
|
214
|
+
validity,
|
|
215
|
+
svg_conform,
|
|
216
|
+
svgcheck,
|
|
217
|
+
errors)
|
|
218
|
+
puts row
|
|
219
|
+
end
|
|
220
|
+
puts
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def display_semantic_batch_statistics(results)
|
|
224
|
+
puts Paint["📈 Statistics:", :blue, :bold]
|
|
225
|
+
|
|
226
|
+
avg_compatibility = results.sum(&:compatibility_score) / results.length
|
|
227
|
+
validity_matches = results.count(&:validity_match?)
|
|
228
|
+
successful_remediations = results.count(&:successful_remediation?) if @context.repair_mode?
|
|
229
|
+
|
|
230
|
+
score_color = if avg_compatibility >= 90
|
|
231
|
+
:green
|
|
232
|
+
else
|
|
233
|
+
avg_compatibility >= 70 ? :yellow : :red
|
|
234
|
+
end
|
|
235
|
+
puts " Average Compatibility: #{Paint[format('%.1f%%', avg_compatibility),
|
|
236
|
+
score_color, :bold]}"
|
|
237
|
+
puts " Validity Matches: #{validity_matches}/#{results.length} (#{format('%.1f%%',
|
|
238
|
+
validity_matches * 100.0 / results.length)})"
|
|
239
|
+
|
|
240
|
+
if @context.repair_mode?
|
|
241
|
+
puts " Successful Remediations: #{successful_remediations}/#{results.length} (#{format('%.1f%%',
|
|
242
|
+
successful_remediations * 100.0 / results.length)})"
|
|
243
|
+
end
|
|
244
|
+
puts
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def display_basic_batch_statistics(results)
|
|
248
|
+
puts Paint["📈 Statistics:", :blue, :bold]
|
|
249
|
+
|
|
250
|
+
validity_matches = results.count(&:validity_match?)
|
|
251
|
+
successful_remediations = results.count(&:successful_remediation?) if @context.repair_mode?
|
|
252
|
+
total_errors = results.sum(&:error_count)
|
|
253
|
+
|
|
254
|
+
puts " Validity Matches: #{validity_matches}/#{results.length} (#{format('%.1f%%',
|
|
255
|
+
validity_matches * 100.0 / results.length)})"
|
|
256
|
+
puts " Total Errors: #{total_errors}"
|
|
257
|
+
|
|
258
|
+
if @context.repair_mode?
|
|
259
|
+
puts " Successful Remediations: #{successful_remediations}/#{results.length} (#{format('%.1f%%',
|
|
260
|
+
successful_remediations * 100.0 / results.length)})"
|
|
261
|
+
end
|
|
262
|
+
puts
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def generate_output_content(results)
|
|
266
|
+
content = []
|
|
267
|
+
content << "# Compatibility Analysis Results"
|
|
268
|
+
content << ""
|
|
269
|
+
content << "Analysis Type: #{@context.semantic_analysis? ? 'Semantic' : 'Basic'}"
|
|
270
|
+
content << "Mode: #{@context.mode.to_s.capitalize}"
|
|
271
|
+
content << "Profile: #{@context.profile}"
|
|
272
|
+
content << "Generated: #{Time.now}"
|
|
273
|
+
content << ""
|
|
274
|
+
|
|
275
|
+
if results.is_a?(Array)
|
|
276
|
+
generate_batch_output_content(content, results)
|
|
277
|
+
else
|
|
278
|
+
generate_single_output_content(content, results)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
content.join("\n")
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def generate_batch_output_content(content, results)
|
|
285
|
+
content << "## Summary"
|
|
286
|
+
content << ""
|
|
287
|
+
|
|
288
|
+
if @context.semantic_analysis?
|
|
289
|
+
avg_compatibility = results.sum(&:compatibility_score) / results.length
|
|
290
|
+
content << "Average Compatibility: #{format('%.1f%%',
|
|
291
|
+
avg_compatibility)}"
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
validity_matches = results.count(&:validity_match?)
|
|
295
|
+
content << "Validity Matches: #{validity_matches}/#{results.length}"
|
|
296
|
+
|
|
297
|
+
if @context.repair_mode?
|
|
298
|
+
successful_remediations = results.count(&:successful_remediation?)
|
|
299
|
+
content << "Successful Remediations: #{successful_remediations}/#{results.length}"
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
content << ""
|
|
303
|
+
content << "## Individual Results"
|
|
304
|
+
content << ""
|
|
305
|
+
|
|
306
|
+
results.each do |result|
|
|
307
|
+
content << "### #{result.filename}"
|
|
308
|
+
content << ""
|
|
309
|
+
add_result_details(content, result)
|
|
310
|
+
content << ""
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def generate_single_output_content(content, result)
|
|
315
|
+
content << "## #{result.filename}"
|
|
316
|
+
content << ""
|
|
317
|
+
add_result_details(content, result)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def add_result_details(content, result)
|
|
321
|
+
if @context.semantic_analysis?
|
|
322
|
+
content << "Compatibility Score: #{format('%.1f%%',
|
|
323
|
+
result.compatibility_score)}"
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
content << "Validity Match: #{result.validity_match?}"
|
|
327
|
+
content << "SvgConform Valid: #{result.svg_conform_valid?}"
|
|
328
|
+
content << "Svgcheck Valid: #{result.svgcheck_valid?}"
|
|
329
|
+
|
|
330
|
+
return unless @context.repair_mode?
|
|
331
|
+
|
|
332
|
+
content << "Successful Remediation: #{result.successful_remediation?}"
|
|
333
|
+
|
|
334
|
+
if result.content_comparison
|
|
335
|
+
content << "Content Equivalence: #{format('%.1f%%',
|
|
336
|
+
result.content_equivalence_score)}"
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
return unless result.xml_equivalence
|
|
340
|
+
|
|
341
|
+
content << "XML Equivalent: #{result.xml_equivalent?}"
|
|
342
|
+
return unless result.xml_error
|
|
343
|
+
|
|
344
|
+
content << "XML Error: #{result.xml_error}"
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# String extension for truncation
|
|
351
|
+
class String
|
|
352
|
+
def truncate(length)
|
|
353
|
+
if self.length > length
|
|
354
|
+
"#{self[0..length - 4]}..."
|
|
355
|
+
else
|
|
356
|
+
self
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../semantic_comparator"
|
|
4
|
+
require_relative "../remediation_runner"
|
|
5
|
+
|
|
6
|
+
module SvgConform
|
|
7
|
+
module Compatibility
|
|
8
|
+
# Handles SVG-specific analysis operations
|
|
9
|
+
class SvgAnalysisEngine
|
|
10
|
+
def initialize(context, file_processor)
|
|
11
|
+
@context = context
|
|
12
|
+
@file_processor = file_processor
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def analyze_file(filename, svgcheck_report)
|
|
16
|
+
if @context.check_mode?
|
|
17
|
+
analyze_validation(filename, svgcheck_report)
|
|
18
|
+
else
|
|
19
|
+
analyze_repair(filename, svgcheck_report)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def analyze_validation(filename, svgcheck_report)
|
|
26
|
+
input_file = @file_processor.input_file_path(filename)
|
|
27
|
+
svg_conform_result = run_validation(input_file)
|
|
28
|
+
svg_conform_report = create_conformance_report(filename,
|
|
29
|
+
svg_conform_result)
|
|
30
|
+
|
|
31
|
+
if @context.semantic_analysis?
|
|
32
|
+
build_semantic_validation_result(filename, svg_conform_report,
|
|
33
|
+
svgcheck_report)
|
|
34
|
+
else
|
|
35
|
+
build_basic_validation_result(filename, svg_conform_report,
|
|
36
|
+
svgcheck_report)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def analyze_repair(filename, svgcheck_report)
|
|
41
|
+
input_file = @file_processor.input_file_path(filename)
|
|
42
|
+
svg_conform_result = run_remediation(input_file, filename)
|
|
43
|
+
|
|
44
|
+
if @context.semantic_analysis?
|
|
45
|
+
build_semantic_repair_result(filename, svg_conform_result,
|
|
46
|
+
svgcheck_report)
|
|
47
|
+
else
|
|
48
|
+
build_basic_repair_result(filename, svg_conform_result,
|
|
49
|
+
svgcheck_report)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def run_validation(input_file)
|
|
54
|
+
validator = SvgConform::Validator.new
|
|
55
|
+
validator.validate_file(input_file, profile: @context.profile)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def run_remediation(input_file, filename)
|
|
59
|
+
remediation_runner = SvgConform::RemediationRunner.new(profile: @context.profile)
|
|
60
|
+
svg_content = File.read(input_file)
|
|
61
|
+
remediation_runner.run_remediation(svg_content, filename: filename)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def create_conformance_report(filename, svg_conform_result)
|
|
65
|
+
SvgConform::ConformanceReport.from_svg_conform_result(
|
|
66
|
+
filename,
|
|
67
|
+
svg_conform_result,
|
|
68
|
+
profile: @context.profile,
|
|
69
|
+
use_svgcheck_mapping: true,
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def build_semantic_validation_result(filename, svg_conform_report,
|
|
74
|
+
svgcheck_report)
|
|
75
|
+
validation_comparison = SvgConform::SemanticComparator.compare_validation_results(
|
|
76
|
+
svg_conform_report,
|
|
77
|
+
svgcheck_report,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
ComparisonResult.new(
|
|
81
|
+
filename: filename,
|
|
82
|
+
type: :semantic_validation,
|
|
83
|
+
validation_comparison: validation_comparison,
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def build_basic_validation_result(filename, svg_conform_report,
|
|
88
|
+
svgcheck_report)
|
|
89
|
+
ComparisonResult.new(
|
|
90
|
+
filename: filename,
|
|
91
|
+
type: :basic_validation,
|
|
92
|
+
svg_conform_result: svg_conform_report,
|
|
93
|
+
svgcheck_result: svgcheck_report,
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def build_semantic_repair_result(filename, svg_conform_result,
|
|
98
|
+
svgcheck_report)
|
|
99
|
+
svg_conform_report = svg_conform_result.generate_conformance_report
|
|
100
|
+
validation_comparison = SvgConform::SemanticComparator.compare_validation_results(
|
|
101
|
+
svg_conform_report,
|
|
102
|
+
svgcheck_report,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
content_comparison = build_content_comparison(svg_conform_result,
|
|
106
|
+
svgcheck_report)
|
|
107
|
+
xml_equivalence = build_xml_equivalence(filename, svg_conform_result)
|
|
108
|
+
|
|
109
|
+
ComparisonResult.new(
|
|
110
|
+
filename: filename,
|
|
111
|
+
type: :semantic_repair,
|
|
112
|
+
validation_comparison: validation_comparison,
|
|
113
|
+
content_comparison: content_comparison,
|
|
114
|
+
xml_equivalence: xml_equivalence,
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def build_basic_repair_result(filename, svg_conform_result,
|
|
119
|
+
svgcheck_report)
|
|
120
|
+
ComparisonResult.new(
|
|
121
|
+
filename: filename,
|
|
122
|
+
type: :basic_repair,
|
|
123
|
+
svg_conform_result: svg_conform_result,
|
|
124
|
+
svgcheck_result: svgcheck_report,
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def build_content_comparison(svg_conform_result, svgcheck_report)
|
|
129
|
+
return nil unless svgcheck_report.respond_to?(:remediated_content) &&
|
|
130
|
+
svg_conform_result.remediated_content
|
|
131
|
+
|
|
132
|
+
SvgConform::SemanticComparator.compare_remediated_content(
|
|
133
|
+
svg_conform_result.remediated_content,
|
|
134
|
+
svgcheck_report.remediated_content,
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def build_xml_equivalence(filename, svg_conform_result)
|
|
139
|
+
return nil unless svg_conform_result.remediated_content
|
|
140
|
+
|
|
141
|
+
unless @file_processor.svgcheck_repaired_file_exists?(filename)
|
|
142
|
+
return {
|
|
143
|
+
error: "Svgcheck repaired file not found: #{@file_processor.svgcheck_repaired_file_path(filename)}",
|
|
144
|
+
xml_equivalent: false,
|
|
145
|
+
}
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
begin
|
|
149
|
+
svgcheck_content = @file_processor.read_svgcheck_repaired_content(filename)
|
|
150
|
+
compare_xml_content(svg_conform_result.remediated_content,
|
|
151
|
+
svgcheck_content)
|
|
152
|
+
rescue StandardError => e
|
|
153
|
+
{
|
|
154
|
+
error: "Error comparing XML files: #{e.message}",
|
|
155
|
+
xml_equivalent: false,
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def compare_xml_content(svg_conform_content, svgcheck_content)
|
|
161
|
+
require "equivalent-xml"
|
|
162
|
+
|
|
163
|
+
xml_equivalent = EquivalentXml.equivalent?(svg_conform_content, svgcheck_content, {
|
|
164
|
+
element_order: false,
|
|
165
|
+
normalize_whitespace: true,
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
if xml_equivalent
|
|
169
|
+
{
|
|
170
|
+
xml_equivalent: true,
|
|
171
|
+
differences: [],
|
|
172
|
+
}
|
|
173
|
+
else
|
|
174
|
+
differences = analyze_xml_differences(svg_conform_content,
|
|
175
|
+
svgcheck_content)
|
|
176
|
+
{
|
|
177
|
+
xml_equivalent: false,
|
|
178
|
+
differences: differences,
|
|
179
|
+
}
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def analyze_xml_differences(svg_conform_content, svgcheck_content)
|
|
184
|
+
differences = []
|
|
185
|
+
|
|
186
|
+
begin
|
|
187
|
+
require "moxml"
|
|
188
|
+
moxml = Moxml.new
|
|
189
|
+
|
|
190
|
+
svg_conform_doc = moxml.parse(svg_conform_content)
|
|
191
|
+
svgcheck_doc = moxml.parse(svgcheck_content)
|
|
192
|
+
|
|
193
|
+
svg_conform_root = svg_conform_doc.root
|
|
194
|
+
svgcheck_root = svgcheck_doc.root
|
|
195
|
+
|
|
196
|
+
# Compare element names
|
|
197
|
+
if svg_conform_root.name != svgcheck_root.name
|
|
198
|
+
differences << {
|
|
199
|
+
type: :root_element_name,
|
|
200
|
+
svg_conform: svg_conform_root.name,
|
|
201
|
+
svgcheck: svgcheck_root.name,
|
|
202
|
+
}
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Compare attributes and children recursively
|
|
206
|
+
differences.concat(compare_element_attributes(svg_conform_root,
|
|
207
|
+
svgcheck_root))
|
|
208
|
+
differences.concat(compare_child_elements(svg_conform_root,
|
|
209
|
+
svgcheck_root))
|
|
210
|
+
rescue StandardError => e
|
|
211
|
+
differences << {
|
|
212
|
+
type: :parsing_error,
|
|
213
|
+
error: e.message,
|
|
214
|
+
}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
differences
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def compare_element_attributes(elem1, elem2)
|
|
221
|
+
differences = []
|
|
222
|
+
attrs1 = normalize_attributes(elem1.attributes)
|
|
223
|
+
attrs2 = normalize_attributes(elem2.attributes)
|
|
224
|
+
all_attr_names = (attrs1.keys + attrs2.keys).uniq
|
|
225
|
+
|
|
226
|
+
all_attr_names.each do |attr_name|
|
|
227
|
+
val1 = attrs1[attr_name]
|
|
228
|
+
val2 = attrs2[attr_name]
|
|
229
|
+
|
|
230
|
+
next unless val1 != val2
|
|
231
|
+
|
|
232
|
+
differences << {
|
|
233
|
+
type: :attribute_difference,
|
|
234
|
+
element: elem1.name,
|
|
235
|
+
attribute: attr_name,
|
|
236
|
+
svg_conform: val1,
|
|
237
|
+
svgcheck: val2,
|
|
238
|
+
}
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
differences
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def normalize_attributes(attributes)
|
|
245
|
+
return {} if attributes.nil?
|
|
246
|
+
|
|
247
|
+
case attributes
|
|
248
|
+
when Hash
|
|
249
|
+
attributes
|
|
250
|
+
when Array
|
|
251
|
+
attributes.each_with_object({}) do |attr, hash|
|
|
252
|
+
if attr.respond_to?(:name) && attr.respond_to?(:value)
|
|
253
|
+
hash[attr.name] = attr.value
|
|
254
|
+
elsif attr.is_a?(Array) && attr.length == 2
|
|
255
|
+
hash[attr[0]] = attr[1]
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
else
|
|
259
|
+
{}
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def compare_child_elements(elem1, elem2)
|
|
264
|
+
differences = []
|
|
265
|
+
children1 = elem1.children.select { |child| child.respond_to?(:name) }
|
|
266
|
+
children2 = elem2.children.select { |child| child.respond_to?(:name) }
|
|
267
|
+
|
|
268
|
+
if children1.length != children2.length
|
|
269
|
+
differences << {
|
|
270
|
+
type: :child_count_difference,
|
|
271
|
+
element: elem1.name,
|
|
272
|
+
svg_conform_count: children1.length,
|
|
273
|
+
svgcheck_count: children2.length,
|
|
274
|
+
}
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
max_children = [children1.length, children2.length].max
|
|
278
|
+
(0...max_children).each do |i|
|
|
279
|
+
child1 = children1[i]
|
|
280
|
+
child2 = children2[i]
|
|
281
|
+
|
|
282
|
+
if child1 && child2
|
|
283
|
+
if child1.name == child2.name
|
|
284
|
+
differences.concat(compare_element_attributes(child1, child2))
|
|
285
|
+
differences.concat(compare_child_elements(child1, child2))
|
|
286
|
+
else
|
|
287
|
+
differences << {
|
|
288
|
+
type: :child_element_name,
|
|
289
|
+
parent: elem1.name,
|
|
290
|
+
position: i,
|
|
291
|
+
svg_conform: child1.name,
|
|
292
|
+
svgcheck: child2.name,
|
|
293
|
+
}
|
|
294
|
+
end
|
|
295
|
+
elsif child1
|
|
296
|
+
differences << {
|
|
297
|
+
type: :extra_child_svg_conform,
|
|
298
|
+
parent: elem1.name,
|
|
299
|
+
position: i,
|
|
300
|
+
element: child1.name,
|
|
301
|
+
}
|
|
302
|
+
elsif child2
|
|
303
|
+
differences << {
|
|
304
|
+
type: :extra_child_svgcheck,
|
|
305
|
+
parent: elem1.name,
|
|
306
|
+
position: i,
|
|
307
|
+
element: child2.name,
|
|
308
|
+
}
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
differences
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|