Commit 5fd4ec28 by Gabriel Falcão

Adding missing files from last commit and implementing Before and After…

Adding missing files from last commit and implementing Before and After callbacks for each feature. closes #16
parent e9c41f64
......@@ -289,7 +289,14 @@ class Feature(object):
return scenarios, description
def run(self, ignore_case=True):
for callback in CALLBACK_REGISTRY['feature']['before_each']:
callback(self)
scenarios_ran = [scenario.run(ignore_case) for scenario in self.scenarios]
for callback in CALLBACK_REGISTRY['feature']['after_each']:
callback(self)
return FeatureResult(self, *scenarios_ran)
class FeatureResult(object):
......
# -*- coding: utf-8 -*-
# <Lettuce - Behaviour Driven Development for python>
# Copyright (C) <2010> Gabriel Falcão <gabriel@nacaolivre.org>
#
# 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/>.
import threading
STEP_REGISTRY = {}
world = threading.local()
world._set = False
CALLBACK_REGISTRY = {
'step': {
'before_each': [],
'after_each': []
},
'scenario': {
'before_each': [],
'after_each': []
},
'feature': {
'before_each': [],
'after_each': []
}
}
......@@ -29,6 +29,11 @@ class before:
CALLBACK_REGISTRY['scenario']['%s_each' % cls.__name__].append(function)
return function
@classmethod
def each_feature(cls, function):
CALLBACK_REGISTRY['feature']['%s_each' % cls.__name__].append(function)
return function
class after:
@classmethod
def each_step(cls, function):
......@@ -40,3 +45,8 @@ class after:
CALLBACK_REGISTRY['scenario']['%s_each' % cls.__name__].append(function)
return function
@classmethod
def each_feature(cls, function):
CALLBACK_REGISTRY['feature']['%s_each' % cls.__name__].append(function)
return function
# -*- coding: utf-8 -*-
# <Lettuce - Behaviour Driven Development for python>
# Copyright (C) <2010> Gabriel Falcão <gabriel@nacaolivre.org>
#
# 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/>.
from lettuce.terrain import world
world.works_fine = True
#!/usr/bin/env python
# -*- coding: utf-8; -*-
#
# Copyright (C) 2009 Gabriel Falcão <gabriel@nacaolivre.org>
# Copyright (C) 2009 Bernardo Heynemann <heynemann@gmail.com>
#
# 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 2 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, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
from os.path import abspath, dirname, join, split
from nose.tools import assert_equals
from lettuce.fs import FileSystem
def test_abspath():
fs = FileSystem()
p = fs.abspath(".")
p2 = abspath(".")
assert p == p2
def test_current_dir_with_join():
fs = FileSystem()
got = fs.current_dir("etc")
expected = join(abspath("."), "etc")
assert_equals(got, expected)
def test_current_dir_without_join():
fs = FileSystem()
got = fs.current_dir()
expected = abspath(".")
assert_equals(got, expected)
def test_join():
fs = FileSystem()
p = fs.join(fs.abspath("."), "test")
p2 = join(abspath("."), "test")
assert p == p2, "Expected:\n%r\nGot:\n%r" % (p2, p)
def test_dirname():
fs = FileSystem()
p = fs.dirname(fs.abspath("."))
p2 = dirname(abspath("."))
assert p == p2, "Expected:\n%r\nGot:\n%r" % (p2, p)
def test_recursive_locate():
fs = FileSystem()
files = fs.locate(path=abspath(join(dirname(__file__), "files_to_locate")), match="*.txt", recursive=True)
assert files
assert isinstance(files, list)
assert len(files) == 2
assert split(files[0])[-1] == "test.txt"
assert split(files[1])[-1] == "test2.txt"
assert split(split(files[1])[0])[-1] == "sub"
def test_non_recursive_locate():
fs = FileSystem()
files = fs.locate(path=abspath(join(dirname(__file__), "files_to_locate")), match="*.txt", recursive=False)
assert files
assert isinstance(files, list)
assert len(files) == 1
assert split(files[0])[-1] == "test.txt"
def test_open_non_abspath():
fs = FileSystem()
assert fs.open('tests/functional/data/some.txt', 'r').read() == 'some text here!\n'
def test_open_abspath():
fs = FileSystem()
assert fs.open(abspath('./tests/functional/data/some.txt'), 'r').read() == 'some text here!\n'
def test_open_raw_non_abspath():
fs = FileSystem()
assert fs.open_raw('tests/functional/data/some.txt', 'r').read() == 'some text here!\n'
def test_open_raw_abspath():
fs = FileSystem()
assert fs.open_raw(abspath('./tests/functional/data/some.txt'), 'r').read() == 'some text here!\n'
# -*- coding: utf-8 -*-
# <Lettuce - Behaviour Driven Development for python>
# Copyright (C) <2010> Gabriel Falcão <gabriel@nacaolivre.org>
#
# 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/>.
from os.path import dirname, abspath, join
from lettuce import Runner
from lettuce.terrain import world
def test_imports_terrain_under_path_that_is_run():
assert not hasattr(world, 'works_fine')
runner = Runner(join(abspath(dirname(__file__)), '1st_feature_dir'))
assert runner.terrain
assert hasattr(world, 'works_fine')
assert world.works_fine
# -*- coding: utf-8 -*-
import sys
from StringIO import StringIO
from mox import Mox
from nose.tools import assert_equals
from nose.tools import assert_raises
from lettuce import fs as io
def test_has_a_stack_list():
assert hasattr(io.FileSystem, 'stack'), \
'FileSystem should have a stack'
assert isinstance(io.FileSystem.stack, list), \
'FileSystem.stack should be a list'
def test_instance_stack_is_not_the_same_as_class_level():
class MyFs(io.FileSystem):
pass
MyFs.stack.append('foo')
MyFs.stack.append('bar')
assert_equals(MyFs().stack, [])
def test_pushd_appends_current_dir_to_stack_if_empty():
mox = Mox()
old_os = io.os
io.os = mox.CreateMockAnything()
class MyFs(io.FileSystem):
stack = []
@classmethod
def current_dir(cls):
return 'should be current dir'
io.os.chdir('somewhere')
mox.ReplayAll()
try:
assert len(MyFs.stack) is 0
MyFs.pushd('somewhere')
assert len(MyFs.stack) is 2
assert_equals(MyFs.stack, ['should be current dir',
'somewhere'])
mox.VerifyAll()
finally:
io.os = old_os
def test_pushd():
mox = Mox()
old_os = io.os
io.os = mox.CreateMockAnything()
class MyFs(io.FileSystem):
stack = ['first']
io.os.chdir('second')
mox.ReplayAll()
try:
assert len(MyFs.stack) is 1
MyFs.pushd('second')
assert len(MyFs.stack) is 2
assert_equals(MyFs.stack, ['first',
'second'])
mox.VerifyAll()
finally:
io.os = old_os
def test_pop_with_more_than_1_item():
mox = Mox()
old_os = io.os
io.os = mox.CreateMockAnything()
class MyFs(io.FileSystem):
stack = ['one', 'two']
io.os.chdir('one')
mox.ReplayAll()
try:
assert len(MyFs.stack) is 2
MyFs.popd()
assert len(MyFs.stack) is 1
assert_equals(MyFs.stack, ['one'])
mox.VerifyAll()
finally:
io.os = old_os
def test_pop_with_1_item():
mox = Mox()
old_os = io.os
io.os = mox.CreateMockAnything()
class MyFs(io.FileSystem):
stack = ['one']
mox.ReplayAll()
try:
assert len(MyFs.stack) is 1
MyFs.popd()
assert len(MyFs.stack) is 0
assert_equals(MyFs.stack, [])
mox.VerifyAll()
finally:
io.os = old_os
def test_pop_with_no_item():
mox = Mox()
old_os = io.os
io.os = mox.CreateMockAnything()
class MyFs(io.FileSystem):
stack = []
mox.ReplayAll()
try:
assert len(MyFs.stack) is 0
MyFs.popd()
assert len(MyFs.stack) is 0
assert_equals(MyFs.stack, [])
mox.VerifyAll()
finally:
io.os = old_os
def test_filename_with_extension():
got = io.FileSystem.filename('/path/to/filename.jpg')
assert_equals(got, 'filename.jpg')
def test_filename_without_extension():
got = io.FileSystem.filename('/path/to/filename.jpg', False)
assert_equals(got, 'filename')
def test_dirname():
got = io.FileSystem.dirname('/path/to/filename.jpg')
assert_equals(got, '/path/to')
def test_exists():
mox = Mox()
old_exists = io.exists
io.exists = mox.CreateMockAnything()
io.exists('some path').AndReturn('should be bool')
mox.ReplayAll()
try:
got = io.FileSystem.exists('some path')
assert_equals(got, 'should be bool')
mox.VerifyAll()
finally:
io.exists = old_exists
def test_extract_zip_non_verbose():
mox = Mox()
class MyFs(io.FileSystem):
stack = []
abspath = mox.CreateMockAnything()
pushd = mox.CreateMockAnything()
popd = mox.CreateMockAnything()
open_raw = mox.CreateMockAnything()
mkdir = mox.CreateMockAnything()
mox.StubOutWithMock(io, 'zipfile')
filename = 'modafoca.zip'
base_path = '../to/project'
full_path = '/full/path/to/project'
MyFs.abspath(base_path).AndReturn(full_path)
MyFs.pushd(full_path)
zip_mock = mox.CreateMockAnything()
io.zipfile.ZipFile(filename).AndReturn(zip_mock)
file_list = [
'settings.yml',
'app',
'app/controllers.py'
]
zip_mock.namelist().AndReturn(file_list)
zip_mock.read('settings.yml').AndReturn('settings.yml content')
zip_mock.read('app/controllers.py').AndReturn('controllers.py content')
file_mock1 = mox.CreateMockAnything()
MyFs.open_raw('settings.yml', 'w').AndReturn(file_mock1)
file_mock1.write('settings.yml content')
file_mock1.close()
MyFs.open_raw('app', 'w').AndRaise(IOError('it is a directory, dumb ass!'))
MyFs.mkdir('app')
file_mock2 = mox.CreateMockAnything()
MyFs.open_raw('app/controllers.py', 'w').AndReturn(file_mock2)
file_mock2.write('controllers.py content')
file_mock2.close()
MyFs.popd()
mox.ReplayAll()
try:
MyFs.extract_zip('modafoca.zip', base_path)
mox.VerifyAll()
finally:
mox.UnsetStubs()
def test_extract_zip_verbose():
mox = Mox()
sys.stdout = StringIO()
class MyFs(io.FileSystem):
stack = []
abspath = mox.CreateMockAnything()
pushd = mox.CreateMockAnything()
popd = mox.CreateMockAnything()
open_raw = mox.CreateMockAnything()
mkdir = mox.CreateMockAnything()
mox.StubOutWithMock(io, 'zipfile')
filename = 'modafoca.zip'
base_path = '../to/project'
full_path = '/full/path/to/project'
MyFs.abspath(base_path).AndReturn(full_path)
MyFs.pushd(full_path)
zip_mock = mox.CreateMockAnything()
io.zipfile.ZipFile(filename).AndReturn(zip_mock)
file_list = [
'settings.yml',
'app',
'app/controllers.py'
]
zip_mock.namelist().AndReturn(file_list)
zip_mock.read('settings.yml').AndReturn('settings.yml content')
zip_mock.read('app/controllers.py').AndReturn('controllers.py content')
file_mock1 = mox.CreateMockAnything()
MyFs.open_raw('settings.yml', 'w').AndReturn(file_mock1)
file_mock1.write('settings.yml content')
file_mock1.close()
MyFs.open_raw('app', 'w').AndRaise(IOError('it is a directory, dumb ass!'))
MyFs.mkdir('app')
file_mock2 = mox.CreateMockAnything()
MyFs.open_raw('app/controllers.py', 'w').AndReturn(file_mock2)
file_mock2.write('controllers.py content')
file_mock2.close()
MyFs.popd()
mox.ReplayAll()
try:
MyFs.extract_zip('modafoca.zip', base_path, verbose=True)
assert_equals(sys.stdout.getvalue(),
'Extracting files to /full/path/to/project\n ' \
'-> Unpacking settings.yml\n -> Unpacking app' \
'\n---> Creating directory app\n -> Unpacking' \
' app/controllers.py\n')
mox.VerifyAll()
finally:
mox.UnsetStubs()
sys.stdout = sys.__stdout__
def test_locate_non_recursive():
mox = Mox()
old_glob = io.glob
io.glob = mox.CreateMockAnything()
base_path = '../to/project'
full_path = '/full/path/to/project'
class MyFs(io.FileSystem):
stack = []
abspath = mox.CreateMockAnything()
io.glob('%s/*match*.py' % full_path)
MyFs.abspath(base_path).AndReturn(full_path)
mox.ReplayAll()
try:
MyFs.locate(base_path, '*match*.py', recursive=False)
mox.VerifyAll()
finally:
mox.UnsetStubs()
io.glob = old_glob
def test_locate_recursive():
mox = Mox()
base_path = '../to/project'
full_path = '/full/path/to/project'
class MyFs(io.FileSystem):
stack = []
abspath = mox.CreateMockAnything()
walk = mox.CreateMockAnything()
io.glob('%s/*match*.py' % full_path)
MyFs.abspath(base_path).AndReturn(full_path)
walk_list = [
(None, None, ['file1.py', 'file2.jpg']),
(None, None, ['path1/file3.png', 'path1/file4.html'])
]
MyFs.walk(full_path).AndReturn(walk_list)
mox.ReplayAll()
try:
MyFs.locate(base_path, '*match*.py', recursive=True)
mox.VerifyAll()
finally:
mox.UnsetStubs()
def test_mkdir_success():
mox = Mox()
mox.StubOutWithMock(io, 'os')
class MyFs(io.FileSystem):
pass
io.os.makedirs('/make/all/those/subdirs')
mox.ReplayAll()
try:
MyFs.mkdir('/make/all/those/subdirs')
mox.VerifyAll()
finally:
mox.UnsetStubs()
def test_mkdir_ignore_dirs_already_exists():
mox = Mox()
mox.StubOutWithMock(io, 'os')
mox.StubOutWithMock(io.os, 'path')
class MyFs(io.FileSystem):
pass
oserror = OSError()
oserror.errno = 17
io.os.makedirs('/make/all/those/subdirs').AndRaise(oserror)
io.os.path.isdir('/make/all/those/subdirs').AndReturn(True)
mox.ReplayAll()
try:
MyFs.mkdir('/make/all/those/subdirs')
mox.VerifyAll()
finally:
mox.UnsetStubs()
def test_mkdir_raises_on_oserror_errno_not_17():
mox = Mox()
mox.StubOutWithMock(io, 'os')
mox.StubOutWithMock(io.os, 'path')
class MyFs(io.FileSystem):
pass
oserror = OSError()
oserror.errno = 0
io.os.makedirs('/make/all/those/subdirs').AndRaise(oserror)
mox.ReplayAll()
try:
assert_raises(OSError, MyFs.mkdir, '/make/all/those/subdirs')
mox.VerifyAll()
finally:
mox.UnsetStubs()
def tes_mkdir_raises_on_oserror_errno_not_17():
mox = Mox()
mox.StubOutWithMock(io, 'os')
mox.StubOutWithMock(io.os, 'path')
class MyFs(io.FileSystem):
pass
oserror = OSError()
oserror.errno = 0
io.os.makedirs('/make/all/those/subdirs').AndRaise(oserror)
mox.ReplayAll()
try:
assert_raises(OSError, MyFs.mkdir, '/make/all/those/subdirs')
mox.VerifyAll()
finally:
mox.UnsetStubs()
def tes_mkdir_raises_when_path_is_not_a_dir():
mox = Mox()
mox.StubOutWithMock(io, 'os')
mox.StubOutWithMock(io.os, 'path')
class MyFs(io.FileSystem):
pass
oserror = OSError()
oserror.errno = 17
io.os.makedirs('/make/all/those/subdirs').AndRaise(oserror)
io.os.isdir('/make/all/those/subdirs').AndReturn(False)
mox.ReplayAll()
try:
assert_raises(OSError, MyFs.mkdir, '/make/all/those/subdirs')
mox.VerifyAll()
finally:
mox.UnsetStubs()
......@@ -17,6 +17,7 @@
from nose.tools import assert_equals
from lettuce import step
from lettuce import registry
from lettuce.terrain import after
from lettuce.terrain import before
from lettuce.terrain import world
......@@ -106,3 +107,27 @@ def test_after_each_scenario_is_executed_before_each_scenario():
['before', 'during', 'after', 'before', 'during', 'after']
)
def test_after_each_feature_is_executed_before_each_feature():
"terrain.before.each_feature and terrain.after.each_feature decorators"
world.feature_steps = []
@before.each_feature
def set_state_to_before(feature):
world.feature_steps.append('before')
@step('append "during" to states')
def append_during_to_feature_steps():
world.feature_steps.append("during")
@after.each_feature
def set_state_to_after(feature):
world.feature_steps.append('after')
feature = Feature.from_string(FEATURE2)
feature.run()
assert_equals(
world.feature_steps,
['before', 'during', 'during', 'after']
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment