summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2014-02-05 14:13:52 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2014-02-11 11:50:44 +0000
commitd80685642ad8d01da34e21f3957df0c06075248a (patch)
tree1c983a6c717cc66cae7c706333561c8c55757c1f
parentea926a07a4b800bcd87d0841c213ad02faae00f3 (diff)
downloadcmdtest-d80685642ad8d01da34e21f3957df0c06075248a.tar.gz
Factor scenario validation into yarnlib
-rwxr-xr-xyarn37
-rw-r--r--yarnlib/__init__.py4
-rw-r--r--yarnlib/scenario_validator.py82
-rw-r--r--yarnlib/scenario_validator_tests.py68
4 files changed, 156 insertions, 35 deletions
diff --git a/yarn b/yarn
index af25d21..f982e77 100755
--- a/yarn
+++ b/yarn
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright 2013 Lars Wirzenius
+# Copyright 2013-2014 Lars Wirzenius
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -119,9 +119,8 @@ class YarnRunner(cliapp.Application):
'%String(step_name)')
scenarios, implementations = self.parse_scenarios(args)
- self.check_there_are_scenarios(scenarios)
- self.check_for_duplicate_scenario_names(scenarios)
- self.check_for_thens(scenarios)
+ sv = yarnlib.ScenarioValidator(scenarios)
+ sv.validate_all()
scenarios = self.connect_implementations(scenarios, implementations)
shell_prelude = self.load_shell_libraries()
@@ -178,36 +177,6 @@ class YarnRunner(cliapp.Application):
return block_parser.scenarios, block_parser.implementations
- def check_there_are_scenarios(self, scenarios):
- if not scenarios:
- raise cliapp.AppException(
- 'There are no scenarios; must have at least one.')
-
- def check_for_duplicate_scenario_names(self, scenarios):
- counts = collections.Counter()
- for s in scenarios:
- counts[s.name] += 1
-
- duplicates = [name for name in counts if counts[name] > 1]
- if duplicates:
- duplist = ''.join(' %s\n' % name for name in duplicates)
- raise cliapp.AppException(
- 'There are scenarios with duplicate names:\n%s' % duplist)
-
- def check_for_thens(self, scenarios):
- no_thens = []
- for scenario in scenarios:
- for step in scenario.steps:
- if step.what == 'THEN':
- break
- else:
- no_thens.append(scenario)
-
- if no_thens:
- raise cliapp.AppException(
- 'Some scenarios have no THENs:\n%s' %
- ''.join(' "%s"\n' % s.name for s in no_thens))
-
def connect_implementations(self, scenarios, implementations):
new_list = []
for scenario in scenarios:
diff --git a/yarnlib/__init__.py b/yarnlib/__init__.py
index 88bf46f..f224a0c 100644
--- a/yarnlib/__init__.py
+++ b/yarnlib/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2013 Lars Wirzenius
+# Copyright 2013-2014 Lars Wirzenius
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,3 +19,5 @@
from mdparser import MarkdownParser
from elements import Scenario, ScenarioStep, Implementation
from block_parser import BlockParser, BlockError
+from scenario_validator import (NoScenariosError, DuplicateScenariosError,
+ NoThensError, ScenarioValidator)
diff --git a/yarnlib/scenario_validator.py b/yarnlib/scenario_validator.py
new file mode 100644
index 0000000..59c86e7
--- /dev/null
+++ b/yarnlib/scenario_validator.py
@@ -0,0 +1,82 @@
+# Copyright 2014 Lars Wirzenius and Codethink Limited
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# =*= License: GPL-3+ =*=
+
+
+import cliapp
+import collections
+
+
+class NoScenariosError(cliapp.AppException):
+
+ def __init__(self):
+ cliapp.AppException.__init__(
+ self, 'There are no scenarios; must have at least one.')
+
+
+class DuplicateScenariosError(cliapp.AppException):
+
+ def __init__(self, duplicates):
+ duplist = ''.join(' %s\n' % name for name in duplicates)
+ cliapp.AppException.__init__(
+ self, 'There are scenarios with duplicate names:\n%s' % duplist)
+
+
+class NoThensError(cliapp.AppException):
+
+ def __init__(self, thenless):
+ cliapp.AppException.__init__(
+ self, 'Some scenarios have no THENs:\n%s' %
+ ''.join(' "%s"\n' % s.name for s in thenless))
+
+
+class ScenarioValidator(object):
+
+ def __init__(self, scenarios):
+ self.scenarios = scenarios
+
+ def validate_all(self): # pragma: no cover
+ '''Convenience method to run all checks.'''
+ self.check_there_are_scenarios()
+ self.check_for_duplicate_scenario_names()
+ self.check_for_thens()
+
+ def check_there_are_scenarios(self):
+ '''Check whether any scenarios were found.'''
+ if not self.scenarios:
+ raise NoScenariosError()
+
+ def check_for_duplicate_scenario_names(self):
+ '''Check whether multiple scenarios were found sharing a name.'''
+ counts = collections.Counter()
+ for s in self.scenarios:
+ counts[s.name] += 1
+
+ duplicates = [name for name in counts if counts[name] > 1]
+ if duplicates:
+ raise DuplicateScenariosError(duplicates)
+
+ def check_for_thens(self):
+ no_thens = []
+ for scenario in self.scenarios:
+ for step in scenario.steps:
+ if step.what == 'THEN':
+ break
+ else:
+ no_thens.append(scenario)
+
+ if no_thens:
+ raise NoThensError(no_thens)
diff --git a/yarnlib/scenario_validator_tests.py b/yarnlib/scenario_validator_tests.py
new file mode 100644
index 0000000..1e482a5
--- /dev/null
+++ b/yarnlib/scenario_validator_tests.py
@@ -0,0 +1,68 @@
+# Copyright 2014 Codethink Limited
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# =*= License: GPL-3+ =*=
+
+
+import unittest
+
+import yarnlib
+
+
+class ScenarioValidatorTests(unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def test_check_scenarios_fail(self):
+ sv = yarnlib.ScenarioValidator([])
+ with self.assertRaises(yarnlib.NoScenariosError):
+ sv.check_there_are_scenarios()
+
+ def test_check_scenarios_pass(self):
+ sv = yarnlib.ScenarioValidator([
+ yarnlib.Scenario('foo')
+ ])
+ sv.check_there_are_scenarios()
+
+ def test_check_duplicate_names_fail(self):
+ sv = yarnlib.ScenarioValidator([
+ yarnlib.Scenario('foo'),
+ yarnlib.Scenario('foo'),
+ ])
+ with self.assertRaises(yarnlib.DuplicateScenariosError):
+ sv.check_for_duplicate_scenario_names()
+
+ def test_check_duplicate_names_pass(self):
+ sv = yarnlib.ScenarioValidator([
+ yarnlib.Scenario('foo'),
+ yarnlib.Scenario('bar'),
+ ])
+ sv.check_for_duplicate_scenario_names()
+
+ def test_check_for_thens_fail(self):
+ sv = yarnlib.ScenarioValidator([
+ yarnlib.Scenario('foo')
+ ])
+ with self.assertRaises(yarnlib.NoThensError):
+ sv.check_for_thens()
+
+ def test_check_for_thens_pass(self):
+ scenario = yarnlib.Scenario('foo')
+ scenario.steps = [
+ yarnlib.ScenarioStep('THEN', 'badger stoat')
+ ]
+ sv = yarnlib.ScenarioValidator([scenario])
+ sv.check_for_thens()