-
Notifications
You must be signed in to change notification settings - Fork 140
/
conftest.py
152 lines (123 loc) · 4.59 KB
/
conftest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
"""py.test plugin configuration."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import logging
from pathlib import Path
import pytest
import scss
from scss.compiler import compile_file
import scss.config
from scss.errors import SassEvaluationError
from scss.errors import SassMissingDependency
from scss.extension.core import CoreExtension
from scss.extension.extra import ExtraExtension
from scss.extension.fonts import FontsExtension
from scss.extension.compass import CompassExtension
try:
import fontforge
except ImportError:
fontforge = None
# Turn on pyscss's logging
console = logging.StreamHandler()
logger = logging.getLogger('scss')
logger.setLevel(logging.ERROR)
logger.addHandler(console)
def pytest_addoption(parser):
"""Add options for filtering which file tests run.
This has to be done in the project root; py.test doesn't (and can't)
recursively look for conftest.py files until after it's parsed the command
line.
"""
parser.addoption(
'--include-ruby',
help='run tests imported from Ruby and sassc, most of which fail',
action='store_true',
dest='include_ruby',
)
def pytest_ignore_collect(path, config):
# Ruby/sassc tests don't even exist without this option
if path.basename in ('from_ruby', 'from-sassc'):
if not config.getoption('include_ruby'):
return True
def pytest_collect_file(path, parent):
if path.ext == '.scss':
parts = str(path).split(path.sep)
# -4 tests / -3 files / -2 directory / -1 file.scss
if parts[-4:-2] == ['tests', 'files']:
if hasattr(SassFile, "from_parent"):
return SassFile.from_parent(parent, fspath=path)
else:
return SassFile(path, parent)
class SassFile(pytest.File):
def collect(self):
parent_name = self.fspath.dirpath().basename
if not fontforge and parent_name == 'fonts':
pytest.skip("font tests require fontforge")
if hasattr(SassItem, "from_parent"):
yield SassItem.from_parent(parent=self, name=str(self.fspath))
else:
yield SassItem(str(self.fspath), self)
class SassItem(pytest.Item):
"""A Sass test input file, collected as its own test item.
A file of the same name but with a .css extension is assumed to contain the
expected output.
"""
_nodeid = None
@property
def nodeid(self):
# Rig the nodeid to be "directory::filename", so all the files in the
# same directory are treated as grouped together
if not self._nodeid:
self._nodeid = "{0}::{1}".format(
self.fspath.dirpath().relto(self.session.fspath),
self.fspath.basename,
)
return self._nodeid
def reportinfo(self):
return (
self.fspath.dirpath(),
None,
self.fspath.relto(self.session.fspath),
)
def _prunetraceback(self, excinfo):
# Traceback implements __getitem__, but list implements __getslice__,
# which wins in Python 2
excinfo.traceback = excinfo.traceback.cut(__file__)
def runtest(self):
scss_file = Path(str(self.fspath))
css_file = scss_file.with_suffix('.css')
with css_file.open('rb') as fh:
# Output is Unicode, so decode this here
expected = fh.read().decode('utf8')
scss.config.STATIC_ROOT = str(scss_file.parent / 'static')
search_path = []
include = scss_file.parent / 'include'
if include.exists():
search_path.append(include)
search_path.append(scss_file.parent)
try:
actual = compile_file(
scss_file,
output_style='expanded',
search_path=search_path,
extensions=[
CoreExtension,
ExtraExtension,
FontsExtension,
CompassExtension,
],
)
except SassEvaluationError as e:
# Treat any missing dependencies (PIL not installed, fontforge not
# installed) as skips
# TODO this is slightly cumbersome and sorta defeats the purpose of
# having separate exceptions
if isinstance(e.exc, SassMissingDependency):
pytest.skip(e.format_message())
else:
raise
# Normalize leading and trailing newlines
actual = actual.strip('\n')
expected = expected.strip('\n')
assert expected == actual