Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
from collections import deque
class InputError(Exception):
pass
class MatchError(Exception):
pass
class OutputError(Exception):
pass
class Line:
def __init__(self, content):
self.content = content
def __str__(self):
return self.content
class Input(Line):
pass
class Output(Line):
pass
def parse_line(line):
if len(line.strip()) == 0:
return
prefix = '>>> '
if line.startswith(prefix):
content = line.strip(prefix)
return Input(content)
else:
content = line
return Output(content)
class ScenarioTester:
def __init__(self, app_class):
self.app = app_class()
self.app.input = self._input
self.app.output = self._output
self.lines = deque()
def test(self, scenario):
self.parse(scenario)
self.app.run()
def parse(self, scenario):
self.lines.clear()
for line in scenario.split('\n'):
parsed_line = parse_line(line)
if parsed_line:
self.lines.append(parsed_line)
def _input(self):
current_line = self.lines.popleft()
if isinstance(current_line, Input):
return str(current_line)
else:
raise InputError, 'Expected input but got output instead!' + \
' Failed at line "%s".' % current_line
def _output(self, result):
current_line = self.lines.popleft()
if isinstance(current_line, Output):
content = current_line.content
if content != str(result):
raise MatchError, "Output content didn't match!" + \
" Expected %s (%s) but got %s (%s) instead." \
% (content, type(content), result, type(result))
else:
raise OutputError, 'Expected output but got input instead!' + \
' Failed at line "%s". Result: %s.' % (current_line, result)
from placidity.scenario_tester import Input, InputError, MatchError, \
Output, OutputError, ScenarioTester
from py.test import raises
class AbstractApplication:
def run(self):
while True:
input = self.input()
if input == 'quit':
break
result = self.interpret(input)
if result:
self.output(result)
class TestScenarioTester:
def test_passing_test(self):
class Application(AbstractApplication):
def interpret(self, input):
if input == 'a':
return 4
scenario = '''
>>> a = 4
>>> a
4
>>> quit
'''
scenario_tester = ScenarioTester(Application)
scenario_tester.parse(scenario)
lines = scenario_tester.lines
assert len(lines) == 4
self.assert_line(lines, 1, Input, 'a = 4')
self.assert_line(lines, 2, Input, 'a')
self.assert_line(lines, 3, Output, '4')
self.assert_line(lines, 4, Input, 'quit')
# this should not trigger any asserts
scenario_tester.test(scenario)
def test_input_fail(self):
class Application(AbstractApplication):
def interpret(self, input):
pass
scenario = '''
fail
'''
scenario_tester = ScenarioTester(Application)
scenario_tester.parse(scenario)
lines = scenario_tester.lines
assert len(lines) == 1
self.assert_line(lines, 1, Output, 'fail')
raises(InputError, scenario_tester.test, scenario)
def test_match_fail(self):
class Application(AbstractApplication):
def interpret(self, input):
if input == 'a':
return 42
scenario = '''
>>> a = 4
>>> a
5
'''
scenario_tester = ScenarioTester(Application)
scenario_tester.parse(scenario)
lines = scenario_tester.lines
assert len(lines) == 3
self.assert_line(lines, 1, Input, 'a = 4')
self.assert_line(lines, 2, Input, 'a')
self.assert_line(lines, 3, Output, '5')
raises(MatchError, scenario_tester.test, scenario)
def test_output_fail(self):
class Application(AbstractApplication):
def interpret(self, input):
return 42
scenario = '''
>>> fail
>>> fail
'''
scenario_tester = ScenarioTester(Application)
scenario_tester.parse(scenario)
lines = scenario_tester.lines
assert len(lines) == 2
self.assert_line(lines, 1, Input, 'fail')
self.assert_line(lines, 2, Input, 'fail')
raises(OutputError, scenario_tester.test, scenario)
def assert_line(self, lines, line_number, line_type, line_content):
line = lines[line_number - 1]
assert isinstance(line, line_type)
assert line.content == line_content
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment