bourne 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Joe Ferris and thoughtbot, inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,59 @@
1
+ = Bourne
2
+
3
+ Bourne extends mocha to allow detailed tracking and querying of stub and mock
4
+ invocations. It allows test spies using the have_received rspec matcher and
5
+ assert_received for Test::Unit. Bourne was extracted from jferris-mocha, a fork
6
+ of mocha that adds test spies.
7
+
8
+ == Test Spies
9
+
10
+ Test spies are a form of test double that preserves the normal four-phase unit
11
+ test order and allows separation of stubbing and verification.
12
+
13
+ Using a test spy is like using a mocked expectation except that there are two steps:
14
+
15
+ 1. Stub out a method for which you want to verify invocations
16
+ 2. Use an assertion or matcher to verify that the stub was invoked correctly
17
+
18
+ == Examples
19
+
20
+ # rspec
21
+
22
+ mock.should have_received(:to_s)
23
+ Radio.should have_received(:new).with(1041)
24
+ radio.should have_received(:volume).with(11).twice
25
+ radio.should have_received(:off).never
26
+
27
+ # Test::Unit
28
+
29
+ assert_received(mock, :to_s)
30
+ assert_received(Radio, :new) {|expect| expect.with(1041) }
31
+ assert_received(radio, :volume) {|expect| expect.with(11).twice }
32
+ assert_received(radio, :off) {|expect| expect.never }
33
+
34
+ See Mocha::API for more information.
35
+
36
+ == Download
37
+
38
+ Rubygems:
39
+ gem install bourne
40
+
41
+ Github: http://github.com/thoughtbot/bourne/tree/master
42
+
43
+ == More Information
44
+
45
+ * RDoc[http://rdoc.info/projects/thoughtbot/bourne]
46
+ * Mocha mailing list[http://groups.google.com/group/mocha-developer?hl=en]
47
+ * Issues[http://github.com/thoughtbot/bourne/issues]
48
+ * GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS[http://giantrobots.thoughtbot.com]
49
+
50
+ == Author
51
+
52
+ Bourne was written by Joe Ferris. Mocha was written by James Mead. Several of
53
+ the test examples and helpers used in the Bourne test suite were copied
54
+ directly from Mocha.
55
+
56
+ Thanks to thoughtbot for inspiration, ideas, and funding. Thanks to James for
57
+ writing mocha.
58
+
59
+ Copyright 2010 Joe Ferris and thoughtbot[http://www.thoughtbot.com], inc.
@@ -0,0 +1,61 @@
1
+ require 'rake/rdoctask'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/testtask'
4
+
5
+ desc "Run all tests"
6
+ task 'default' => ['test:units', 'test:acceptance', 'test:performance']
7
+
8
+ namespace 'test' do
9
+ unit_tests = FileList['test/unit/**/*_test.rb']
10
+ acceptance_tests = FileList['test/acceptance/*_test.rb']
11
+
12
+ desc "Run unit tests"
13
+ Rake::TestTask.new('units') do |t|
14
+ t.libs << 'test'
15
+ t.test_files = unit_tests
16
+ end
17
+
18
+ desc "Run acceptance tests"
19
+ Rake::TestTask.new('acceptance') do |t|
20
+ t.libs << 'test'
21
+ t.test_files = acceptance_tests
22
+ end
23
+
24
+ desc "Run performance tests"
25
+ task 'performance' do
26
+ require File.join(File.dirname(__FILE__), 'test', 'acceptance', 'stubba_example_test')
27
+ require File.join(File.dirname(__FILE__), 'test', 'acceptance', 'mocha_example_test')
28
+ iterations = 1000
29
+ puts "\nBenchmarking with #{iterations} iterations..."
30
+ [MochaExampleTest, StubbaExampleTest].each do |test_case|
31
+ puts "#{test_case}: #{benchmark_test_case(test_case, iterations)} seconds."
32
+ end
33
+ end
34
+ end
35
+
36
+ def benchmark_test_case(klass, iterations)
37
+ require 'benchmark'
38
+ require 'test/unit/ui/console/testrunner'
39
+ begin
40
+ require 'test/unit/ui/console/outputlevel'
41
+ silent_option = { :output_level => Test::Unit::UI::Console::OutputLevel::SILENT }
42
+ rescue LoadError
43
+ silent_option = Test::Unit::UI::SILENT
44
+ end
45
+ time = Benchmark.realtime { iterations.times { Test::Unit::UI::Console::TestRunner.run(klass, silent_option) } }
46
+ end
47
+
48
+ eval("$specification = #{IO.read('bourne.gemspec')}")
49
+ Rake::GemPackageTask.new($specification) do |package|
50
+ package.need_zip = true
51
+ package.need_tar = true
52
+ end
53
+
54
+ desc 'Generate documentation.'
55
+ Rake::RDocTask.new(:rdoc) do |rdoc|
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = 'Bourne'
58
+ rdoc.options << '--line-numbers' << "--main" << "README"
59
+ rdoc.rdoc_files.include('README')
60
+ rdoc.rdoc_files.include('lib/**/*.rb')
61
+ end
@@ -0,0 +1,2 @@
1
+ require 'mocha'
2
+ require 'bourne/api'
@@ -0,0 +1,82 @@
1
+ require 'mocha/api'
2
+ require 'bourne/mockery'
3
+
4
+ module Mocha # :nodoc:
5
+ module API
6
+ # Asserts that the given mock received the given method.
7
+ #
8
+ # Examples:
9
+ #
10
+ # assert_received(mock, :to_s)
11
+ # assert_received(Radio, :new) {|expect| expect.with(1041) }
12
+ # assert_received(radio, :volume) {|expect| expect.with(11).twice }
13
+ def assert_received(mock, expected_method_name)
14
+ matcher = have_received(expected_method_name)
15
+ yield(matcher) if block_given?
16
+ assert matcher.matches?(mock), matcher.failure_message
17
+ end
18
+
19
+ class HaveReceived #:nodoc:
20
+ def initialize(expected_method_name)
21
+ @expected_method_name = expected_method_name
22
+ @expectations = []
23
+ end
24
+
25
+ def method_missing(method, *args, &block)
26
+ @expectations << [method, args, block]
27
+ self
28
+ end
29
+
30
+ def matches?(mock)
31
+ if mock.respond_to?(:mocha)
32
+ @mock = mock.mocha
33
+ else
34
+ @mock = mock
35
+ end
36
+
37
+ @expectation = Expectation.new(@mock, @expected_method_name)
38
+ @expectations.each do |method, args, block|
39
+ @expectation.send(method, *args, &block)
40
+ end
41
+ @expectation.invocation_count = invocation_count
42
+ @expectation.verified?
43
+ end
44
+
45
+ def failure_message
46
+ @expectation.mocha_inspect
47
+ end
48
+
49
+ private
50
+
51
+ def invocation_count
52
+ matching_invocations.size
53
+ end
54
+
55
+ def matching_invocations
56
+ invocations.select do |invocation|
57
+ @expectation.match?(invocation.method_name, *invocation.arguments)
58
+ end
59
+ end
60
+
61
+ def invocations
62
+ Mockery.instance.invocations.select do |invocation|
63
+ invocation.mock.equal?(@mock)
64
+ end
65
+ end
66
+ end
67
+
68
+ # :call-seq:
69
+ # should have_received(method).with(arguments).times(times)
70
+ #
71
+ # Ensures that the given mock received the given method.
72
+ #
73
+ # Examples:
74
+ #
75
+ # mock.should have_received(:to_s)
76
+ # Radio.should have_received(:new).with(1041)
77
+ # radio.should have_received(:volume).with(11).twice
78
+ def have_received(expected_method_name)
79
+ HaveReceived.new(expected_method_name)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ require 'mocha/expectation'
2
+
3
+ module Mocha # :nodoc:
4
+ # Extends Mocha::Expectation to record the full arguments and count whenver a
5
+ # stubbed or mocked method is invoked.
6
+ class Expectation # :nodoc:
7
+ attr_accessor :invocation_count
8
+
9
+ def invoke_with_args(args, &block)
10
+ Mockery.instance.invocation(@mock, method_name, args)
11
+ invoke_without_args(&block)
12
+ end
13
+
14
+ alias_method :invoke_without_args, :invoke
15
+ alias_method :invoke, :invoke_with_args
16
+
17
+ private
18
+
19
+ def method_name
20
+ @method_matcher.expected_method_name
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Mocha # :nodoc:
2
+ # Used internally by Bourne extensions to Mocha. Represents a single
3
+ # invocation of a stubbed or mocked method. The mock, method name, and
4
+ # arguments are recorded and can be used to determine how a method was
5
+ # invoked.
6
+ class Invocation
7
+ attr_reader :mock, :method_name, :arguments
8
+ def initialize(mock, method_name, arguments)
9
+ @mock = mock
10
+ @method_name = method_name
11
+ @arguments = arguments
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ require 'mocha/mock'
2
+ require 'bourne/expectation'
3
+
4
+ module Mocha # :nodoc:
5
+ # Overwrites #method_missing on Mocha::Mock so pass arguments to
6
+ # Mocha::Expectation#invoke so that an Invocation can be created.
7
+ class Mock # :nodoc:
8
+ def method_missing(symbol, *arguments, &block)
9
+ if @responder and not @responder.respond_to?(symbol)
10
+ raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
11
+ end
12
+ if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
13
+ matching_expectation_allowing_invocation.invoke(arguments, &block)
14
+ else
15
+ if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
16
+ message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
17
+ message << Mockery.instance.mocha_inspect
18
+ raise ExpectationError.new(message, caller)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'mocha/mockery'
2
+ require 'bourne/mock'
3
+ require 'bourne/invocation'
4
+
5
+ module Mocha
6
+ # Used internally by Bourne extensions to Mocha when recording invocations of
7
+ # stubbed and mocked methods. You shouldn't need to interact with this module
8
+ # through normal testing, but you can access the full list of invocations
9
+ # directly if necessary.
10
+ class Mockery
11
+ def invocation(mock, method_name, args)
12
+ invocations << Invocation.new(mock, method_name, args)
13
+ end
14
+
15
+ def invocations
16
+ @invocations ||= []
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+ require 'test_runner'
3
+ require 'mocha/configuration'
4
+
5
+ module AcceptanceTest
6
+
7
+ class FakeLogger
8
+
9
+ attr_reader :warnings
10
+
11
+ def initialize
12
+ @warnings = []
13
+ end
14
+
15
+ def warn(message)
16
+ @warnings << message
17
+ end
18
+
19
+ end
20
+
21
+ attr_reader :logger
22
+
23
+ include TestRunner
24
+
25
+ def setup_acceptance_test
26
+ Mocha::Configuration.reset_configuration
27
+ @logger = FakeLogger.new
28
+ mockery = Mocha::Mockery.instance
29
+ @original_logger = mockery.logger
30
+ mockery.logger = @logger
31
+ end
32
+
33
+ def teardown_acceptance_test
34
+ Mocha::Configuration.reset_configuration
35
+ Mocha::Mockery.instance.logger = @original_logger
36
+ end
37
+
38
+ end
@@ -0,0 +1,98 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+ require 'mocha'
3
+
4
+ class MochaExampleTest < Test::Unit::TestCase
5
+
6
+ class Rover
7
+
8
+ def initialize(left_track, right_track, steps_per_metre, steps_per_degree)
9
+ @left_track, @right_track, @steps_per_metre, @steps_per_degree = left_track, right_track, steps_per_metre, steps_per_degree
10
+ end
11
+
12
+ def forward(metres)
13
+ @left_track.step(metres * @steps_per_metre)
14
+ @right_track.step(metres * @steps_per_metre)
15
+ wait
16
+ end
17
+
18
+ def backward(metres)
19
+ forward(-metres)
20
+ end
21
+
22
+ def left(degrees)
23
+ @left_track.step(-degrees * @steps_per_degree)
24
+ @right_track.step(+degrees * @steps_per_degree)
25
+ wait
26
+ end
27
+
28
+ def right(degrees)
29
+ left(-degrees)
30
+ end
31
+
32
+ def wait
33
+ while (@left_track.moving? or @right_track.moving?); end
34
+ end
35
+
36
+ end
37
+
38
+ def test_should_step_both_tracks_forward_ten_steps
39
+ left_track = mock('left_track')
40
+ right_track = mock('right_track')
41
+ steps_per_metre = 5
42
+ rover = Rover.new(left_track, right_track, steps_per_metre, nil)
43
+
44
+ left_track.expects(:step).with(10)
45
+ right_track.expects(:step).with(10)
46
+
47
+ left_track.stubs(:moving?).returns(false)
48
+ right_track.stubs(:moving?).returns(false)
49
+
50
+ rover.forward(2)
51
+ end
52
+
53
+ def test_should_step_both_tracks_backward_ten_steps
54
+ left_track = mock('left_track')
55
+ right_track = mock('right_track')
56
+ steps_per_metre = 5
57
+ rover = Rover.new(left_track, right_track, steps_per_metre, nil)
58
+
59
+ left_track.expects(:step).with(-10)
60
+ right_track.expects(:step).with(-10)
61
+
62
+ left_track.stubs(:moving?).returns(false)
63
+ right_track.stubs(:moving?).returns(false)
64
+
65
+ rover.backward(2)
66
+ end
67
+
68
+ def test_should_step_left_track_forwards_five_steps_and_right_track_backwards_five_steps
69
+ left_track = mock('left_track')
70
+ right_track = mock('right_track')
71
+ steps_per_degree = 5.0 / 90.0
72
+ rover = Rover.new(left_track, right_track, nil, steps_per_degree)
73
+
74
+ left_track.expects(:step).with(+5)
75
+ right_track.expects(:step).with(-5)
76
+
77
+ left_track.stubs(:moving?).returns(false)
78
+ right_track.stubs(:moving?).returns(false)
79
+
80
+ rover.right(90)
81
+ end
82
+
83
+ def test_should_step_left_track_backwards_five_steps_and_right_track_forwards_five_steps
84
+ left_track = mock('left_track')
85
+ right_track = mock('right_track')
86
+ steps_per_degree = 5.0 / 90.0
87
+ rover = Rover.new(left_track, right_track, nil, steps_per_degree)
88
+
89
+ left_track.expects(:step).with(-5)
90
+ right_track.expects(:step).with(+5)
91
+
92
+ left_track.stubs(:moving?).returns(false)
93
+ right_track.stubs(:moving?).returns(false)
94
+
95
+ rover.left(90)
96
+ end
97
+
98
+ end