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,4 @@
1
+ <?xml version='1.0' encoding='utf-8'?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" height="100" datatype="foobar">
3
+ <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="black"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ Tests/viewBox-height.svg:1: The attribute viewBox is required on the root svg element
2
+ Tests/viewBox-height.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black'
3
+ ERROR: File does not conform to SVG requirements
@@ -0,0 +1,4 @@
1
+ <?xml version='1.0' encoding='utf-8'?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" datatype="foobar">
3
+ <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="black"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ Tests/viewBox-none.svg:1: The attribute viewBox is required on the root svg element
2
+ Tests/viewBox-none.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black'
3
+ ERROR: File does not conform to SVG requirements
@@ -0,0 +1,4 @@
1
+ <?xml version='1.0' encoding='utf-8'?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" width="100" datatype="foobar">
3
+ <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="black"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ Tests/viewBox-width.svg:1: The attribute viewBox is required on the root svg element
2
+ Tests/viewBox-width.svg:2: The attribute 'fill' does not allow the value 'red', replaced with 'black'
3
+ ERROR: File does not conform to SVG requirements
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
3
+ width="100" height="80">
4
+ <title>ViewBox Required Test</title>
5
+ <desc>Testing viewBox requirement - root SVG missing viewBox</desc>
6
+
7
+ <rect x="10" y="10" width="80" height="60" fill="black" stroke="none"/>
8
+ <circle cx="50" cy="40" r="20" fill="white"/>
9
+ <text x="50" y="45" text-anchor="middle" font-family="serif">No ViewBox</text>
10
+ </svg>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
3
+ width="100" height="80" viewBox="0 0 100 80">
4
+ <title>ViewBox Required Test</title>
5
+ <desc>Testing viewBox requirement - root SVG missing viewBox</desc>
6
+
7
+ <rect x="10" y="10" width="80" height="60" fill="black" stroke="none"/>
8
+ <circle cx="50" cy="40" r="20" fill="white"/>
9
+ <text x="50" y="45" text-anchor="middle" font-family="serif">No ViewBox</text>
10
+ </svg>
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "svg_conform"
4
+ require "canon"
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = ".rspec_status"
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::BatchReport do
6
+ describe "initialization" do
7
+ it "creates a batch report with default values" do
8
+ report = described_class.new
9
+ expect(report.files).to eq([])
10
+ expect(report.manifest).to eq({})
11
+ expect(report.timestamp).not_to be_nil
12
+ end
13
+ end
14
+
15
+ describe "calculate_statistics" do
16
+ it "calculates statistics correctly" do
17
+ report = described_class.new
18
+ report.profile = "metanorma"
19
+
20
+ # Add some file results
21
+ 3.times do |i|
22
+ file_result = SvgConform::FileResult.new
23
+ file_result.filename = "file#{i}.svg"
24
+ file_result.valid_before = false
25
+ file_result.valid_after = i < 2 # 2 out of 3 valid after
26
+ file_result.status = i < 2 ? "remediated" : "failed"
27
+ report.files << file_result
28
+ end
29
+
30
+ report.calculate_statistics
31
+
32
+ expect(report.total_files).to eq(3)
33
+ expect(report.valid_before).to eq(0)
34
+ expect(report.valid_after).to eq(2)
35
+ expect(report.remediated).to eq(2)
36
+ expect(report.failed).to eq(1)
37
+ expect(report.success_rate).to eq(66.7)
38
+ end
39
+ end
40
+
41
+ describe "serialization" do
42
+ it "serializes to JSON" do
43
+ report = described_class.new
44
+ report.profile = "metanorma"
45
+ report.total_files = 10
46
+
47
+ json = report.to_json
48
+ expect(json).to be_a(String)
49
+ expect(json).to include('"profile":"metanorma"')
50
+ expect(json).to include('"total_files":10')
51
+ end
52
+
53
+ it "serializes to YAML" do
54
+ report = described_class.new
55
+ report.profile = "metanorma"
56
+ report.total_files = 10
57
+
58
+ yaml = report.to_yaml
59
+ expect(yaml).to be_a(String)
60
+ expect(yaml).to include("profile: metanorma")
61
+ expect(yaml).to include("total_files: 10")
62
+ end
63
+ end
64
+ end
65
+
66
+ RSpec.describe SvgConform::FileResult do
67
+ describe "initialization" do
68
+ it "creates a file result" do
69
+ result = described_class.new
70
+ result.filename = "test.svg"
71
+ result.status = "valid"
72
+
73
+ expect(result.filename).to eq("test.svg")
74
+ expect(result.status).to eq("valid")
75
+ end
76
+ end
77
+
78
+ describe "serialization" do
79
+ it "serializes to JSON" do
80
+ result = described_class.new
81
+ result.filename = "test.svg"
82
+ result.status = "remediated"
83
+
84
+ json = result.to_json
85
+ expect(json).to include('"filename":"test.svg"')
86
+ expect(json).to include('"status":"remediated"')
87
+ end
88
+
89
+ it "serializes to YAML" do
90
+ result = described_class.new
91
+ result.filename = "test.svg"
92
+ result.status = "remediated"
93
+
94
+ yaml = result.to_yaml
95
+ expect(yaml).to include("filename: test.svg")
96
+ expect(yaml).to include("status: remediated")
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "tempfile"
5
+
6
+ RSpec.describe SvgConform::Commands::Check do
7
+ let(:valid_svg) do
8
+ <<~SVG
9
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
10
+ <rect x="10" y="10" width="50" height="50" fill="red"/>
11
+ </svg>
12
+ SVG
13
+ end
14
+
15
+ let(:invalid_svg) do
16
+ <<~SVG
17
+ <svg width="100" height="100">
18
+ <rect x="10" y="10" width="50" height="50" fill="red"/>
19
+ </svg>
20
+ SVG
21
+ end
22
+
23
+ describe "#execute" do
24
+ it "validates a file and returns status" do
25
+ tempfile = Tempfile.new(["test", ".svg"])
26
+ tempfile.write(valid_svg)
27
+ tempfile.close
28
+
29
+ options = { profile: "svg_1_2_rfc", format: "table" }
30
+ command = described_class.new(tempfile.path, options)
31
+
32
+ expect { command.execute }.to output(/SVG Validation Report/).to_stdout
33
+ .and raise_error(SystemExit)
34
+
35
+ tempfile.unlink
36
+ end
37
+
38
+ it "reports errors for invalid files" do
39
+ tempfile = Tempfile.new(["test", ".svg"])
40
+ tempfile.write(invalid_svg)
41
+ tempfile.close
42
+
43
+ options = { profile: "svg_1_2_rfc", format: "table" }
44
+ command = described_class.new(tempfile.path, options)
45
+
46
+ expect { command.execute }.to output(/Validation Errors/).to_stdout
47
+ .and raise_error(SystemExit)
48
+
49
+ tempfile.unlink
50
+ end
51
+
52
+ it "supports YAML output format" do
53
+ tempfile = Tempfile.new(["test", ".svg"])
54
+ tempfile.write(valid_svg)
55
+ tempfile.close
56
+
57
+ options = { profile: "svg_1_2_rfc", format: "yaml" }
58
+ command = described_class.new(tempfile.path, options)
59
+
60
+ expect { command.execute }.to output(/---/).to_stdout
61
+ .and raise_error(SystemExit)
62
+
63
+ tempfile.unlink
64
+ end
65
+
66
+ it "supports JSON output format" do
67
+ tempfile = Tempfile.new(["test", ".svg"])
68
+ tempfile.write(valid_svg)
69
+ tempfile.close
70
+
71
+ options = { profile: "svg_1_2_rfc", format: "json" }
72
+ command = described_class.new(tempfile.path, options)
73
+
74
+ expect { command.execute }.to output(/\{/).to_stdout
75
+ .and raise_error(SystemExit)
76
+
77
+ tempfile.unlink
78
+ end
79
+
80
+ it "handles missing files gracefully" do
81
+ options = { profile: "svg_1_2_rfc", format: "table" }
82
+ command = described_class.new("nonexistent.svg", options)
83
+
84
+ expect do
85
+ command.execute
86
+ end.to output(/Error: File 'nonexistent.svg' not found/).to_stdout
87
+ .and raise_error(SystemExit)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::Commands::Profiles do
6
+ describe "#execute" do
7
+ it "initializes with options" do
8
+ options = {}
9
+ command = described_class.new(options)
10
+ expect(command).to be_a(described_class)
11
+ end
12
+
13
+ it "lists available profiles" do
14
+ options = {}
15
+ command = described_class.new(options)
16
+
17
+ expect { command.execute }.to output(/Available SVG Profiles/).to_stdout
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::Commands::SvgcheckCompare do
6
+ describe "#execute" do
7
+ it "initializes with file and options" do
8
+ options = { profile: "svg_1_2_rfc" }
9
+ command = described_class.new("test.svg", options)
10
+ expect(command).to be_a(described_class)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::Commands::SvgcheckCompatibility do
6
+ describe "#execute" do
7
+ it "initializes with options" do
8
+ options = {}
9
+ command = described_class.new(options)
10
+ expect(command).to be_a(described_class)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::Commands::SvgcheckGenerate do
6
+ describe "#execute" do
7
+ it "initializes with svgcheck_repo_path and options" do
8
+ svgcheck_repo_path = "svgcheck-reference"
9
+ options = { single_file: "test.svg" }
10
+ command = described_class.new(svgcheck_repo_path, options)
11
+ expect(command).to be_a(described_class)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Base Profile" do
6
+ let(:base_profile_path) { "config/profiles/base.yml" }
7
+
8
+ describe "profile loading" do
9
+ it "loads the base profile successfully" do
10
+ profile = SvgConform::Profile.load_from_file(base_profile_path)
11
+ expect(profile).not_to be_nil
12
+ expect(profile.name).to eq("base")
13
+ end
14
+
15
+ it "has minimal requirements" do
16
+ profile = SvgConform::Profile.load_from_file(base_profile_path)
17
+ expect(profile.requirements).to be_an(Array)
18
+ end
19
+
20
+ it "serves as a foundation for other profiles" do
21
+ profile = SvgConform::Profile.load_from_file(base_profile_path)
22
+ expect(profile.description).to be_a(String)
23
+ end
24
+ end
25
+
26
+ describe "validation" do
27
+ it "can validate a simple SVG document" do
28
+ svg_content = <<~SVG
29
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
30
+ <rect x="10" y="10" width="50" height="50" fill="red"/>
31
+ </svg>
32
+ SVG
33
+
34
+ document = SvgConform::Document.from_content(svg_content)
35
+ profile = SvgConform::Profile.load_from_file(base_profile_path)
36
+
37
+ result = profile.validate(document)
38
+ expect(result).to respond_to(:valid?)
39
+ expect(result).to respond_to(:errors)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Lucid Fix Profile" do
6
+ let(:lucid_fix_profile_path) { "config/profiles/lucid_fix.yml" }
7
+
8
+ describe "profile loading" do
9
+ it "loads the lucid fix profile successfully" do
10
+ profile = SvgConform::Profile.load_from_file(lucid_fix_profile_path)
11
+ expect(profile).not_to be_nil
12
+ expect(profile.name).to eq("lucid_fix")
13
+ end
14
+
15
+ it "includes requirements specific to Lucid diagrams" do
16
+ profile = SvgConform::Profile.load_from_file(lucid_fix_profile_path)
17
+ expect(profile.requirements).to be_an(Array)
18
+ expect(profile.requirements).not_to be_empty
19
+ end
20
+
21
+ it "has description indicating Lucid-specific fixes" do
22
+ profile = SvgConform::Profile.load_from_file(lucid_fix_profile_path)
23
+ expect(profile.description).to be_a(String)
24
+ end
25
+ end
26
+
27
+ describe "validation with lucid fixtures" do
28
+ let(:lucid_fixtures_dir) { "spec/fixtures/lucid" }
29
+
30
+ it "handles lucid-specific SVG patterns" do
31
+ skip "Lucid fixtures not found" unless Dir.exist?(lucid_fixtures_dir)
32
+
33
+ input_files = Dir.glob(File.join(lucid_fixtures_dir, "inputs/*.svg"))
34
+ skip "No lucid input files found" if input_files.empty?
35
+
36
+ profile = SvgConform::Profile.load_from_file(lucid_fix_profile_path)
37
+ input_file = input_files.first
38
+
39
+ document = SvgConform::Document.from_file(input_file)
40
+ result = profile.validate(document)
41
+
42
+ expect(result).to respond_to(:valid?)
43
+ expect(result).to respond_to(:errors)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "canon"
5
+ require "tempfile"
6
+
7
+ RSpec.describe "Lucid Profile" do
8
+ describe "namespace attribute remediation" do
9
+ let(:lucid_profile_path) { "config/profiles/lucid_fix.yml" }
10
+ let(:fixtures_dir) { "spec/fixtures/lucid" }
11
+
12
+ # Get all fixture files that have both input and expected repair versions
13
+ fixture_files = Dir.glob("spec/fixtures/lucid/inputs/*.svg").select do |input_file|
14
+ basename = File.basename(input_file)
15
+ File.exist?("spec/fixtures/lucid/repair/#{basename}")
16
+ end.map do |f|
17
+ File.basename(f, ".svg")
18
+ end
19
+
20
+ fixture_files.each do |fixture_name|
21
+ describe "fixture: #{fixture_name}" do
22
+ let(:input_file) { "spec/fixtures/lucid/inputs/#{fixture_name}.svg" }
23
+ let(:expected_output_file) do
24
+ "spec/fixtures/lucid/repair/#{fixture_name}.svg"
25
+ end
26
+
27
+ it "produces canonically equivalent output using profile remediation" do
28
+ skip "Expected repair file not found" unless File.exist?(expected_output_file)
29
+
30
+ # Load the document and apply profile remediations
31
+ document = SvgConform::Document.from_file(input_file)
32
+ profile = SvgConform::Profile.load_from_file(lucid_profile_path)
33
+
34
+ changes = profile.apply_remediations(document)
35
+
36
+ # Verify namespace remediation changes were made
37
+ namespace_changes = changes.select do |c|
38
+ c[:description]&.include?("namespace attribute")
39
+ end
40
+ expect(namespace_changes).not_to be_empty
41
+
42
+ # Get the remediated XML
43
+ actual_xml = document.to_xml
44
+ expected_xml = File.read(expected_output_file)
45
+
46
+ # Use canon matcher for XML equivalence
47
+ expect(actual_xml).to be_analogous_with(expected_xml)
48
+ end
49
+
50
+ it "removes lucid namespace attributes correctly" do
51
+ # Load the document and profile
52
+ document = SvgConform::Document.from_file(input_file)
53
+ profile = SvgConform::Profile.load_from_file(lucid_profile_path)
54
+
55
+ # Check that the document contains lucid attributes before remediation
56
+ original_xml = document.to_xml
57
+ expect(original_xml).to include("lucid:page-tab-id")
58
+ expect(original_xml).to include('xmlns:lucid="lucid"')
59
+
60
+ # Apply profile remediations
61
+ changes = profile.apply_remediations(document)
62
+
63
+ # Verify changes were made
64
+ expect(changes).not_to be_empty
65
+
66
+ # Find namespace attribute changes
67
+ attr_changes = changes.select do |c|
68
+ c[:description]&.include?("attribute")
69
+ end
70
+ expect(attr_changes).not_to be_empty
71
+
72
+ # Verify the result doesn't contain the lucid page-tab-id attribute
73
+ actual_xml = document.to_xml
74
+ expect(actual_xml).not_to include("lucid:page-tab-id")
75
+
76
+ # The namespace declaration removal is the main functionality we want to test
77
+ # For now, let's verify the attribute removal is working
78
+ puts "Namespace attribute remediation is working - removed: #{attr_changes.size} attributes"
79
+ puts "xmlns:lucid still present: #{actual_xml.include?('xmlns:lucid=\"lucid\"')}"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Metanorma Profile" do
6
+ let(:metanorma_profile_path) { "config/profiles/metanorma.yml" }
7
+
8
+ describe "profile loading" do
9
+ it "loads the Metanorma profile successfully" do
10
+ profile = SvgConform::Profile.load_from_file(metanorma_profile_path)
11
+ expect(profile).not_to be_nil
12
+ expect(profile.name).to eq("metanorma")
13
+ end
14
+
15
+ it "includes external resource requirements" do
16
+ profile = SvgConform::Profile.load_from_file(metanorma_profile_path)
17
+ requirement_ids = profile.requirements.map(&:id)
18
+ expect(requirement_ids).to include("no_external_css")
19
+ expect(requirement_ids).to include("no_external_fonts")
20
+ expect(requirement_ids).to include("no_external_images")
21
+ end
22
+
23
+ it "includes comprehensive element support" do
24
+ profile = SvgConform::Profile.load_from_file(metanorma_profile_path)
25
+ requirement_ids = profile.requirements.map(&:id)
26
+ expect(requirement_ids).to include("allowed_elements")
27
+ end
28
+ end
29
+
30
+ describe "validation" do
31
+ it "allows flexible colors unlike RFC 7996" do
32
+ svg_with_colors = <<~SVG
33
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
34
+ <rect x="10" y="10" width="50" height="50" fill="#ff0000"/>
35
+ </svg>
36
+ SVG
37
+
38
+ document = SvgConform::Document.from_content(svg_with_colors)
39
+ profile = SvgConform::Profile.load_from_file(metanorma_profile_path)
40
+
41
+ result = profile.validate(document)
42
+ color_errors = result.errors.select do |e|
43
+ e.requirement_id == "color_restrictions"
44
+ end
45
+ expect(color_errors).to be_empty
46
+ end
47
+
48
+ it "supports image elements" do
49
+ svg_with_image = <<~SVG
50
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
51
+ <image href="data:image/png;base64,abc" width="50" height="50"/>
52
+ </svg>
53
+ SVG
54
+
55
+ document = SvgConform::Document.from_content(svg_with_image)
56
+ profile = SvgConform::Profile.load_from_file(metanorma_profile_path)
57
+
58
+ result = profile.validate(document)
59
+ expect(result).to respond_to(:valid?)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "No External CSS Profile" do
6
+ let(:no_external_css_profile_path) { "config/profiles/no_external_css.yml" }
7
+
8
+ describe "profile loading" do
9
+ it "loads the no external css profile successfully" do
10
+ profile = SvgConform::Profile.load_from_file(no_external_css_profile_path)
11
+ expect(profile).not_to be_nil
12
+ expect(profile.name).to eq("no_external_css")
13
+ end
14
+
15
+ it "includes no_external_css requirement" do
16
+ profile = SvgConform::Profile.load_from_file(no_external_css_profile_path)
17
+ requirement_ids = profile.requirements.map(&:id)
18
+ expect(requirement_ids).to include("no_external_css")
19
+ end
20
+
21
+ it "has description indicating external CSS restriction" do
22
+ profile = SvgConform::Profile.load_from_file(no_external_css_profile_path)
23
+ expect(profile.description).to be_a(String)
24
+ expect(profile.description.downcase).to match(/external.*css/)
25
+ end
26
+ end
27
+
28
+ describe "validation" do
29
+ it "rejects SVG with external CSS references" do
30
+ svg_with_external_css = <<~SVG
31
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
32
+ <defs>
33
+ <style>
34
+ @import url("external.css");
35
+ </style>
36
+ </defs>
37
+ <rect x="10" y="10" width="50" height="50"/>
38
+ </svg>
39
+ SVG
40
+
41
+ document = SvgConform::Document.from_content(svg_with_external_css)
42
+ profile = SvgConform::Profile.load_from_file(no_external_css_profile_path)
43
+
44
+ result = profile.validate(document)
45
+ expect(result.valid?).to be false
46
+ expect(result.errors.map(&:requirement_id)).to include("no_external_css")
47
+ end
48
+
49
+ it "accepts SVG with inline styles" do
50
+ svg_with_inline_styles = <<~SVG
51
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
52
+ <rect x="10" y="10" width="50" height="50" style="fill:red"/>
53
+ </svg>
54
+ SVG
55
+
56
+ document = SvgConform::Document.from_content(svg_with_inline_styles)
57
+ profile = SvgConform::Profile.load_from_file(no_external_css_profile_path)
58
+
59
+ result = profile.validate(document)
60
+ external_css_errors = result.errors.select do |e|
61
+ e.requirement_id == "no_external_css"
62
+ end
63
+ expect(external_css_errors).to be_empty
64
+ end
65
+ end
66
+ end