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,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
+