diff options
author | Richard Maw <richard.maw@codethink.co.uk> | 2014-02-05 14:13:52 +0000 |
---|---|---|
committer | Richard Maw <richard.maw@codethink.co.uk> | 2014-02-11 11:50:44 +0000 |
commit | d80685642ad8d01da34e21f3957df0c06075248a (patch) | |
tree | 1c983a6c717cc66cae7c706333561c8c55757c1f | |
parent | ea926a07a4b800bcd87d0841c213ad02faae00f3 (diff) | |
download | cmdtest-d80685642ad8d01da34e21f3957df0c06075248a.tar.gz |
Factor scenario validation into yarnlib
-rwxr-xr-x | yarn | 37 | ||||
-rw-r--r-- | yarnlib/__init__.py | 4 | ||||
-rw-r--r-- | yarnlib/scenario_validator.py | 82 | ||||
-rw-r--r-- | yarnlib/scenario_validator_tests.py | 68 |
4 files changed, 156 insertions, 35 deletions
@@ -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() |