Created
January 10, 2010 12:48
-
-
Save bebraw/273484 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
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) |
This file contains hidden or 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
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