shoulda-matchers 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
  2. data/Gemfile +10 -0
  3. data/Gemfile.lock +116 -0
  4. data/MIT-LICENSE +22 -0
  5. data/README.rdoc +70 -0
  6. data/Rakefile +50 -0
  7. data/lib/shoulda-matchers.rb +8 -0
  8. data/lib/shoulda/matchers/action_controller.rb +38 -0
  9. data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +114 -0
  10. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +50 -0
  11. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +62 -0
  12. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +54 -0
  13. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +99 -0
  14. data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +74 -0
  15. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +85 -0
  16. data/lib/shoulda/matchers/action_controller/route_matcher.rb +93 -0
  17. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +98 -0
  18. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +94 -0
  19. data/lib/shoulda/matchers/action_mailer.rb +22 -0
  20. data/lib/shoulda/matchers/action_mailer/have_sent_email.rb +115 -0
  21. data/lib/shoulda/matchers/active_record.rb +42 -0
  22. data/lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb +83 -0
  23. data/lib/shoulda/matchers/active_record/allow_value_matcher.rb +110 -0
  24. data/lib/shoulda/matchers/active_record/association_matcher.rb +226 -0
  25. data/lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb +87 -0
  26. data/lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb +141 -0
  27. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +169 -0
  28. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +112 -0
  29. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +59 -0
  30. data/lib/shoulda/matchers/active_record/helpers.rb +34 -0
  31. data/lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb +41 -0
  32. data/lib/shoulda/matchers/active_record/validate_format_of_matcher.rb +65 -0
  33. data/lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb +39 -0
  34. data/lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb +60 -0
  35. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +148 -0
  36. data/lib/shoulda/matchers/active_record/validation_matcher.rb +56 -0
  37. data/lib/shoulda/matchers/integrations/rspec.rb +23 -0
  38. data/lib/shoulda/matchers/integrations/test_unit.rb +41 -0
  39. data/lib/shoulda/matchers/version.rb +5 -0
  40. metadata +113 -0
@@ -0,0 +1,98 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActionController # :nodoc:
4
+
5
+ # Ensures that a session key was set to the expected value.
6
+ #
7
+ # Example:
8
+ #
9
+ # it { should set_session(:message) }
10
+ # it { should set_session(:user_id).to(@user.id) }
11
+ # it { should_not set_session(:user_id) }
12
+ def set_session(key)
13
+ SetSessionMatcher.new(key)
14
+ end
15
+
16
+ class SetSessionMatcher # :nodoc:
17
+
18
+ def initialize(key)
19
+ @key = key.to_s
20
+ end
21
+
22
+ def to(value = nil, &block)
23
+ @value = value
24
+ @value_block = block
25
+ self
26
+ end
27
+
28
+ def matches?(controller)
29
+ @controller = controller
30
+ @value = @context.instance_eval(&@value_block) if @value_block
31
+ (assigned_value? && assigned_correct_value?) || cleared_value?
32
+ end
33
+
34
+ def failure_message
35
+ "Expected #{expectation}, but #{result}"
36
+ end
37
+
38
+ def negative_failure_message
39
+ "Didn't expect #{expectation}, but #{result}"
40
+ end
41
+
42
+ def description
43
+ description = "set session variable #{@key.inspect}"
44
+ description << " to #{@value.inspect}" if defined?(@value)
45
+ description
46
+ end
47
+
48
+ def in_context(context)
49
+ @context = context
50
+ self
51
+ end
52
+
53
+ private
54
+
55
+ def assigned_value?
56
+ !assigned_value.nil?
57
+ end
58
+
59
+ def cleared_value?
60
+ defined?(@value) && @value.nil? && assigned_value.nil?
61
+ end
62
+
63
+ def assigned_correct_value?
64
+ return true if @value.nil?
65
+ assigned_value == @value
66
+ end
67
+
68
+ def assigned_value
69
+ session[@key]
70
+ end
71
+
72
+ def session
73
+ if @controller.request.respond_to?(:session)
74
+ @controller.request.session.to_hash
75
+ else
76
+ @controller.response.session.data
77
+ end
78
+ end
79
+
80
+ def expectation
81
+ expectation = "session variable #{@key} to be set"
82
+ expectation << " to #{@value.inspect}" if @value
83
+ expectation
84
+ end
85
+
86
+ def result
87
+ if session.empty?
88
+ "no session variables were set"
89
+ else
90
+ "the session was #{session.inspect}"
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,94 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActionController # :nodoc:
4
+
5
+ # Ensures that the flash contains the given value. Can be a String, a
6
+ # Regexp, or nil (indicating that the flash should not be set).
7
+ #
8
+ # Example:
9
+ #
10
+ # it { should set_the_flash }
11
+ # it { should set_the_flash.to("Thank you for placing this order.") }
12
+ # it { should set_the_flash.to(/created/i) }
13
+ # it { should set_the_flash.to(/logged in/i).now }
14
+ # it { should_not set_the_flash }
15
+ def set_the_flash
16
+ SetTheFlashMatcher.new
17
+ end
18
+
19
+ class SetTheFlashMatcher # :nodoc:
20
+
21
+ def to(value)
22
+ @value = value
23
+ self
24
+ end
25
+
26
+ def now
27
+ @now = true
28
+ self
29
+ end
30
+
31
+ def matches?(controller)
32
+ @controller = controller
33
+ sets_the_flash? && string_value_matches? && regexp_value_matches?
34
+ end
35
+
36
+ attr_reader :failure_message, :negative_failure_message
37
+
38
+ def description
39
+ description = "set the flash"
40
+ description << " to #{@value.inspect}" unless @value.nil?
41
+ description
42
+ end
43
+
44
+ def failure_message
45
+ "Expected #{expectation}"
46
+ end
47
+
48
+ def negative_failure_message
49
+ "Did not expect #{expectation}"
50
+ end
51
+
52
+ private
53
+
54
+ def sets_the_flash?
55
+ !flash.blank?
56
+ end
57
+
58
+ def string_value_matches?
59
+ return true unless String === @value
60
+ flash.values.any? {|value| value == @value }
61
+ end
62
+
63
+ def regexp_value_matches?
64
+ return true unless Regexp === @value
65
+ flash.values.any? {|value| value =~ @value }
66
+ end
67
+
68
+ def flash
69
+ return @flash if @flash
70
+ @flash = @controller.flash.dup
71
+ @flash.sweep unless @now
72
+ @flash
73
+ end
74
+
75
+ def expectation
76
+ expectation = "the flash#{".now" if @now} to be set"
77
+ expectation << " to #{@value.inspect}" unless @value.nil?
78
+ expectation << ", but #{flash_description}"
79
+ expectation
80
+ end
81
+
82
+ def flash_description
83
+ if flash.blank?
84
+ "no flash was set"
85
+ else
86
+ "was #{flash.inspect}"
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,22 @@
1
+ require 'shoulda/matchers/action_mailer/have_sent_email'
2
+
3
+ module Shoulda
4
+ module Matchers
5
+ # = Matchers for your mailers
6
+ #
7
+ # This matcher will test that email is sent properly
8
+ #
9
+ # describe User do
10
+ # it { should have_sent_email.with_subject(/is spam$/) }
11
+ # it { should have_sent_email.from('do-not-reply@example.com') }
12
+ # it { should have_sent_email.with_body(/is spam\./) }
13
+ # it { should have_sent_email.to('myself@me.com') }
14
+ # it { should have_sent_email.with_subject(/spam/).
15
+ # from('do-not-reply@example.com').
16
+ # with_body(/spam/).
17
+ # to('myself@me.com') }
18
+ # end
19
+ module ActionMailer
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,115 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActionMailer # :nodoc:
4
+
5
+ # The right email is sent.
6
+ #
7
+ # it { should have_sent_email.with_subject(/is spam$/) }
8
+ # it { should have_sent_email.from('do-not-reply@example.com') }
9
+ # it { should have_sent_email.with_body(/is spam\./) }
10
+ # it { should have_sent_email.to('myself@me.com') }
11
+ # it { should have_sent_email.with_subject(/spam/).
12
+ # from('do-not-reply@example.com').
13
+ # with_body(/spam/).
14
+ # to('myself@me.com') }
15
+ def have_sent_email
16
+ HaveSentEmailMatcher.new
17
+ end
18
+
19
+ class HaveSentEmailMatcher # :nodoc:
20
+
21
+ def initialize
22
+ end
23
+
24
+ def with_subject(email_subject)
25
+ @email_subject = email_subject
26
+ self
27
+ end
28
+
29
+ def from(sender)
30
+ @sender = sender
31
+ self
32
+ end
33
+
34
+ def with_body(body)
35
+ @body = body
36
+ self
37
+ end
38
+
39
+ def to(recipient)
40
+ @recipient = recipient
41
+ self
42
+ end
43
+
44
+ def matches?(subject)
45
+ ::ActionMailer::Base.deliveries.each do |mail|
46
+ @subject_failed = !regexp_or_string_match(mail.subject, @email_subject) if @email_subject
47
+ @body_failed = !regexp_or_string_match(mail.body, @body) if @body
48
+ @sender_failed = !regexp_or_string_match_in_array(mail.from, @sender) if @sender
49
+ @recipient_failed = !regexp_or_string_match_in_array(mail.to, @recipient) if @recipient
50
+ return true unless anything_failed?
51
+ end
52
+
53
+ false
54
+ end
55
+
56
+ def failure_message
57
+ "Expected #{expectation}"
58
+ end
59
+
60
+ def negative_failure_message
61
+ "Did not expect #{expectation}"
62
+ end
63
+
64
+ def description
65
+ description = "send an email"
66
+ description << " with a subject of #{@email_subject.inspect}" if @email_subject
67
+ description << " containing #{@body.inspect}" if @body
68
+ description << " from #{@sender.inspect}" if @sender
69
+ description << " to #{@recipient.inspect}" if @recipient
70
+ description
71
+ end
72
+
73
+ private
74
+
75
+ def expectation
76
+ expectation = "sent email"
77
+ expectation << " with subject #{@email_subject.inspect}" if @subject_failed
78
+ expectation << " with body #{@body.inspect}" if @body_failed
79
+ expectation << " from #{@sender.inspect}" if @sender_failed
80
+ expectation << " to #{@recipient.inspect}" if @recipient_failed
81
+ expectation << "\nDeliveries:\n#{inspect_deliveries}"
82
+ end
83
+
84
+ def inspect_deliveries
85
+ ::ActionMailer::Base.deliveries.map do |delivery|
86
+ "#{delivery.subject.inspect} to #{delivery.to.inspect}"
87
+ end.join("\n")
88
+ end
89
+
90
+ def anything_failed?
91
+ @subject_failed || @body_failed || @sender_failed || @recipient_failed
92
+ end
93
+
94
+ def regexp_or_string_match(a_string, a_regexp_or_string)
95
+ case a_regexp_or_string
96
+ when Regexp
97
+ a_string =~ a_regexp_or_string
98
+ when String
99
+ a_string == a_regexp_or_string
100
+ end
101
+ end
102
+
103
+ def regexp_or_string_match_in_array(an_array, a_regexp_or_string)
104
+ case a_regexp_or_string
105
+ when Regexp
106
+ an_array.any? { |string| string =~ a_regexp_or_string }
107
+ when String
108
+ an_array.include?(a_regexp_or_string)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,42 @@
1
+ require 'shoulda/matchers/active_record/helpers'
2
+ require 'shoulda/matchers/active_record/validation_matcher'
3
+ require 'shoulda/matchers/active_record/allow_value_matcher'
4
+ require 'shoulda/matchers/active_record/ensure_length_of_matcher'
5
+ require 'shoulda/matchers/active_record/ensure_inclusion_of_matcher'
6
+ require 'shoulda/matchers/active_record/validate_presence_of_matcher'
7
+ require 'shoulda/matchers/active_record/validate_format_of_matcher'
8
+ require 'shoulda/matchers/active_record/validate_uniqueness_of_matcher'
9
+ require 'shoulda/matchers/active_record/validate_acceptance_of_matcher'
10
+ require 'shoulda/matchers/active_record/validate_numericality_of_matcher'
11
+ require 'shoulda/matchers/active_record/association_matcher'
12
+ require 'shoulda/matchers/active_record/have_db_column_matcher'
13
+ require 'shoulda/matchers/active_record/have_db_index_matcher'
14
+ require 'shoulda/matchers/active_record/have_readonly_attribute_matcher'
15
+ require 'shoulda/matchers/active_record/allow_mass_assignment_of_matcher'
16
+
17
+
18
+ module Shoulda
19
+ module Matchers
20
+ # = Matchers for your active record models
21
+ #
22
+ # These matchers will test most of the validations and associations for your
23
+ # ActiveRecord models.
24
+ #
25
+ # describe User do
26
+ # it { should validate_presence_of(:name) }
27
+ # it { should validate_presence_of(:phone_number) }
28
+ # %w(abcd 1234).each do |value|
29
+ # it { should_not allow_value(value).for(:phone_number) }
30
+ # end
31
+ # it { should allow_value("(123) 456-7890").for(:phone_number) }
32
+ # it { should_not allow_mass_assignment_of(:password) }
33
+ # it { should have_one(:profile) }
34
+ # it { should have_many(:dogs) }
35
+ # it { should have_many(:messes).through(:dogs) }
36
+ # it { should belong_to(:lover) }
37
+ # end
38
+ #
39
+ module ActiveRecord
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,83 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActiveRecord # :nodoc:
4
+
5
+ # Ensures that the attribute can be set on mass update.
6
+ #
7
+ # it { should_not allow_mass_assignment_of(:password) }
8
+ # it { should allow_mass_assignment_of(:first_name) }
9
+ #
10
+ def allow_mass_assignment_of(value)
11
+ AllowMassAssignmentOfMatcher.new(value)
12
+ end
13
+
14
+ class AllowMassAssignmentOfMatcher # :nodoc:
15
+
16
+ def initialize(attribute)
17
+ @attribute = attribute.to_s
18
+ end
19
+
20
+ def matches?(subject)
21
+ @subject = subject
22
+ if attr_mass_assignable?
23
+ if whitelisting?
24
+ @negative_failure_message = "#{@attribute} was made accessible"
25
+ else
26
+ if protected_attributes.empty?
27
+ @negative_failure_message = "no attributes were protected"
28
+ else
29
+ @negative_failure_message = "#{class_name} is protecting " <<
30
+ "#{protected_attributes.to_a.to_sentence}, " <<
31
+ "but not #{@attribute}."
32
+ end
33
+ end
34
+ true
35
+ else
36
+ if whitelisting?
37
+ @failure_message =
38
+ "Expected #{@attribute} to be accessible"
39
+ else
40
+ @failure_message =
41
+ "Did not expect #{@attribute} to be protected"
42
+ end
43
+ false
44
+ end
45
+ end
46
+
47
+ attr_reader :failure_message, :negative_failure_message
48
+
49
+ def description
50
+ "allow mass assignment of #{@attribute}"
51
+ end
52
+
53
+ private
54
+
55
+ def protected_attributes
56
+ @protected_attributes ||= (@subject.class.protected_attributes || [])
57
+ end
58
+
59
+ def accessible_attributes
60
+ @accessible_attributes ||= (@subject.class.accessible_attributes || [])
61
+ end
62
+
63
+ def whitelisting?
64
+ !accessible_attributes.empty?
65
+ end
66
+
67
+ def attr_mass_assignable?
68
+ if whitelisting?
69
+ accessible_attributes.include?(@attribute)
70
+ else
71
+ !protected_attributes.include?(@attribute)
72
+ end
73
+ end
74
+
75
+ def class_name
76
+ @subject.class.name
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+ end
83
+ end