shoulda-callback-matchers 0.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.
@@ -0,0 +1,13 @@
1
+ # :enddoc:
2
+
3
+ if defined?(::ActiveRecord)
4
+ require 'shoulda/callback/matchers/active_model'
5
+ module RSpec::Matchers
6
+ include Shoulda::Callback::Matchers::ActiveModel
7
+ end
8
+ elsif defined?(::ActiveModel)
9
+ require 'shoulda/callback/matchers/active_model'
10
+ module RSpec::Matchers
11
+ include Shoulda::Callback::Matchers::ActiveModel
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ # :enddoc:
2
+
3
+ # in environments where test/unit is not required, this is necessary
4
+ unless defined?(Test::Unit::TestCase)
5
+ begin
6
+ require 'test/unit'
7
+ rescue LoadError
8
+ # silent
9
+ end
10
+ end
11
+
12
+ if defined?(ActiveRecord)
13
+ require 'shoulda/callback/matchers/active_model'
14
+
15
+ module Test
16
+ module Unit
17
+ class TestCase
18
+ include Shoulda::Callback::Matchers::ActiveModel
19
+ extend Shoulda::Callback::Matchers::ActiveModel
20
+ end
21
+ end
22
+ end
23
+ elsif defined?(ActiveModel)
24
+ require 'shoulda/callback/matchers/active_model'
25
+
26
+ module Test
27
+ module Unit
28
+ class TestCase
29
+ include Shoulda::Callback::Matchers::ActiveModel
30
+ extend Shoulda::Callback::Matchers::ActiveModel
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ module Shoulda
2
+ module Callback
3
+ module Matchers
4
+ VERSION = '0.1.0'.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
2
+ require 'shoulda/callback/matchers/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "shoulda-callback-matchers"
6
+ s.version = Shoulda::Callback::Matchers::VERSION.dup
7
+ s.authors = ["Beat Richartz"]
8
+ s.date = Time.now.strftime("%Y-%m-%d")
9
+ s.email = "attraccessor@gmail.com"
10
+ s.homepage = "http://github.com/beatrichartz/shoulda-callback-matchers"
11
+ s.summary = "Making callback tests easy on the fingers and eyes"
12
+ s.description = "Making callback tests easy on the fingers and eyes"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency('activesupport', '>= 3.0.0')
20
+
21
+ s.add_development_dependency('appraisal', '~> 0.4.0')
22
+ s.add_development_dependency('aruba')
23
+ s.add_development_dependency('bourne', '~> 1.1.2')
24
+ s.add_development_dependency('bundler', '>= 1.1.0')
25
+ s.add_development_dependency('rails', '~> 3.0')
26
+ s.add_development_dependency('rake', '~> 0.9.2')
27
+ s.add_development_dependency('rspec-rails', '~> 2.8.1')
28
+ end
@@ -0,0 +1,6 @@
1
+ first:
2
+ id: 1
3
+ name: Some dude
4
+ age: 2
5
+ email: none@none.com
6
+ ssn: 123456789
@@ -0,0 +1,229 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Callback::Matchers::ActiveModel do
4
+
5
+ context "invalid use" do
6
+ before do
7
+ @model = define_model(:example, :attr => :string,
8
+ :other => :integer) do
9
+ attr_accessible :attr, :other
10
+ before_create :dance!, :if => :evaluates_to_false!
11
+ after_save :shake!, :unless => :evaluates_to_true!
12
+ end.new
13
+ end
14
+ it "should return a meaningful failure message when used without a defined lifecycle" do
15
+ matcher = callback(:dance!)
16
+ matcher.matches?(@model).should be_false
17
+ matcher.failure_message.should == "callback dance! can not be tested against an undefined lifecycle, use .before, .after or .around"
18
+ matcher.negative_failure_message.should == "callback dance! can not be tested against an undefined lifecycle, use .before, .after or .around"
19
+ end
20
+ it "should return a meaningful failure message when used with an optional lifecycle without the original lifecycle being validation" do
21
+ matcher = callback(:dance!).after(:create).on(:save)
22
+ matcher.matches?(@model).should be_false
23
+ matcher.failure_message.should == "The .on option is only valid for the validation lifecycle and cannot be used with create, use with .before(:validation) or .after(:validation)"
24
+ matcher.negative_failure_message.should == "The .on option is only valid for the validation lifecycle and cannot be used with create, use with .before(:validation) or .after(:validation)"
25
+ end
26
+ end
27
+
28
+ [:save, :create, :update, :destroy].each do |lifecycle|
29
+ context "on #{lifecycle}" do
30
+ before do
31
+ @model = define_model(:example, :attr => :string,
32
+ :other => :integer) do
33
+ attr_accessible :attr, :other
34
+ send(:"before_#{lifecycle}", :dance!, :if => :evaluates_to_false!)
35
+ send(:"after_#{lifecycle}", :shake!, :unless => :evaluates_to_true!)
36
+ send(:"around_#{lifecycle}", :giggle!)
37
+ end.new
38
+ end
39
+ context "as a simple callback test" do
40
+ it "should find the callback before the fact" do
41
+ @model.should callback(:dance!).before(lifecycle)
42
+ end
43
+ it "should find the callback after the fact" do
44
+ @model.should callback(:shake!).after(lifecycle)
45
+ end
46
+ it "should find the callback around the fact" do
47
+ @model.should callback(:giggle!).around(lifecycle)
48
+ end
49
+ it "should not find callbacks that are not there" do
50
+ @model.should_not callback(:scream!).around(lifecycle)
51
+ end
52
+ it "should have a meaningful description" do
53
+ matcher = callback(:dance!).before(lifecycle)
54
+ matcher.description.should == "callback dance! before #{lifecycle}"
55
+ end
56
+ end
57
+ context "with conditions" do
58
+ it "should match the if condition" do
59
+ @model.should callback(:dance!).before(lifecycle).if(:evaluates_to_false!)
60
+ end
61
+ it "should match the unless condition" do
62
+ @model.should callback(:shake!).after(lifecycle).unless(:evaluates_to_true!)
63
+ end
64
+ it "should not find callbacks not matching the conditions" do
65
+ @model.should_not callback(:giggle!).around(lifecycle).unless(:evaluates_to_false!)
66
+ end
67
+ it "should not find callbacks that are not there entirely" do
68
+ @model.should_not callback(:scream!).before(lifecycle).unless(:evaluates_to_false!)
69
+ end
70
+ it "should have a meaningful description" do
71
+ matcher = callback(:dance!).after(lifecycle).unless(:evaluates_to_false!)
72
+ matcher.description.should == "callback dance! after #{lifecycle} unless evaluates_to_false! evaluates to false"
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ context "on validation" do
79
+ before do
80
+ @model = define_model(:example, :attr => :string,
81
+ :other => :integer) do
82
+ attr_accessible :attr, :other
83
+ before_validation :dance!, :if => :evaluates_to_false!
84
+ after_validation :shake!, :unless => :evaluates_to_true!
85
+ before_validation :dress!, :on => :create
86
+ after_validation :shriek!, :on => :update, :unless => :evaluates_to_true!
87
+ after_validation :pucker!, :on => :save, :if => :evaluates_to_false!
88
+ end.new
89
+ end
90
+
91
+ context "as a simple callback test" do
92
+ it "should find the callback before the fact" do
93
+ @model.should callback(:dance!).before(:validation)
94
+ end
95
+ it "should find the callback after the fact" do
96
+ @model.should callback(:shake!).after(:validation)
97
+ end
98
+ it "should not find a callback around the fact" do
99
+ @model.should_not callback(:giggle!).around(:validation)
100
+ end
101
+ it "should not find callbacks that are not there" do
102
+ @model.should_not callback(:scream!).around(:validation)
103
+ end
104
+ it "should have a meaningful description" do
105
+ matcher = callback(:dance!).before(:validation)
106
+ matcher.description.should == "callback dance! before validation"
107
+ end
108
+ end
109
+
110
+ context "with additinal lifecycles defined" do
111
+ it "should find the callback before the fact on create" do
112
+ @model.should callback(:dress!).before(:validation).on(:create)
113
+ end
114
+ it "should find the callback after the fact on update" do
115
+ @model.should callback(:shriek!).after(:validation).on(:update)
116
+ end
117
+ it "should find the callback after the fact on save" do
118
+ @model.should callback(:pucker!).after(:validation).on(:save)
119
+ end
120
+ it "should not find a callback for pucker! after the fact on update" do
121
+ @model.should_not callback(:pucker!).after(:validation).on(:update)
122
+ end
123
+ it "should have a meaningful description" do
124
+ matcher = callback(:dance!).after(:validation).on(:update)
125
+ matcher.description.should == "callback dance! after validation on update"
126
+ end
127
+ end
128
+
129
+ context "with conditions" do
130
+ it "should match the if condition" do
131
+ @model.should callback(:dance!).before(:validation).if(:evaluates_to_false!)
132
+ end
133
+ it "should match the unless condition" do
134
+ @model.should callback(:shake!).after(:validation).unless(:evaluates_to_true!)
135
+ end
136
+ it "should not find callbacks not matching the conditions" do
137
+ @model.should_not callback(:giggle!).around(:validation).unless(:evaluates_to_false!)
138
+ end
139
+ it "should not find callbacks that are not there entirely" do
140
+ @model.should_not callback(:scream!).before(:validation).unless(:evaluates_to_false!)
141
+ end
142
+ it "should have a meaningful description" do
143
+ matcher = callback(:dance!).after(:validation).unless(:evaluates_to_false!)
144
+ matcher.description.should == "callback dance! after validation unless evaluates_to_false! evaluates to false"
145
+ end
146
+ end
147
+
148
+ context "with conditions and additional lifecycles" do
149
+ it "should find the callback before the fact on create" do
150
+ @model.should callback(:dress!).before(:validation).on(:create)
151
+ end
152
+ it "should find the callback after the fact on update with the unless condition" do
153
+ @model.should callback(:shriek!).after(:validation).on(:update).unless(:evaluates_to_true!)
154
+ end
155
+ it "should find the callback after the fact on save with the if condition" do
156
+ @model.should callback(:pucker!).after(:validation).on(:save).if(:evaluates_to_false!)
157
+ end
158
+ it "should not find a callback for pucker! after the fact on save with the wrong condition" do
159
+ @model.should_not callback(:pucker!).after(:validation).on(:save).unless(:evaluates_to_false!)
160
+ end
161
+ it "should have a meaningful description" do
162
+ matcher = callback(:dance!).after(:validation).on(:save).unless(:evaluates_to_false!)
163
+ matcher.description.should == "callback dance! after validation on save unless evaluates_to_false! evaluates to false"
164
+ end
165
+ end
166
+ end
167
+
168
+ [:initialize, :find, :touch].each do |lifecycle|
169
+
170
+ context "on #{lifecycle}" do
171
+ before do
172
+ @model = define_model(:example, :attr => :string,
173
+ :other => :integer) do
174
+ attr_accessible :attr, :other
175
+ send(:"after_#{lifecycle}", :dance!, :if => :evaluates_to_false!)
176
+ send(:"after_#{lifecycle}", :shake!, :unless => :evaluates_to_true!)
177
+
178
+ define_method :evaluates_to_false! do
179
+ false
180
+ end
181
+
182
+ define_method :evaluates_to_true! do
183
+ true
184
+ end
185
+
186
+ end.new
187
+ end
188
+
189
+ context "as a simple callback test" do
190
+ it "should not find a callback before the fact" do
191
+ @model.should_not callback(:dance!).before(lifecycle)
192
+ end
193
+ it "should find the callback after the fact" do
194
+ @model.should callback(:shake!).after(lifecycle)
195
+ end
196
+ it "should not find a callback around the fact" do
197
+ @model.should_not callback(:giggle!).around(lifecycle)
198
+ end
199
+ it "should not find callbacks that are not there" do
200
+ @model.should_not callback(:scream!).around(lifecycle)
201
+ end
202
+ it "should have a meaningful description" do
203
+ matcher = callback(:dance!).before(lifecycle)
204
+ matcher.description.should == "callback dance! before #{lifecycle}"
205
+ end
206
+ end
207
+
208
+ context "with conditions" do
209
+ it "should match the if condition" do
210
+ @model.should callback(:dance!).after(lifecycle).if(:evaluates_to_false!)
211
+ end
212
+ it "should match the unless condition" do
213
+ @model.should callback(:shake!).after(lifecycle).unless(:evaluates_to_true!)
214
+ end
215
+ it "should not find callbacks not matching the conditions" do
216
+ @model.should_not callback(:giggle!).around(lifecycle).unless(:evaluates_to_false!)
217
+ end
218
+ it "should not find callbacks that are not there entirely" do
219
+ @model.should_not callback(:scream!).before(lifecycle).unless(:evaluates_to_false!)
220
+ end
221
+ it "should have a meaningful description" do
222
+ matcher = callback(:dance!).after(lifecycle).unless(:evaluates_to_false!)
223
+ matcher.description.should == "callback dance! after #{lifecycle} unless evaluates_to_false! evaluates to false"
224
+ end
225
+ end
226
+
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,27 @@
1
+ # Create Rails environment based on the version given from Appraisal
2
+ TESTAPP_ROOT = File.join(File.dirname(__FILE__), '..', 'tmp', 'aruba', 'testapp')
3
+ FileUtils.rm_rf(TESTAPP_ROOT) if File.exists?(TESTAPP_ROOT)
4
+ `rails new #{TESTAPP_ROOT}`
5
+
6
+ ENV['RAILS_ENV'] = 'test'
7
+ ENV['BUNDLE_GEMFILE'] ||= TESTAPP_ROOT + '/Gemfile'
8
+
9
+ require "#{TESTAPP_ROOT}/config/environment"
10
+ require 'rspec'
11
+ require 'bourne'
12
+ require 'shoulda-callback-matchers'
13
+ require 'rspec/rails'
14
+
15
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
16
+
17
+ $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
18
+
19
+ Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
20
+
21
+ # Run the migrations
22
+ ActiveRecord::Migration.verbose = false
23
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
24
+
25
+ RSpec.configure do |config|
26
+ config.mock_with :mocha
27
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.configure do |c|
2
+ def active_model_3_1?
3
+ ::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR >= 1
4
+ end
5
+
6
+ def active_model_3_2?
7
+ ::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR >= 2
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module ClassBuilder
2
+ def self.included(example_group)
3
+ example_group.class_eval do
4
+ after do
5
+ teardown_defined_constants
6
+ end
7
+ end
8
+ end
9
+
10
+ def define_class(class_name, base = Object, &block)
11
+ class_name = class_name.to_s.camelize
12
+
13
+ # FIXME: ActionMailer 3.2 calls `name.underscore` immediately upon
14
+ # subclassing. Class.new.name == nil. So, Class.new(ActionMailer::Base)
15
+ # errors out since it's trying to do `nil.underscore`. This is very ugly but
16
+ # allows us to test against ActionMailer 3.2.x.
17
+ eval <<-A_REAL_CLASS_FOR_ACTION_MAILER_3_2
18
+ class ::#{class_name} < #{base}
19
+ end
20
+ A_REAL_CLASS_FOR_ACTION_MAILER_3_2
21
+
22
+ Object.const_get(class_name).tap do |constant_class|
23
+ constant_class.unloadable
24
+
25
+ if block_given?
26
+ constant_class.class_eval(&block)
27
+ end
28
+
29
+ if constant_class.respond_to?(:reset_column_information)
30
+ constant_class.reset_column_information
31
+ end
32
+ end
33
+ end
34
+
35
+ def teardown_defined_constants
36
+ ActiveSupport::Dependencies.clear
37
+ end
38
+ end
39
+
40
+ RSpec.configure do |config|
41
+ config.include ClassBuilder
42
+ end
@@ -0,0 +1,73 @@
1
+ module ModelBuilder
2
+ def self.included(example_group)
3
+ example_group.class_eval do
4
+ before do
5
+ @created_tables ||= []
6
+ end
7
+
8
+ after do
9
+ drop_created_tables
10
+ end
11
+ end
12
+ end
13
+
14
+ def create_table(table_name, options = {}, &block)
15
+ connection = ActiveRecord::Base.connection
16
+
17
+ begin
18
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
19
+ connection.create_table(table_name, options, &block)
20
+ @created_tables << table_name
21
+ connection
22
+ rescue Exception => e
23
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
24
+ raise e
25
+ end
26
+ end
27
+
28
+ def define_model_class(class_name, &block)
29
+ define_class(class_name, ActiveRecord::Base, &block)
30
+ end
31
+
32
+ def define_active_model_class(class_name, options = {}, &block)
33
+ define_class(class_name) do
34
+ include ActiveModel::Validations
35
+ extend ActiveModel::Callbacks
36
+ define_model_callbacks :initialize, :find, :touch, :only => :after
37
+ define_model_callbacks :save, :create, :update, :destroy
38
+
39
+ options[:accessors].each do |column|
40
+ attr_accessor column.to_sym
41
+ end
42
+
43
+ if block_given?
44
+ class_eval(&block)
45
+ end
46
+ end
47
+ end
48
+
49
+ def define_model(name, columns = {}, &block)
50
+ class_name = name.to_s.pluralize.classify
51
+ table_name = class_name.tableize
52
+
53
+ create_table(table_name) do |table|
54
+ columns.each do |name, type|
55
+ table.column name, type
56
+ end
57
+ end
58
+
59
+ define_model_class(class_name, &block)
60
+ end
61
+
62
+ def drop_created_tables
63
+ connection = ActiveRecord::Base.connection
64
+
65
+ @created_tables.each do |table_name|
66
+ connection.execute("DROP TABLE IF EXISTS #{table_name}")
67
+ end
68
+ end
69
+ end
70
+
71
+ RSpec.configure do |config|
72
+ config.include ModelBuilder
73
+ end