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,39 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActiveRecord # :nodoc:
4
+
5
+ # Ensure that the attribute is numeric
6
+ #
7
+ # Options:
8
+ # * <tt>with_message</tt> - value the test expects to find in
9
+ # <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
10
+ # translation for <tt>:not_a_number</tt>.
11
+ #
12
+ # Example:
13
+ # it { should validate_numericality_of(:age) }
14
+ #
15
+ def validate_numericality_of(attr)
16
+ ValidateNumericalityOfMatcher.new(attr)
17
+ end
18
+
19
+ class ValidateNumericalityOfMatcher < ValidationMatcher # :nodoc:
20
+
21
+ def with_message(message)
22
+ @expected_message = message if message
23
+ self
24
+ end
25
+
26
+ def matches?(subject)
27
+ super(subject)
28
+ @expected_message ||= :not_a_number
29
+ disallows_value_of('abcd', @expected_message)
30
+ end
31
+
32
+ def description
33
+ "only allow numeric values for #{@attribute}"
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,60 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActiveRecord # :nodoc:
4
+
5
+ # Ensures that the model is not valid if the given attribute is not
6
+ # present.
7
+ #
8
+ # Options:
9
+ # * <tt>with_message</tt> - value the test expects to find in
10
+ # <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
11
+ # Defaults to the translation for <tt>:blank</tt>.
12
+ #
13
+ # Examples:
14
+ # it { should validate_presence_of(:name) }
15
+ # it { should validate_presence_of(:name).
16
+ # with_message(/is not optional/) }
17
+ #
18
+ def validate_presence_of(attr)
19
+ ValidatePresenceOfMatcher.new(attr)
20
+ end
21
+
22
+ class ValidatePresenceOfMatcher < ValidationMatcher # :nodoc:
23
+
24
+ def with_message(message)
25
+ @expected_message = message if message
26
+ self
27
+ end
28
+
29
+ def matches?(subject)
30
+ super(subject)
31
+ @expected_message ||= :blank
32
+ disallows_value_of(blank_value, @expected_message)
33
+ end
34
+
35
+ def description
36
+ "require #{@attribute} to be set"
37
+ end
38
+
39
+ private
40
+
41
+ def blank_value
42
+ if collection?
43
+ []
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def collection?
50
+ if reflection = @subject.class.reflect_on_association(@attribute)
51
+ [:has_many, :has_and_belongs_to_many].include?(reflection.macro)
52
+ else
53
+ false
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,148 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActiveRecord # :nodoc:
4
+
5
+ # Ensures that the model is invalid if the given attribute is not unique.
6
+ #
7
+ # Internally, this uses values from existing records to test validations,
8
+ # so this will always fail if you have not saved at least one record for
9
+ # the model being tested, like so:
10
+ #
11
+ # describe User do
12
+ # before(:each) { User.create!(:email => 'address@example.com') }
13
+ # it { should validate_uniqueness_of(:email) }
14
+ # end
15
+ #
16
+ # Options:
17
+ #
18
+ # * <tt>with_message</tt> - value the test expects to find in
19
+ # <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
20
+ # Defaults to the translation for <tt>:taken</tt>.
21
+ # * <tt>scoped_to</tt> - field(s) to scope the uniqueness to.
22
+ # * <tt>case_insensitive</tt> - ensures that the validation does not
23
+ # check case. Off by default. Ignored by non-text attributes.
24
+ #
25
+ # Examples:
26
+ # it { should validate_uniqueness_of(:keyword) }
27
+ # it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
28
+ # it { should validate_uniqueness_of(:email).scoped_to(:name) }
29
+ # it { should validate_uniqueness_of(:email).
30
+ # scoped_to(:first_name, :last_name) }
31
+ # it { should validate_uniqueness_of(:keyword).case_insensitive }
32
+ #
33
+ def validate_uniqueness_of(attr)
34
+ ValidateUniquenessOfMatcher.new(attr)
35
+ end
36
+
37
+ class ValidateUniquenessOfMatcher < ValidationMatcher # :nodoc:
38
+ include Helpers
39
+
40
+ def initialize(attribute)
41
+ @attribute = attribute
42
+ end
43
+
44
+ def scoped_to(*scopes)
45
+ @scopes = [*scopes].flatten
46
+ self
47
+ end
48
+
49
+ def with_message(message)
50
+ @expected_message = message
51
+ self
52
+ end
53
+
54
+ def case_insensitive
55
+ @case_insensitive = true
56
+ self
57
+ end
58
+
59
+ def description
60
+ result = "require "
61
+ result << "case sensitive " unless @case_insensitive
62
+ result << "unique value for #{@attribute}"
63
+ result << " scoped to #{@scopes.join(', ')}" unless @scopes.blank?
64
+ result
65
+ end
66
+
67
+ def matches?(subject)
68
+ @subject = subject.class.new
69
+ @expected_message ||= :taken
70
+ find_existing &&
71
+ set_scoped_attributes &&
72
+ validate_attribute &&
73
+ validate_after_scope_change
74
+ end
75
+
76
+ private
77
+
78
+ def find_existing
79
+ if @existing = @subject.class.find(:first)
80
+ true
81
+ else
82
+ @failure_message = "Can't find first #{class_name}"
83
+ false
84
+ end
85
+ end
86
+
87
+ def set_scoped_attributes
88
+ unless @scopes.blank?
89
+ @scopes.each do |scope|
90
+ setter = :"#{scope}="
91
+ unless @subject.respond_to?(setter)
92
+ @failure_message =
93
+ "#{class_name} doesn't seem to have a #{scope} attribute."
94
+ return false
95
+ end
96
+ @subject.send("#{scope}=", @existing.send(scope))
97
+ end
98
+ end
99
+ true
100
+ end
101
+
102
+ def validate_attribute
103
+ disallows_value_of(existing_value, @expected_message)
104
+ end
105
+
106
+ # TODO: There is a chance that we could change the scoped field
107
+ # to a value that's already taken. An alternative implementation
108
+ # could actually find all values for scope and create a unique
109
+ def validate_after_scope_change
110
+ if @scopes.blank?
111
+ true
112
+ else
113
+ @scopes.all? do |scope|
114
+ previous_value = @existing.send(scope)
115
+
116
+ # Assume the scope is a foreign key if the field is nil
117
+ previous_value ||= 0
118
+
119
+ next_value = previous_value.next
120
+
121
+ @subject.send("#{scope}=", next_value)
122
+
123
+ if allows_value_of(existing_value, @expected_message)
124
+ @negative_failure_message <<
125
+ " (with different value of #{scope})"
126
+ true
127
+ else
128
+ @failure_message << " (with different value of #{scope})"
129
+ false
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def class_name
136
+ @subject.class.name
137
+ end
138
+
139
+ def existing_value
140
+ value = @existing.send(@attribute)
141
+ value.swapcase! if @case_insensitive && value.respond_to?(:swapcase!)
142
+ value
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,56 @@
1
+ module Shoulda # :nodoc:
2
+ module Matchers
3
+ module ActiveRecord # :nodoc:
4
+
5
+ class ValidationMatcher # :nodoc:
6
+
7
+ attr_reader :failure_message
8
+
9
+ def initialize(attribute)
10
+ @attribute = attribute
11
+ end
12
+
13
+ def negative_failure_message
14
+ @negative_failure_message || @failure_message
15
+ end
16
+
17
+ def matches?(subject)
18
+ @subject = subject
19
+ false
20
+ end
21
+
22
+ private
23
+
24
+ def allows_value_of(value, message = nil)
25
+ allow = AllowValueMatcher.
26
+ new(value).
27
+ for(@attribute).
28
+ with_message(message)
29
+ if allow.matches?(@subject)
30
+ @negative_failure_message = allow.failure_message
31
+ true
32
+ else
33
+ @failure_message = allow.negative_failure_message
34
+ false
35
+ end
36
+ end
37
+
38
+ def disallows_value_of(value, message = nil)
39
+ disallow = AllowValueMatcher.
40
+ new(value).
41
+ for(@attribute).
42
+ with_message(message)
43
+ if disallow.matches?(@subject)
44
+ @failure_message = disallow.negative_failure_message
45
+ false
46
+ else
47
+ @negative_failure_message = disallow.failure_message
48
+ true
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,23 @@
1
+ # :enddoc:
2
+
3
+ if defined?(::ActiveRecord)
4
+ require 'shoulda/matchers/active_record'
5
+ module RSpec::Matchers
6
+ include Shoulda::Matchers::ActiveRecord
7
+ end
8
+ end
9
+
10
+ if defined?(::ActionController)
11
+ require 'shoulda/matchers/action_controller'
12
+ module RSpec::Rails::ControllerExampleGroup
13
+ include Shoulda::Matchers::ActionController
14
+ end
15
+ end
16
+
17
+ if defined?(::ActionMailer)
18
+ require 'shoulda/matchers/action_mailer'
19
+ module RSpec::Rails::MailerExampleGroup
20
+ include Shoulda::Matchers::ActionMailer
21
+ end
22
+ end
23
+
@@ -0,0 +1,41 @@
1
+ # :enddoc:
2
+
3
+ if defined?(ActionController)
4
+ require 'shoulda/matchers/action_controller'
5
+
6
+ class ActionController::TestCase
7
+ include Shoulda::Matchers::ActionController
8
+ extend Shoulda::Matchers::ActionController
9
+
10
+ def subject
11
+ @controller
12
+ end
13
+ end
14
+ end
15
+
16
+ if defined?(ActionMailer)
17
+ require 'shoulda/matchers/action_mailer'
18
+
19
+ module Test
20
+ module Unit
21
+ class TestCase
22
+ include Shoulda::Matchers::ActionMailer
23
+ extend Shoulda::Matchers::ActionMailer
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ if defined?(ActiveRecord)
30
+ require 'shoulda/matchers/active_record'
31
+
32
+ module Test
33
+ module Unit
34
+ class TestCase
35
+ include Shoulda::Matchers::ActiveRecord
36
+ extend Shoulda::Matchers::ActiveRecord
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,5 @@
1
+ module Shoulda
2
+ module Matchers
3
+ VERSION = "1.0.0.beta1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shoulda-matchers
3
+ version: !ruby/object:Gem::Version
4
+ hash: 299253597
5
+ prerelease: true
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ - beta1
11
+ version: 1.0.0.beta1
12
+ platform: ruby
13
+ authors:
14
+ - Tammer Saleh
15
+ - Joe Ferris
16
+ - Ryan McGeary
17
+ - Dan Croak
18
+ - Matt Jankowski
19
+ autorequire:
20
+ bindir: bin
21
+ cert_chain: []
22
+
23
+ date: 2011-01-19 00:00:00 -05:00
24
+ default_executable:
25
+ dependencies: []
26
+
27
+ description: Making tests easy on the fingers and eyes
28
+ email: support@thoughtbot.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - README.rdoc
35
+ - CONTRIBUTION_GUIDELINES.rdoc
36
+ files:
37
+ - CONTRIBUTION_GUIDELINES.rdoc
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - MIT-LICENSE
41
+ - Rakefile
42
+ - README.rdoc
43
+ - lib/shoulda/matchers/action_controller/assign_to_matcher.rb
44
+ - lib/shoulda/matchers/action_controller/filter_param_matcher.rb
45
+ - lib/shoulda/matchers/action_controller/redirect_to_matcher.rb
46
+ - lib/shoulda/matchers/action_controller/render_template_matcher.rb
47
+ - lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb
48
+ - lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb
49
+ - lib/shoulda/matchers/action_controller/respond_with_matcher.rb
50
+ - lib/shoulda/matchers/action_controller/route_matcher.rb
51
+ - lib/shoulda/matchers/action_controller/set_session_matcher.rb
52
+ - lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb
53
+ - lib/shoulda/matchers/action_controller.rb
54
+ - lib/shoulda/matchers/action_mailer/have_sent_email.rb
55
+ - lib/shoulda/matchers/action_mailer.rb
56
+ - lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb
57
+ - lib/shoulda/matchers/active_record/allow_value_matcher.rb
58
+ - lib/shoulda/matchers/active_record/association_matcher.rb
59
+ - lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb
60
+ - lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb
61
+ - lib/shoulda/matchers/active_record/have_db_column_matcher.rb
62
+ - lib/shoulda/matchers/active_record/have_db_index_matcher.rb
63
+ - lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb
64
+ - lib/shoulda/matchers/active_record/helpers.rb
65
+ - lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb
66
+ - lib/shoulda/matchers/active_record/validate_format_of_matcher.rb
67
+ - lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb
68
+ - lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb
69
+ - lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb
70
+ - lib/shoulda/matchers/active_record/validation_matcher.rb
71
+ - lib/shoulda/matchers/active_record.rb
72
+ - lib/shoulda/matchers/integrations/rspec.rb
73
+ - lib/shoulda/matchers/integrations/test_unit.rb
74
+ - lib/shoulda/matchers/version.rb
75
+ - lib/shoulda-matchers.rb
76
+ has_rdoc: true
77
+ homepage: http://thoughtbot.com/community/
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options:
82
+ - --line-numbers
83
+ - --main
84
+ - README.rdoc
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ requirements: []
106
+
107
+ rubyforge_project:
108
+ rubygems_version: 1.3.7
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: Making tests easy on the fingers and eyes
112
+ test_files: []
113
+