shoulda-matchers 1.2.0 → 1.3.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/Gemfile.lock +1 -1
- data/NEWS.md +18 -0
- data/README.md +1 -6
- data/features/rails_integration.feature +28 -0
- data/features/step_definitions/rails_steps.rb +18 -0
- data/gemfiles/3.0.gemfile.lock +7 -7
- data/gemfiles/3.1.gemfile.lock +10 -10
- data/gemfiles/3.2.gemfile.lock +11 -11
- data/lib/shoulda/matchers.rb +2 -2
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +1 -10
- data/lib/shoulda/matchers/active_model/validate_format_of_matcher.rb +36 -2
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +18 -11
- data/lib/shoulda/matchers/active_record/association_matcher.rb +31 -1
- data/lib/shoulda/matchers/assertion_error.rb +5 -3
- data/lib/shoulda/matchers/version.rb +1 -1
- data/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb +8 -0
- data/spec/shoulda/active_model/validate_format_of_matcher_spec.rb +47 -6
- data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +15 -11
- data/spec/shoulda/active_record/association_matcher_spec.rb +185 -0
- data/spec/shoulda/active_record/serialize_matcher_spec.rb +1 -1
- data/spec/support/class_builder.rb +42 -0
- data/spec/support/controller_builder.rb +78 -0
- data/spec/support/mailer_builder.rb +10 -0
- data/spec/support/model_builder.rb +3 -90
- metadata +9 -8
data/Gemfile.lock
CHANGED
data/NEWS.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# v1.3.0
|
2
|
+
|
3
|
+
* `validate_format_of` will accept `allow_blank(bool)` and `allow_nil(bool)`
|
4
|
+
|
5
|
+
* Prefer Test::Unit to Minitest when loading integrations so that RubyMine is
|
6
|
+
happy (#88).
|
7
|
+
|
8
|
+
* `validates_uniqueness_of` will now create a record if one does not exist.
|
9
|
+
Previously, users were required to create a record in the database before
|
10
|
+
using this matcher.
|
11
|
+
|
12
|
+
* Fix an edge case when where the matchers weren't loaded into Test::Unit when
|
13
|
+
mixing RSpec and Test::Unit tests and also loading both the 'rspec-rails' gem
|
14
|
+
and 'shoulda-matchers' gem from the same Gemfile group, namely [:test,
|
15
|
+
:development].
|
16
|
+
|
17
|
+
* `controller.should_not render_partial` now correctly matches `render partial: "partial"`.
|
18
|
+
|
1
19
|
# v1.2.0
|
2
20
|
|
3
21
|
* `ensure_inclusion_of` now has an `in_array` parameter:
|
data/README.md
CHANGED
@@ -30,12 +30,7 @@ Matchers to test validations and mass assignments:
|
|
30
30
|
it { should validate_presence_of(:body).with_message(/wtf/) }
|
31
31
|
it { should validate_presence_of(:title) }
|
32
32
|
it { should validate_numericality_of(:user_id) }
|
33
|
-
|
34
|
-
# validates_uniqueness_of requires an entry to be in the database already
|
35
|
-
it "validates uniqueness of title" do
|
36
|
-
Post.create!(title: "My Awesome Post", body: "whatever")
|
37
|
-
should validate_uniqueness_of(:title)
|
38
|
-
end
|
33
|
+
it { should ensure_inclusion_of(:status).in_array(['draft', 'public']) }
|
39
34
|
end
|
40
35
|
|
41
36
|
describe User do
|
@@ -86,3 +86,31 @@ Feature: integrate with Rails
|
|
86
86
|
Then the output should contain "2 examples, 0 failures"
|
87
87
|
And the output should contain "should require name to be set"
|
88
88
|
And the output should contain "should assign @example"
|
89
|
+
|
90
|
+
Scenario: generate a Rails application that mixes Rspec and Test::Unit
|
91
|
+
When I configure the application to use rspec-rails in test and development
|
92
|
+
And I configure the application to use "shoulda-matchers" from this project in test and development
|
93
|
+
And I run the rspec generator
|
94
|
+
And I write to "spec/models/user_spec.rb" with:
|
95
|
+
"""
|
96
|
+
require 'spec_helper'
|
97
|
+
|
98
|
+
describe User do
|
99
|
+
it { should validate_presence_of(:name) }
|
100
|
+
end
|
101
|
+
"""
|
102
|
+
When I write to "test/functional/examples_controller_test.rb" with:
|
103
|
+
"""
|
104
|
+
require 'test_helper'
|
105
|
+
|
106
|
+
class ExamplesControllerTest < ActionController::TestCase
|
107
|
+
test 'assigns to @example' do
|
108
|
+
get :show
|
109
|
+
assert assign_to(:example).matches?(@controller)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
"""
|
113
|
+
When I successfully run `bundle exec rake spec test:functionals SPEC_OPTS=-fs --trace`
|
114
|
+
Then the output should contain "1 example, 0 failures"
|
115
|
+
And the output should contain "1 tests, 1 assertions, 0 failures, 0 errors"
|
116
|
+
And the output should contain "should require name to be set"
|
@@ -36,6 +36,15 @@ When /^I configure the application to use "([^\"]+)" from this project$/ do |nam
|
|
36
36
|
steps %{And I run `bundle install --local`}
|
37
37
|
end
|
38
38
|
|
39
|
+
When /^I configure the application to use "([^\"]+)" from this project in test and development$/ do |name|
|
40
|
+
append_to_gemfile <<-GEMFILE
|
41
|
+
group :test, :development do
|
42
|
+
gem '#{name}', :path => '#{PROJECT_ROOT}'
|
43
|
+
end
|
44
|
+
GEMFILE
|
45
|
+
steps %{And I run `bundle install --local`}
|
46
|
+
end
|
47
|
+
|
39
48
|
When 'I run the rspec generator' do
|
40
49
|
steps %{
|
41
50
|
When I successfully run `rails generate rspec:install`
|
@@ -47,6 +56,15 @@ When 'I configure the application to use rspec-rails' do
|
|
47
56
|
steps %{And I run `bundle install --local`}
|
48
57
|
end
|
49
58
|
|
59
|
+
When 'I configure the application to use rspec-rails in test and development' do
|
60
|
+
append_to_gemfile <<-GEMFILE
|
61
|
+
group :test, :development do
|
62
|
+
gem 'rspec-rails', '~> 2.8.1'
|
63
|
+
end
|
64
|
+
GEMFILE
|
65
|
+
steps %{And I run `bundle install --local`}
|
66
|
+
end
|
67
|
+
|
50
68
|
When 'I configure the application to use shoulda-context' do
|
51
69
|
append_to_gemfile "gem 'shoulda-context', '~> 1.0.0'"
|
52
70
|
steps %{And I run `bundle install --local`}
|
data/gemfiles/3.0.gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
|
-
remote: /Users/
|
2
|
+
remote: /Users/joshuaclayton/dev/gems/shoulda-matchers
|
3
3
|
specs:
|
4
|
-
shoulda-matchers (1.
|
4
|
+
shoulda-matchers (1.3.0)
|
5
5
|
activesupport (>= 3.0.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -46,8 +46,8 @@ GEM
|
|
46
46
|
bourne (1.1.2)
|
47
47
|
mocha (= 0.10.5)
|
48
48
|
builder (2.1.2)
|
49
|
-
childprocess (0.3.
|
50
|
-
ffi (~> 1.0.6)
|
49
|
+
childprocess (0.3.5)
|
50
|
+
ffi (~> 1.0, >= 1.0.6)
|
51
51
|
cucumber (1.1.9)
|
52
52
|
builder (>= 2.1.2)
|
53
53
|
diff-lcs (>= 1.1.2)
|
@@ -57,18 +57,18 @@ GEM
|
|
57
57
|
diff-lcs (1.1.3)
|
58
58
|
erubis (2.6.6)
|
59
59
|
abstract (>= 1.0.0)
|
60
|
-
ffi (1.
|
60
|
+
ffi (1.1.5)
|
61
61
|
gherkin (2.9.3)
|
62
62
|
json (>= 1.4.6)
|
63
63
|
i18n (0.5.0)
|
64
|
-
json (1.7.
|
64
|
+
json (1.7.5)
|
65
65
|
mail (2.2.19)
|
66
66
|
activesupport (>= 2.3.6)
|
67
67
|
i18n (>= 0.4.0)
|
68
68
|
mime-types (~> 1.16)
|
69
69
|
treetop (~> 1.4.8)
|
70
70
|
metaclass (0.0.1)
|
71
|
-
mime-types (1.
|
71
|
+
mime-types (1.19)
|
72
72
|
mocha (0.10.5)
|
73
73
|
metaclass (~> 0.0.1)
|
74
74
|
polyglot (0.3.3)
|
data/gemfiles/3.1.gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
|
-
remote: /Users/
|
2
|
+
remote: /Users/joshuaclayton/dev/gems/shoulda-matchers
|
3
3
|
specs:
|
4
|
-
shoulda-matchers (1.
|
4
|
+
shoulda-matchers (1.3.0)
|
5
5
|
activesupport (>= 3.0.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -47,8 +47,8 @@ GEM
|
|
47
47
|
bourne (1.1.2)
|
48
48
|
mocha (= 0.10.5)
|
49
49
|
builder (3.0.0)
|
50
|
-
childprocess (0.3.
|
51
|
-
ffi (~> 1.0.6)
|
50
|
+
childprocess (0.3.5)
|
51
|
+
ffi (~> 1.0, >= 1.0.6)
|
52
52
|
cucumber (1.1.9)
|
53
53
|
builder (>= 2.1.2)
|
54
54
|
diff-lcs (>= 1.1.2)
|
@@ -57,21 +57,21 @@ GEM
|
|
57
57
|
term-ansicolor (>= 1.0.6)
|
58
58
|
diff-lcs (1.1.3)
|
59
59
|
erubis (2.7.0)
|
60
|
-
ffi (1.
|
60
|
+
ffi (1.1.5)
|
61
61
|
gherkin (2.9.3)
|
62
62
|
json (>= 1.4.6)
|
63
63
|
hike (1.2.1)
|
64
64
|
i18n (0.6.0)
|
65
|
-
jquery-rails (1.
|
66
|
-
railties (
|
65
|
+
jquery-rails (2.1.1)
|
66
|
+
railties (>= 3.1.0, < 5.0)
|
67
67
|
thor (~> 0.14)
|
68
|
-
json (1.7.
|
68
|
+
json (1.7.5)
|
69
69
|
mail (2.3.3)
|
70
70
|
i18n (>= 0.4.0)
|
71
71
|
mime-types (~> 1.16)
|
72
72
|
treetop (~> 1.4.8)
|
73
73
|
metaclass (0.0.1)
|
74
|
-
mime-types (1.
|
74
|
+
mime-types (1.19)
|
75
75
|
mocha (0.10.5)
|
76
76
|
metaclass (~> 0.0.1)
|
77
77
|
multi_json (1.3.6)
|
@@ -116,7 +116,7 @@ GEM
|
|
116
116
|
activesupport (>= 3.0)
|
117
117
|
railties (>= 3.0)
|
118
118
|
rspec (~> 2.8.0)
|
119
|
-
sass (3.1
|
119
|
+
sass (3.2.1)
|
120
120
|
sass-rails (3.1.6)
|
121
121
|
actionpack (~> 3.1.0)
|
122
122
|
railties (~> 3.1.0)
|
data/gemfiles/3.2.gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
|
-
remote: /Users/
|
2
|
+
remote: /Users/joshuaclayton/dev/gems/shoulda-matchers
|
3
3
|
specs:
|
4
|
-
shoulda-matchers (1.
|
4
|
+
shoulda-matchers (1.3.0)
|
5
5
|
activesupport (>= 3.0.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -46,8 +46,8 @@ GEM
|
|
46
46
|
bourne (1.1.2)
|
47
47
|
mocha (= 0.10.5)
|
48
48
|
builder (3.0.0)
|
49
|
-
childprocess (0.3.
|
50
|
-
ffi (~> 1.0.6)
|
49
|
+
childprocess (0.3.5)
|
50
|
+
ffi (~> 1.0, >= 1.0.6)
|
51
51
|
cucumber (1.1.9)
|
52
52
|
builder (>= 2.1.2)
|
53
53
|
diff-lcs (>= 1.1.2)
|
@@ -56,22 +56,22 @@ GEM
|
|
56
56
|
term-ansicolor (>= 1.0.6)
|
57
57
|
diff-lcs (1.1.3)
|
58
58
|
erubis (2.7.0)
|
59
|
-
ffi (1.
|
59
|
+
ffi (1.1.5)
|
60
60
|
gherkin (2.9.3)
|
61
61
|
json (>= 1.4.6)
|
62
62
|
hike (1.2.1)
|
63
63
|
i18n (0.6.0)
|
64
|
-
journey (1.0.
|
65
|
-
jquery-rails (2.
|
66
|
-
railties (>= 3.
|
64
|
+
journey (1.0.4)
|
65
|
+
jquery-rails (2.1.1)
|
66
|
+
railties (>= 3.1.0, < 5.0)
|
67
67
|
thor (~> 0.14)
|
68
|
-
json (1.7.
|
68
|
+
json (1.7.5)
|
69
69
|
mail (2.4.4)
|
70
70
|
i18n (>= 0.4.0)
|
71
71
|
mime-types (~> 1.16)
|
72
72
|
treetop (~> 1.4.8)
|
73
73
|
metaclass (0.0.1)
|
74
|
-
mime-types (1.
|
74
|
+
mime-types (1.19)
|
75
75
|
mocha (0.10.5)
|
76
76
|
metaclass (~> 0.0.1)
|
77
77
|
multi_json (1.3.6)
|
@@ -114,7 +114,7 @@ GEM
|
|
114
114
|
activesupport (>= 3.0)
|
115
115
|
railties (>= 3.0)
|
116
116
|
rspec (~> 2.8.0)
|
117
|
-
sass (3.1
|
117
|
+
sass (3.2.1)
|
118
118
|
sass-rails (3.2.5)
|
119
119
|
railties (~> 3.2.0)
|
120
120
|
sass (>= 3.1.10)
|
data/lib/shoulda/matchers.rb
CHANGED
@@ -66,16 +66,7 @@ module Shoulda # :nodoc:
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def rendered_layouts
|
69
|
-
|
70
|
-
recorded_layouts.keys.compact.map { |layout| layout.sub(%r{^layouts/}, '') }
|
71
|
-
else
|
72
|
-
layout = @controller.response.layout
|
73
|
-
if layout.nil?
|
74
|
-
[]
|
75
|
-
else
|
76
|
-
[layout.split('/').last]
|
77
|
-
end
|
78
|
-
end
|
69
|
+
recorded_layouts.keys.compact.map { |layout| layout.sub(%r{^layouts/}, '') }
|
79
70
|
end
|
80
71
|
|
81
72
|
def recorded_layouts
|
@@ -7,6 +7,8 @@ module Shoulda # :nodoc:
|
|
7
7
|
#
|
8
8
|
# Options:
|
9
9
|
# * <tt>with_message</tt> - value the test expects to find in
|
10
|
+
# <tt>allow_blank</tt> - allows a blank value
|
11
|
+
# <tt>allow_nil</tt> - allows a nil value
|
10
12
|
# <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
|
11
13
|
# Defaults to the translation for <tt>:invalid</tt>.
|
12
14
|
# * <tt>with(string to test against)</tt>
|
@@ -28,6 +30,17 @@ module Shoulda # :nodoc:
|
|
28
30
|
|
29
31
|
def initialize(attribute)
|
30
32
|
super
|
33
|
+
@options = {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def allow_blank(allow_blank = true)
|
37
|
+
@options[:allow_blank] = allow_blank
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def allow_nil(allow_nil = true)
|
42
|
+
@options[:allow_nil] = allow_nil
|
43
|
+
self
|
31
44
|
end
|
32
45
|
|
33
46
|
def with_message(message)
|
@@ -50,14 +63,35 @@ module Shoulda # :nodoc:
|
|
50
63
|
def matches?(subject)
|
51
64
|
super(subject)
|
52
65
|
@expected_message ||= :invalid
|
53
|
-
|
54
|
-
|
66
|
+
|
67
|
+
if @value_to_fail
|
68
|
+
disallows_value_of(@value_to_fail, @expected_message) && allows_blank_value? && allows_nil_value?
|
69
|
+
else
|
70
|
+
allows_value_of(@value_to_pass, @expected_message) && allows_blank_value? && allows_nil_value?
|
71
|
+
end
|
55
72
|
end
|
56
73
|
|
57
74
|
def description
|
58
75
|
"#{@attribute} have a valid format"
|
59
76
|
end
|
60
77
|
|
78
|
+
private
|
79
|
+
|
80
|
+
def allows_blank_value?
|
81
|
+
if @options.key?(:allow_blank)
|
82
|
+
@options[:allow_blank] == allows_value_of('')
|
83
|
+
else
|
84
|
+
true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def allows_nil_value?
|
89
|
+
if @options.key?(:allow_nil)
|
90
|
+
@options[:allow_nil] == allows_value_of(nil)
|
91
|
+
else
|
92
|
+
true
|
93
|
+
end
|
94
|
+
end
|
61
95
|
end
|
62
96
|
|
63
97
|
end
|
@@ -68,20 +68,25 @@ module Shoulda # :nodoc:
|
|
68
68
|
def matches?(subject)
|
69
69
|
@subject = subject.class.new
|
70
70
|
@expected_message ||= :taken
|
71
|
-
|
72
|
-
set_scoped_attributes &&
|
71
|
+
set_scoped_attributes &&
|
73
72
|
validate_attribute? &&
|
74
73
|
validate_after_scope_change?
|
75
74
|
end
|
76
75
|
|
77
76
|
private
|
78
77
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
78
|
+
def existing
|
79
|
+
@existing ||= first_instance
|
80
|
+
end
|
81
|
+
|
82
|
+
def first_instance
|
83
|
+
@subject.class.first || create_instance_in_database
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_instance_in_database
|
87
|
+
@subject.class.new.tap do |instance|
|
88
|
+
instance.send("#{@attribute}=", "arbitrary_string")
|
89
|
+
instance.save(:validate => false)
|
85
90
|
end
|
86
91
|
end
|
87
92
|
|
@@ -90,7 +95,7 @@ module Shoulda # :nodoc:
|
|
90
95
|
@options[:scopes].all? do |scope|
|
91
96
|
setter = :"#{scope}="
|
92
97
|
if @subject.respond_to?(setter)
|
93
|
-
@subject.send(
|
98
|
+
@subject.send(setter, existing.send(scope))
|
94
99
|
true
|
95
100
|
else
|
96
101
|
@failure_message = "#{class_name} doesn't seem to have a #{scope} attribute."
|
@@ -114,7 +119,7 @@ module Shoulda # :nodoc:
|
|
114
119
|
true
|
115
120
|
else
|
116
121
|
@options[:scopes].all? do |scope|
|
117
|
-
previous_value =
|
122
|
+
previous_value = existing.send(scope)
|
118
123
|
|
119
124
|
# Assume the scope is a foreign key if the field is nil
|
120
125
|
previous_value ||= 0
|
@@ -128,6 +133,8 @@ module Shoulda # :nodoc:
|
|
128
133
|
@subject.send("#{scope}=", next_value)
|
129
134
|
|
130
135
|
if allows_value_of(existing_value, @expected_message)
|
136
|
+
@subject.send("#{scope}=", previous_value)
|
137
|
+
|
131
138
|
@negative_failure_message <<
|
132
139
|
" (with different value of #{scope})"
|
133
140
|
true
|
@@ -144,7 +151,7 @@ module Shoulda # :nodoc:
|
|
144
151
|
end
|
145
152
|
|
146
153
|
def existing_value
|
147
|
-
value =
|
154
|
+
value = existing.send(@attribute)
|
148
155
|
if @options[:case_insensitive] && value.respond_to?(:swapcase!)
|
149
156
|
value.swapcase!
|
150
157
|
end
|
@@ -3,6 +3,12 @@ module Shoulda # :nodoc:
|
|
3
3
|
module ActiveRecord # :nodoc:
|
4
4
|
# Ensure that the belongs_to relationship exists.
|
5
5
|
#
|
6
|
+
# Options:
|
7
|
+
# * <tt>:class_name</tt> - tests that the association makes use of the class_name option.
|
8
|
+
# * <tt>:validate</tt> - tests that the association makes use of the validate
|
9
|
+
# option.
|
10
|
+
#
|
11
|
+
# Example:
|
6
12
|
# it { should belong_to(:parent) }
|
7
13
|
#
|
8
14
|
def belong_to(name)
|
@@ -18,6 +24,8 @@ module Shoulda # :nodoc:
|
|
18
24
|
# * <tt>dependent</tt> - tests that the association makes use of the
|
19
25
|
# dependent option.
|
20
26
|
# * <tt>:class_name</tt> - tests that the association makes use of the class_name option.
|
27
|
+
# * <tt>:validate</tt> - tests that the association makes use of the validate
|
28
|
+
# option.
|
21
29
|
#
|
22
30
|
# Example:
|
23
31
|
# it { should have_many(:friends) }
|
@@ -36,6 +44,8 @@ module Shoulda # :nodoc:
|
|
36
44
|
# * <tt>:dependent</tt> - tests that the association makes use of the
|
37
45
|
# dependent option.
|
38
46
|
# * <tt>:class_name</tt> - tests that the association makes use of the class_name option.
|
47
|
+
# * <tt>:validate</tt> - tests that the association makes use of the validate
|
48
|
+
# option.
|
39
49
|
#
|
40
50
|
# Example:
|
41
51
|
# it { should have_one(:god) } # unless hindu
|
@@ -47,6 +57,11 @@ module Shoulda # :nodoc:
|
|
47
57
|
# Ensures that the has_and_belongs_to_many relationship exists, and that
|
48
58
|
# the join table is in place.
|
49
59
|
#
|
60
|
+
# Options:
|
61
|
+
# * <tt>:validate</tt> - tests that the association makes use of the validate
|
62
|
+
# option.
|
63
|
+
#
|
64
|
+
# Example:
|
50
65
|
# it { should have_and_belong_to_many(:posts) }
|
51
66
|
#
|
52
67
|
def have_and_belong_to_many(name)
|
@@ -85,6 +100,11 @@ module Shoulda # :nodoc:
|
|
85
100
|
self
|
86
101
|
end
|
87
102
|
|
103
|
+
def validate(validate = true)
|
104
|
+
@validate = validate
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
88
108
|
def matches?(subject)
|
89
109
|
@subject = subject
|
90
110
|
association_exists? &&
|
@@ -95,7 +115,8 @@ module Shoulda # :nodoc:
|
|
95
115
|
class_name_correct? &&
|
96
116
|
order_correct? &&
|
97
117
|
conditions_correct? &&
|
98
|
-
join_table_exists?
|
118
|
+
join_table_exists? &&
|
119
|
+
validate_correct?
|
99
120
|
end
|
100
121
|
|
101
122
|
def failure_message
|
@@ -230,6 +251,15 @@ module Shoulda # :nodoc:
|
|
230
251
|
end
|
231
252
|
end
|
232
253
|
|
254
|
+
def validate_correct?
|
255
|
+
if !@validate && !reflection.options[:validate] || @validate == reflection.options[:validate]
|
256
|
+
true
|
257
|
+
else
|
258
|
+
@missing = "#{@name} should have #{@validate} as validate"
|
259
|
+
false
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
233
263
|
def class_has_foreign_key?(klass)
|
234
264
|
if klass.column_names.include?(foreign_key)
|
235
265
|
true
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module Shoulda
|
2
2
|
module Matchers
|
3
|
-
if
|
3
|
+
if Gem.ruby_version >= Gem::Version.new('1.8') && Gem.ruby_version < Gem::Version.new('1.9')
|
4
|
+
require 'test/unit'
|
5
|
+
AssertionError = Test::Unit::AssertionFailedError
|
6
|
+
elsif Gem.ruby_version >= Gem::Version.new("1.9")
|
4
7
|
require 'minitest/unit'
|
5
8
|
AssertionError = MiniTest::Assertion
|
6
9
|
else
|
7
|
-
|
8
|
-
AssertionError = Test::Unit::AssertionFailedError
|
10
|
+
raise "No unit test library available"
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -31,6 +31,14 @@ describe Shoulda::Matchers::ActionController::RenderWithLayoutMatcher do
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
context "a controller that renders a partial" do
|
35
|
+
let(:controller) { build_response { render :partial => 'partial' } }
|
36
|
+
|
37
|
+
it "should reject rendering with a layout" do
|
38
|
+
controller.should_not render_with_layout
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
34
42
|
context "given a context with layouts" do
|
35
43
|
let(:layout) { 'happy' }
|
36
44
|
let(:controller) { build_response { render :layout => false } }
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Shoulda::Matchers::ActiveModel::ValidateFormatOfMatcher do
|
4
|
-
|
5
4
|
context "a postal code" do
|
6
5
|
before do
|
7
6
|
define_model :example, :attr => :string do
|
@@ -10,29 +9,71 @@ describe Shoulda::Matchers::ActiveModel::ValidateFormatOfMatcher do
|
|
10
9
|
@model = Example.new
|
11
10
|
end
|
12
11
|
|
13
|
-
it "
|
12
|
+
it "is valid" do
|
14
13
|
@model.should validate_format_of(:attr).with('12345')
|
15
14
|
end
|
16
15
|
|
17
|
-
it "
|
16
|
+
it "is not valid with blank" do
|
17
|
+
@model.should_not validate_format_of(:attr).with(' ')
|
18
|
+
@model.should validate_format_of(:attr).not_with(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "is not valid with nil" do
|
22
|
+
@model.should_not validate_format_of(:attr).with(nil)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "is not valid with alpha in zip" do
|
18
26
|
@model.should_not validate_format_of(:attr).with('1234a')
|
19
27
|
@model.should validate_format_of(:attr).not_with('1234a')
|
20
28
|
end
|
21
29
|
|
22
|
-
it "
|
30
|
+
it "is not valid with too few digits" do
|
23
31
|
@model.should_not validate_format_of(:attr).with('1234')
|
24
32
|
@model.should validate_format_of(:attr).not_with('1234')
|
25
33
|
end
|
26
34
|
|
27
|
-
it "
|
35
|
+
it "is not valid with too many digits" do
|
28
36
|
@model.should_not validate_format_of(:attr).with('123456')
|
29
37
|
@model.should validate_format_of(:attr).not_with('123456')
|
30
38
|
end
|
31
39
|
|
32
|
-
it "
|
40
|
+
it "raises error if you try to call both with and not_with" do
|
33
41
|
expect { validate_format_of(:attr).not_with('123456').with('12345') }.
|
34
42
|
to raise_error(RuntimeError)
|
35
43
|
end
|
36
44
|
end
|
37
45
|
|
46
|
+
context "when allow_blank and allow_nil are set" do
|
47
|
+
before do
|
48
|
+
define_model :example, :attr => :string do
|
49
|
+
validates_format_of :attr, :with => /^\d{5}$/, :allow_blank => true, :allow_nil => true
|
50
|
+
end
|
51
|
+
@model = Example.new
|
52
|
+
end
|
53
|
+
|
54
|
+
it "is valid when attr is nil" do
|
55
|
+
@model.should validate_format_of(:attr).with(nil)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "is valid when attr is blank" do
|
59
|
+
@model.should validate_format_of(:attr).with(' ')
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#allow_blank" do
|
63
|
+
it "allows allow_blank" do
|
64
|
+
@model.should validate_format_of(:attr).allow_blank
|
65
|
+
@model.should validate_format_of(:attr).allow_blank(true)
|
66
|
+
@model.should_not validate_format_of(:attr).allow_blank(false)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#allow_nil" do
|
71
|
+
it "allows allow_nil" do
|
72
|
+
@model.should validate_format_of(:attr).allow_nil
|
73
|
+
@model.should validate_format_of(:attr).allow_nil(true)
|
74
|
+
@model.should_not validate_format_of(:attr).allow_nil(false)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
38
79
|
end
|
@@ -34,13 +34,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|
34
34
|
@matcher = validate_uniqueness_of(:attr)
|
35
35
|
end
|
36
36
|
|
37
|
-
it "
|
38
|
-
@model.
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should alert the tester that an existing value is not present" do
|
42
|
-
@matcher.matches?(@model)
|
43
|
-
@matcher.negative_failure_message.should =~ /^Can't find first .*/
|
37
|
+
it "does not not require a created instance" do
|
38
|
+
@model.should @matcher
|
44
39
|
end
|
45
40
|
end
|
46
41
|
end
|
@@ -71,11 +66,12 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|
71
66
|
before do
|
72
67
|
@model = define_model(:example, :attr => :string,
|
73
68
|
:scope1 => :integer,
|
74
|
-
:scope2 => :integer
|
75
|
-
|
69
|
+
:scope2 => :integer,
|
70
|
+
:other => :integer) do
|
71
|
+
attr_accessible :attr, :scope1, :scope2, :other
|
76
72
|
validates_uniqueness_of :attr, :scope => [:scope1, :scope2]
|
77
73
|
end.new
|
78
|
-
@existing = Example.create!(:attr => 'value', :scope1 => 1, :scope2 => 2)
|
74
|
+
@existing = Example.create!(:attr => 'value', :scope1 => 1, :scope2 => 2, :other => 3)
|
79
75
|
end
|
80
76
|
|
81
77
|
it "should pass when the correct scope is specified" do
|
@@ -86,10 +82,18 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
|
|
86
82
|
@existing.should validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2)
|
87
83
|
end
|
88
84
|
|
89
|
-
it "should fail when a
|
85
|
+
it "should fail when too narrow of a scope is specified" do
|
86
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2, :other)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should fail when too broad of a scope is specified" do
|
90
90
|
@model.should_not validate_uniqueness_of(:attr).scoped_to(:scope1)
|
91
91
|
end
|
92
92
|
|
93
|
+
it "should fail when a different scope is specified" do
|
94
|
+
@model.should_not validate_uniqueness_of(:attr).scoped_to(:other)
|
95
|
+
end
|
96
|
+
|
93
97
|
it "should fail when no scope is specified" do
|
94
98
|
@model.should_not validate_uniqueness_of(:attr)
|
95
99
|
end
|
@@ -98,6 +98,46 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|
98
98
|
end
|
99
99
|
Child.new.should_not @matcher.class_name('TreeChild')
|
100
100
|
end
|
101
|
+
|
102
|
+
context 'should accept an association with a false :validate option' do
|
103
|
+
before do
|
104
|
+
define_model :parent, :adopter => :boolean
|
105
|
+
define_model :child, :parent_id => :integer do
|
106
|
+
belongs_to :parent, :validate => false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
subject { Child.new }
|
110
|
+
specify { subject.should @matcher.validate(false) }
|
111
|
+
specify { subject.should_not @matcher.validate(true) }
|
112
|
+
specify { subject.should_not @matcher.validate }
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'should accept an association with a true :validate option' do
|
116
|
+
before do
|
117
|
+
define_model :parent, :adopter => :boolean
|
118
|
+
define_model :child, :parent_id => :integer do
|
119
|
+
belongs_to :parent, :validate => true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
subject { Child.new }
|
123
|
+
specify { subject.should_not @matcher.validate(false) }
|
124
|
+
specify { subject.should @matcher.validate(true) }
|
125
|
+
specify { subject.should @matcher.validate }
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'should accept an association without a :validate option' do
|
129
|
+
before do
|
130
|
+
define_model :parent, :adopter => :boolean
|
131
|
+
define_model :child, :parent_id => :integer do
|
132
|
+
belongs_to :parent
|
133
|
+
end
|
134
|
+
end
|
135
|
+
subject { Child.new }
|
136
|
+
specify { subject.should @matcher.validate(false) }
|
137
|
+
specify { subject.should_not @matcher.validate(true) }
|
138
|
+
specify { subject.should_not @matcher.validate }
|
139
|
+
end
|
140
|
+
|
101
141
|
end
|
102
142
|
|
103
143
|
context "have_many" do
|
@@ -240,6 +280,45 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|
240
280
|
Parent.new.should_not @matcher.class_name('Node')
|
241
281
|
end
|
242
282
|
|
283
|
+
context 'should accept an association with a false :validate option' do
|
284
|
+
before do
|
285
|
+
define_model :child, :parent_id => :integer, :adopted => :boolean
|
286
|
+
define_model :parent do
|
287
|
+
has_many :children, :validate => false
|
288
|
+
end
|
289
|
+
end
|
290
|
+
subject { Parent.new }
|
291
|
+
specify { subject.should @matcher.validate(false) }
|
292
|
+
specify { subject.should_not @matcher.validate(true) }
|
293
|
+
specify { subject.should_not @matcher.validate }
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'should accept an association with a true :validate option' do
|
297
|
+
before do
|
298
|
+
define_model :child, :parent_id => :integer, :adopted => :boolean
|
299
|
+
define_model :parent do
|
300
|
+
has_many :children, :validate => true
|
301
|
+
end
|
302
|
+
end
|
303
|
+
subject { Parent.new }
|
304
|
+
specify { subject.should_not @matcher.validate(false) }
|
305
|
+
specify { subject.should @matcher.validate(true) }
|
306
|
+
specify { subject.should @matcher.validate }
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'should accept an association without a :validate option' do
|
310
|
+
before do
|
311
|
+
define_model :child, :parent_id => :integer, :adopted => :boolean
|
312
|
+
define_model :parent do
|
313
|
+
has_many :children
|
314
|
+
end
|
315
|
+
end
|
316
|
+
subject { Parent.new }
|
317
|
+
specify { subject.should @matcher.validate(false) }
|
318
|
+
specify { subject.should_not @matcher.validate(true) }
|
319
|
+
specify { subject.should_not @matcher.validate }
|
320
|
+
end
|
321
|
+
|
243
322
|
it "should accept an association with a nonstandard reverse foreign key, using :inverse_of" do
|
244
323
|
define_model :child, :ancestor_id => :integer do
|
245
324
|
belongs_to :ancestor, :inverse_of => :children, :class_name => :Parent
|
@@ -364,6 +443,70 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|
364
443
|
Person.new.should_not @matcher.class_name('PersonDetail')
|
365
444
|
end
|
366
445
|
|
446
|
+
it "should accept an association with a through" do
|
447
|
+
define_model :detail
|
448
|
+
|
449
|
+
define_model :account do
|
450
|
+
has_one :detail
|
451
|
+
end
|
452
|
+
|
453
|
+
define_model :person do
|
454
|
+
has_one :account
|
455
|
+
has_one :detail, :through => :account
|
456
|
+
end
|
457
|
+
|
458
|
+
Person.new.should @matcher.through(:account)
|
459
|
+
end
|
460
|
+
|
461
|
+
it "should reject an association with a through" do
|
462
|
+
define_model :detail
|
463
|
+
|
464
|
+
define_model :person do
|
465
|
+
has_one :detail
|
466
|
+
end
|
467
|
+
|
468
|
+
Person.new.should_not @matcher.through(:account)
|
469
|
+
end
|
470
|
+
|
471
|
+
context 'should accept an association with a false :validate option' do
|
472
|
+
before do
|
473
|
+
define_model :detail, :person_id => :integer, :disabled => :boolean
|
474
|
+
define_model :person do
|
475
|
+
has_one :detail, :validate => false
|
476
|
+
end
|
477
|
+
end
|
478
|
+
subject { Person.new }
|
479
|
+
specify { subject.should @matcher.validate(false) }
|
480
|
+
specify { subject.should_not @matcher.validate(true) }
|
481
|
+
specify { subject.should_not @matcher.validate }
|
482
|
+
end
|
483
|
+
|
484
|
+
context 'should accept an association with a true :validate option' do
|
485
|
+
before do
|
486
|
+
define_model :detail, :person_id => :integer, :disabled => :boolean
|
487
|
+
define_model :person do
|
488
|
+
has_one :detail, :validate => true
|
489
|
+
end
|
490
|
+
end
|
491
|
+
subject { Person.new }
|
492
|
+
specify { subject.should_not @matcher.validate(false) }
|
493
|
+
specify { subject.should @matcher.validate(true) }
|
494
|
+
specify { subject.should @matcher.validate }
|
495
|
+
end
|
496
|
+
|
497
|
+
context 'should accept an association without a :validate option' do
|
498
|
+
before do
|
499
|
+
define_model :detail, :person_id => :integer, :disabled => :boolean
|
500
|
+
define_model :person do
|
501
|
+
has_one :detail
|
502
|
+
end
|
503
|
+
end
|
504
|
+
subject { Person.new }
|
505
|
+
specify { subject.should @matcher.validate(false) }
|
506
|
+
specify { subject.should_not @matcher.validate(true) }
|
507
|
+
specify { subject.should_not @matcher.validate }
|
508
|
+
end
|
509
|
+
|
367
510
|
end
|
368
511
|
|
369
512
|
context "have_and_belong_to_many" do
|
@@ -445,5 +588,47 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
|
|
445
588
|
Person.new.should_not @matcher.class_name('PersonRelatives')
|
446
589
|
end
|
447
590
|
|
591
|
+
context 'should accept an association with a false :validate option' do
|
592
|
+
before do
|
593
|
+
define_model :relatives, :adopted => :boolean
|
594
|
+
define_model :person do
|
595
|
+
has_and_belongs_to_many :relatives, :validate => false
|
596
|
+
end
|
597
|
+
define_model :people_relative, :person_id => :integer, :relative_id => :integer
|
598
|
+
end
|
599
|
+
subject { Person.new }
|
600
|
+
specify { subject.should @matcher.validate(false) }
|
601
|
+
specify { subject.should_not @matcher.validate(true) }
|
602
|
+
specify { subject.should_not @matcher.validate }
|
603
|
+
end
|
604
|
+
|
605
|
+
context 'should accept an association with a true :validate option' do
|
606
|
+
before do
|
607
|
+
define_model :relatives, :adopted => :boolean
|
608
|
+
define_model :person do
|
609
|
+
has_and_belongs_to_many :relatives, :validate => true
|
610
|
+
end
|
611
|
+
define_model :people_relative, :person_id => :integer, :relative_id => :integer
|
612
|
+
end
|
613
|
+
subject { Person.new }
|
614
|
+
specify { subject.should_not @matcher.validate(false) }
|
615
|
+
specify { subject.should @matcher.validate(true) }
|
616
|
+
specify { subject.should @matcher.validate }
|
617
|
+
end
|
618
|
+
|
619
|
+
context 'should accept an association without a :validate option' do
|
620
|
+
before do
|
621
|
+
define_model :relatives, :adopted => :boolean
|
622
|
+
define_model :person do
|
623
|
+
has_and_belongs_to_many :relatives
|
624
|
+
end
|
625
|
+
define_model :people_relative, :person_id => :integer, :relative_id => :integer
|
626
|
+
end
|
627
|
+
subject { Person.new }
|
628
|
+
specify { subject.should @matcher.validate(false) }
|
629
|
+
specify { subject.should_not @matcher.validate(true) }
|
630
|
+
specify { subject.should_not @matcher.validate }
|
631
|
+
end
|
632
|
+
|
448
633
|
end
|
449
634
|
end
|
@@ -59,7 +59,7 @@ describe Shoulda::Matchers::ActiveRecord::SerializeMatcher do
|
|
59
59
|
|
60
60
|
context "a serializer that is an instance of a class" do
|
61
61
|
before do
|
62
|
-
define_class(:ExampleSerializer
|
62
|
+
define_class(:ExampleSerializer) do
|
63
63
|
def load(*); end
|
64
64
|
def dump(*); end
|
65
65
|
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,78 @@
|
|
1
|
+
module ControllerBuilder
|
2
|
+
TMP_VIEW_PATH =
|
3
|
+
File.expand_path(File.join(TESTAPP_ROOT, 'tmp', 'views')).freeze
|
4
|
+
|
5
|
+
def self.included(example_group)
|
6
|
+
example_group.class_eval do
|
7
|
+
after do
|
8
|
+
delete_temporary_views
|
9
|
+
restore_original_routes
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_controller(class_name, &block)
|
15
|
+
class_name = class_name.to_s
|
16
|
+
class_name << 'Controller' unless class_name =~ /Controller$/
|
17
|
+
define_class(class_name, ActionController::Base, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_routes(&block)
|
21
|
+
Rails.application.routes.draw(&block)
|
22
|
+
@routes = Rails.application.routes
|
23
|
+
class << self
|
24
|
+
include ActionDispatch::Assertions
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_response(opts = {}, &block)
|
29
|
+
action = opts[:action] || 'example'
|
30
|
+
partial = opts[:partial] || '_partial'
|
31
|
+
block ||= lambda { render :nothing => true }
|
32
|
+
controller_class = define_controller('Examples') do
|
33
|
+
layout false
|
34
|
+
define_method(action, &block)
|
35
|
+
end
|
36
|
+
controller_class.view_paths = [TMP_VIEW_PATH]
|
37
|
+
|
38
|
+
define_routes do
|
39
|
+
match 'examples', :to => "examples##{action}"
|
40
|
+
end
|
41
|
+
|
42
|
+
create_view("examples/#{action}.html.erb", "abc")
|
43
|
+
create_view("examples/#{partial}.html.erb", "partial")
|
44
|
+
|
45
|
+
@controller = controller_class.new
|
46
|
+
@request = ActionController::TestRequest.new
|
47
|
+
@response = ActionController::TestResponse.new
|
48
|
+
|
49
|
+
class << self
|
50
|
+
include ActionController::TestCase::Behavior
|
51
|
+
end
|
52
|
+
@routes = Rails.application.routes
|
53
|
+
|
54
|
+
get action
|
55
|
+
|
56
|
+
@controller
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_view(path, contents)
|
60
|
+
full_path = File.join(TMP_VIEW_PATH, path)
|
61
|
+
FileUtils.mkdir_p(File.dirname(full_path))
|
62
|
+
File.open(full_path, 'w') { |file| file.write(contents) }
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def delete_temporary_views
|
68
|
+
FileUtils.rm_rf(TMP_VIEW_PATH)
|
69
|
+
end
|
70
|
+
|
71
|
+
def restore_original_routes
|
72
|
+
Rails.application.reload_routes!
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
RSpec.configure do |config|
|
77
|
+
config.include ControllerBuilder
|
78
|
+
end
|
@@ -1,7 +1,4 @@
|
|
1
1
|
module ModelBuilder
|
2
|
-
TMP_VIEW_PATH =
|
3
|
-
File.expand_path(File.join(TESTAPP_ROOT, 'tmp', 'views')).freeze
|
4
|
-
|
5
2
|
def self.included(example_group)
|
6
3
|
example_group.class_eval do
|
7
4
|
before do
|
@@ -9,7 +6,7 @@ module ModelBuilder
|
|
9
6
|
end
|
10
7
|
|
11
8
|
after do
|
12
|
-
|
9
|
+
drop_created_tables
|
13
10
|
end
|
14
11
|
end
|
15
12
|
end
|
@@ -28,37 +25,12 @@ module ModelBuilder
|
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
31
|
-
def define_class(class_name, base = Object, &block)
|
32
|
-
class_name = class_name.to_s.camelize
|
33
|
-
|
34
|
-
# FIXME: ActionMailer 3.2 calls `name.underscore` immediately upon
|
35
|
-
# subclassing. Class.new.name == nil. So, Class.new(ActionMailer::Base)
|
36
|
-
# errors out since it's trying to do `nil.underscore`. This is very ugly but
|
37
|
-
# allows us to test against ActionMailer 3.2.x.
|
38
|
-
eval <<-A_REAL_CLASS_FOR_ACTION_MAILER_3_2
|
39
|
-
class ::#{class_name} < #{base}
|
40
|
-
end
|
41
|
-
A_REAL_CLASS_FOR_ACTION_MAILER_3_2
|
42
|
-
|
43
|
-
Object.const_get(class_name).tap do |constant_class|
|
44
|
-
constant_class.unloadable
|
45
|
-
|
46
|
-
if block_given?
|
47
|
-
constant_class.class_eval(&block)
|
48
|
-
end
|
49
|
-
|
50
|
-
if constant_class.respond_to?(:reset_column_information)
|
51
|
-
constant_class.reset_column_information
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
28
|
def define_model_class(class_name, &block)
|
57
29
|
define_class(class_name, ActiveRecord::Base, &block)
|
58
30
|
end
|
59
31
|
|
60
32
|
def define_active_model_class(class_name, options = {}, &block)
|
61
|
-
define_class(class_name
|
33
|
+
define_class(class_name) do
|
62
34
|
include ActiveModel::Validations
|
63
35
|
|
64
36
|
options[:accessors].each do |column|
|
@@ -84,71 +56,12 @@ module ModelBuilder
|
|
84
56
|
define_model_class(class_name, &block)
|
85
57
|
end
|
86
58
|
|
87
|
-
def
|
88
|
-
class_name = name.to_s.pluralize.classify
|
89
|
-
define_class(class_name, ActionMailer::Base, &block)
|
90
|
-
end
|
91
|
-
|
92
|
-
def define_controller(class_name, &block)
|
93
|
-
class_name = class_name.to_s
|
94
|
-
class_name << 'Controller' unless class_name =~ /Controller$/
|
95
|
-
define_class(class_name, ActionController::Base, &block)
|
96
|
-
end
|
97
|
-
|
98
|
-
def define_routes(&block)
|
99
|
-
Rails.application.routes.draw(&block)
|
100
|
-
@routes = Rails.application.routes
|
101
|
-
class << self
|
102
|
-
include ActionDispatch::Assertions
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def build_response(opts = {}, &block)
|
107
|
-
action = opts[:action] || 'example'
|
108
|
-
partial = opts[:partial] || '_partial'
|
109
|
-
klass = define_controller('Examples')
|
110
|
-
block ||= lambda { render :nothing => true }
|
111
|
-
klass.class_eval { layout false; define_method(action, &block) }
|
112
|
-
define_routes do
|
113
|
-
match 'examples', :to => "examples##{action}"
|
114
|
-
end
|
115
|
-
|
116
|
-
create_view("examples/#{action}.html.erb", "abc")
|
117
|
-
create_view("examples/#{partial}.html.erb", "partial")
|
118
|
-
klass.view_paths = [TMP_VIEW_PATH]
|
119
|
-
|
120
|
-
@controller = klass.new
|
121
|
-
@request = ActionController::TestRequest.new
|
122
|
-
@response = ActionController::TestResponse.new
|
123
|
-
|
124
|
-
class << self
|
125
|
-
include ActionController::TestCase::Behavior
|
126
|
-
end
|
127
|
-
@routes = Rails.application.routes
|
128
|
-
|
129
|
-
get action
|
130
|
-
|
131
|
-
@controller
|
132
|
-
end
|
133
|
-
|
134
|
-
def create_view(path, contents)
|
135
|
-
full_path = File.join(TMP_VIEW_PATH, path)
|
136
|
-
FileUtils.mkdir_p(File.dirname(full_path))
|
137
|
-
File.open(full_path, 'w') { |file| file.write(contents) }
|
138
|
-
end
|
139
|
-
|
140
|
-
def teardown_defined_constants
|
141
|
-
ActiveSupport::Dependencies.clear
|
142
|
-
|
59
|
+
def drop_created_tables
|
143
60
|
connection = ActiveRecord::Base.connection
|
144
61
|
|
145
62
|
@created_tables.each do |table_name|
|
146
63
|
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
147
64
|
end
|
148
|
-
|
149
|
-
FileUtils.rm_rf(TMP_VIEW_PATH)
|
150
|
-
|
151
|
-
Rails.application.reload_routes!
|
152
65
|
end
|
153
66
|
end
|
154
67
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shoulda-matchers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2012-
|
17
|
+
date: 2012-08-30 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: activesupport
|
@@ -266,6 +266,9 @@ files:
|
|
266
266
|
- spec/shoulda/active_record/serialize_matcher_spec.rb
|
267
267
|
- spec/spec_helper.rb
|
268
268
|
- spec/support/active_model_versions.rb
|
269
|
+
- spec/support/class_builder.rb
|
270
|
+
- spec/support/controller_builder.rb
|
271
|
+
- spec/support/mailer_builder.rb
|
269
272
|
- spec/support/model_builder.rb
|
270
273
|
homepage: http://thoughtbot.com/community/
|
271
274
|
licenses: []
|
@@ -279,18 +282,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
279
282
|
- - ! '>='
|
280
283
|
- !ruby/object:Gem::Version
|
281
284
|
version: '0'
|
282
|
-
segments:
|
283
|
-
- 0
|
284
|
-
hash: -2813664721542156285
|
285
285
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
286
286
|
none: false
|
287
287
|
requirements:
|
288
288
|
- - ! '>='
|
289
289
|
- !ruby/object:Gem::Version
|
290
290
|
version: '0'
|
291
|
-
segments:
|
292
|
-
- 0
|
293
|
-
hash: -2813664721542156285
|
294
291
|
requirements: []
|
295
292
|
rubyforge_project:
|
296
293
|
rubygems_version: 1.8.23
|
@@ -340,4 +337,8 @@ test_files:
|
|
340
337
|
- spec/shoulda/active_record/serialize_matcher_spec.rb
|
341
338
|
- spec/spec_helper.rb
|
342
339
|
- spec/support/active_model_versions.rb
|
340
|
+
- spec/support/class_builder.rb
|
341
|
+
- spec/support/controller_builder.rb
|
342
|
+
- spec/support/mailer_builder.rb
|
343
343
|
- spec/support/model_builder.rb
|
344
|
+
has_rdoc:
|