Skip to content

Commit

Permalink
Migrate 2d.canvas.host.size.attributes.* to the new canvas WPT generator
Browse files Browse the repository at this point in the history
This test uses different types of newline characters, like \n, \r and
\f. The `indent` Jinja filter used by the test template [1] was dropping
all of these, replacing them with normal newlines. This looks like a
bug in Jinja: the `indent` filter could easily be made to preserve
newline types. This CL overrides the default `indent` filter with a
version doing exactly that.

[1]: https://crsrc.org/c/third_party/blink/web_tests/external/wpt/html/canvas/tools/templates/testharness_element.html;l=62;drc=44ada975c0f28bc2d30c780314081ec2bb97bbe5

Bug: 40207206
Change-Id: I5ece8e0ce4199bb0c915e59131c26eed4ce58693
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6172748
Commit-Queue: Jean-Philippe Gravel <[email protected]>
Reviewed-by: Yi Xu <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1408116}
  • Loading branch information
graveljp authored and chromium-wpt-export-bot committed Jan 17, 2025
1 parent a806ea5 commit f98387d
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 111 deletions.
28 changes: 26 additions & 2 deletions html/canvas/tools/gentestutilsunion.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
# * Test the tests, add new ones to Git, remove deleted ones from Git, etc.

from typing import Any, DefaultDict, FrozenSet, List, Mapping, MutableMapping
from typing import Set
from typing import Set, Union

import re
import collections
Expand Down Expand Up @@ -439,7 +439,7 @@ def finalize_params(self, jinja_env: jinja2.Environment,
variant_id: int) -> None:
"""Finalize this variant by adding computed param fields."""
self._params['id'] = variant_id
for param_name in ('name', 'desc', 'attributes'):
for param_name in ('attributes', 'desc', 'expected', 'name'):
self._render_param(jinja_env, param_name)
self._params['file_name'] = self._get_file_name()
self._params['canvas_types'] = self._get_canvas_types()
Expand Down Expand Up @@ -875,6 +875,29 @@ def _check_uniqueness(tested: DefaultDict[str, Set[_CanvasType]], name: str,
tested[name].update(canvas_types)


def _indent_filter(s: str, width: Union[int, str] = 4,
first: bool = False, blank: bool = False) -> str:
"""Returns a copy of the string with each line indented by the `width` str.
If `width` is a number, `s` is indented by that number of whitespaces. The
first line and blank lines are not indented by default, unless `first` or
`blank` are `True`, respectively.
This is a re-implementation of the default `indent` Jinja filter, preserving
line ending characters (\r, \n, \f, etc.) The default `indent` Jinja filter
incorrectly replaces all of these characters with newlines."""
is_first_line = True
def indent_needed(line):
nonlocal first, blank, is_first_line
is_blank = not line.strip()
need_indent = (not is_first_line or first) and (not is_blank or blank)
is_first_line = False
return need_indent

indentation = width if isinstance(width, str) else ' ' * width
return textwrap.indent(s, indentation, indent_needed)


def generate_test_files(name_to_dir_file: str) -> None:
"""Generate Canvas tests from YAML file definition."""
output_dirs = _OutputPaths(element=pathlib.Path('..') / 'element',
Expand All @@ -887,6 +910,7 @@ def generate_test_files(name_to_dir_file: str) -> None:
lstrip_blocks=True)

jinja_env.filters['double_quote_escape'] = _double_quote_escape
jinja_env.filters['indent'] = _indent_filter

# Run with --test argument to run unit tests.
if len(sys.argv) > 1 and sys.argv[1] == '--test':
Expand Down
136 changes: 136 additions & 0 deletions html/canvas/tools/yaml-new/the-canvas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,142 @@
new_canvas: |-
new OffscreenCanvas(100, 50)
- name: 2d.canvas.host.size.attributes
canvas_types: ['HtmlCanvas']
code: |
{{ set_attributes -}}
@assert canvas.width === {{ result_size[0] }};
@assert canvas.height === {{ result_size[1] }};
{% if result_size[0] != 300 %}
{# With "100%", Opera gets canvas.width = 100 but renders at 100% of the
frame width, so check the CSS display width -#}
@assert window.getComputedStyle(canvas, null)\-
.getPropertyValue("width") === "{{ result_size[0] }}px";
{% endif -%}
{% set attrib_size = escaped_size or input_size %}
@assert canvas.getAttribute('width') === '{{ attrib_size }}';
@assert canvas.getAttribute('height') === '{{ attrib_size }}';
expected: |
{% if result_size[0] != 0 -%}
size {{ result_size[0] }} {{ result_size[1] }}
{% endif %}
variants:
- parse:
desc: Parsing of non-negative integers
size: ['{{ input_size }}', '{{ input_size }}']
setAttribute:
desc: Parsing of non-negative integers in setAttribute
size: [ 50, 50 ]
set_attributes: |
canvas.setAttribute('width', '{{ escaped_size or input_size }}');
canvas.setAttribute('height', '{{ escaped_size or input_size }}');
- zero:
input_size: '0'
result_size: [0, 0]
empty:
input_size: ''
result_size: [300, 150]
onlyspace:
input_size: ' '
result_size: [300, 150]
space:
input_size: ' 100'
result_size: [100, 100]
whitespace:
input_size: "&#xD;\n\t\x0c100"
escaped_size: "\\r\\n\\t\\x0c100"
result_size: [100, 100]
plus:
input_size: '+100'
result_size: [100, 100]
minus:
input_size: '-100'
result_size: [300, 150]
octal:
input_size: '0100'
result_size: [100, 100]
hex:
input_size: '0x100'
result_size: [0, 0]
exp:
input_size: '100e1'
result_size: [100, 100]
decimal:
input_size: '100.999'
result_size: [100, 100]
percent:
input_size: '100%'
result_size: [100, 100]
em:
input_size: '100em'
result_size: [100, 100]
junk:
input_size: '#!?'
result_size: [300, 150]
trailingjunk:
input_size: '100#!?'
result_size: [100, 100]

- name: 2d.canvas.host.size.attributes.parse
desc: Parsing of non-negative integers
canvas_types: ['OffscreenCanvas', 'Worker']
code: |
{% if result_size == 'exception' %}
@assert throws TypeError canvas.width = '{{ input_size }}';
{% else %}
canvas.width = '{{ input_size }}';
canvas.height = '{{ input_size }}';
@assert canvas.width === {{ result_size }};
@assert canvas.height === {{ result_size }};
{% endif %}
variants:
- zero:
input_size: '0'
result_size: 0
empty:
input_size: ''
result_size: 0
onlyspace:
input_size: ' '
result_size: 0
space:
input_size: ' 100'
result_size: 100
whitespace:
input_size: "\t\f100"
result_size: 100
plus:
input_size: '+100'
result_size: 100
minus:
input_size: '-100'
result_size: 'exception'
octal:
input_size: '0100'
result_size: 100
hex:
input_size: '0x100'
result_size: 0x100
exp:
input_size: '100e1'
result_size: 1000.0
decimal:
input_size: '100.999'
result_size: 100
percent:
input_size: '100%'
result_size: 'exception'
em:
input_size: '100em'
result_size: 'exception'
junk:
input_size: '#!?'
result_size: 'exception'
trailingjunk:
input_size: '100#!?'
result_size: 'exception'

- name: 2d.canvas.host.type.delete
canvas_types: ['HtmlCanvas']
desc: window.HTMLCanvasElement interface object is [[Configurable]]
Expand Down
62 changes: 0 additions & 62 deletions html/canvas/tools/yaml/element/meta.yaml
Original file line number Diff line number Diff line change
@@ -1,65 +1,3 @@
- meta: |
cases = [
("zero", "0", 0),
("empty", "", None),
("onlyspace", " ", None),
("space", " 100", 100),
("whitespace", "\r\n\t\f100", 100),
("plus", "+100", 100),
("minus", "-100", None),
("octal", "0100", 100),
("hex", "0x100", 0),
("exp", "100e1", 100),
("decimal", "100.999", 100),
("percent", "100%", 100),
("em", "100em", 100),
("junk", "#!?", None),
("trailingjunk", "100#!?", 100),
]
def gen(name, string, exp, code):
if exp is None:
code += "@assert canvas.width === 300;\n@assert canvas.height === 150;\n"
expected = "size 300 150"
else:
code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp)
expected = "size %s %s" % (exp, exp)
# With "100%", Opera gets canvas.width = 100 but renders at 100% of the frame width,
# so check the CSS display width
code += '@assert window.getComputedStyle(canvas, null).getPropertyValue("width") === "%spx";\n' % (exp, )
code += "@assert canvas.getAttribute('width') === %r;\n" % string
code += "@assert canvas.getAttribute('height') === %r;\n" % string
if exp == 0:
expected = None # can't generate zero-sized PNGs for the expected image
return code, expected
for name, string, exp in cases:
code = ""
code, expected = gen(name, string, exp, code)
# We need to replace \r with &#xD; because \r\n gets converted to \n in the HTML parser.
htmlString = string.replace('\r', '&#xD;')
tests.append( {
"name": "2d.canvas.host.size.attributes.parse.%s" % name,
"desc": "Parsing of non-negative integers",
"size": '%s, %s' % (htmlString, htmlString),
"code": code,
"expected": expected
} )
for name, string, exp in cases:
code = "canvas.setAttribute('width', %r);\ncanvas.setAttribute('height', %r);\n" % (string, string)
code, expected = gen(name, string, exp, code)
tests.append( {
"name": "2d.canvas.host.size.attributes.setAttribute.%s" % name,
"desc": "Parsing of non-negative integers in setAttribute",
"size": '50, 50',
"code": code,
"expected": expected
} )
- meta: |
# Composite operation tests
# <http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2007-March/010608.html>
Expand Down
47 changes: 0 additions & 47 deletions html/canvas/tools/yaml/offscreen/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -429,50 +429,3 @@
""" % (string,),
}
tests.append(test)
- meta: |
cases = [
("zero", "0", 0),
("empty", "", 0),
("onlyspace", " ", 0),
("space", " 100", 100),
("whitespace", "\t\f100", 100),
("plus", "+100", 100),
("minus", "-100", "exception"),
("octal", "0100", 100),
("hex", "0x100", 0x100),
("exp", "100e1", 100e1),
("decimal", "100.999", 100),
("percent", "100%", "exception"),
("em", "100em", "exception"),
("junk", "#!?", "exception"),
("trailingjunk", "100#!?", "exception"),
]
def gen(name, string, exp, code):
if exp is None:
code += "canvas.width = '%s';\ncanvas.height = '%s';\n" % (string, string)
code += "@assert canvas.width === 100;\n@assert canvas.height === 50;\n"
expected = None
elif exp == "exception":
code += "@assert throws TypeError canvas.width = '%s';\n" % string
expected = None
else:
code += "canvas.width = '%s';\ncanvas.height = '%s';\n" % (string, string)
code += "@assert canvas.width === %s;\n@assert canvas.height === %s;\n" % (exp, exp)
expected = None
code += "t.done();\n"
if exp == 0:
expected = None # can't generate zero-sized PNGs for the expected image
return code, expected
for name, string, exp in cases:
code = ""
code, expected = gen(name, string, exp, code)
tests.append( {
"name": "2d.canvas.host.size.attributes.parse.%s" % name,
"desc": "Parsing of non-negative integers",
"code": code,
} )

0 comments on commit f98387d

Please sign in to comment.