Mini Shell
from contextlib import contextmanager
import inspect
from io import BytesIO, StringIO
import sys
import tempfile
import unittest
from unittest import mock
from tap.parser import Parser
try:
import yaml
from more_itertools import peekable # noqa
have_yaml = True
except ImportError:
have_yaml = False
@contextmanager
def captured_output():
if sys.version_info[0] < 3:
new_out, new_err = BytesIO(), BytesIO()
else:
new_out, new_err = StringIO(), StringIO()
old_out, old_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = new_out, new_err
yield sys.stdout, sys.stderr
finally:
sys.stdout, sys.stderr = old_out, old_err
class TestParser(unittest.TestCase):
"""Tests for tap.parser.Parser"""
def test_finds_ok(self):
"""The parser extracts an ok line."""
parser = Parser()
line = parser.parse_line("ok - This is a passing test line.")
self.assertEqual("test", line.category)
self.assertTrue(line.ok)
self.assertTrue(line.number is None)
def test_finds_number(self):
"""The parser extracts a test number."""
parser = Parser()
line = parser.parse_line("ok 42 is the magic number.")
self.assertEqual("test", line.category)
self.assertEqual(42, line.number)
def test_finds_description(self):
parser = Parser()
line = parser.parse_line("ok 42 A passing test.")
self.assertEqual("test", line.category)
self.assertEqual("A passing test.", line.description)
def test_after_hash_is_not_description(self):
parser = Parser()
line = parser.parse_line("ok A description # Not part of description.")
self.assertEqual("test", line.category)
self.assertEqual("A description", line.description)
def test_finds_todo(self):
parser = Parser()
line = parser.parse_line("ok A description # TODO Not done")
self.assertEqual("test", line.category)
self.assertTrue(line.todo)
def test_finds_skip(self):
parser = Parser()
line = parser.parse_line("ok A description # SKIP for now")
self.assertEqual("test", line.category)
self.assertTrue(line.skip)
def test_finds_not_ok(self):
"""The parser extracts a not ok line."""
parser = Parser()
line = parser.parse_line("not ok - This is a failing test line.")
self.assertEqual("test", line.category)
self.assertFalse(line.ok)
self.assertTrue(line.number is None)
self.assertEqual("", line.directive.text)
def test_finds_directive(self):
"""The parser extracts a directive"""
parser = Parser()
test_line = "not ok - This line fails # TODO not implemented"
line = parser.parse_line(test_line)
directive = line.directive
self.assertEqual("test", line.category)
self.assertEqual("TODO not implemented", directive.text)
self.assertFalse(directive.skip)
self.assertTrue(directive.todo)
self.assertEqual("not implemented", directive.reason)
def test_unrecognizable_line(self):
"""The parser returns an unrecognizable line."""
parser = Parser()
line = parser.parse_line("This is not a valid TAP line. # srsly")
self.assertEqual("unknown", line.category)
def test_diagnostic_line(self):
"""The parser extracts a diagnostic line."""
text = "# An example diagnostic line"
parser = Parser()
line = parser.parse_line(text)
self.assertEqual("diagnostic", line.category)
self.assertEqual(text, line.text)
def test_bail_out_line(self):
"""The parser extracts a bail out line."""
parser = Parser()
line = parser.parse_line("Bail out! This is the reason to bail.")
self.assertEqual("bail", line.category)
self.assertEqual("This is the reason to bail.", line.reason)
def test_finds_version(self):
"""The parser extracts a version line."""
parser = Parser()
line = parser.parse_line("TAP version 13")
self.assertEqual("version", line.category)
self.assertEqual(13, line.version)
def test_errors_on_old_version(self):
"""The TAP spec dictates that anything less than 13 is an error."""
parser = Parser()
with self.assertRaises(ValueError):
parser.parse_line("TAP version 12")
def test_finds_plan(self):
"""The parser extracts a plan line."""
parser = Parser()
line = parser.parse_line("1..42")
self.assertEqual("plan", line.category)
self.assertEqual(42, line.expected_tests)
def test_finds_plan_with_skip(self):
"""The parser extracts a plan line containing a SKIP."""
parser = Parser()
line = parser.parse_line("1..42 # Skipping this test file.")
self.assertEqual("plan", line.category)
self.assertTrue(line.skip)
def test_ignores_plan_with_any_non_skip_directive(self):
"""The parser only recognizes SKIP directives in plans."""
parser = Parser()
line = parser.parse_line("1..42 # TODO will not work.")
self.assertEqual("unknown", line.category)
def test_parses_text(self):
sample = inspect.cleandoc(
u"""1..2
ok 1 A passing test
not ok 2 A failing test"""
)
parser = Parser()
lines = []
for line in parser.parse_text(sample):
lines.append(line)
self.assertEqual(3, len(lines))
self.assertEqual("plan", lines[0].category)
self.assertEqual("test", lines[1].category)
self.assertTrue(lines[1].ok)
self.assertEqual("test", lines[2].category)
self.assertFalse(lines[2].ok)
def test_parses_file(self):
sample = inspect.cleandoc(
"""1..2
ok 1 A passing test
not ok 2 A failing test"""
)
temp = tempfile.NamedTemporaryFile(delete=False)
temp.write(sample.encode("utf-8"))
temp.close()
parser = Parser()
lines = []
for line in parser.parse_file(temp.name):
lines.append(line)
self.assertEqual(3, len(lines))
self.assertEqual("plan", lines[0].category)
self.assertEqual("test", lines[1].category)
self.assertTrue(lines[1].ok)
self.assertIsNone(lines[1].yaml_block)
self.assertEqual("test", lines[2].category)
self.assertFalse(lines[2].ok)
def test_parses_yaml(self):
sample = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing test
---
test: sample yaml
...
not ok 2 A failing test"""
)
parser = Parser()
lines = []
for line in parser.parse_text(sample):
lines.append(line)
if have_yaml:
converted_yaml = yaml.safe_load(u"""test: sample yaml""")
self.assertEqual(4, len(lines))
self.assertEqual(13, lines[0].version)
self.assertEqual(converted_yaml, lines[2].yaml_block)
self.assertEqual("test", lines[3].category)
self.assertIsNone(lines[3].yaml_block)
else:
self.assertEqual(7, len(lines))
self.assertEqual(13, lines[0].version)
for line_index in list(range(3, 6)):
self.assertEqual("unknown", lines[line_index].category)
self.assertEqual("test", lines[6].category)
def test_parses_mixed(self):
# Test that we can parse both a version 13 and earlier version files
# using the same parser. Make sure that parsing works regardless of
# the order of the incoming documents.
sample_version_13 = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing version 13 test
---
test: sample yaml
...
not ok 2 A failing version 13 test"""
)
sample_pre_13 = inspect.cleandoc(
"""1..2
ok 1 A passing pre-13 test
not ok 2 A failing pre-13 test"""
)
parser = Parser()
lines = []
lines.extend(parser.parse_text(sample_version_13))
lines.extend(parser.parse_text(sample_pre_13))
if have_yaml:
self.assertEqual(13, lines[0].version)
self.assertEqual("A passing version 13 test", lines[2].description)
self.assertEqual("A failing version 13 test", lines[3].description)
self.assertEqual("A passing pre-13 test", lines[5].description)
self.assertEqual("A failing pre-13 test", lines[6].description)
else:
self.assertEqual(13, lines[0].version)
self.assertEqual("A passing version 13 test", lines[2].description)
self.assertEqual("A failing version 13 test", lines[6].description)
self.assertEqual("A passing pre-13 test", lines[8].description)
self.assertEqual("A failing pre-13 test", lines[9].description)
# Test parsing documents in reverse order
parser = Parser()
lines = []
lines.extend(parser.parse_text(sample_pre_13))
lines.extend(parser.parse_text(sample_version_13))
if have_yaml:
self.assertEqual("A passing pre-13 test", lines[1].description)
self.assertEqual("A failing pre-13 test", lines[2].description)
self.assertEqual(13, lines[3].version)
self.assertEqual("A passing version 13 test", lines[5].description)
self.assertEqual("A failing version 13 test", lines[6].description)
else:
self.assertEqual("A passing pre-13 test", lines[1].description)
self.assertEqual("A failing pre-13 test", lines[2].description)
self.assertEqual(13, lines[3].version)
self.assertEqual("A passing version 13 test", lines[5].description)
self.assertEqual("A failing version 13 test", lines[9].description)
def test_parses_yaml_no_end(self):
sample = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing test
---
test: sample yaml
not ok 2 A failing test"""
)
parser = Parser()
lines = []
for line in parser.parse_text(sample):
lines.append(line)
if have_yaml:
converted_yaml = yaml.safe_load(u"""test: sample yaml""")
self.assertEqual(4, len(lines))
self.assertEqual(13, lines[0].version)
self.assertEqual(converted_yaml, lines[2].yaml_block)
self.assertEqual("test", lines[3].category)
self.assertIsNone(lines[3].yaml_block)
else:
self.assertEqual(6, len(lines))
self.assertEqual(13, lines[0].version)
for line_index in list(range(3, 5)):
self.assertEqual("unknown", lines[line_index].category)
self.assertEqual("test", lines[5].category)
def test_parses_yaml_more_complex(self):
sample = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing test
---
message: test
severity: fail
data:
got:
- foo
expect:
- bar
output: |-
a multiline string
must be handled properly
even with | pipes
| here > and: there"""
)
parser = Parser()
lines = []
for line in parser.parse_text(sample):
lines.append(line)
if have_yaml:
converted_yaml = yaml.safe_load(
u'''
message: test
severity: fail
data:
got:
- foo
expect:
- bar
output: "a multiline string\\nmust be handled properly\\neven with | pipes\\n| here > and: there"''' # noqa
)
self.assertEqual(3, len(lines))
self.assertEqual(13, lines[0].version)
self.assertEqual(converted_yaml, lines[2].yaml_block)
else:
self.assertEqual(16, len(lines))
self.assertEqual(13, lines[0].version)
for line_index in list(range(3, 11)):
self.assertEqual("unknown", lines[line_index].category)
def test_parses_yaml_no_association(self):
sample = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing test
# Diagnostic line
---
test: sample yaml
...
not ok 2 A failing test"""
)
parser = Parser()
lines = []
for line in parser.parse_text(sample):
lines.append(line)
self.assertEqual(8, len(lines))
self.assertEqual(13, lines[0].version)
self.assertIsNone(lines[2].yaml_block)
self.assertEqual("diagnostic", lines[3].category)
for line_index in list(range(4, 7)):
self.assertEqual("unknown", lines[line_index].category)
self.assertEqual("test", lines[7].category)
def test_parses_yaml_no_start(self):
sample = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing test
test: sample yaml
...
not ok 2 A failing test"""
)
parser = Parser()
lines = []
for line in parser.parse_text(sample):
lines.append(line)
self.assertEqual(6, len(lines))
self.assertEqual(13, lines[0].version)
self.assertIsNone(lines[2].yaml_block)
for line_index in list(range(3, 5)):
self.assertEqual("unknown", lines[line_index].category)
self.assertEqual("test", lines[5].category)
def test_malformed_yaml(self):
self.maxDiff = None
sample = inspect.cleandoc(
u"""TAP version 13
1..2
ok 1 A passing test
---
test: sample yaml
\tfail: tabs are not allowed!
...
not ok 2 A failing test"""
)
yaml_err = inspect.cleandoc(
u"""
WARNING: Optional imports not found, TAP 13 output will be
ignored. To parse yaml, see requirements in docs:
https://tappy.readthedocs.io/en/latest/consumers.html#tap-version-13"""
)
parser = Parser()
lines = []
with captured_output() as (parse_out, _):
for line in parser.parse_text(sample):
lines.append(line)
if have_yaml:
self.assertEqual(4, len(lines))
self.assertEqual(13, lines[0].version)
with captured_output() as (out, _):
self.assertIsNone(lines[2].yaml_block)
self.assertEqual(
"Error parsing yaml block. Check formatting.", out.getvalue().strip()
)
self.assertEqual("test", lines[3].category)
self.assertIsNone(lines[3].yaml_block)
else:
self.assertEqual(8, len(lines))
self.assertEqual(13, lines[0].version)
for line_index in list(range(3, 7)):
self.assertEqual("unknown", lines[line_index].category)
self.assertEqual("test", lines[7].category)
self.assertEqual(yaml_err, parse_out.getvalue().strip())
def test_parse_empty_file(self):
temp = tempfile.NamedTemporaryFile(delete=False)
temp.close()
parser = Parser()
lines = []
for line in parser.parse_file(temp.name):
lines.append(line)
self.assertEqual(0, len(lines))
@mock.patch(
"tap.parser.sys.stdin",
StringIO(
u"""1..2
ok 1 A passing test
not ok 2 A failing test"""
),
)
def test_parses_stdin(self):
parser = Parser()
lines = []
for line in parser.parse_stdin():
lines.append(line)
self.assertEqual(3, len(lines))
self.assertEqual("plan", lines[0].category)
self.assertEqual("test", lines[1].category)
self.assertTrue(lines[1].ok)
self.assertEqual("test", lines[2].category)
self.assertFalse(lines[2].ok)
Zerion Mini Shell 1.0