shoulda-matchers 1.0.0.beta1

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.
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