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.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rake.yml +15 -0
  3. data/.github/workflows/release.yml +23 -0
  4. data/.github/workflows/svgcheck-compatibility.yml +135 -0
  5. data/.gitignore +12 -0
  6. data/.rspec +3 -0
  7. data/.rubocop.yml +13 -0
  8. data/.rubocop_todo.yml +183 -0
  9. data/CODE_OF_CONDUCT.md +132 -0
  10. data/Gemfile +14 -0
  11. data/README.adoc +1384 -0
  12. data/Rakefile +15 -0
  13. data/config/profiles/base.yml +34 -0
  14. data/config/profiles/lucid_fix.yml +37 -0
  15. data/config/profiles/metanorma.yml +212 -0
  16. data/config/profiles/no_external_css.yml +20 -0
  17. data/config/profiles/svg_1_2_rfc.yml +284 -0
  18. data/config/profiles/svg_1_2_rfc_with_rdf.yml +145 -0
  19. data/config/svgcheck_mapping.yml +180 -0
  20. data/docs/profiles.adoc +547 -0
  21. data/docs/rdf_metadata_support.adoc +212 -0
  22. data/docs/remediation.adoc +732 -0
  23. data/docs/requirements.adoc +709 -0
  24. data/examples/demo.rb +116 -0
  25. data/examples/requirements_demo.rb +240 -0
  26. data/exe/svg_conform +7 -0
  27. data/lib/svg_conform/batch_report.rb +70 -0
  28. data/lib/svg_conform/cli.rb +107 -0
  29. data/lib/svg_conform/commands/check.rb +390 -0
  30. data/lib/svg_conform/commands/profiles.rb +118 -0
  31. data/lib/svg_conform/commands/svgcheck.rb +90 -0
  32. data/lib/svg_conform/commands/svgcheck_compare.rb +92 -0
  33. data/lib/svg_conform/commands/svgcheck_compatibility.rb +43 -0
  34. data/lib/svg_conform/commands/svgcheck_generate.rb +262 -0
  35. data/lib/svg_conform/compatibility/analysis_context.rb +68 -0
  36. data/lib/svg_conform/compatibility/comparison_result.rb +147 -0
  37. data/lib/svg_conform/compatibility/compatibility_analyzer.rb +85 -0
  38. data/lib/svg_conform/compatibility/file_processor.rb +109 -0
  39. data/lib/svg_conform/compatibility/pattern_discovery.rb +319 -0
  40. data/lib/svg_conform/compatibility/report_formatter.rb +359 -0
  41. data/lib/svg_conform/compatibility/svg_analysis_engine.rb +316 -0
  42. data/lib/svg_conform/compatibility/validity_analysis.rb +252 -0
  43. data/lib/svg_conform/compatibility/xml_analysis_engine.rb +198 -0
  44. data/lib/svg_conform/compatibility_analyzer.rb +285 -0
  45. data/lib/svg_conform/conformance_report.rb +267 -0
  46. data/lib/svg_conform/constants.rb +199 -0
  47. data/lib/svg_conform/css_color.rb +262 -0
  48. data/lib/svg_conform/document.rb +203 -0
  49. data/lib/svg_conform/external_checkers/svgcheck/compatibility_engine.rb +166 -0
  50. data/lib/svg_conform/external_checkers/svgcheck/output_generator.rb +101 -0
  51. data/lib/svg_conform/external_checkers/svgcheck/parser.rb +200 -0
  52. data/lib/svg_conform/external_checkers/svgcheck/report_comparator.rb +175 -0
  53. data/lib/svg_conform/external_checkers/svgcheck/report_generator.rb +82 -0
  54. data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +249 -0
  55. data/lib/svg_conform/external_checkers/svgcheck.rb +56 -0
  56. data/lib/svg_conform/external_checkers.rb +34 -0
  57. data/lib/svg_conform/fixer.rb +56 -0
  58. data/lib/svg_conform/profile.rb +164 -0
  59. data/lib/svg_conform/profiles.rb +60 -0
  60. data/lib/svg_conform/remediation_engine.rb +92 -0
  61. data/lib/svg_conform/remediation_result.rb +36 -0
  62. data/lib/svg_conform/remediation_runner.rb +225 -0
  63. data/lib/svg_conform/remediations/base_remediation.rb +165 -0
  64. data/lib/svg_conform/remediations/color_remediation.rb +226 -0
  65. data/lib/svg_conform/remediations/font_embedding_remediation.rb +145 -0
  66. data/lib/svg_conform/remediations/font_remediation.rb +122 -0
  67. data/lib/svg_conform/remediations/image_embedding_remediation.rb +154 -0
  68. data/lib/svg_conform/remediations/invalid_id_references_remediation.rb +129 -0
  69. data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +244 -0
  70. data/lib/svg_conform/remediations/namespace_remediation.rb +151 -0
  71. data/lib/svg_conform/remediations/no_external_css_remediation.rb +192 -0
  72. data/lib/svg_conform/remediations/style_promotion_remediation.rb +93 -0
  73. data/lib/svg_conform/remediations/viewbox_remediation.rb +127 -0
  74. data/lib/svg_conform/remediations.rb +40 -0
  75. data/lib/svg_conform/report_comparator.rb +772 -0
  76. data/lib/svg_conform/requirements/allowed_elements_requirement.rb +367 -0
  77. data/lib/svg_conform/requirements/base_requirement.rb +98 -0
  78. data/lib/svg_conform/requirements/color_restrictions_requirement.rb +126 -0
  79. data/lib/svg_conform/requirements/element_requirement_config.rb +75 -0
  80. data/lib/svg_conform/requirements/font_family_requirement.rb +133 -0
  81. data/lib/svg_conform/requirements/forbidden_content_requirement.rb +60 -0
  82. data/lib/svg_conform/requirements/id_reference_requirement.rb +133 -0
  83. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +132 -0
  84. data/lib/svg_conform/requirements/link_validation_requirement.rb +55 -0
  85. data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +211 -0
  86. data/lib/svg_conform/requirements/namespace_requirement.rb +294 -0
  87. data/lib/svg_conform/requirements/no_external_css_requirement.rb +132 -0
  88. data/lib/svg_conform/requirements/no_external_fonts_requirement.rb +121 -0
  89. data/lib/svg_conform/requirements/no_external_images_requirement.rb +91 -0
  90. data/lib/svg_conform/requirements/style_promotion_requirement.rb +72 -0
  91. data/lib/svg_conform/requirements/style_requirement.rb +226 -0
  92. data/lib/svg_conform/requirements/viewbox_required_requirement.rb +96 -0
  93. data/lib/svg_conform/requirements.rb +49 -0
  94. data/lib/svg_conform/semantic_comparator.rb +829 -0
  95. data/lib/svg_conform/validation_context.rb +408 -0
  96. data/lib/svg_conform/validation_result.rb +146 -0
  97. data/lib/svg_conform/validator.rb +91 -0
  98. data/lib/svg_conform/version.rb +5 -0
  99. data/lib/svg_conform.rb +68 -0
  100. data/lib/tasks/fixtures.rake +321 -0
  101. data/lib/tasks/svgcheck.rake +111 -0
  102. data/reference-docs/SVG-1.2-RFC.rnc.txt +1676 -0
  103. data/reference-docs/Scalable Vector Graphics (SVG) 1.1 (Second Edition).html +40764 -0
  104. data/reference-docs/Scalable Vector Graphics (SVG) Tiny 1.2 Specification.html +44591 -0
  105. data/reference-docs/rfc7996.txt +2971 -0
  106. data/sig/svg_conform.rbs +4 -0
  107. data/spec/fixtures/allowed_elements/inputs/basic_violations.svg +21 -0
  108. data/spec/fixtures/allowed_elements/repair/basic_violations.svg +18 -0
  109. data/spec/fixtures/color_restrictions/inputs/basic_violations.svg +23 -0
  110. data/spec/fixtures/color_restrictions/repair/basic_violations.svg +23 -0
  111. data/spec/fixtures/comprehensive/inputs/multiple_violations.svg +21 -0
  112. data/spec/fixtures/comprehensive/repair/multiple_violations.svg +16 -0
  113. data/spec/fixtures/font_family/inputs/basic_violations.svg +17 -0
  114. data/spec/fixtures/font_family/repair/basic_violations.svg +17 -0
  115. data/spec/fixtures/forbidden_content/inputs/basic_violations.svg +27 -0
  116. data/spec/fixtures/forbidden_content/repair/basic_violations.svg +19 -0
  117. data/spec/fixtures/id_reference/inputs/basic_violations.svg +17 -0
  118. data/spec/fixtures/id_reference/repair/basic_violations.svg +15 -0
  119. data/spec/fixtures/link_validation/inputs/basic_violations.svg +20 -0
  120. data/spec/fixtures/link_validation/repair/basic_violations.svg +16 -0
  121. data/spec/fixtures/lucid/inputs/simple.svg +67 -0
  122. data/spec/fixtures/lucid/repair/simple.svg +63 -0
  123. data/spec/fixtures/namespace/inputs/basic_violations.svg +20 -0
  124. data/spec/fixtures/namespace/repair/basic_violations.svg +17 -0
  125. data/spec/fixtures/namespace_attributes/inputs/basic_violations.svg +16 -0
  126. data/spec/fixtures/namespace_attributes/repair/basic_violations.svg +15 -0
  127. data/spec/fixtures/no_external_css/inputs/basic_violations.svg +20 -0
  128. data/spec/fixtures/no_external_css/repair/basic_violations.svg +18 -0
  129. data/spec/fixtures/style/inputs/basic_violations.svg +22 -0
  130. data/spec/fixtures/style/repair/basic_violations.svg +22 -0
  131. data/spec/fixtures/style_promotion/inputs/basic_test.svg +15 -0
  132. data/spec/fixtures/style_promotion/repair/basic_test.svg +15 -0
  133. data/spec/fixtures/svg_1_2_rfc/inputs/allowed_elements_violations.svg +18 -0
  134. data/spec/fixtures/svg_1_2_rfc/inputs/color_restrictions_violations.svg +23 -0
  135. data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.code +1 -0
  136. data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.err +0 -0
  137. data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.out +23 -0
  138. data/spec/fixtures/svgcheck/check/IETF-test.svg.code +1 -0
  139. data/spec/fixtures/svgcheck/check/IETF-test.svg.err +0 -0
  140. data/spec/fixtures/svgcheck/check/IETF-test.svg.out +20 -0
  141. data/spec/fixtures/svgcheck/check/circle.svg.code +1 -0
  142. data/spec/fixtures/svgcheck/check/circle.svg.err +0 -0
  143. data/spec/fixtures/svgcheck/check/circle.svg.out +2 -0
  144. data/spec/fixtures/svgcheck/check/colors.svg.code +1 -0
  145. data/spec/fixtures/svgcheck/check/colors.svg.err +0 -0
  146. data/spec/fixtures/svgcheck/check/colors.svg.out +13 -0
  147. data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.code +1 -0
  148. data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.err +0 -0
  149. data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.out +76 -0
  150. data/spec/fixtures/svgcheck/check/example-dot.svg.code +1 -0
  151. data/spec/fixtures/svgcheck/check/example-dot.svg.err +0 -0
  152. data/spec/fixtures/svgcheck/check/example-dot.svg.out +11 -0
  153. data/spec/fixtures/svgcheck/check/full-tiny.svg.code +1 -0
  154. data/spec/fixtures/svgcheck/check/full-tiny.svg.err +0 -0
  155. data/spec/fixtures/svgcheck/check/full-tiny.svg.out +5835 -0
  156. data/spec/fixtures/svgcheck/check/good.svg.code +1 -0
  157. data/spec/fixtures/svgcheck/check/good.svg.err +0 -0
  158. data/spec/fixtures/svgcheck/check/good.svg.out +1 -0
  159. data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.code +1 -0
  160. data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.err +0 -0
  161. data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.out +5 -0
  162. data/spec/fixtures/svgcheck/check/malformed.svg.code +1 -0
  163. data/spec/fixtures/svgcheck/check/malformed.svg.err +0 -0
  164. data/spec/fixtures/svgcheck/check/malformed.svg.out +8 -0
  165. data/spec/fixtures/svgcheck/check/rfc-svg.svg.code +1 -0
  166. data/spec/fixtures/svgcheck/check/rfc-svg.svg.err +0 -0
  167. data/spec/fixtures/svgcheck/check/rfc-svg.svg.out +1 -0
  168. data/spec/fixtures/svgcheck/check/rfc.xml.code +1 -0
  169. data/spec/fixtures/svgcheck/check/rfc.xml.err +0 -0
  170. data/spec/fixtures/svgcheck/check/rfc.xml.out +2 -0
  171. data/spec/fixtures/svgcheck/check/rgb.svg.code +1 -0
  172. data/spec/fixtures/svgcheck/check/rgb.svg.err +0 -0
  173. data/spec/fixtures/svgcheck/check/rgb.svg.out +9 -0
  174. data/spec/fixtures/svgcheck/check/svg-wordle.svg.code +1 -0
  175. data/spec/fixtures/svgcheck/check/svg-wordle.svg.err +0 -0
  176. data/spec/fixtures/svgcheck/check/svg-wordle.svg.out +508 -0
  177. data/spec/fixtures/svgcheck/check/threshold.svg.code +1 -0
  178. data/spec/fixtures/svgcheck/check/threshold.svg.err +0 -0
  179. data/spec/fixtures/svgcheck/check/threshold.svg.out +20 -0
  180. data/spec/fixtures/svgcheck/check/utf8.svg.code +1 -0
  181. data/spec/fixtures/svgcheck/check/utf8.svg.err +0 -0
  182. data/spec/fixtures/svgcheck/check/utf8.svg.out +162 -0
  183. data/spec/fixtures/svgcheck/check/viewBox-both.svg.code +1 -0
  184. data/spec/fixtures/svgcheck/check/viewBox-both.svg.err +0 -0
  185. data/spec/fixtures/svgcheck/check/viewBox-both.svg.out +4 -0
  186. data/spec/fixtures/svgcheck/check/viewBox-height.svg.code +1 -0
  187. data/spec/fixtures/svgcheck/check/viewBox-height.svg.err +0 -0
  188. data/spec/fixtures/svgcheck/check/viewBox-height.svg.out +3 -0
  189. data/spec/fixtures/svgcheck/check/viewBox-none.svg.code +1 -0
  190. data/spec/fixtures/svgcheck/check/viewBox-none.svg.err +0 -0
  191. data/spec/fixtures/svgcheck/check/viewBox-none.svg.out +3 -0
  192. data/spec/fixtures/svgcheck/check/viewBox-width.svg.code +1 -0
  193. data/spec/fixtures/svgcheck/check/viewBox-width.svg.err +0 -0
  194. data/spec/fixtures/svgcheck/check/viewBox-width.svg.out +3 -0
  195. data/spec/fixtures/svgcheck/inputs/DrawBerry-sample-2.svg +28 -0
  196. data/spec/fixtures/svgcheck/inputs/IETF-test.svg +28 -0
  197. data/spec/fixtures/svgcheck/inputs/circle.svg +3 -0
  198. data/spec/fixtures/svgcheck/inputs/colors.svg +18 -0
  199. data/spec/fixtures/svgcheck/inputs/dia-sample-svg.svg +47 -0
  200. data/spec/fixtures/svgcheck/inputs/example-dot.svg +75 -0
  201. data/spec/fixtures/svgcheck/inputs/full-tiny.svg +16194 -0
  202. data/spec/fixtures/svgcheck/inputs/good.svg +19 -0
  203. data/spec/fixtures/svgcheck/inputs/httpbis-proxy20-fig6.svg +2 -0
  204. data/spec/fixtures/svgcheck/inputs/malformed.svg +11 -0
  205. data/spec/fixtures/svgcheck/inputs/rfc-svg.svg +1028 -0
  206. data/spec/fixtures/svgcheck/inputs/rfc.xml +37 -0
  207. data/spec/fixtures/svgcheck/inputs/rgb.svg +9 -0
  208. data/spec/fixtures/svgcheck/inputs/svg-wordle.svg +330 -0
  209. data/spec/fixtures/svgcheck/inputs/threshold.svg +26 -0
  210. data/spec/fixtures/svgcheck/inputs/utf8.svg +448 -0
  211. data/spec/fixtures/svgcheck/inputs/viewBox-both.svg +3 -0
  212. data/spec/fixtures/svgcheck/inputs/viewBox-height.svg +3 -0
  213. data/spec/fixtures/svgcheck/inputs/viewBox-none.svg +3 -0
  214. data/spec/fixtures/svgcheck/inputs/viewBox-width.svg +3 -0
  215. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.code +1 -0
  216. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.err +0 -0
  217. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.file +0 -0
  218. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.out +23 -0
  219. data/spec/fixtures/svgcheck/repair/IETF-test.svg.code +1 -0
  220. data/spec/fixtures/svgcheck/repair/IETF-test.svg.err +0 -0
  221. data/spec/fixtures/svgcheck/repair/IETF-test.svg.file +29 -0
  222. data/spec/fixtures/svgcheck/repair/IETF-test.svg.out +20 -0
  223. data/spec/fixtures/svgcheck/repair/circle.svg.code +1 -0
  224. data/spec/fixtures/svgcheck/repair/circle.svg.err +0 -0
  225. data/spec/fixtures/svgcheck/repair/circle.svg.file +4 -0
  226. data/spec/fixtures/svgcheck/repair/circle.svg.out +2 -0
  227. data/spec/fixtures/svgcheck/repair/colors.svg.code +1 -0
  228. data/spec/fixtures/svgcheck/repair/colors.svg.err +0 -0
  229. data/spec/fixtures/svgcheck/repair/colors.svg.file +19 -0
  230. data/spec/fixtures/svgcheck/repair/colors.svg.out +13 -0
  231. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.code +1 -0
  232. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.err +0 -0
  233. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.file +47 -0
  234. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.out +76 -0
  235. data/spec/fixtures/svgcheck/repair/example-dot.svg.code +1 -0
  236. data/spec/fixtures/svgcheck/repair/example-dot.svg.err +0 -0
  237. data/spec/fixtures/svgcheck/repair/example-dot.svg.file +69 -0
  238. data/spec/fixtures/svgcheck/repair/example-dot.svg.out +11 -0
  239. data/spec/fixtures/svgcheck/repair/good.svg.code +1 -0
  240. data/spec/fixtures/svgcheck/repair/good.svg.err +0 -0
  241. data/spec/fixtures/svgcheck/repair/good.svg.file +0 -0
  242. data/spec/fixtures/svgcheck/repair/good.svg.out +1 -0
  243. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.code +1 -0
  244. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.err +0 -0
  245. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.file +73 -0
  246. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.out +5 -0
  247. data/spec/fixtures/svgcheck/repair/malformed.svg.code +1 -0
  248. data/spec/fixtures/svgcheck/repair/malformed.svg.err +0 -0
  249. data/spec/fixtures/svgcheck/repair/malformed.svg.file +9 -0
  250. data/spec/fixtures/svgcheck/repair/malformed.svg.out +8 -0
  251. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.code +1 -0
  252. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.err +0 -0
  253. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.file +0 -0
  254. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.out +1 -0
  255. data/spec/fixtures/svgcheck/repair/rfc.xml.code +1 -0
  256. data/spec/fixtures/svgcheck/repair/rfc.xml.err +0 -0
  257. data/spec/fixtures/svgcheck/repair/rfc.xml.file +37 -0
  258. data/spec/fixtures/svgcheck/repair/rfc.xml.out +2 -0
  259. data/spec/fixtures/svgcheck/repair/rgb.svg.code +1 -0
  260. data/spec/fixtures/svgcheck/repair/rgb.svg.err +0 -0
  261. data/spec/fixtures/svgcheck/repair/rgb.svg.file +10 -0
  262. data/spec/fixtures/svgcheck/repair/rgb.svg.out +9 -0
  263. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.code +1 -0
  264. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.err +0 -0
  265. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.file +112 -0
  266. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.out +508 -0
  267. data/spec/fixtures/svgcheck/repair/threshold.svg.code +1 -0
  268. data/spec/fixtures/svgcheck/repair/threshold.svg.err +0 -0
  269. data/spec/fixtures/svgcheck/repair/threshold.svg.file +27 -0
  270. data/spec/fixtures/svgcheck/repair/threshold.svg.out +20 -0
  271. data/spec/fixtures/svgcheck/repair/utf8.svg.code +1 -0
  272. data/spec/fixtures/svgcheck/repair/utf8.svg.err +0 -0
  273. data/spec/fixtures/svgcheck/repair/utf8.svg.file +381 -0
  274. data/spec/fixtures/svgcheck/repair/utf8.svg.out +162 -0
  275. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.code +1 -0
  276. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.err +0 -0
  277. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.file +4 -0
  278. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.out +4 -0
  279. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.code +1 -0
  280. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.err +0 -0
  281. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.file +4 -0
  282. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.out +3 -0
  283. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.code +1 -0
  284. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.err +0 -0
  285. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.file +4 -0
  286. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.out +3 -0
  287. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.code +1 -0
  288. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.err +0 -0
  289. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.file +4 -0
  290. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.out +3 -0
  291. data/spec/fixtures/viewbox_required/inputs/missing_viewbox.svg +10 -0
  292. data/spec/fixtures/viewbox_required/repair/missing_viewbox.svg +10 -0
  293. data/spec/spec_helper.rb +16 -0
  294. data/spec/svg_conform/batch_report_spec.rb +99 -0
  295. data/spec/svg_conform/commands/check_command_spec.rb +90 -0
  296. data/spec/svg_conform/commands/profiles_command_spec.rb +20 -0
  297. data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +13 -0
  298. data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +13 -0
  299. data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +14 -0
  300. data/spec/svg_conform/profiles/base_profile_spec.rb +42 -0
  301. data/spec/svg_conform/profiles/lucid_fix_profile_spec.rb +46 -0
  302. data/spec/svg_conform/profiles/lucid_profile_spec.rb +84 -0
  303. data/spec/svg_conform/profiles/metanorma_profile_spec.rb +62 -0
  304. data/spec/svg_conform/profiles/no_external_css_profile_spec.rb +66 -0
  305. data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +200 -0
  306. data/spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb +81 -0
  307. data/spec/svg_conform/remediations/color_remediation_spec.rb +95 -0
  308. data/spec/svg_conform/remediations/font_embedding_remediation_spec.rb +20 -0
  309. data/spec/svg_conform/remediations/font_remediation_spec.rb +95 -0
  310. data/spec/svg_conform/remediations/image_embedding_remediation_spec.rb +20 -0
  311. data/spec/svg_conform/remediations/invalid_id_references_remediation_spec.rb +97 -0
  312. data/spec/svg_conform/remediations/namespace_attribute_remediation_spec.rb +97 -0
  313. data/spec/svg_conform/remediations/namespace_remediation_spec.rb +95 -0
  314. data/spec/svg_conform/remediations/no_external_css_remediation_spec.rb +97 -0
  315. data/spec/svg_conform/remediations/style_promotion_remediation_spec.rb +97 -0
  316. data/spec/svg_conform/remediations/viewbox_remediation_spec.rb +95 -0
  317. data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +118 -0
  318. data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +168 -0
  319. data/spec/svg_conform/requirements/font_family_requirement_spec.rb +188 -0
  320. data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +195 -0
  321. data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +78 -0
  322. data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +78 -0
  323. data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +78 -0
  324. data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +86 -0
  325. data/spec/svg_conform/requirements/namespace_requirement_spec.rb +184 -0
  326. data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +78 -0
  327. data/spec/svg_conform/requirements/no_external_fonts_requirement_spec.rb +20 -0
  328. data/spec/svg_conform/requirements/no_external_images_requirement_spec.rb +20 -0
  329. data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +78 -0
  330. data/spec/svg_conform/requirements/style_requirement_spec.rb +76 -0
  331. data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +165 -0
  332. data/spec/svg_conform_spec.rb +32 -0
  333. data/spec/svgcheck_compatibility_spec.rb +355 -0
  334. data/svg_conform.gemspec +35 -0
  335. metadata +436 -0
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "canon"
5
+
6
+ RSpec.describe SvgConform::Requirements::ColorRestrictionsRequirement do
7
+ let(:fixtures_dir) { "spec/fixtures/color_restrictions" }
8
+
9
+ # Get all fixture files that have both input and expected repair versions
10
+ fixture_files = Dir.glob("spec/fixtures/color_restrictions/inputs/*.svg").select do |input_file|
11
+ basename = File.basename(input_file)
12
+ File.exist?("spec/fixtures/color_restrictions/repair/#{basename}")
13
+ end.map do |f|
14
+ File.basename(f, ".svg")
15
+ end
16
+
17
+ fixture_files.each do |fixture_name|
18
+ describe "fixture: #{fixture_name}" do
19
+ let(:input_file) do
20
+ "spec/fixtures/color_restrictions/inputs/#{fixture_name}.svg"
21
+ end
22
+ let(:expected_output_file) do
23
+ "spec/fixtures/color_restrictions/repair/#{fixture_name}.svg"
24
+ end
25
+
26
+ it "validates input file and identifies color violations" do
27
+ skip "Input file not found" unless File.exist?(input_file)
28
+
29
+ document = SvgConform::Document.from_file(input_file)
30
+ requirement = described_class.new(
31
+ id: "color_restrictions",
32
+ description: "Test color restrictions requirement",
33
+ allowed_colors: %w[black white],
34
+ )
35
+
36
+ context = SvgConform::ValidationContext.new(document, nil)
37
+ requirement.validate_document(document, context)
38
+
39
+ expect(context.errors).not_to be_empty
40
+ puts "Found #{context.errors.count} color violations in #{fixture_name}"
41
+
42
+ context.errors.each do |error|
43
+ expect(error.requirement_id).to eq("color_restrictions")
44
+ expect(error.message).to be_a(String)
45
+ expect(error.message).not_to be_empty
46
+ end
47
+ end
48
+
49
+ it "correctly identifies specific color violations" do
50
+ skip "Input file not found" unless File.exist?(input_file)
51
+
52
+ document = SvgConform::Document.from_file(input_file)
53
+ requirement = described_class.new(
54
+ id: "color_restrictions",
55
+ description: "Test color restrictions requirement",
56
+ grayscale_only: true,
57
+ allowed_colors: %w[black white gray grey silver],
58
+ )
59
+
60
+ context = SvgConform::ValidationContext.new(document, nil)
61
+ requirement.validate_document(document, context)
62
+
63
+ # Check that errors are specific to invalid colors
64
+ context.errors.each do |error|
65
+ expect(error.message).to match(/color|fill|stroke/i)
66
+ end
67
+ end
68
+
69
+ it "passes validation for documents with only allowed colors" do
70
+ # Create a simple valid document for testing
71
+ valid_svg = <<~SVG
72
+ <?xml version="1.0"?>
73
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
74
+ <rect x="10" y="10" width="20" height="20" fill="black" stroke="white"/>
75
+ <circle cx="50" cy="50" r="10" fill="black"/>
76
+ <text x="10" y="80" fill="white">Test</text>
77
+ </svg>
78
+ SVG
79
+
80
+ document = SvgConform::Document.from_content(valid_svg)
81
+ requirement = described_class.new(
82
+ id: "color_restrictions",
83
+ description: "Test color restrictions requirement",
84
+ allowed_colors: %w[black white],
85
+ )
86
+
87
+ context = SvgConform::ValidationContext.new(document, nil)
88
+ requirement.validate_document(document, context)
89
+
90
+ expect(context.errors).to be_empty
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "configuration" do
96
+ it "accepts custom allowed colors list" do
97
+ requirement = described_class.new(
98
+ id: "test_color_restrictions",
99
+ description: "Test with custom colors",
100
+ allowed_colors: %w[red green blue],
101
+ )
102
+
103
+ expect(requirement.allowed_colors).to eq(%w[red green blue])
104
+ end
105
+
106
+ it "supports different modes" do
107
+ requirement = described_class.new(
108
+ id: "test_color_restrictions",
109
+ description: "Test mode",
110
+ mode: "custom_mode",
111
+ )
112
+
113
+ expect(requirement.mode).to eq("custom_mode")
114
+ end
115
+
116
+ it "has default mode" do
117
+ requirement = described_class.new(
118
+ id: "test_color_restrictions",
119
+ description: "Test requirement",
120
+ )
121
+
122
+ expect(requirement.mode).to eq("black_white_only")
123
+ end
124
+ end
125
+
126
+ describe "color validation logic" do
127
+ let(:requirement) do
128
+ described_class.new(
129
+ id: "test_color_restrictions",
130
+ description: "Test color restrictions",
131
+ grayscale_only: true,
132
+ allowed_colors: %w[black white gray grey silver],
133
+ )
134
+ end
135
+
136
+ it "detects invalid colors in fill attributes" do
137
+ invalid_svg = <<~SVG
138
+ <?xml version="1.0"?>
139
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
140
+ <rect x="10" y="10" width="20" height="20" fill="red"/>
141
+ </svg>
142
+ SVG
143
+
144
+ document = SvgConform::Document.from_content(invalid_svg)
145
+ context = SvgConform::ValidationContext.new(document, nil)
146
+ requirement.validate_document(document, context)
147
+
148
+ expect(context.errors).not_to be_empty
149
+ expect(context.errors.first.message).to match(/red/i)
150
+ end
151
+
152
+ it "detects invalid colors in stroke attributes" do
153
+ invalid_svg = <<~SVG
154
+ <?xml version="1.0"?>
155
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
156
+ <rect x="10" y="10" width="20" height="20" stroke="blue"/>
157
+ </svg>
158
+ SVG
159
+
160
+ document = SvgConform::Document.from_content(invalid_svg)
161
+ context = SvgConform::ValidationContext.new(document, nil)
162
+ requirement.validate_document(document, context)
163
+
164
+ expect(context.errors).not_to be_empty
165
+ expect(context.errors.first.message).to match(/blue/i)
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "canon"
5
+
6
+ RSpec.describe SvgConform::Requirements::FontFamilyRequirement do
7
+ let(:fixtures_dir) { "spec/fixtures/font_family" }
8
+
9
+ # Get all fixture files that have both input and expected repair versions
10
+ fixture_files = Dir.glob("spec/fixtures/font_family/inputs/*.svg").select do |input_file|
11
+ basename = File.basename(input_file)
12
+ File.exist?("spec/fixtures/font_family/repair/#{basename}")
13
+ end.map do |f|
14
+ File.basename(f, ".svg")
15
+ end
16
+
17
+ fixture_files.each do |fixture_name|
18
+ describe "fixture: #{fixture_name}" do
19
+ let(:input_file) do
20
+ "spec/fixtures/font_family/inputs/#{fixture_name}.svg"
21
+ end
22
+ let(:expected_output_file) do
23
+ "spec/fixtures/font_family/repair/#{fixture_name}.svg"
24
+ end
25
+
26
+ it "validates input file and identifies font family violations" do
27
+ skip "Input file not found" unless File.exist?(input_file)
28
+
29
+ document = SvgConform::Document.from_file(input_file)
30
+ requirement = described_class.new(
31
+ id: "font_family",
32
+ description: "Test font family requirement",
33
+ allowed_families: %w[serif sans-serif monospace],
34
+ default_family: "sans-serif",
35
+ )
36
+
37
+ context = SvgConform::ValidationContext.new(document, nil)
38
+ requirement.validate_document(document, context)
39
+
40
+ expect(context.errors).not_to be_empty
41
+ puts "Found #{context.errors.count} font family violations in #{fixture_name}"
42
+
43
+ context.errors.each do |error|
44
+ expect(error.requirement_id).to eq("font_family")
45
+ expect(error.message).to be_a(String)
46
+ expect(error.message).not_to be_empty
47
+ end
48
+ end
49
+
50
+ it "correctly identifies specific font family violations" do
51
+ skip "Input file not found" unless File.exist?(input_file)
52
+
53
+ document = SvgConform::Document.from_file(input_file)
54
+ requirement = described_class.new(
55
+ id: "font_family",
56
+ description: "Test font family requirement",
57
+ allowed_families: %w[serif sans-serif monospace],
58
+ default_family: "sans-serif",
59
+ )
60
+
61
+ context = SvgConform::ValidationContext.new(document, nil)
62
+ requirement.validate_document(document, context)
63
+
64
+ # Check that errors are specific to invalid font families
65
+ context.errors.each do |error|
66
+ expect(error.message).to match(/font.*family|Invalid font family/i)
67
+ end
68
+ end
69
+
70
+ it "passes validation for documents with only allowed font families" do
71
+ # Create a simple valid document for testing
72
+ valid_svg = <<~SVG
73
+ <?xml version="1.0"?>
74
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
75
+ <text x="10" y="20" font-family="serif">Serif Text</text>
76
+ <text x="10" y="40" font-family="sans-serif">Sans Serif Text</text>
77
+ <text x="10" y="60" font-family="monospace">Monospace Text</text>
78
+ </svg>
79
+ SVG
80
+
81
+ document = SvgConform::Document.from_content(valid_svg)
82
+ requirement = described_class.new(
83
+ id: "font_family",
84
+ description: "Test font family requirement",
85
+ allowed_families: %w[serif sans-serif monospace],
86
+ default_family: "sans-serif",
87
+ )
88
+
89
+ context = SvgConform::ValidationContext.new(document, nil)
90
+ requirement.validate_document(document, context)
91
+
92
+ expect(context.errors).to be_empty
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "configuration" do
98
+ it "accepts custom allowed font families list" do
99
+ requirement = described_class.new(
100
+ id: "test_font_family",
101
+ description: "Test with custom font families",
102
+ allowed_families: %w[Arial Helvetica Times],
103
+ )
104
+
105
+ expect(requirement.allowed_families).to eq(%w[Arial Helvetica Times])
106
+ end
107
+
108
+ it "supports default fallback configuration" do
109
+ requirement = described_class.new(
110
+ id: "test_font_family",
111
+ description: "Test default fallback",
112
+ default_fallback: "serif",
113
+ )
114
+
115
+ expect(requirement.default_fallback).to eq("serif")
116
+ end
117
+
118
+ it "has default allowed families" do
119
+ requirement = described_class.new(
120
+ id: "test_font_family",
121
+ description: "Test requirement",
122
+ )
123
+
124
+ expect(requirement.allowed_families).to eq(%w[serif sans-serif monospace])
125
+ end
126
+ end
127
+
128
+ describe "font family validation logic" do
129
+ let(:requirement) do
130
+ described_class.new(
131
+ id: "test_font_family",
132
+ description: "Test font family requirement",
133
+ allowed_families: %w[serif sans-serif monospace],
134
+ default_family: "sans-serif",
135
+ )
136
+ end
137
+
138
+ it "detects invalid font families in font-family attributes" do
139
+ invalid_svg = <<~SVG
140
+ <?xml version="1.0"?>
141
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
142
+ <text x="10" y="20" font-family="Times New Roman">Invalid Font</text>
143
+ </svg>
144
+ SVG
145
+
146
+ document = SvgConform::Document.from_content(invalid_svg)
147
+ context = SvgConform::ValidationContext.new(document, nil)
148
+ requirement.validate_document(document, context)
149
+
150
+ expect(context.errors).not_to be_empty
151
+ expect(context.errors.first.message).to match(/Times New Roman/i)
152
+ end
153
+
154
+ it "does not check style attributes (handled by StylePromotionRequirement to avoid duplication)" do
155
+ # FontFamilyRequirement only checks font-family attributes
156
+ # Style properties are handled by StylePromotionRequirement
157
+ svg_with_style = <<~SVG
158
+ <?xml version="1.0"?>
159
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
160
+ <text x="10" y="20" style="font-family: Arial">Font in Style</text>
161
+ </svg>
162
+ SVG
163
+
164
+ document = SvgConform::Document.from_content(svg_with_style)
165
+ context = SvgConform::ValidationContext.new(document, nil)
166
+ requirement.validate_document(document, context)
167
+
168
+ # Should not detect errors in style attributes (that's StylePromotionRequirement's job)
169
+ expect(context.errors).to be_empty
170
+ end
171
+
172
+ it "handles font family lists correctly" do
173
+ invalid_svg = <<~SVG
174
+ <?xml version="1.0"?>
175
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
176
+ <text x="10" y="20" font-family="Arial, sans-serif">Mixed Font List</text>
177
+ </svg>
178
+ SVG
179
+
180
+ document = SvgConform::Document.from_content(invalid_svg)
181
+ context = SvgConform::ValidationContext.new(document, nil)
182
+ requirement.validate_document(document, context)
183
+
184
+ expect(context.errors).not_to be_empty
185
+ expect(context.errors.first.message).to match(/Arial/i)
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "canon"
5
+
6
+ RSpec.describe SvgConform::Requirements::ForbiddenContentRequirement do
7
+ let(:fixtures_dir) { "spec/fixtures/forbidden_content" }
8
+
9
+ # Get all fixture files that have both input and expected repair versions
10
+ fixture_files = Dir.glob("spec/fixtures/forbidden_content/inputs/*.svg").select do |input_file|
11
+ basename = File.basename(input_file)
12
+ File.exist?("spec/fixtures/forbidden_content/repair/#{basename}")
13
+ end.map do |f|
14
+ File.basename(f, ".svg")
15
+ end
16
+
17
+ fixture_files.each do |fixture_name|
18
+ describe "fixture: #{fixture_name}" do
19
+ let(:input_file) do
20
+ "spec/fixtures/forbidden_content/inputs/#{fixture_name}.svg"
21
+ end
22
+ let(:expected_output_file) do
23
+ "spec/fixtures/forbidden_content/repair/#{fixture_name}.svg"
24
+ end
25
+
26
+ it "validates input file and identifies forbidden content violations" do
27
+ skip "Input file not found" unless File.exist?(input_file)
28
+
29
+ document = SvgConform::Document.from_file(input_file)
30
+ requirement = described_class.new(
31
+ id: "forbidden_content",
32
+ description: "Test forbidden content requirement",
33
+ forbidden_elements: %w[script audio video animate animateColor],
34
+ forbidden_attributes: %w[onclick onmouseover onload onerror],
35
+ )
36
+
37
+ context = SvgConform::ValidationContext.new(document, nil)
38
+ requirement.validate_document(document, context)
39
+
40
+ expect(context.errors).not_to be_empty
41
+ puts "Found #{context.errors.count} forbidden content violations in #{fixture_name}"
42
+
43
+ context.errors.each do |error|
44
+ expect(error.requirement_id).to eq("forbidden_content")
45
+ expect(error.message).to be_a(String)
46
+ expect(error.message).not_to be_empty
47
+ end
48
+ end
49
+
50
+ it "correctly identifies specific forbidden content violations" do
51
+ skip "Input file not found" unless File.exist?(input_file)
52
+
53
+ document = SvgConform::Document.from_file(input_file)
54
+ requirement = described_class.new(
55
+ id: "forbidden_content",
56
+ description: "Test forbidden content requirement",
57
+ forbidden_elements: %w[script audio video animate animateColor],
58
+ forbidden_attributes: %w[onclick onmouseover onload onerror],
59
+ )
60
+
61
+ context = SvgConform::ValidationContext.new(document, nil)
62
+ requirement.validate_document(document, context)
63
+
64
+ # Check that errors are specific to forbidden elements or attributes
65
+ context.errors.each do |error|
66
+ expect(error.message).to match(/Forbidden.*element|Forbidden.*attribute/i)
67
+ end
68
+ end
69
+
70
+ it "passes validation for documents without forbidden content" do
71
+ # Create a simple valid document for testing
72
+ valid_svg = <<~SVG
73
+ <?xml version="1.0"?>
74
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
75
+ <g>
76
+ <rect x="10" y="10" width="20" height="20" fill="black"/>
77
+ <circle cx="50" cy="50" r="10" fill="black"/>
78
+ <text x="10" y="80">Safe Content</text>
79
+ </g>
80
+ </svg>
81
+ SVG
82
+
83
+ document = SvgConform::Document.from_content(valid_svg)
84
+ requirement = described_class.new(
85
+ id: "forbidden_content",
86
+ description: "Test forbidden content requirement",
87
+ forbidden_elements: %w[script audio video animate animateColor],
88
+ forbidden_attributes: %w[onclick onmouseover onload onerror],
89
+ )
90
+
91
+ context = SvgConform::ValidationContext.new(document, nil)
92
+ requirement.validate_document(document, context)
93
+
94
+ expect(context.errors).to be_empty
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "configuration" do
100
+ it "accepts custom forbidden elements list" do
101
+ requirement = described_class.new(
102
+ id: "test_forbidden_content",
103
+ description: "Test with custom forbidden elements",
104
+ forbidden_elements: %w[script iframe embed],
105
+ )
106
+
107
+ expect(requirement.forbidden_elements).to eq(%w[script iframe embed])
108
+ end
109
+
110
+ it "accepts custom forbidden attributes list" do
111
+ requirement = described_class.new(
112
+ id: "test_forbidden_content",
113
+ description: "Test with custom forbidden attributes",
114
+ forbidden_attributes: %w[onclick onload href],
115
+ )
116
+
117
+ expect(requirement.forbidden_attributes).to eq(%w[onclick onload href])
118
+ end
119
+
120
+ it "can be instantiated with basic parameters" do
121
+ requirement = described_class.new(
122
+ id: "test_forbidden_content",
123
+ description: "Test requirement",
124
+ )
125
+
126
+ expect(requirement).to be_a(described_class)
127
+ end
128
+ end
129
+
130
+ describe "forbidden content validation logic" do
131
+ let(:requirement) do
132
+ described_class.new(
133
+ id: "test_forbidden_content",
134
+ description: "Test forbidden content requirement",
135
+ forbidden_elements: %w[script audio video],
136
+ forbidden_attributes: %w[onclick onmouseover],
137
+ )
138
+ end
139
+
140
+ it "detects forbidden elements" do
141
+ invalid_svg = <<~SVG
142
+ <?xml version="1.0"?>
143
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
144
+ <script>alert('forbidden');</script>
145
+ <rect x="10" y="10" width="20" height="20"/>
146
+ </svg>
147
+ SVG
148
+
149
+ document = SvgConform::Document.from_content(invalid_svg)
150
+ context = SvgConform::ValidationContext.new(document, nil)
151
+ requirement.validate_document(document, context)
152
+
153
+ expect(context.errors).not_to be_empty
154
+ expect(context.errors.first.message).to match(/script/i)
155
+ end
156
+
157
+ it "detects forbidden attributes" do
158
+ invalid_svg = <<~SVG
159
+ <?xml version="1.0"?>
160
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
161
+ <rect x="10" y="10" width="20" height="20" onclick="handleClick()"/>
162
+ </svg>
163
+ SVG
164
+
165
+ document = SvgConform::Document.from_content(invalid_svg)
166
+ context = SvgConform::ValidationContext.new(document, nil)
167
+ requirement.validate_document(document, context)
168
+
169
+ expect(context.errors).not_to be_empty
170
+ expect(context.errors.first.message).to match(/onclick/i)
171
+ end
172
+
173
+ it "detects multiple forbidden items in one document" do
174
+ invalid_svg = <<~SVG
175
+ <?xml version="1.0"?>
176
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
177
+ <script>alert('forbidden');</script>
178
+ <audio src="sound.mp3"/>
179
+ <rect x="10" y="10" width="20" height="20" onclick="handleClick()" onmouseover="hover()"/>
180
+ </svg>
181
+ SVG
182
+
183
+ document = SvgConform::Document.from_content(invalid_svg)
184
+ context = SvgConform::ValidationContext.new(document, nil)
185
+ requirement.validate_document(document, context)
186
+
187
+ expect(context.errors.count).to be >= 4 # script, audio, onclick, onmouseover
188
+ forbidden_items = context.errors.map(&:message).join(" ")
189
+ expect(forbidden_items).to match(/script/i)
190
+ expect(forbidden_items).to match(/audio/i)
191
+ expect(forbidden_items).to match(/onclick/i)
192
+ expect(forbidden_items).to match(/onmouseover/i)
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "canon"
5
+
6
+ RSpec.describe SvgConform::Requirements::IdReferenceRequirement do
7
+ let(:fixtures_dir) { "spec/fixtures/id_reference" }
8
+
9
+ # Get all fixture files that have both input and expected repair versions
10
+ fixture_files = Dir.glob("spec/fixtures/id_reference/inputs/*.svg").select do |input_file|
11
+ basename = File.basename(input_file)
12
+ File.exist?("spec/fixtures/id_reference/repair/#{basename}")
13
+ end.map do |f|
14
+ File.basename(f, ".svg")
15
+ end
16
+
17
+ fixture_files.each do |fixture_name|
18
+ describe "fixture: #{fixture_name}" do
19
+ let(:input_file) do
20
+ "spec/fixtures/id_reference/inputs/#{fixture_name}.svg"
21
+ end
22
+ let(:expected_output_file) do
23
+ "spec/fixtures/id_reference/repair/#{fixture_name}.svg"
24
+ end
25
+
26
+ it "validates input file and identifies violations" do
27
+ skip "Input file not found" unless File.exist?(input_file)
28
+
29
+ document = SvgConform::Document.from_file(input_file)
30
+ requirement = described_class.new(
31
+ id: "id_reference",
32
+ description: "Test id reference requirement",
33
+ )
34
+
35
+ context = SvgConform::ValidationContext.new(document, nil)
36
+ requirement.validate_document(document, context)
37
+
38
+ expect(context.errors).not_to be_empty
39
+ puts "Found #{context.errors.count} id reference violations in #{fixture_name}"
40
+
41
+ context.errors.each do |error|
42
+ expect(error.requirement_id).to eq("id_reference")
43
+ expect(error.message).to be_a(String)
44
+ expect(error.message).not_to be_empty
45
+ end
46
+ end
47
+
48
+ it "correctly identifies specific violations" do
49
+ skip "Input file not found" unless File.exist?(input_file)
50
+
51
+ document = SvgConform::Document.from_file(input_file)
52
+ requirement = described_class.new(
53
+ id: "id_reference",
54
+ description: "Test id reference requirement",
55
+ )
56
+
57
+ context = SvgConform::ValidationContext.new(document, nil)
58
+ requirement.validate_document(document, context)
59
+
60
+ # Check that errors are relevant to this requirement
61
+ context.errors.each do |error|
62
+ expect(error.message).not_to be_empty
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "configuration" do
69
+ it "can be instantiated with basic parameters" do
70
+ requirement = described_class.new(
71
+ id: "test_id_reference",
72
+ description: "Test requirement",
73
+ )
74
+
75
+ expect(requirement).to be_a(described_class)
76
+ end
77
+ end
78
+ end