rspec_candy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/README.md +7 -0
- data/Rakefile +18 -0
- data/lib/rspec_candy/helpers/disposable_copy.rb +16 -0
- data/lib/rspec_candy/helpers/it_should_act_like.rb +39 -0
- data/lib/rspec_candy/helpers/new_with_stubs.rb +16 -0
- data/lib/rspec_candy/helpers/rails/create_without_callbacks.rb +25 -0
- data/lib/rspec_candy/helpers/rails/it_should_run_callbacks.rb +111 -0
- data/lib/rspec_candy/helpers/rails/prevent_storage.rb +20 -0
- data/lib/rspec_candy/helpers/should_receive_and_execute.rb +38 -0
- data/lib/rspec_candy/helpers/should_receive_and_return.rb +17 -0
- data/lib/rspec_candy/helpers/should_receive_chain.rb +43 -0
- data/lib/rspec_candy/helpers/stub_any_instance.rb +25 -0
- data/lib/rspec_candy/helpers/stub_existing.rb +20 -0
- data/lib/rspec_candy/switcher.rb +44 -0
- data/lib/rspec_candy/version.rb +3 -0
- data/lib/rspec_candy.rb +16 -0
- data/rspec_candy.gemspec +19 -0
- data/spec/rspec1/Gemfile +13 -0
- data/spec/rspec1/Rakefile +11 -0
- data/spec/rspec1/app_root/config/boot.rb +114 -0
- data/spec/rspec1/app_root/config/database.yml +21 -0
- data/spec/rspec1/app_root/config/environment.rb +14 -0
- data/spec/rspec1/app_root/config/environments/in_memory.rb +0 -0
- data/spec/rspec1/app_root/config/environments/mysql.rb +0 -0
- data/spec/rspec1/app_root/config/environments/postgresql.rb +0 -0
- data/spec/rspec1/app_root/config/environments/sqlite.rb +0 -0
- data/spec/rspec1/app_root/config/environments/sqlite3.rb +0 -0
- data/spec/rspec1/app_root/config/initializers/state_machine.rb +1 -0
- data/spec/rspec1/app_root/config/routes.rb +4 -0
- data/spec/rspec1/app_root/log/.gitignore +1 -0
- data/spec/rspec1/rcov.opts +2 -0
- data/spec/rspec1/spec.opts +4 -0
- data/spec/rspec1/spec_helper.rb +24 -0
- data/spec/rspec2/.rspec +2 -0
- data/spec/rspec2/Gemfile +13 -0
- data/spec/rspec2/Rakefile +11 -0
- data/spec/rspec2/app_root/.gitignore +4 -0
- data/spec/rspec2/app_root/config/application.rb +32 -0
- data/spec/rspec2/app_root/config/boot.rb +13 -0
- data/spec/rspec2/app_root/config/database.yml +21 -0
- data/spec/rspec2/app_root/config/environment.rb +5 -0
- data/spec/rspec2/app_root/config/environments/in_memory.rb +0 -0
- data/spec/rspec2/app_root/config/environments/mysql.rb +0 -0
- data/spec/rspec2/app_root/config/environments/postgresql.rb +0 -0
- data/spec/rspec2/app_root/config/environments/sqlite.rb +0 -0
- data/spec/rspec2/app_root/config/environments/sqlite3.rb +0 -0
- data/spec/rspec2/app_root/config/environments/test.rb +35 -0
- data/spec/rspec2/app_root/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rspec2/app_root/config/initializers/inflections.rb +10 -0
- data/spec/rspec2/app_root/config/initializers/mime_types.rb +5 -0
- data/spec/rspec2/app_root/config/initializers/secret_token.rb +7 -0
- data/spec/rspec2/app_root/config/initializers/session_store.rb +8 -0
- data/spec/rspec2/app_root/config/initializers/state_machine.rb +1 -0
- data/spec/rspec2/app_root/config/locales/en.yml +5 -0
- data/spec/rspec2/app_root/config/routes.rb +58 -0
- data/spec/rspec2/app_root/log/.gitkeep +0 -0
- data/spec/rspec2/rcov.opts +2 -0
- data/spec/rspec2/spec_helper.rb +25 -0
- data/spec/shared/app_root/app/controllers/application_controller.rb +2 -0
- data/spec/shared/app_root/app/models/model.rb +19 -0
- data/spec/shared/app_root/app/models/state_machine_model.rb +30 -0
- data/spec/shared/app_root/config/initializers/state_machine.rb +1 -0
- data/spec/shared/app_root/db/migrate/001_create_model.rb +13 -0
- data/spec/shared/app_root/db/migrate/002_create_state_machine_model.rb +13 -0
- data/spec/shared/rspec_candy/helpers/disposable_copy_spec.rb +45 -0
- data/spec/shared/rspec_candy/helpers/it_should_act_like_spec.rb +139 -0
- data/spec/shared/rspec_candy/helpers/new_with_stubs_spec.rb +41 -0
- data/spec/shared/rspec_candy/helpers/rails/create_without_callbacks_spec.rb +41 -0
- data/spec/shared/rspec_candy/helpers/rails/it_should_run_callbacks_spec.rb +142 -0
- data/spec/shared/rspec_candy/helpers/rails/prevent_storage_spec.rb +85 -0
- data/spec/shared/rspec_candy/helpers/should_receive_and_execute_spec.rb +32 -0
- data/spec/shared/rspec_candy/helpers/should_receive_and_return_spec.rb +30 -0
- data/spec/shared/rspec_candy/helpers/should_receive_chain_spec.rb +99 -0
- data/spec/shared/rspec_candy/helpers/stub_any_instance_spec.rb +32 -0
- data/spec/shared/rspec_candy/helpers/stub_existing_spec.rb +27 -0
- data/spec/shared/support/matchers/pass_as_describe_block.rb +32 -0
- data/spec/shared/support/matchers/pass_as_example.rb +30 -0
- data/template/spec_candy.rails2.rb +171 -0
- data/template/spec_candy.rails3.rb +175 -0
- metadata +159 -0
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Changes from previous versions:
|
2
|
+
|
3
|
+
- `new_and_store` has been renamed `create_without_callbacks`
|
4
|
+
- `keep_invalid!` has been renamed to `prevent_storage`
|
5
|
+
- `Object#should_not_receive_and_execute` has been removed (same as `Object#should_not_receive`)
|
6
|
+
- `should_receive_all_with` (over-generic method name for a helper that is rarely useful)
|
7
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
|
6
|
+
|
7
|
+
desc 'Default: Run all specs.'
|
8
|
+
task :default => :all_specs
|
9
|
+
|
10
|
+
desc "Run all specs"
|
11
|
+
task :all_specs do
|
12
|
+
Dir['spec/**/Rakefile'].sort.each do |rakefile|
|
13
|
+
directory = File.dirname(rakefile)
|
14
|
+
puts '', "\033[44m#{directory}\033[0m", ''
|
15
|
+
env = "SPEC=../../#{ENV['SPEC']} " if ENV['SPEC']
|
16
|
+
system("cd #{directory} && #{env} bundle exec rake")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module DisposableCopy
|
4
|
+
|
5
|
+
def disposable_copy(&body)
|
6
|
+
this = self
|
7
|
+
copy = Class.new(self, &body)
|
8
|
+
copy.singleton_class.send(:define_method, :name) { this.name }
|
9
|
+
copy
|
10
|
+
end
|
11
|
+
|
12
|
+
Class.send(:include, self)
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module ItShouldActLike
|
4
|
+
|
5
|
+
def self.included(by)
|
6
|
+
by.class_eval do
|
7
|
+
|
8
|
+
# Improves it_should_behave_like in some ways:
|
9
|
+
# - It scopes the reused examples so #let und #subject does not bleed into the reusing example groups
|
10
|
+
# - It allows to parametrize the reused example group by appending a hash argument.
|
11
|
+
# Every key/value pair in the hash will become a #let variable for the reused example group
|
12
|
+
# - You can call it with a block. It will be available to the reused example group as let(:block)
|
13
|
+
def it_should_act_like(shared_example_group, environment = {}, &block)
|
14
|
+
if Switcher.rspec_version == :rspec2
|
15
|
+
warn('"it_should_act_like" is deprecated. Consider using "it_should_behave_like".')
|
16
|
+
end
|
17
|
+
|
18
|
+
description = "as #{shared_example_group}"
|
19
|
+
description << " (#{environment.inspect})" if environment.present?
|
20
|
+
describe description do
|
21
|
+
environment.each do |name, value|
|
22
|
+
let(name) { value }
|
23
|
+
end
|
24
|
+
let(:block) { block } if block
|
25
|
+
it_should_behave_like(shared_example_group)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
case Switcher.rspec_version
|
32
|
+
when :rspec1
|
33
|
+
Spec::Example::ExampleGroupMethods.send(:include, self)
|
34
|
+
when :rspec2
|
35
|
+
RSpec::Core::ExampleGroup.singleton_class.send(:include, self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module Rails
|
4
|
+
module CreateWithoutCallbacks
|
5
|
+
|
6
|
+
def create_without_callbacks(*args)
|
7
|
+
table_name = self.table_name
|
8
|
+
plain_model = Class.new(ActiveRecord::Base) do
|
9
|
+
self.table_name = table_name
|
10
|
+
end
|
11
|
+
plain_record = plain_model.create!(*args)
|
12
|
+
find plain_record.id
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_and_store(*args)
|
16
|
+
warn 'new_and_store is deprecated. Use create_without_callbacks instead.'
|
17
|
+
create_without_callbacks(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
ActiveRecord::Base.send(:extend, self)
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module Rails
|
4
|
+
module ItShouldRunCallbacks
|
5
|
+
|
6
|
+
module ExampleGroupMethods
|
7
|
+
def self.included(by)
|
8
|
+
by.class_eval do
|
9
|
+
|
10
|
+
def it_should_run_callbacks_in_order(*callbacks)
|
11
|
+
callbacks.push(:ordered => true)
|
12
|
+
it_should_run_callbacks(*callbacks)
|
13
|
+
end
|
14
|
+
|
15
|
+
def it_should_run_callbacks(*callbacks)
|
16
|
+
options = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
|
17
|
+
reason = callbacks.pop if callbacks.last.is_a?(String)
|
18
|
+
should = ['should run callbacks', callbacks.inspect, ('in order' if options[:ordered]), reason].compact.join ' '
|
19
|
+
|
20
|
+
prose = case Switcher.rspec_version
|
21
|
+
when :rspec1
|
22
|
+
description_parts.last
|
23
|
+
when :rspec2
|
24
|
+
description.split(/(?=#)/).last
|
25
|
+
end
|
26
|
+
|
27
|
+
send(:it, should) do
|
28
|
+
extend ExampleMethods
|
29
|
+
if subject.class.respond_to?(:state_machine) and defined?(StateMachine)
|
30
|
+
extend StateMachineExampleMethods
|
31
|
+
end
|
32
|
+
callbacks.each do |callback|
|
33
|
+
expectation = subject.should_receive(callback).once
|
34
|
+
expectation.ordered if options[:ordered]
|
35
|
+
end
|
36
|
+
run_all_callbacks(prose)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ExampleMethods
|
44
|
+
private
|
45
|
+
|
46
|
+
def run_all_callbacks(prose)
|
47
|
+
run_active_record_callbacks_from_prose(prose)
|
48
|
+
end
|
49
|
+
|
50
|
+
case Switcher.rspec_version
|
51
|
+
when :rspec1
|
52
|
+
|
53
|
+
def run_active_record_callbacks_from_prose(prose)
|
54
|
+
subject.run_callbacks(prose.sub(/^#/, ''))
|
55
|
+
end
|
56
|
+
|
57
|
+
when :rspec2
|
58
|
+
|
59
|
+
def run_active_record_callbacks_from_prose(prose)
|
60
|
+
hook = prose.split.last.sub(/^#/, '')
|
61
|
+
if hook.sub!(/_on_(create|update)$/, '')
|
62
|
+
condition = "validation_context == :#{$1}"
|
63
|
+
else
|
64
|
+
condition = nil
|
65
|
+
end
|
66
|
+
if hook == 'validate'
|
67
|
+
kind = 'before'
|
68
|
+
action = 'validate'
|
69
|
+
else
|
70
|
+
hook =~ /^(before|after|around)_(.*)$/
|
71
|
+
kind = $1
|
72
|
+
action = $2
|
73
|
+
end
|
74
|
+
# Run all matching callbacks
|
75
|
+
subject.send("_#{action}_callbacks").send(kind == 'after' ? :reverse_each : :each) do |callback|
|
76
|
+
if callback.kind.to_s == kind && (condition.nil? || callback.options[:if].include?(condition))
|
77
|
+
subject.send(callback.filter.to_s.gsub(/[\(,\)]/, '').to_sym) {}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module StateMachineExampleMethods
|
86
|
+
def run_all_callbacks(prose)
|
87
|
+
run_state_machine_callbacks_from_prose(prose) or super
|
88
|
+
end
|
89
|
+
|
90
|
+
def run_state_machine_callbacks_from_prose(prose)
|
91
|
+
if parts = prose.match(/^(#\w+) from ([\:\w]+) to ([\:\w]+)$/)
|
92
|
+
name = parts[1].sub(/^#/, '').to_sym
|
93
|
+
from = parts[2].sub(/^:/, '').to_sym
|
94
|
+
to = parts[3].sub(/^:/, '').to_sym
|
95
|
+
transition = StateMachine::Transition.new(subject, subject.class.state_machine, name, from, to)
|
96
|
+
transition.run_callbacks
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
case Switcher.rspec_version
|
102
|
+
when :rspec1
|
103
|
+
Spec::Example::ExampleGroupMethods.send(:include, self::ExampleGroupMethods)
|
104
|
+
when :rspec2
|
105
|
+
RSpec::Core::ExampleGroup.singleton_class.send(:include, self::ExampleGroupMethods)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module Rails
|
4
|
+
module PreventStorage
|
5
|
+
|
6
|
+
def prevent_storage
|
7
|
+
errors.stub :empty? => false
|
8
|
+
end
|
9
|
+
|
10
|
+
def keep_invalid!
|
11
|
+
warn 'keep_invalid! is deprecated. Use prevent_storage instead.'
|
12
|
+
prevent_storage
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Base.send(:include, self)
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module ShouldReceiveAndExecute
|
4
|
+
|
5
|
+
def should_receive_and_execute(method)
|
6
|
+
method_base = method.to_s.gsub(/([\?\!\=\[\]]+)$/, '')
|
7
|
+
method_suffix = $1
|
8
|
+
|
9
|
+
method_called = "_#{method_base}_called#{method_suffix}"
|
10
|
+
method_with_spy = "#{method_base}_with_spy#{method_suffix}"
|
11
|
+
method_without_spy = "#{method_base}_without_spy#{method_suffix}"
|
12
|
+
|
13
|
+
prototype = respond_to?(:singleton_class) ? singleton_class : metaclass
|
14
|
+
prototype.class_eval do
|
15
|
+
|
16
|
+
unless method_defined?(method_with_spy)
|
17
|
+
|
18
|
+
define_method method_called do
|
19
|
+
end
|
20
|
+
|
21
|
+
define_method method_with_spy do |*args, &block|
|
22
|
+
send(method_called, *args)
|
23
|
+
send(method_without_spy, *args, &block)
|
24
|
+
end
|
25
|
+
alias_method_chain method, :spy
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
should_receive(method_called)
|
31
|
+
end
|
32
|
+
|
33
|
+
Object.send(:include, self)
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module ShouldReceiveAndReturn
|
4
|
+
|
5
|
+
def should_receive_and_return(methods_and_values)
|
6
|
+
methods_and_values.each do |method, value|
|
7
|
+
should_receive(method).and_return(value)
|
8
|
+
end
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
Object.send(:include, self)
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module ShouldReceiveChain
|
4
|
+
|
5
|
+
def should_receive_chain(*parts)
|
6
|
+
setup_expectation_chain(parts)
|
7
|
+
end
|
8
|
+
|
9
|
+
def should_not_receive_chain(*parts)
|
10
|
+
setup_expectation_chain(parts, :negate => true)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def setup_expectation_chain(parts, options = {})
|
16
|
+
obj = self
|
17
|
+
for part in parts
|
18
|
+
if part == parts.last
|
19
|
+
expectation = options[:negate] ? :should_not_receive : :should_receive
|
20
|
+
obj = add_expectation_chain_link(obj, expectation, part)
|
21
|
+
else
|
22
|
+
next_obj = Switcher.new_mock('chain link')
|
23
|
+
add_expectation_chain_link(obj, :stub, part).and_return(next_obj)
|
24
|
+
obj = next_obj
|
25
|
+
end
|
26
|
+
end
|
27
|
+
obj
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_expectation_chain_link(obj, expectation, part)
|
31
|
+
if part.is_a?(Array)
|
32
|
+
obj.send(expectation, part.first).with(*part[1..-1])
|
33
|
+
else
|
34
|
+
obj.send(expectation, part)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Object.send(:include, self)
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module StubAnyInstance
|
4
|
+
|
5
|
+
def stub_any_instance(stubs)
|
6
|
+
case Switcher.rspec_version
|
7
|
+
when :rspec1
|
8
|
+
unstubbed_new = method(:new)
|
9
|
+
stub(:new).and_return do |*args|
|
10
|
+
unstubbed_new.call(*args).tap do |obj|
|
11
|
+
obj.stub stubs
|
12
|
+
end
|
13
|
+
end
|
14
|
+
stubs
|
15
|
+
when :rspec2
|
16
|
+
any_instance.stub(stubs)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Class.send(:include, self)
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Helpers
|
3
|
+
module StubExisting
|
4
|
+
|
5
|
+
def stub_existing(attrs)
|
6
|
+
attrs.each do |method, value|
|
7
|
+
if respond_to?(method, true)
|
8
|
+
stub(method => value)
|
9
|
+
else
|
10
|
+
raise "Attempted to stub non-existing method ##{method} on #{inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Object.send(:include, self)
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RSpecCandy
|
2
|
+
module Switcher
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def rspec_version
|
6
|
+
if defined?(RSpec)
|
7
|
+
:rspec2
|
8
|
+
elsif defined?(Spec)
|
9
|
+
:rspec1
|
10
|
+
else
|
11
|
+
raise 'Cannot determine RSpec version'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def rails_version
|
16
|
+
if Rails.version.to_i < 3
|
17
|
+
:rails2
|
18
|
+
else
|
19
|
+
:rails3
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def rails_loaded?
|
24
|
+
defined?(Rails)
|
25
|
+
end
|
26
|
+
|
27
|
+
def new_mock(*args)
|
28
|
+
rspec_root.const_get(:Mocks).const_get(:Mock).new(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def rspec_root
|
32
|
+
(defined?(RSpec) ? RSpec : Spec)
|
33
|
+
end
|
34
|
+
|
35
|
+
def rspec_matcher_registry
|
36
|
+
rspec_root.const_get(:Matchers)
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_matcher(*args, &block)
|
40
|
+
rspec_matcher_registry.define(*args, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|