Skip to content

Commit

Permalink
Merge pull request #5 from renanivo/support-preffix-flags
Browse files Browse the repository at this point in the history
Add support to python_* configurations
  • Loading branch information
renanivo authored Mar 14, 2017
2 parents e4c616a + 067b583 commit d55f896
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 44 deletions.
43 changes: 37 additions & 6 deletions pytest_testdox/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ def format_outcome(outcome):
return 'x' if outcome == 'passed' else ' '


def format_title(title):
return re.sub(r'^test_', '', title).replace('_', ' ')
def format_title(title, patterns):
return _remove_patterns(
patterns=patterns,
statement=title
).replace('_', ' ').strip()


def format_class_name(class_name):
def format_class_name(class_name, patterns):
formatted = ''

class_name = re.sub(r'^Test', '', class_name)
class_name = _remove_patterns(patterns, class_name)

for letter in class_name:
if letter.isupper():
Expand All @@ -26,5 +29,33 @@ def format_class_name(class_name):
return formatted.strip()


def format_module_name(module_name):
return format_title(re.sub(r'.py$', '', module_name)).replace('/', '.')
def format_module_name(module_name, patterns):
return format_title(
_remove_patterns(patterns, module_name),
patterns
).replace('/', '.')


def _remove_patterns(patterns, statement):
for glob_pattern in patterns:
pattern = glob_pattern.replace('*', '')

if glob_pattern.startswith('*'):
pattern = '{0}$'.format(pattern)
statement = re.sub(pattern, '', statement)

elif glob_pattern.endswith('*'):
pattern = '^{0}'.format(pattern)
statement = re.sub(pattern, '', statement)

elif '*' in glob_pattern:
infix_patterns = glob_pattern.split('*', 2)
infix_patterns[0] = '{}*'.format(infix_patterns[0])
infix_patterns[1] = '*{}'.format(infix_patterns[1])
statement = _remove_patterns(infix_patterns, statement)

else:
pattern = '^{0}'.format(pattern)
statement = re.sub(pattern, '', statement)

return statement
14 changes: 9 additions & 5 deletions pytest_testdox/parsers.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import re
from collections import namedtuple

from . import formatters

Node = namedtuple('Node', 'title class_name module_name')
PatternConfig = namedtuple('PatternConfig', 'files functions classes')


def parse_node(nodeid):
def parse_node(nodeid, pattern_config):
node_parts = nodeid.split('::')
title = formatters.format_title(node_parts[-1])
title = formatters.format_title(node_parts[-1], pattern_config.functions)
module_name = formatters.format_module_name(
re.sub('.py$', '', node_parts[0]).replace('/', '.')
node_parts[0],
pattern_config.files
)

class_name = node_parts[-2]
if '()' not in class_name:
class_name = None
else:
class_name = formatters.format_class_name(node_parts[-3])
class_name = formatters.format_class_name(
node_parts[-3],
pattern_config.classes
)

return Node(title, class_name, module_name)
7 changes: 6 additions & 1 deletion pytest_testdox/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ def pytest_runtest_logreport(self, report):
if report.when != 'call':
return

node = parsers.parse_node(report.nodeid)
pattern_config = parsers.PatternConfig(
files=self.config.getini('python_files'),
functions=self.config.getini('python_functions'),
classes=self.config.getini('python_classes')
)
node = parsers.parse_node(report.nodeid, pattern_config)

if node.class_name:
header = node.class_name
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def read(fname):
url='https://github.com/renanivo/pytest-testdox',
keywords='pytest testdox test report bdd',
install_requires=[
'pytest'
'pytest>=3.0.0'
],
packages=['pytest_testdox'],
classifiers=[
Expand Down
81 changes: 59 additions & 22 deletions tests/test_formatters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import pytest
from pytest_testdox import formatters


Expand All @@ -15,36 +16,72 @@ def test_should_return_a_space_when_failed(self):

class TestFormatTitle(object):

def test_should_replace_underscores_with_spaces(self):
assert formatters.format_title('a_test_name') == 'a test name'
@pytest.fixture
def patterns(self):
return ['test*']

def test_should_remove_test_prefix(self):
assert formatters.format_title('test_a_thing') == 'a thing'
assert formatters.format_title('a_thing_test') == 'a thing test'
def test_should_replace_underscores_with_spaces(self, patterns):
assert formatters.format_title('a_test_name', patterns) == (
'a test name'
)

def test_should_remove_test_pattern(self, patterns):
assert formatters.format_title('test_a_thing', patterns) == 'a thing'
assert formatters.format_title('a_thing_test', patterns) == (
'a thing test'
)


class TestFormatClassName(object):

def test_should_add_spaces_before_upercased_letters(self):
result = formatters.format_class_name('AThingBuilder')
@pytest.fixture
def patterns(self):
return ['Test*']

def test_should_add_spaces_before_upercased_letters(self, patterns):
result = formatters.format_class_name('AThingBuilder', patterns)
assert result == 'A Thing Builder'

def test_should_remove_test_prefix(self):
assert formatters.format_class_name('TestAThing') == 'A Thing'
assert formatters.format_class_name('AThingTest') == 'A Thing Test'
def test_should_remove_test_pattern(self, patterns):
assert formatters.format_class_name('TestAThing', patterns) == (
'A Thing'
)
assert formatters.format_class_name('AThingTest', patterns) == (
'A Thing Test'
)


class TestFormatModuleName(object):

def test_should_remove_py_file_suffix(self):
assert formatters.format_module_name('pymodule.py') == 'pymodule'

def test_should_replace_underscores_with_spaces(self):
assert formatters.format_module_name('a_test_name') == 'a test name'

def test_should_remove_test_prefix(self):
assert formatters.format_module_name('test_a_thing.py') == 'a thing'
assert formatters.format_module_name('a_test.py') == 'a test'

def test_should_replace_slashes_with_dots(self):
assert formatters.format_module_name('sub/module.py') == 'sub.module'
@pytest.fixture
def patterns(self):
return ['test*.py']

def test_should_remove_py_file_pattern(self, patterns):
assert formatters.format_module_name('pymodule.py', patterns) == (
'pymodule'
)

def test_should_replace_underscores_with_spaces(self, patterns):
assert formatters.format_module_name('a_test_name', patterns) == (
'a test name'
)

def test_should_remove_test_pattern(self, patterns):
assert formatters.format_module_name('test_a_thing.py', patterns) == (
'a thing'
)
assert formatters.format_module_name('a_test.py', patterns) == 'a test'

def test_should_replace_slashes_with_dots(self, patterns):
assert formatters.format_module_name('sub/module.py', patterns) == (
'sub.module'
)

def test_should_remove_infix_glob_patterns(self):
formatted = formatters.format_module_name(
'test_module.py',
['test_*.py']
)

assert formatted == 'module'
28 changes: 19 additions & 9 deletions tests/test_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,39 @@

class TestParseNodeId(object):

def test_should_return_a_node_instance(self):
@pytest.fixture
def pattern_config(self):
return parsers.PatternConfig(
files=['test_*.py'],
functions=['test*'],
classes=['Test*']
)

def test_should_return_a_node_instance(self, pattern_config):
nodeid = 'tests/test_module.py::test_title'
node = parsers.parse_node(nodeid)
node = parsers.parse_node(nodeid, pattern_config)

assert isinstance(node, parsers.Node)

def test_should_parse_node_id_attributes(self):
def test_should_parse_node_id_attributes(self, pattern_config):
nodeid = 'tests/test_module.py::test_title'
node = parsers.parse_node(nodeid)
node = parsers.parse_node(nodeid, pattern_config)

assert node.title == formatters.format_title('test_title')
assert node.title == formatters.format_title('test_title',
pattern_config.functions)
assert node.module_name == (
formatters.format_module_name('tests.test_module')
formatters.format_module_name('tests.test_module',
pattern_config.files)
)

@pytest.mark.parametrize('nodeid,class_name', (
('tests/test_module.py::test_title', None),
(
'tests/test_module.py::TestClassName::()::test_title',
formatters.format_class_name('TestClassName')
formatters.format_class_name('TestClassName', ['Test*'])
)
))
def test_should_parse_class_name(self, nodeid, class_name):
node = parsers.parse_node(nodeid)
def test_should_parse_class_name(self, pattern_config, nodeid, class_name):
node = parsers.parse_node(nodeid, pattern_config)

assert node.class_name == class_name
18 changes: 18 additions & 0 deletions tests/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,21 @@ def test_a_passing_test():

result = testdir.runpytest('--testdox')
assert '1 passed' in result.stdout.str()

def test_should_use_python_patterns_configuration(self, testdir):
testdir.makeini("""
[pytest]
python_classes=Describe*
python_files=*spec.py
python_functions=it*
""")
testdir.makefile('.py', module_spec="""
class DescribeTest(object):
def it_runs(self):
pass
""")

result = testdir.runpytest('--testdox')

lines = result.stdout.get_lines_after('Test')
assert '- [x] runs' in lines[0]

0 comments on commit d55f896

Please sign in to comment.