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
|
"""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']:
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")
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
|