rspec-process-mocks 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ doc
7
+ tmp
8
+ rerun.txt
9
+ Gemfile.lock
10
+ .bundle
11
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,40 @@
1
+ source "http://rubygems.org"
2
+
3
+ ### rspec libs
4
+ %w[rspec rspec-core rspec-expectations rspec-mocks].each do |lib|
5
+ library_path = File.expand_path("../../#{lib}", __FILE__)
6
+ if File.exist?(library_path)
7
+ gem lib, :path => library_path
8
+ else
9
+ gem lib, :git => "git://github.com/rspec/#{lib}.git"
10
+ end
11
+ end
12
+
13
+ ### dev dependencies
14
+ gem "rake", "~> 0.8"
15
+ gem "cucumber", "~> 0.10.2"
16
+ gem "aruba", "~> 0.3.6"
17
+ gem "rcov", "0.9.9", :platforms => :mri
18
+ gem "relish", "0.2.0"
19
+ gem "guard-rspec", "0.1.9"
20
+ gem "growl", "1.0.3"
21
+ gem "nokogiri", "1.4.4"
22
+
23
+ platforms :mri_18 do
24
+ gem 'ruby-debug'
25
+ end
26
+
27
+ platforms :mri_19 do
28
+ gem 'linecache19', '0.5.11' # 0.5.12 cannot install on 1.9.1, and 0.5.11 appears to work with both 1.9.1 & 1.9.2
29
+ gem 'ruby-debug19'
30
+ gem 'ruby-debug-base19', RUBY_VERSION == '1.9.1' ? '0.11.23' : '~> 0.11.24'
31
+ end
32
+
33
+ platforms :mri_18, :mri_19 do
34
+ gem "rb-fsevent", "~> 0.3.9"
35
+ gem "ruby-prof", "~> 0.9.2"
36
+ end
37
+
38
+ platforms :jruby do
39
+ gem "jruby-openssl"
40
+ end
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ WARNING: This is just a big hack right now. If you are interested in using this
2
+ project but I haven't removed this warning yet, please bug me to lessen the
3
+ hackiness and make it more usable.
4
+
5
+
6
+ # RSpec Process Mocks
7
+
8
+ rspec-process-mocks is an addon to rspec-mocks that provides support
9
+ for method stubs, fakes, and message expectations within child processes.
10
+
11
+ ## Documentation
12
+
13
+ ## Setup
14
+
15
+ Gemfile
16
+
17
+ gem 'rspec-process-mocks', :git => 'git://github.com/thoughtless/rspec-process-mocks.git'
18
+
19
+ `bundle install`
20
+
21
+ spec/spec_helper.rb
22
+
23
+ require 'rspec/process_mocks' # This line must be after 'config.mock_with :rspec'
24
+
25
+ ## Message Expectations
26
+
27
+ describe "some action" do
28
+ context "when bad stuff happens" do
29
+ it "logs the error" do
30
+ logger = double('logger')
31
+ doer = Doer.new(logger)
32
+ logger.should_receive_in_child_process(:log)
33
+ doer.do_something_with(:bad_data)
34
+ sleep 0.1 # Leave time for the child process to run.
35
+ end
36
+ end
37
+ end
38
+
39
+ class Doer
40
+ attr_accessor :logger
41
+ def do_something_with(data)
42
+ Process.fork { logger.log(data) }
43
+ end
44
+ end
45
+
46
+ ## Contribute
47
+
48
+ See [http://github.com/thoughtless/rspec-process-mocks](http://github.com/thoughtless/rspec-process-mocks)
49
+
50
+ ## Also see
51
+
52
+ * [http://github.com/rspec/rspec](http://github.com/rspec/rspec)
53
+ * [http://github.com/rspec/rspec-core](http://github.com/rspec/rspec-core)
54
+ * [http://github.com/rspec/rspec-expectations](http://github.com/rspec/rspec-expectations)
data/cucumber.yml ADDED
@@ -0,0 +1,2 @@
1
+ default: --require features --tags ~@wip features --format progress
2
+ wip: --require features --tags @wip:3 --wip features
@@ -0,0 +1,154 @@
1
+ Feature: expect a message
2
+
3
+ Use should_receive() to set an expectation that a receiver should receive a
4
+ message before the example is completed.
5
+
6
+ Scenario: expect a message
7
+ Given a file named "spec/account_spec.rb" with:
8
+ """
9
+ RSpec.configuration.mock_framework = :rspec
10
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'lib'))
11
+ require 'rspec/process_mocks'
12
+ require "account"
13
+
14
+ describe Account do
15
+ context "when closed" do
16
+ it "logs an account closed message in a child process" do
17
+
18
+ logger = double("logger")
19
+ account = Account.new
20
+ account.logger = logger
21
+
22
+ logger.should_receive_in_child_process(:account_closed)
23
+
24
+ account.close
25
+
26
+ sleep 0.1
27
+ end
28
+ end
29
+ end
30
+ """
31
+ And a file named "lib/account.rb" with:
32
+ """
33
+ class Account
34
+ attr_accessor :logger
35
+
36
+ def close
37
+ Process.fork { logger.account_closed }
38
+ end
39
+ end
40
+ """
41
+ When I run `rspec spec/account_spec.rb`
42
+ Then the output should contain "1 example, 0 failures"
43
+
44
+ Scenario: expect a message, but it isn't called
45
+ Given a file named "spec/account_spec.rb" with:
46
+ """
47
+ RSpec.configuration.mock_framework = :rspec
48
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'lib'))
49
+ require 'rspec/process_mocks'
50
+ require "account"
51
+
52
+ describe Account do
53
+ context "when closed" do
54
+ it "logs an account closed message in a child process" do
55
+
56
+ logger = double("logger")
57
+ account = Account.new
58
+ account.logger = logger
59
+
60
+ logger.should_receive_in_child_process(:account_closed)
61
+
62
+ account.close
63
+
64
+ sleep 0.1
65
+ end
66
+ end
67
+ end
68
+ """
69
+ And a file named "lib/account.rb" with:
70
+ """
71
+ class Account
72
+ attr_accessor :logger
73
+
74
+ def close
75
+ Process.fork { logger.object_id }
76
+ end
77
+ end
78
+ """
79
+ When I run `rspec spec/account_spec.rb`
80
+ Then the output should contain "1 example, 1 failure"
81
+ And the output should contain "expected: 1 time"
82
+ And the output should contain "received: 0 times"
83
+
84
+ @wip
85
+ Scenario: expect a message with an argument
86
+ Given a file named "spec/account_spec.rb" with:
87
+ """
88
+ RSpec.configuration.mock_framework = :rspec
89
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'lib'))
90
+ require 'rspec/process_mocks'
91
+ require "account"
92
+
93
+ describe Account do
94
+ context "when closed" do
95
+ it "logs an account closed message" do
96
+ logger = double("logger")
97
+ account = Account.new
98
+ account.logger = logger
99
+
100
+ logger.should_receive_in_child_process(:account_closed).with(account)
101
+
102
+ account.close
103
+
104
+ puts 'start sleep'
105
+ sleep 1
106
+ puts 'end sleep'
107
+
108
+ account.logger
109
+ end
110
+ end
111
+ end
112
+ """
113
+ And a file named "lib/account.rb" with:
114
+ """
115
+ class Account
116
+ attr_accessor :logger
117
+
118
+ def close
119
+ Process.fork { logger.account_closed(self) }
120
+ end
121
+ end
122
+ """
123
+ When I run `rspec spec/account_spec.rb`
124
+ Then the output should contain "1 example, 0 failures"
125
+
126
+ @wip
127
+ Scenario: provide a return value
128
+ Given a file named "message_expectation_spec.rb" with:
129
+ """
130
+ RSpec.configuration.mock_framework = :rspec
131
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'lib'))
132
+ require 'rspec/process_mocks'
133
+ describe "a message expectation" do
134
+ context "with a return value" do
135
+ context "specified in a block" do
136
+ it "returns the specified value" do
137
+ receiver = double("receiver")
138
+ receiver.should_receive_in_child_process(:message) { :return_value }
139
+ receiver.message.should eq(:return_value)
140
+ end
141
+ end
142
+
143
+ context "specified with and_return" do
144
+ it "returns the specified value" do
145
+ receiver = double("receiver")
146
+ receiver.should_receive_in_child_process(:message).and_return(:return_value)
147
+ receiver.message.should eq(:return_value)
148
+ end
149
+ end
150
+ end
151
+ end
152
+ """
153
+ When I run `rspec message_expectation_spec.rb`
154
+ Then the output should contain "2 examples, 0 failures"
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler.require(:default, :development, :test)
3
+
4
+ require 'aruba/cucumber'
5
+ require 'rspec/expectations'
6
+
7
+ Before do
8
+ @aruba_timeout_seconds = 3
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'rspec/process_mocks/methods'
2
+ require 'rspec/process_mocks/proxy'
3
+ require 'rspec/process_mocks/method_double'
4
+ require 'rspec/process_mocks/message_expectation'
@@ -0,0 +1,66 @@
1
+ require 'tempfile'
2
+
3
+ module RSpec
4
+ module ProcessMocks
5
+ class ChildProcessMessageExpectation < RSpec::Mocks::MessageExpectation
6
+ def initialize(*args)
7
+ super
8
+
9
+ # The tempfile is used for interprocess communication
10
+ @tempfile = Tempfile.new("should-receive-#{@expected_from.object_id}-#{@sym}")
11
+ end
12
+ def verify_messages_received
13
+ # Maybe we should add a sleep loop here if @tempfile is empty. This may
14
+ # prevent a user of this library from having to add a sleep in the spec.
15
+ # Maybe this:
16
+ # @tempfile.rewind
17
+ # lines = @tempfile.readlines
18
+ # timeout = Configure.verify_timeout
19
+ # while lines.empty? && timeout > 0
20
+ # sleep 0.1
21
+ # timeout -= 0.1
22
+ # @tempfile.rewind
23
+ # lines = @tempfile.readlines
24
+ # end
25
+
26
+ @tempfile.rewind
27
+ lines = @tempfile.readlines
28
+ #puts "lines in verify_messages_received: #{lines.inspect}"
29
+ return true if lines.size == 1 #&& # Called exactly once.
30
+ # lines[0] == "[]\n" # Called with no arguments.
31
+
32
+ generate_error
33
+ rescue RSpec::Mocks::MockExpectationError => error
34
+ error.backtrace.insert(0, @expected_from)
35
+ Kernel::raise error
36
+ end
37
+
38
+ # This is a hack to get it to work. But it means we can only ever expect
39
+ # exactly 1 message.
40
+ def matches_exact_count?
41
+ lines.size == 1
42
+ end
43
+
44
+ # This method is executed in the _child_ process when the stubbed method
45
+ # is called.
46
+ def invoke(*args, &block)
47
+
48
+ msg = args.inspect
49
+ @tempfile.puts msg
50
+ @tempfile.flush
51
+ # puts "##{@sym} called on #{@expected_from.class}-#{@expected_from.object_id}; args: #{args.inspect}"
52
+ # yield block, *args if defined?(block)
53
+ end
54
+
55
+ # This is a hack to get it to work. But it means we don't get info about
56
+ # "similar" methods in the failure output. Similar messages are those with
57
+ # a matching method name, but not matching arguments.
58
+ # Note: this is only a rough definition of "similar" methods. "Similar"
59
+ # methods are not part of RSpec's external API, so their definition is not
60
+ # strictly documented.
61
+ def similar_messages
62
+ []
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ module RSpec
2
+ module ProcessMocks
3
+ module MethodDouble
4
+ # This has no checking for existing expectations on this object (like RSpec
5
+ # does). It will probably only work if you set one expectation per object.
6
+ def add_child_process_expectation(error_generator, expectation_ordering, expected_from, opts, &block)
7
+ configure_method
8
+ # expectation = if existing_stub = stubs.first
9
+ # existing_stub.build_child(expected_from, block, 1, opts)
10
+ # else
11
+ # ChildProcessMessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, block, 1, opts)
12
+ # end
13
+ # expectations << expectation
14
+ expectation = ChildProcessMessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, block, 1, opts)
15
+ expectations << expectation
16
+ expectation
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module RSpec
23
+ module Mocks
24
+ class MethodDouble
25
+ include RSpec::ProcessMocks::MethodDouble
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module RSpec
2
+ module ProcessMocks
3
+ module Methods
4
+ def should_receive_in_child_process(sym, opts={}, &block)
5
+ __mock_proxy.add_child_process_message_expectation(opts[:expected_from] || caller(1)[0], sym.to_sym, opts, &block)
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ module RSpec
12
+ module Mocks
13
+ module Methods
14
+ include RSpec::ProcessMocks::Methods
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module RSpec
2
+ module ProcessMocks
3
+ module Proxy
4
+ def add_child_process_message_expectation(location, method_name, opts={}, &block)
5
+ method_double[method_name].add_child_process_expectation @error_generator, @expectation_ordering, location, opts, &block
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ module RSpec
12
+ module Mocks
13
+ class Proxy
14
+ include RSpec::ProcessMocks::Proxy
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module RSpec # :nodoc:
2
+ module ProcessMocks # :nodoc:
3
+ module Version # :nodoc:
4
+ STRING = '0.0.1'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'rspec/process_mocks/framework'
2
+ require 'rspec/process_mocks/version'
3
+
4
+ module RSpec
5
+ module ProcessMocks
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
3
+ require "rspec/process_mocks/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rspec-process-mocks"
7
+ s.version = RSpec::ProcessMocks::Version::STRING
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Paul Cortens"]
10
+ s.email = "paul@thoughtless.ca"
11
+ s.homepage = "http://github.com/thoughtless/rspec-process-mocks"
12
+ s.summary = "rspec-process-mocks-#{RSpec::ProcessMocks::Version::STRING}"
13
+ s.description = "Add-on for RSpec's 'test double' framework, with support for stubbing and mocking within child processes"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.extra_rdoc_files = [ "README.md" ]
19
+ s.rdoc_options = ["--charset=UTF-8"]
20
+ s.require_path = "lib"
21
+ end
22
+
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-process-mocks
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Paul Cortens
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-28 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Add-on for RSpec's 'test double' framework, with support for stubbing and mocking within child processes
18
+ email: paul@thoughtless.ca
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README.md
25
+ files:
26
+ - .gitignore
27
+ - Gemfile
28
+ - README.md
29
+ - cucumber.yml
30
+ - features/message_expectations/expect_message.feature
31
+ - features/support/env.rb
32
+ - lib/rspec/process_mocks.rb
33
+ - lib/rspec/process_mocks/framework.rb
34
+ - lib/rspec/process_mocks/message_expectation.rb
35
+ - lib/rspec/process_mocks/method_double.rb
36
+ - lib/rspec/process_mocks/methods.rb
37
+ - lib/rspec/process_mocks/proxy.rb
38
+ - lib/rspec/process_mocks/version.rb
39
+ - rspec-process-mocks.gemspec
40
+ has_rdoc: true
41
+ homepage: http://github.com/thoughtless/rspec-process-mocks
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.5.0
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: rspec-process-mocks-0.0.1
68
+ test_files: []
69
+