summaryrefslogtreecommitdiff
path: root/yarnlib
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2013-06-09 11:56:29 +0100
committerLars Wirzenius <liw@liw.fi>2013-06-09 11:56:29 +0100
commita91ac948b037f58217d89553fa031a18960b9623 (patch)
tree854a96f1d2d3fb3a58411ac6ae661a089a6ae607 /yarnlib
parent7fdb775486405a334b2f0db4e47eac9c7ed53023 (diff)
downloadcmdtest-a91ac948b037f58217d89553fa031a18960b9623.tar.gz
Implement BlockParser
Diffstat (limited to 'yarnlib')
-rw-r--r--yarnlib/block_parser.py112
-rw-r--r--yarnlib/block_parser_tests.py14
2 files changed, 118 insertions, 8 deletions
diff --git a/yarnlib/block_parser.py b/yarnlib/block_parser.py
index 8fd87d2..09a7a22 100644
--- a/yarnlib/block_parser.py
+++ b/yarnlib/block_parser.py
@@ -16,6 +16,116 @@
# =*= License: GPL-3+ =*=
+import yarnlib
+
+
+# Parse a sequence of textual blocks into Story and Implementation
+# objects, and their constituent objects.
+
class BlockParser(object):
- pass
+ def __init__(self):
+ self.stories = []
+ self.implementations = []
+ self.line_parsers = {
+ 'STORY': self.parse_story,
+ 'GIVEN': self.parse_given,
+ 'WHEN': self.parse_when,
+ 'THEN': self.parse_then,
+ 'FINALLY': self.parse_finally,
+ 'AND': self.parse_and,
+ 'IMPLEMENTS': self.parse_implementing,
+ }
+
+ def parse_blocks(self, blocks):
+ while blocks:
+ blocks = self.parse_one(blocks)
+
+ def parse_one(self, blocks):
+ assert blocks
+ block = blocks[0]
+ assert block
+ t = block.split('\n', 1)
+ assert len(t) in [1,2]
+ if len(t) == 1:
+ line1 = block
+ block = ''
+ else:
+ line1, block = t
+ if block:
+ blocks[0] = block
+ else:
+ del blocks[0]
+
+ words = line1.split()
+ if not words:
+ return blocks
+ rest = ' '.join(words[1:])
+
+ for keyword in self.line_parsers:
+ if words[0] == keyword:
+ return self.line_parsers[keyword](rest, blocks)
+
+ raise StoryTestSyntaxError("Syntax error: unknown step: %s" % line1)
+
+ def parse_story(self, line, blocks):
+ self.stories.append(yarnlib.Story(line))
+ return blocks
+
+ def parse_simple(self, what, line, blocks):
+ if not self.stories:
+ raise StoryTestSyntaxError('Syntax errror: %s before STORY' % what)
+ step = yarnlib.StoryStep(what, line)
+ self.stories[-1].steps.append(step)
+ return blocks
+
+ def parse_given(self, line, blocks):
+ return self.parse_simple('GIVEN', line, blocks)
+
+ def parse_when(self, line, blocks):
+ return self.parse_simple('WHEN', line, blocks)
+
+ def parse_then(self, line, blocks):
+ return self.parse_simple('THEN', line, blocks)
+
+ def parse_finally(self, line, blocks):
+ return self.parse_simple('FINALLY', line, blocks)
+
+ def parse_and(self, line, blocks):
+ if not self.stories:
+ raise StoryTestSyntaxError('Syntax errror: AND before STORY')
+ story = self.stories[-1]
+ if not story.steps:
+ raise StoryTestSyntaxError(
+ 'Syntax errror: AND before what it would continue')
+ step = story.steps[-1]
+ assert step.what in self.line_parsers
+ return self.line_parsers[step.what](line, blocks)
+
+ def parse_implementing(self, line, blocks):
+ words = line.split()
+ if len(words) < 2:
+ raise StoryTestSyntaxError(
+ 'Syntax error: IMPLEMENTING must have what and regexp')
+ what = words[0]
+ regexp = ' '.join(words[1:])
+ if blocks:
+ block = blocks[0]
+ shell = []
+ rest = []
+ for block_line in block.splitlines():
+ if rest or block_line.startswith('IMPLEMENTS'):
+ rest.append(block_line)
+ else:
+ shell.append(block_line)
+ shell = '\n'.join(shell)
+ if rest:
+ blocks[0] = '\n'.join(rest)
+ else:
+ del blocks[0]
+ else:
+ shell = ''
+ implementation = yarnlib.Implementation(what, regexp, shell)
+ self.implementations.append(implementation)
+ return blocks
+
diff --git a/yarnlib/block_parser_tests.py b/yarnlib/block_parser_tests.py
index 1c14a80..ff1feab 100644
--- a/yarnlib/block_parser_tests.py
+++ b/yarnlib/block_parser_tests.py
@@ -42,17 +42,17 @@ class BlockParserTests(unittest.TestCase):
self.assertEqual(len(story.steps), 3)
self.assertEqual(story.steps[0].what, 'GIVEN')
self.assertEqual(story.steps[0].text, 'bar')
- self.assertEqual(story.steps[0].what, 'WHEN')
- self.assertEqual(story.steps[0].text, 'foobar')
- self.assertEqual(story.steps[0].what, 'THEN')
- self.assertEqual(story.steps[0].text, 'yoyo')
+ self.assertEqual(story.steps[1].what, 'WHEN')
+ self.assertEqual(story.steps[1].text, 'foobar')
+ self.assertEqual(story.steps[2].what, 'THEN')
+ self.assertEqual(story.steps[2].text, 'yoyo')
def test_normalises_whitespace(self):
- self.parser.parse_code_blocks(['STORY foo bar '])
+ self.parser.parse_blocks(['STORY foo bar '])
self.assertEqual(self.parser.stories[0].name, 'foo bar')
def test_parses_implements_in_a_block_by_itself(self):
- self.parser.parse_code_blocks(['IMPLEMENTS GIVEN foo\ntrue'])
+ self.parser.parse_blocks(['IMPLEMENTS GIVEN foo\ntrue'])
impls = self.parser.implementations
self.assertEqual(len(impls), 1)
self.assertEqual(impls[0].what, 'GIVEN')
@@ -60,7 +60,7 @@ class BlockParserTests(unittest.TestCase):
self.assertEqual(impls[0].shell, 'true')
def test_parses_two_implements_in_a_code_block(self):
- self.parser.parse_code_blocks(
+ self.parser.parse_blocks(
['IMPLEMENTS GIVEN foo\ntrue\nIMPLEMENTS WHEN bar\ncat /dev/null'])
impls = self.parser.implementations
self.assertEqual(len(impls), 2)