|
41 | 41 | import requests_mock |
42 | 42 | import shutil |
43 | 43 | import sys |
44 | | -import subprocess |
| 44 | +# import subprocess |
45 | 45 |
|
46 | 46 | from urllib.parse import unquote |
47 | 47 | from unittest.util import strclass |
48 | 48 | from bs4 import BeautifulSoup |
49 | 49 | from contextlib import contextmanager |
50 | 50 | from pathlib import Path |
51 | 51 | from tempfile import NamedTemporaryFile |
52 | | -from tidylib import tidy_document |
| 52 | +# from tidylib import tidy_document |
53 | 53 |
|
54 | 54 | import django.test |
55 | | -from django.test.client import Client |
| 55 | +# from django.test.client import Client |
56 | 56 | from django.conf import settings |
57 | 57 | from django.utils.text import slugify |
58 | 58 |
|
@@ -156,128 +156,128 @@ def test_redirect_with_lazy_reverse(self): |
156 | 156 | self.assertRedirects(response, "/ipr/", status_code=301) |
157 | 157 |
|
158 | 158 |
|
159 | | -class VerifyingClient(Client): |
160 | | - def __init__(self, test): |
161 | | - super(VerifyingClient, self).__init__() |
162 | | - self.test = test |
163 | | - |
164 | | - def handle_error(self, path, source, errors): |
165 | | - file_name = "error" + re.sub("/", "-", path) |
166 | | - if not file_name.endswith("-"): |
167 | | - file_name += "-" |
168 | | - file_name += "source.html" |
169 | | - with open(file_name, "w") as src: |
170 | | - src.write(source) |
171 | | - print("\nHTML validation error for URL path", path) |
172 | | - print("HTML source saved to", file_name) |
173 | | - print("See AssertionError below for error location in HTML source.") |
174 | | - self.test.maxDiff = None |
175 | | - self.test.assertEqual("", errors) |
176 | | - |
177 | | - def get(self, path, *args, skip_verify=False, **extra): |
178 | | - """GET request |
179 | | -
|
180 | | - Performs verification of HTML responses unless skip_verify is True. |
181 | | - """ |
182 | | - r = super(VerifyingClient, self).get(path, *args, **extra) |
183 | | - |
184 | | - if ( |
185 | | - skip_verify |
186 | | - or r.status_code >= 300 |
187 | | - or not r["content-type"].lower().startswith("text/html") |
188 | | - ): |
189 | | - return r |
190 | | - source = r.content.decode() |
191 | | - |
192 | | - if settings.VNU: |
193 | | - # First, run through https://validator.github.io/validator/ |
194 | | - result = subprocess.run( |
195 | | - ["java", "-jar", "/vnu.jar", "nu.validator.client.HttpClient", "-"], |
196 | | - input=r.content, |
197 | | - stdout=subprocess.PIPE, |
198 | | - stderr=subprocess.DEVNULL, |
199 | | - ) |
200 | | - errors = result.stdout.decode() |
201 | | - |
202 | | - if errors: |
203 | | - msg = "" |
204 | | - for err in errors.splitlines(): |
205 | | - # TODO: check if some can be removed after validating database templates |
206 | | - if ( |
207 | | - re.match(r'.*Attribute "required" not allowed', err) |
208 | | - or re.match( |
209 | | - r'.*The "type" attribute is unnecessary for JavaScript', err |
210 | | - ) |
211 | | - or re.match( |
212 | | - r'.*Element "option" without attribute "label" must not be empty', |
213 | | - err, |
214 | | - ) |
215 | | - or re.match(r".*The character encoding was not declared", err) |
216 | | - or re.match(r".*Consider avoiding viewport values", err) |
217 | | - or re.match( |
218 | | - r'.*The value of the "for" attribute of the "label" element must be the ID of a non-hidden form control', |
219 | | - err, |
220 | | - ) |
221 | | - or re.match(r".*is not in Unicode Normalization Form C", err) |
222 | | - ): |
223 | | - continue |
224 | | - # ignore some errors about obsolete HTML coming from the database |
225 | | - if re.match( |
226 | | - r"/meeting/\d+/proceedings/overview/", path |
227 | | - ) and re.match( |
228 | | - r'.*The "\w+" attribute on the "\w+" element is obsolete', err |
229 | | - ): |
230 | | - continue |
231 | | - # ignore some errors coming from outdated but still-needed iframes |
232 | | - if re.match(r"/meeting/\d+/week-view", path) and re.match( |
233 | | - r".*Start tag seen without seeing a doctype first", err |
234 | | - ): |
235 | | - continue |
236 | | - pos = re.match(r'".*":((\d+)\.(\d+)-(\d+)\.(\d+):.*)', err) |
237 | | - if not pos: |
238 | | - self.handle_error(path, source, err) |
239 | | - return r |
240 | | - msg += pos.group(1).strip(" .") + ":\n" |
241 | | - for line in source.splitlines()[ |
242 | | - int(pos.group(2)) - 1 : int(pos.group(4)) |
243 | | - ]: |
244 | | - msg += line.strip() + "\n" |
245 | | - |
246 | | - if msg: |
247 | | - self.handle_error(path, source, msg) |
248 | | - return r |
249 | | - |
250 | | - # Next, run through https://www.html-tidy.org/ |
251 | | - document, errors = tidy_document( |
252 | | - r.content, |
253 | | - options={ |
254 | | - # this is causing way too many generic warnings: |
255 | | - # "accessibility-check": 1, |
256 | | - }, |
257 | | - ) |
258 | | - |
259 | | - errors = "\n".join( |
260 | | - [ |
261 | | - e |
262 | | - # TODO: check if some can be removed after validating database templates |
263 | | - for e in errors.splitlines() |
264 | | - # FIXME: django-bootstrap5 incorrectly sets a "required" |
265 | | - # proprietary attribute on some <div>s; remove those errors |
266 | | - if not re.match(r'.*proprietary attribute "required"', e) |
267 | | - # FIXME: some secretariat templates have this issue, ignore |
268 | | - and not re.match(r".*id and name attribute value mismatch", e) |
269 | | - # FIXME: bootstrap-icons and close buttons render as empty, remove those errors. |
270 | | - # Also, django seems to generate some empty tags, so remove those, too. |
271 | | - and not re.match(r".*trimming empty <(i|em|button|span|optgroup)>", e) |
272 | | - # FIXME: some old pages only work correctly in quirks mode :-( |
273 | | - and not re.match(r".*missing <!DOCTYPE> declaration", e) |
274 | | - ] |
275 | | - ) |
276 | | - |
277 | | - if errors: |
278 | | - self.handle_error(path, source, errors) |
279 | | - |
280 | | - return r |
| 159 | +# class VerifyingClient(Client): |
| 160 | +# def __init__(self, test): |
| 161 | +# super(VerifyingClient, self).__init__() |
| 162 | +# self.test = test |
| 163 | + |
| 164 | +# def handle_error(self, path, source, errors): |
| 165 | +# file_name = "error" + re.sub("/", "-", path) |
| 166 | +# if not file_name.endswith("-"): |
| 167 | +# file_name += "-" |
| 168 | +# file_name += "source.html" |
| 169 | +# with open(file_name, "w") as src: |
| 170 | +# src.write(source) |
| 171 | +# print("\nHTML validation error for URL path", path) |
| 172 | +# print("HTML source saved to", file_name) |
| 173 | +# print("See AssertionError below for error location in HTML source.") |
| 174 | +# self.test.maxDiff = None |
| 175 | +# self.test.assertEqual("", errors) |
| 176 | + |
| 177 | +# def get(self, path, *args, skip_verify=False, **extra): |
| 178 | +# """GET request |
| 179 | + |
| 180 | +# Performs verification of HTML responses unless skip_verify is True. |
| 181 | +# """ |
| 182 | +# r = super(VerifyingClient, self).get(path, *args, **extra) |
| 183 | + |
| 184 | +# if ( |
| 185 | +# skip_verify |
| 186 | +# or r.status_code >= 300 |
| 187 | +# or not r["content-type"].lower().startswith("text/html") |
| 188 | +# ): |
| 189 | +# return r |
| 190 | +# source = r.content.decode() |
| 191 | + |
| 192 | +# if settings.VNU: |
| 193 | +# # First, run through https://validator.github.io/validator/ |
| 194 | +# result = subprocess.run( |
| 195 | +# ["java", "-jar", "/vnu.jar", "nu.validator.client.HttpClient", "-"], |
| 196 | +# input=r.content, |
| 197 | +# stdout=subprocess.PIPE, |
| 198 | +# stderr=subprocess.DEVNULL, |
| 199 | +# ) |
| 200 | +# errors = result.stdout.decode() |
| 201 | + |
| 202 | +# if errors: |
| 203 | +# msg = "" |
| 204 | +# for err in errors.splitlines(): |
| 205 | +# # TODO: check if some can be removed after validating database templates |
| 206 | +# if ( |
| 207 | +# re.match(r'.*Attribute "required" not allowed', err) |
| 208 | +# or re.match( |
| 209 | +# r'.*The "type" attribute is unnecessary for JavaScript', err |
| 210 | +# ) |
| 211 | +# or re.match( |
| 212 | +# r'.*Element "option" without attribute "label" must not be empty', |
| 213 | +# err, |
| 214 | +# ) |
| 215 | +# or re.match(r".*The character encoding was not declared", err) |
| 216 | +# or re.match(r".*Consider avoiding viewport values", err) |
| 217 | +# or re.match( |
| 218 | +# r'.*The value of the "for" attribute of the "label" element must be the ID of a non-hidden form control', |
| 219 | +# err, |
| 220 | +# ) |
| 221 | +# or re.match(r".*is not in Unicode Normalization Form C", err) |
| 222 | +# ): |
| 223 | +# continue |
| 224 | +# # ignore some errors about obsolete HTML coming from the database |
| 225 | +# if re.match( |
| 226 | +# r"/meeting/\d+/proceedings/overview/", path |
| 227 | +# ) and re.match( |
| 228 | +# r'.*The "\w+" attribute on the "\w+" element is obsolete', err |
| 229 | +# ): |
| 230 | +# continue |
| 231 | +# # ignore some errors coming from outdated but still-needed iframes |
| 232 | +# if re.match(r"/meeting/\d+/week-view", path) and re.match( |
| 233 | +# r".*Start tag seen without seeing a doctype first", err |
| 234 | +# ): |
| 235 | +# continue |
| 236 | +# pos = re.match(r'".*":((\d+)\.(\d+)-(\d+)\.(\d+):.*)', err) |
| 237 | +# if not pos: |
| 238 | +# self.handle_error(path, source, err) |
| 239 | +# return r |
| 240 | +# msg += pos.group(1).strip(" .") + ":\n" |
| 241 | +# for line in source.splitlines()[ |
| 242 | +# int(pos.group(2)) - 1 : int(pos.group(4)) |
| 243 | +# ]: |
| 244 | +# msg += line.strip() + "\n" |
| 245 | + |
| 246 | +# if msg: |
| 247 | +# self.handle_error(path, source, msg) |
| 248 | +# return r |
| 249 | + |
| 250 | +# # Next, run through https://www.html-tidy.org/ |
| 251 | +# document, errors = tidy_document( |
| 252 | +# r.content, |
| 253 | +# options={ |
| 254 | +# # this is causing way too many generic warnings: |
| 255 | +# # "accessibility-check": 1, |
| 256 | +# }, |
| 257 | +# ) |
| 258 | + |
| 259 | +# errors = "\n".join( |
| 260 | +# [ |
| 261 | +# e |
| 262 | +# # TODO: check if some can be removed after validating database templates |
| 263 | +# for e in errors.splitlines() |
| 264 | +# # FIXME: django-bootstrap5 incorrectly sets a "required" |
| 265 | +# # proprietary attribute on some <div>s; remove those errors |
| 266 | +# if not re.match(r'.*proprietary attribute "required"', e) |
| 267 | +# # FIXME: some secretariat templates have this issue, ignore |
| 268 | +# and not re.match(r".*id and name attribute value mismatch", e) |
| 269 | +# # FIXME: bootstrap-icons and close buttons render as empty, remove those errors. |
| 270 | +# # Also, django seems to generate some empty tags, so remove those, too. |
| 271 | +# and not re.match(r".*trimming empty <(i|em|button|span|optgroup)>", e) |
| 272 | +# # FIXME: some old pages only work correctly in quirks mode :-( |
| 273 | +# and not re.match(r".*missing <!DOCTYPE> declaration", e) |
| 274 | +# ] |
| 275 | +# ) |
| 276 | + |
| 277 | +# if errors: |
| 278 | +# self.handle_error(path, source, errors) |
| 279 | + |
| 280 | +# return r |
281 | 281 |
|
282 | 282 |
|
283 | 283 | class TestCase(django.test.TestCase): |
@@ -399,7 +399,7 @@ def setUp(self): |
399 | 399 | self.requests_mock = requests_mock.Mocker() |
400 | 400 | self.requests_mock.start() |
401 | 401 |
|
402 | | - self.client = VerifyingClient(self) # Set up the HTML verifier |
| 402 | + # self.client = VerifyingClient(self) # Set up the HTML verifier |
403 | 403 |
|
404 | 404 | # Replace settings paths with temporary directories. |
405 | 405 | self._ietf_temp_dirs = {} # trashed during tearDown, DO NOT put paths you care about in this |
|
0 commit comments