-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move parser tests from rtd-build repo (#4225)
* Import parser tests * Move code * Linter * Move utils module * Isort * Move tests for find.py * Move implementation from find.py * Add fixture * Fix path for test * Fix test about encoding Probably the file was corrupted, the test pass with a proper unicode filename. See #3732 (comment) * Linter * Isort * Remove wrong assert We are using unicode literals
- Loading branch information
Showing
9 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
"""Helper functions to search files.""" | ||
|
||
from __future__ import division, print_function, unicode_literals | ||
|
||
import os | ||
|
||
|
||
def find_all(path, filenames): | ||
"""Find all files in ``path`` that match in ``filenames``.""" | ||
path = os.path.abspath(path) | ||
for root, dirs, files in os.walk(path, topdown=True): | ||
dirs.sort() | ||
for filename in filenames: | ||
if filename in files: | ||
yield os.path.abspath(os.path.join(root, filename)) | ||
|
||
|
||
def find_one(path, filenames): | ||
"""Find the first file in ``path`` that match in ``filenames``.""" | ||
for _path in find_all(path, filenames): | ||
return _path | ||
return '' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# -*- coding: utf-8 -*- | ||
"""YAML parser for the RTD configuration file.""" | ||
|
||
from __future__ import division, print_function, unicode_literals | ||
|
||
import yaml | ||
|
||
__all__ = ('parse', 'ParseError') | ||
|
||
|
||
class ParseError(Exception): | ||
|
||
"""Parser related errors.""" | ||
|
||
pass | ||
|
||
|
||
def parse(stream): | ||
""" | ||
Take file-like object and return a list of project configurations. | ||
The files need be valid YAML and only contain mappings as documents. | ||
Everything else raises a ``ParseError``. | ||
""" | ||
try: | ||
configs = list(yaml.safe_load_all(stream)) | ||
except yaml.YAMLError as error: | ||
raise ParseError('YAML: {message}'.format(message=error)) | ||
if not configs: | ||
raise ParseError('Empty config') | ||
for config in configs: | ||
if not isinstance(config, dict): | ||
raise ParseError('Expected mapping') | ||
return configs |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
from __future__ import division, print_function, unicode_literals | ||
|
||
import os | ||
|
||
import pytest | ||
import six | ||
|
||
from readthedocs.config.find import find_all, find_one | ||
|
||
from .utils import apply_fs | ||
|
||
|
||
def test_find_no_files(tmpdir): | ||
with tmpdir.as_cwd(): | ||
paths = list(find_all(os.getcwd(), ('readthedocs.yml',))) | ||
assert len(paths) == 0 | ||
|
||
|
||
def test_find_at_root(tmpdir): | ||
apply_fs(tmpdir, {'readthedocs.yml': '', 'otherfile.txt': ''}) | ||
|
||
base = str(tmpdir) | ||
paths = list(find_all(base, ('readthedocs.yml',))) | ||
assert paths == [ | ||
os.path.abspath(os.path.join(base, 'readthedocs.yml')) | ||
] | ||
|
||
|
||
def test_find_nested(tmpdir): | ||
apply_fs(tmpdir, { | ||
'first': { | ||
'readthedocs.yml': '', | ||
}, | ||
'second': { | ||
'confuser.txt': 'content', | ||
}, | ||
'third': { | ||
'readthedocs.yml': 'content', | ||
'Makefile': '', | ||
}, | ||
}) | ||
apply_fs(tmpdir, {'first/readthedocs.yml': ''}) | ||
|
||
base = str(tmpdir) | ||
paths = list(find_all(base, ('readthedocs.yml',))) | ||
assert set(paths) == set([ | ||
str(tmpdir.join('first', 'readthedocs.yml')), | ||
str(tmpdir.join('third', 'readthedocs.yml')), | ||
]) | ||
|
||
|
||
def test_find_multiple_files(tmpdir): | ||
apply_fs(tmpdir, { | ||
'first': { | ||
'readthedocs.yml': '', | ||
'.readthedocs.yml': 'content', | ||
}, | ||
'second': { | ||
'confuser.txt': 'content', | ||
}, | ||
'third': { | ||
'readthedocs.yml': 'content', | ||
'Makefile': '', | ||
}, | ||
}) | ||
apply_fs(tmpdir, {'first/readthedocs.yml': ''}) | ||
|
||
base = str(tmpdir) | ||
paths = list(find_all(base, ('readthedocs.yml', | ||
'.readthedocs.yml'))) | ||
assert paths == [ | ||
str(tmpdir.join('first', 'readthedocs.yml')), | ||
str(tmpdir.join('first', '.readthedocs.yml')), | ||
str(tmpdir.join('third', 'readthedocs.yml')), | ||
] | ||
|
||
paths = list(find_all(base, ('.readthedocs.yml', | ||
'readthedocs.yml'))) | ||
assert paths == [ | ||
str(tmpdir.join('first', '.readthedocs.yml')), | ||
str(tmpdir.join('first', 'readthedocs.yml')), | ||
str(tmpdir.join('third', 'readthedocs.yml')), | ||
] | ||
|
||
|
||
@pytest.mark.skipif(not six.PY2, reason='Only for python2') | ||
def test_find_unicode_path(tmpdir): | ||
base_path = os.path.abspath( | ||
os.path.join(os.path.dirname(__file__), 'fixtures/bad_encode_project') | ||
) | ||
path = find_one(base_path, ('readthedocs.yml',)) | ||
assert path == '' | ||
unicode_base_path = base_path.decode('utf-8') | ||
assert isinstance(unicode_base_path, unicode) | ||
path = find_one(unicode_base_path, ('readthedocs.yml',)) | ||
assert path == '' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from __future__ import division, print_function, unicode_literals | ||
|
||
from io import StringIO | ||
|
||
from pytest import raises | ||
|
||
from readthedocs.config.parser import ParseError, parse | ||
|
||
|
||
def test_parse_empty_config_file(): | ||
buf = StringIO(u'') | ||
with raises(ParseError): | ||
parse(buf) | ||
|
||
|
||
def test_parse_invalid_yaml(): | ||
buf = StringIO(u'- - !asdf') | ||
with raises(ParseError): | ||
parse(buf) | ||
|
||
|
||
def test_parse_bad_type(): | ||
buf = StringIO(u'Hello') | ||
with raises(ParseError): | ||
parse(buf) | ||
|
||
|
||
def test_parse_single_config(): | ||
buf = StringIO(u'base: path') | ||
config = parse(buf) | ||
assert isinstance(config, list) | ||
assert len(config) == 1 | ||
assert config[0]['base'] == 'path' | ||
|
||
|
||
def test_parse_empty_list(): | ||
buf = StringIO(u'base: []') | ||
config = parse(buf) | ||
assert config[0]['base'] == [] | ||
|
||
|
||
def test_parse_multiple_configs_in_one_file(): | ||
buf = StringIO( | ||
u''' | ||
base: path | ||
--- | ||
base: other_path | ||
name: second | ||
nested: | ||
works: true | ||
''') | ||
configs = parse(buf) | ||
assert isinstance(configs, list) | ||
assert len(configs) == 2 | ||
assert configs[0]['base'] == 'path' | ||
assert configs[1]['nested'] == {'works': True} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from __future__ import division, print_function, unicode_literals | ||
|
||
from .utils import apply_fs | ||
|
||
|
||
def test_apply_fs_with_empty_contents(tmpdir): | ||
# Doesn't do anything if second paramter is empty. | ||
apply_fs(tmpdir, {}) | ||
assert tmpdir.listdir() == [] | ||
|
||
|
||
def test_apply_fs_create_empty_file(tmpdir): | ||
# Create empty file. | ||
apply_fs(tmpdir, {'file': ''}) | ||
assert len(tmpdir.listdir()) == 1 | ||
assert tmpdir.join('file').read() == '' | ||
|
||
|
||
def test_apply_fs_create_file_with_content(tmpdir): | ||
# Create file with content. | ||
apply_fs(tmpdir, {'file': 'content'}) | ||
assert tmpdir.join('file').read() == 'content' | ||
|
||
|
||
def test_apply_fs_create_subdirectory(tmpdir): | ||
# Create file with content. | ||
apply_fs(tmpdir, {'subdir': {'file': 'content'}}) | ||
assert tmpdir.join('subdir', 'file').read() == 'content' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from __future__ import division, print_function, unicode_literals | ||
|
||
|
||
def apply_fs(tmpdir, contents): | ||
""" | ||
Create the directory structure specified in ``contents``. It's a dict of | ||
filenames as keys and the file contents as values. If the value is another | ||
dict, it's a subdirectory. | ||
""" | ||
for filename, content in contents.items(): | ||
if hasattr(content, 'items'): | ||
apply_fs(tmpdir.mkdir(filename), content) | ||
else: | ||
file = tmpdir.join(filename) | ||
file.write(content) | ||
return tmpdir |