1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-08-17 00:20:42 +03:00

Tests n’ fixes. Lots of them.

This commit is contained in:
Simon Sapin 2012-04-02 14:45:44 +02:00
parent ad3cdf5dae
commit 46b1d225c7
21 changed files with 223 additions and 147 deletions

View File

@ -1,5 +1,6 @@
[report]
exclude_lines =
pragma: no cover
def __repr__
raise NotImplementedError
omit =

2
.gitignore vendored
View File

@ -1,6 +1,8 @@
*.pyc
/*.egg-info
/.coverage
/htmlcov
/coverage.xml
/.tox
/dist
/env

View File

@ -73,5 +73,5 @@ def main(argv=None, stdout=sys.stdout, stdin=sys.stdin):
getattr(html, 'write_' + format_)(output, stylesheets=args.stylesheet)
if __name__ == '__main__':
if __name__ == '__main__': # pragma: no cover
main()

View File

@ -140,17 +140,6 @@ class StyleDict(object):
object.__setattr__(style, 'anonymous', True)
return style
def as_dict(self):
"""Return a new dict completly separate from this object."""
if hasattr(self._parent, 'as_dict'):
rv = self._parent.as_dict()
elif hasattr(self._parent, 'items'):
rv = dict(self._parent)
else:
rv = {}
rv.update(self._storage)
return rv
def inherit_from(self):
"""Return a new StyleDict with inherited properties from this one.
@ -167,7 +156,7 @@ class StyleDict(object):
anonymous = False
def find_stylesheets(document):
def find_stylesheets(document, medium):
"""Yield the stylesheets of ``document``.
The output order is the same as the order of the dom.
@ -176,14 +165,15 @@ def find_stylesheets(document):
for element in document.dom.iter():
if element.tag not in ('style', 'link'):
continue
mimetype = element.get('type')
mime_type = element.get('type', 'text/css').split(';', 1)[0].strip()
# Only keep 'type/subtype' from 'type/subtype ; param1; param2'.
if mimetype and mimetype.split(';', 1)[0].strip() != 'text/css':
if mime_type != 'text/css':
continue
media_attr = element.get('media', '').strip() or 'all'
media = [media_type.strip() for media_type in media_attr.split(',')]
if not evaluate_media_query(media, medium):
continue
if element.tag == 'style':
# TODO: handle the `scoped` attribute
# Content is text that is directly in the <style> element, not its
# descendants
content = [element.text or '']
@ -193,17 +183,14 @@ def find_stylesheets(document):
# lxml should give us either unicode or ASCII-only bytestrings, so
# we don't need `encoding` here.
css = CSS(string=content, base_url=element.base_url)
css.media = media
yield css
elif element.tag == 'link' and element.get('href') and (
element.get('type', 'text/css').strip() == 'text/css'):
elif element.tag == 'link' and element.get('href'):
rel = element.get('rel', '').split()
if 'stylesheet' not in rel or 'alternate' in rel:
continue
href = get_url_attribute(element, 'href')
css = CSS(url=href, _check_mime_type=True)
if css.mime_type == 'text/css':
css.media = media
yield css
else:
LOGGER.warn('Unsupported stylesheet type: %s', css.mime_type)
@ -253,10 +240,9 @@ def declaration_precedence(origin, importance):
return 3
elif origin == 'author': # and importance
return 4
elif origin == 'user': # and importance
return 5
else:
assert ValueError('Unkown origin: %r' % origin)
assert origin == 'user' # and importance
return 5
def add_declaration(cascaded_styles, prop_name, prop_values, weight, element,
@ -428,7 +414,7 @@ def get_all_computed_styles(document, medium,
Return a dict of (DOM element, pseudo element type) -> StyleDict instance.
"""
author_stylesheets = list(find_stylesheets(document))
author_stylesheets = list(find_stylesheets(document, medium))
# keys: (element, pseudo_element_type)
# element: a lxml element object or the '@page' string for @page styles

View File

@ -340,8 +340,6 @@ def compute_float(computer, name, value):
@register_computer('font-size')
def font_size(computer, name, value):
"""Compute the ``font-size`` property."""
if isinstance(value, (int, float)):
return value
if value in FONT_SIZE_KEYWORDS:
return FONT_SIZE_KEYWORDS[value]

View File

@ -21,8 +21,7 @@ from tinycss.parsing import split_on_comma
from ..logger import LOGGER
from ..formatting_structure import counters
from ..compat import urljoin
from .values import (get_keyword, get_single_keyword, as_css,
make_percentage_value)
from .values import get_keyword, get_single_keyword, make_percentage_value
from .properties import INITIAL_VALUES, NOT_PRINT_MEDIA
from . import computed_values
@ -157,6 +156,11 @@ def background_attachment(keyword):
@validator('border-right-color')
@validator('border-bottom-color')
@validator('border-left-color')
@single_value
def other_colors(value):
return parse_color(value)
@validator('color')
@single_value
def color(value):
@ -967,7 +971,7 @@ def expand_border_side(name, values):
"""
for value in values:
if color([value]) is not None:
if parse_color(value) is not None:
suffix = '_color'
elif border_width([value]) is not None:
suffix = '_width'
@ -999,7 +1003,7 @@ def expand_background(name, values, base_url):
values = list(reversed(values))
while values:
value = values.pop()
if color([value]) is not None:
if parse_color(value) is not None:
suffix = '_color'
elif image([value], base_url) is not None:
suffix = '_image'

View File

@ -51,14 +51,11 @@ def get_percentage_value(value):
return None
def as_css(values):
"""Return the string reperesentation of the ``values`` list."""
return ' '.join('%s' % getattr(value, 'as_css', value) for value in values)
class FakePercentage(object):
type = 'PERCENTAGE'
def __init__(self, value):
self.value = value
self.as_css = '{}%'.format(value)
FakeValue = collections.namedtuple('FakeValue', ('type', 'value', 'as_css'))
def make_percentage_value(value):
"""Return an object that ``get_percentage_value()`` will accept."""
return FakeValue('PERCENTAGE', value, '{0}%'.format(value))
make_percentage_value = FakePercentage

View File

@ -144,15 +144,14 @@ def box_rectangle(box, which_rectangle):
box.padding_width(),
box.padding_height(),
)
elif which_rectangle == 'content-box':
else:
assert which_rectangle == 'content-box', which_rectangle
return (
box.content_box_x(),
box.content_box_y(),
box.width,
box.height,
)
else:
raise ValueError(which_rectangle)
def background_positioning_area(page, box, style):

View File

@ -219,16 +219,14 @@ def update_counters(state, style):
sibling_scopes.add(name)
counter_values.setdefault(name, []).append(value)
# Disabled for now, only exists in Lists3s editors draft.
for name, value in []: # XXX style.counter_set:
values = counter_values.setdefault(name, [])
if not values:
if name in sibling_scopes:
counter_values[name].pop()
else:
sibling_scopes.add(name)
values.append(0)
values[-1] = value
# XXX Disabled for now, only exists in Lists3s editors draft.
# for name, value in style.counter_set:
# values = counter_values.setdefault(name, [])
# if not values:
# assert name not in sibling_scopes
# sibling_scopes.add(name)
# values.append(0)
# values[-1] = value
counter_increment = style.counter_increment
if counter_increment == 'auto':
@ -243,10 +241,8 @@ def update_counters(state, style):
for name, value in counter_increment:
values = counter_values.setdefault(name, [])
if not values:
if name in sibling_scopes:
counter_values[name].pop()
else:
sibling_scopes.add(name)
assert name not in sibling_scopes
sibling_scopes.add(name)
values.append(0)
values[-1] += value

View File

@ -49,7 +49,7 @@ def block_level_layout(document, box, max_position_y, skip_stack,
adjoining_margins = []
collapsing_through = False
return box, resume_at, next_page, adjoining_margins, collapsing_through
else:
else: # pragma: no cover
raise TypeError('Layout for %s not handled yet' % type(box).__name__)
@ -373,7 +373,7 @@ def block_table_wrapper(document, wrapper, max_position_y, skip_stack,
if isinstance(child, boxes.TableBox):
table = child
break
else:
else: # pragma: no cover
raise ValueError('Table wrapper without a table')
resolve_percentages(wrapper, containing_block)
resolve_percentages(table, containing_block)

View File

@ -265,7 +265,7 @@ def atomic_box(box, containing_block, device_size):
image_marker_layout(box)
else:
inline_replaced_box_layout(box, containing_block, device_size)
else:
else: # pragma: no cover
raise TypeError('Layout for %s not handled yet' % type(box).__name__)
return box

View File

@ -351,12 +351,11 @@ def cell_baseline(cell):
if child is None:
stack.pop()
continue
if not child.is_in_normal_flow():
continue
if isinstance(child, (boxes.LineBox, boxes.TableRowBox)):
# First in-flow line or row.
return child.baseline + child.position_y - cell.position_y
if isinstance(child, boxes.ParentBox):
stack.append(iter(child.children))
if child.is_in_normal_flow():
if isinstance(child, (boxes.LineBox, boxes.TableRowBox)):
# First in-flow line or row.
return child.baseline + child.position_y - cell.position_y
if isinstance(child, boxes.ParentBox):
stack.append(iter(child.children))
# Default to the bottom of the content area.
return cell.border_top_width + cell.padding_top + cell.height

View File

@ -1,12 +1,13 @@
<html>
<head>
<meta http-equiv=Content-Type content=text/html;charset=utf8>
<link rel=stylesheet href="sheet1.css" media=screen>
<!-- currentColor means 'inherit' on color itself. -->
<link rel=stylesheet href="data:text/css;charset=ASCII,a%7Bcolor%3AcurrentColor%7D">
<style media=print>
@import url(sheet1.css);
@import url(data:text/css;charset=utf32;base64,//4AAGwAAABpAAAAewAAAGMAAABvAAAAbAAAAG8AAAByAAAAOgAAAHIAAABlAAAAZAAAAH0AAAA=);
@import url(sub_directory/sheet1.css);
@import "data:text/css;charset=utf-16-le;base64,\
bABpAHsAYwBvAGwAbwByADoAcgBlAGQAfQA=";
@import "data:,ul {border-width: 1000px !important}" screen;
a:after {
content: " [" attr(href) "]"
}
@ -14,6 +15,7 @@
ul {
border-style: none solid hidden;
border-width: thin thick 4px .25in;
font-weight: bold;
}
body > h1:first-child {
background-image: url(logo_small.png);
@ -22,12 +24,25 @@
background: red;
}
</style>
<style type=text/NOT-css>
ul {
border-width: 1000px !important;
}
</style>
<style media=screen>
ul {
border-width: 1000px !important;
}
</style>
<link rel=not_stylesheet href="data:,ul {border-width: 1000px !important}">
</head>
<body>
<h1>WeasyPrint test document (with Ünicōde)</h1>
<p style="color: black; font-size: 2em">Hello</p>
<ul>
<li><a href=home.html style="padding: 1px 2px 3px 4px">Home</a>
<h1 style="font-size: 2em">WeasyPrint test document (with Ünicōde)</h1>
<p style="color: blue; font-size: x-large">Hello</p>
<ul style="font-size: 5ex">
<li style="font-size: 6pt; font-weight: bolder">
<a href=home.html
style="padding: 1px 2px 3px 4px; font-size: 300%">Home</a>
<li>
</ul>
</body>

View File

@ -1,10 +0,0 @@
@import url(sheet2.css) all;
p {
background-color: blue;
}
@media print {
ul {
margin: 2em;
}
}

View File

@ -0,0 +1,16 @@
@import url(../sheet2.css) all;
p {
background: currentColor;
}
@media print {
ul {
/* Currently, 1ex == 0.5em exactly. */
margin: 2em 4ex;
}
}
@media screen {
ul {
border-width: 1000px !important;
}
}

View File

@ -153,12 +153,11 @@ def sanity_checks(box):
if not isinstance(box, boxes.ParentBox):
return
acceptable_types_lists = None # raises when iterated
for class_ in type(box).mro():
if class_ in PROPER_CHILDREN:
acceptable_types_lists = PROPER_CHILDREN[class_]
break
else:
raise TypeError
assert any(
all(isinstance(child, acceptable_types) for child in box.children)
@ -218,6 +217,23 @@ def test_inline_in_block():
box = build.inline_in_block(box)
assert_tree(box, expected)
source = '<div><p>Lipsum.</p>Hello, <em>World</em>!\n</div>'
expected = [
('div', 'Block', [
('p', 'Block', [
('p', 'Line', [
('p', 'Text', 'Lipsum.')])]),
('div', 'AnonBlock', [
('div', 'Line', [
('div', 'Text', 'Hello, '),
('em', 'Inline', [
('em', 'Text', 'World')]),
('div', 'Text', '!\n')])])])]
box = parse(source)
box = build.inline_in_block(box)
assert_tree(box, expected)
@assert_no_logs
def test_block_in_inline():

View File

@ -63,6 +63,9 @@ def test_data_url():
parse('data:text/plain;base64,Zm9vbw', b'fooo', 'text/plain', None)
parse('data:text/plain;base64,Zm9vb28', b'foooo', 'text/plain', None)
with raises(IOError):
parse_data_url('data:foo')
@assert_no_logs
def test_style_dict():
@ -81,22 +84,20 @@ def test_find_stylesheets():
"""Test if the stylesheets are found in a HTML document."""
document = parse_html('doc1.html')
sheets = list(css.find_stylesheets(document))
assert len(sheets) == 3
sheets = list(css.find_stylesheets(document, 'print'))
assert len(sheets) == 2
# Also test that stylesheets are in tree order
assert [s.base_url.rsplit('/', 1)[-1].rsplit(',', 1)[-1] for s in sheets] \
== ['sheet1.css', 'a%7Bcolor%3AcurrentColor%7D',
'doc1.html']
== ['a%7Bcolor%3AcurrentColor%7D', 'doc1.html']
rules = [rule for sheet in sheets for rule in sheet.rules]
assert len(rules) == 13
assert len(rules) == 10
# Also test appearance order
assert [
rule.selector if rule.at_keyword else ''.join(
v.as_css for v in rule.selector)
for rule, _selector_list, _declarations in rules
] == [
'li', 'p', 'ul', # imported
'a', 'li', 'p', 'ul', 'li', 'a:after', (None, 'first'), 'ul',
'body > h1:first-child', 'h1 ~ p ~ ul a:after'
]
@ -117,7 +118,7 @@ def test_expand_shorthands():
assert 'margin-top' not in style
style = dict(
(name, css.values.as_css([value]))
(name, value.as_css)
for _rule, _selectors, declarations in sheet.rules
for name, value, _priority in declarations)
@ -159,39 +160,43 @@ def test_annotate_document():
+ os.path.abspath(resource_filename('logo_small.png'))
assert h1.font_weight == 700
assert h1.font_size == 32 # 4ex
# 32px = 1em * font-size: 2em * initial 16px
assert p.margin_top == 32
# 32px = 1em * font-size = x-large = 3/2 * initial 16px = 24px
assert p.margin_top == 24
assert p.margin_right == 0
assert p.margin_bottom == 32
assert p.margin_bottom == 24
assert p.margin_left == 0
assert p.background_color == (0, 0, 1, 1) # blue
# 32px = 2em * initial 16px
assert ul.margin_top == 32
assert ul.margin_right == 32
assert ul.margin_bottom == 32
assert ul.margin_left == 32
# 80px = 2em * 5ex = 10 * half of initial 16px
assert ul.margin_top == 80
assert ul.margin_right == 80
assert ul.margin_bottom == 80
assert ul.margin_left == 80
assert ul.font_weight == 700
# thick = 5px, 0.25 inches = 96*.25 = 24px
assert ul.border_top_width == 0
assert ul.border_right_width == 5
assert ul.border_bottom_width == 0
assert ul.border_left_width == 24
# 32px = 2em * initial 16px
# 64px = 4em * initial 16px
assert li_0.margin_top == 32
assert li_0.font_weight == 900
assert li_0.font_size == 8 # 6pt
assert li_0.margin_top == 16 # 2em
assert li_0.margin_right == 0
assert li_0.margin_bottom == 32
assert li_0.margin_left == 64
assert li_0.margin_bottom == 16
assert li_0.margin_left == 32 # 4em
assert a.text_decoration == frozenset(['underline'])
assert a.font_size == 24 # 300% of 8px
assert a.padding_top == 1
assert a.padding_right == 2
assert a.padding_bottom == 3
assert a.padding_left == 4
assert a.color == (1, 0, 0, 1)
# Test the initial border-color: currentColor
assert a.border_top_color == (1, 0, 0, 1)
@ -343,4 +348,39 @@ def test_line_height_inheritance():
assert paragraph.style.font_size == 20
# 1.4 is inherited from p, 1.4 * 20px on em = 28px
assert used_line_height(paragraph.style) == 28
assert paragraph.style.vertical_align == 14 # 50% of 28pxhh
assert paragraph.style.vertical_align == 14 # 50% of 28px
@assert_no_logs
def test_important():
document = TestPNGDocument('''
<style>
p:nth-child(1) { color: lime }
body p:nth-child(2) { color: red }
p:nth-child(3) { color: lime !important }
body p:nth-child(3) { color: red }
body p:nth-child(5) { color: lime }
p:nth-child(5) { color: red }
p:nth-child(6) { color: red }
p:nth-child(6) { color: lime }
</style>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
''', user_stylesheets=[CSS(string='''
body p:nth-child(1) { color: red }
p:nth-child(2) { color: lime !important }
p:nth-child(4) { color: lime !important }
body p:nth-child(4) { color: red }
''')])
html = document.formatting_structure
body, = html.children
for paragraph in body.children:
assert paragraph.style.color == (0, 1, 0, 1) # lime (light green)

View File

@ -14,25 +14,25 @@ from __future__ import division, unicode_literals
from pytest import raises
from tinycss.color3 import RGBA
from tinycss.parsing import remove_whitespace
from .testing_utils import assert_no_logs
from ..css import validation, PARSER
from ..css.values import as_css
# TODO: merge this into test_css.py ?
# TODO: rewrite this mess
def expand_to_dict(short_name, short_values):
"""Helper to test shorthand properties expander functions."""
return dict((name, value if isinstance(value, RGBA)
else as_css(value) if isinstance(value, (list, tuple))
declarations, errors = PARSER.parse_style_attr('prop: ' + short_values)
assert not errors
assert len(declarations) == 1
tokens = remove_whitespace(declarations[0].value)
expanded = validation.EXPANDERS[short_name]('', short_name, tokens)
return dict((name, tuple(v.as_css for v in value)
if name == 'background_position'
else getattr(value, 'as_css', value))
for name, value in validation.EXPANDERS[short_name](
'', short_name,
[token for token in PARSER.parse_style_attr(
'prop: ' + short_values)[0][0].value
if token.type != 'S']))
for name, value in expanded)
@assert_no_logs
@ -162,7 +162,7 @@ def test_expand_background():
image='none',
repeat='repeat',
attachment='scroll',
position='0% 0%'
position=('0%', '0%'),
)
assert_background(
@ -171,7 +171,7 @@ def test_expand_background():
image='foo.png', ##
repeat='repeat',
attachment='scroll',
position='0% 0%'
position=('0%', '0%'),
)
assert_background(
'no-repeat',
@ -179,7 +179,7 @@ def test_expand_background():
image='none',
repeat='no-repeat', ##
attachment='scroll',
position='0% 0%'
position=('0%', '0%'),
)
assert_background(
'fixed',
@ -187,7 +187,7 @@ def test_expand_background():
image='none',
repeat='repeat',
attachment='fixed', ##
position='0% 0%'
position=('0%', '0%'),
)
assert_background(
'top right',
@ -196,7 +196,7 @@ def test_expand_background():
repeat='repeat',
attachment='scroll',
# Order swapped to be in (horizontal, vertical) order.
position='100% 0%' ##
position=('100%', '0%'), ##
)
assert_background(
'url(bar) #f00 repeat-y center left fixed',
@ -205,7 +205,7 @@ def test_expand_background():
repeat='repeat-y', ##
attachment='fixed', ##
# Order swapped to be in (horizontal, vertical) order.
position='0% 50%' ##
position=('0%', '50%'), ##
)
assert_background(
'#00f 10% 200px',
@ -213,7 +213,7 @@ def test_expand_background():
image='none',
repeat='repeat',
attachment='scroll',
position='10% 200px' ##
position=('10%', '200px'), ##
)
assert_background(
'right 78px fixed',
@ -221,20 +221,20 @@ def test_expand_background():
image='none',
repeat='repeat',
attachment='fixed', ##
position='100% 78px' ##
position=('100%', '78px'), ##
)
@assert_no_logs
def test_font():
"""Test the ``font`` property."""
assert expand_to_dict('font', '12px sans_serif') == {
assert expand_to_dict('font', '12px My Fancy Font, serif') == {
'font_style': 'normal',
'font_variant': 'normal',
'font_weight': 400,
'font_size': '12px', ##
'line_height': 'normal',
'font_family': 'sans_serif', ##
'font_family': ['My Fancy Font', 'serif'], ##
}
assert expand_to_dict('font', 'small/1.2 "Some Font", serif') == {
'font_style': 'normal',
@ -242,8 +242,7 @@ def test_font():
'font_weight': 400,
'font_size': 'small', ##
'line_height': '1.2', ##
# The comma and quotes were lost in expand_to_dict()
'font_family': 'Some Font serif', ##
'font_family': ['Some Font', 'serif'], ##
}
assert expand_to_dict('font', 'small-caps italic 700 large serif') == {
'font_style': 'italic', ##
@ -251,5 +250,5 @@ def test_font():
'font_weight': 700, ##
'font_size': 'large', ##
'line_height': 'normal',
'font_family': 'serif', ##
'font_family': ['serif'], ##
}

View File

@ -37,7 +37,7 @@ BYTES_PER_PIXELS = 4
PIXEL_FORMAT = 'rgba(%i, %i, %i, %i)'
def format_pixel(pixels, width, x, y):
def format_pixel(pixels, width, x, y): # pragma: no cover
"""Return the pixel color as ``#RRGGBB``."""
start = (y * width + x) * BYTES_PER_PIXELS
end = start + BYTES_PER_PIXELS
@ -93,13 +93,13 @@ def assert_different_renderings(expected_width, expected_height, documents):
for i, (name_1, lines_1) in enumerate(lines_list):
for name_2, lines_2 in lines_list[i + 1:]:
if lines_1 == lines_2:
if lines_1 == lines_2: # pragma: no cover
# Same as "assert lines_1 != lines_2" but the output of
# the assert hook would be gigantic and useless.
assert False, '%s and %s are the same' % (name_1, name_2)
def write_png(basename, lines, width, height):
def write_png(basename, lines, width, height): # pragma: no cover
"""Take a pixel matrix and write a PNG file."""
directory = os.path.join(os.path.dirname(__file__), 'test_results')
if not os.path.isdir(directory):
@ -144,7 +144,7 @@ def assert_pixels_equal(name, width, height, lines, expected_lines):
Take 2 matrices of height by width pixels and assert that they
are the same.
"""
if lines != expected_lines:
if lines != expected_lines: # pragma: no cover
write_png(name + '.expected', expected_lines, width, height)
write_png(name, lines, width, height)
for y in xrange(height):

View File

@ -372,17 +372,21 @@ def test_lists():
@assert_no_logs
def test_empty_linebox():
"""Test lineboxes with no content other than space-like characters."""
page, = parse('''
<style>
p { font-size: 12px; width: 500px;
font-family:%(fonts)s;}
</style>
<p> </p>
''' % {'fonts': FONTS})
page, = parse('<p> </p>')
paragraph, = body_children(page)
assert len(paragraph.children) == 0
assert paragraph.height == 0
# Whitespace removed at the beginning of the line => empty line => no line
page, = parse('''
<style>
p { width: 1px }
</style>
<p><br> </p>
''')
paragraph, = body_children(page)
assert len(paragraph.children) == 1
@assert_no_logs
def test_breaking_linebox():
@ -1421,6 +1425,20 @@ def test_text_align_justify():
assert image_5.position_x == 0
# single-word line (zero spaces)
page, = parse('''
<style>
body { text-align: justify; width: 50px }
</style>
<p>Supercalifragilisticexpialidocious bar</p>
''')
html, = page.children
body, = html.children
paragraph, = body.children
line_1, line_2 = paragraph.children
text, = line_1.children
assert text.position_x == 0
@assert_no_logs
def test_word_spacing():
@ -1454,23 +1472,23 @@ def test_word_spacing():
def test_letter_spacing():
"""Test letter-spacing."""
page, = parse('''
<body><strong>Supercalifragilisticexpialidocious></strong>
<body><strong>Supercalifragilisticexpialidocious</strong>
''')
html, = page.children
body, = html.children
line, = body.children
strong_1, = line.children
assert 280 <= strong_1.width <= 310
assert 250 <= strong_1.width <= 300
page, = parse('''
<style>strong { letter-spacing: 11px }</style>
<body><strong>Supercalifragilisticexpialidocious></strong>
<body><strong>Supercalifragilisticexpialidocious</strong>
''')
html, = page.children
body, = html.children
line, = body.children
strong_2, = line.children
assert strong_2.width - strong_1.width == 34 * 11
assert strong_2.width - strong_1.width == 33 * 11
@assert_no_logs

View File

@ -38,10 +38,10 @@ class TestPNGDocument(PNGDocument):
This stylesheet is shorter, which makes tests faster.
"""
def __init__(self, html_source, base_url=None):
def __init__(self, html_source, base_url=None, user_stylesheets=()):
super(TestPNGDocument, self).__init__(
HTML(string=html_source, base_url=base_url).root_element,
user_stylesheets=[],
user_stylesheets=user_stylesheets,
user_agent_stylesheets=[TEST_UA_STYLESHEET])
@ -87,7 +87,7 @@ def assert_no_logs(function):
with capture_logs() as logs:
try:
function()
except Exception:
except Exception: # pragma: no cover
if logs:
print('%i errors logged:' % len(logs), file=sys.stderr)
raise