gnip 0.4.2

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 (89) hide show
  1. data/README +144 -0
  2. data/Rakefile +53 -0
  3. data/TODO +72 -0
  4. data/bin/gnip +651 -0
  5. data/doc/api.html +1201 -0
  6. data/gemspec.rb +47 -0
  7. data/gnip-0.4.2.gem +0 -0
  8. data/lib/gnip.rb +71 -0
  9. data/lib/gnip/activity.rb +663 -0
  10. data/lib/gnip/api.rb +191 -0
  11. data/lib/gnip/arguments.rb +21 -0
  12. data/lib/gnip/blankslate.rb +5 -0
  13. data/lib/gnip/config.rb +144 -0
  14. data/lib/gnip/filter.rb +304 -0
  15. data/lib/gnip/list.rb +126 -0
  16. data/lib/gnip/options.rb +96 -0
  17. data/lib/gnip/orderedhash.rb +199 -0
  18. data/lib/gnip/publisher.rb +309 -0
  19. data/lib/gnip/resource.rb +301 -0
  20. data/lib/gnip/template.rb +44 -0
  21. data/lib/gnip/util.rb +120 -0
  22. data/sample/data/activity.yml +21 -0
  23. data/test/auth.rb +60 -0
  24. data/test/config.yml +2 -0
  25. data/test/data/activity.xml +14 -0
  26. data/test/data/activity_only_required.xml +4 -0
  27. data/test/data/activity_with_payload.xml +22 -0
  28. data/test/data/activity_with_place.xml +18 -0
  29. data/test/data/activity_with_place_wo_bounds.xml +36 -0
  30. data/test/data/activity_with_unbounded_media_urls.xml +44 -0
  31. data/test/data/activity_without_bounds.xml +24 -0
  32. data/test/helper.rb +115 -0
  33. data/test/helper.rb.bak +28 -0
  34. data/test/integration/auth.rb +12 -0
  35. data/test/integration/publisher.rb +86 -0
  36. data/test/lib/shoulda.rb +9 -0
  37. data/test/lib/shoulda/action_controller.rb +28 -0
  38. data/test/lib/shoulda/action_controller/helpers.rb +47 -0
  39. data/test/lib/shoulda/action_controller/macros.rb +277 -0
  40. data/test/lib/shoulda/action_controller/matchers.rb +37 -0
  41. data/test/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  42. data/test/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  43. data/test/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  44. data/test/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +70 -0
  45. data/test/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +77 -0
  46. data/test/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  47. data/test/lib/shoulda/action_controller/matchers/set_session_matcher.rb +83 -0
  48. data/test/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  49. data/test/lib/shoulda/action_mailer.rb +10 -0
  50. data/test/lib/shoulda/action_mailer/assertions.rb +38 -0
  51. data/test/lib/shoulda/action_view.rb +10 -0
  52. data/test/lib/shoulda/action_view/macros.rb +56 -0
  53. data/test/lib/shoulda/active_record.rb +16 -0
  54. data/test/lib/shoulda/active_record/assertions.rb +69 -0
  55. data/test/lib/shoulda/active_record/helpers.rb +40 -0
  56. data/test/lib/shoulda/active_record/macros.rb +586 -0
  57. data/test/lib/shoulda/active_record/matchers.rb +42 -0
  58. data/test/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  59. data/test/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  60. data/test/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  61. data/test/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  62. data/test/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  63. data/test/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  64. data/test/lib/shoulda/active_record/matchers/have_index_matcher.rb +105 -0
  65. data/test/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +125 -0
  66. data/test/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  67. data/test/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  68. data/test/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  69. data/test/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  70. data/test/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  71. data/test/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
  72. data/test/lib/shoulda/assertions.rb +59 -0
  73. data/test/lib/shoulda/autoload_macros.rb +46 -0
  74. data/test/lib/shoulda/context.rb +304 -0
  75. data/test/lib/shoulda/helpers.rb +8 -0
  76. data/test/lib/shoulda/macros.rb +73 -0
  77. data/test/lib/shoulda/private_helpers.rb +20 -0
  78. data/test/lib/shoulda/proc_extensions.rb +14 -0
  79. data/test/lib/shoulda/rails.rb +13 -0
  80. data/test/lib/shoulda/rspec.rb +9 -0
  81. data/test/lib/shoulda/tasks.rb +3 -0
  82. data/test/lib/shoulda/tasks/list_tests.rake +29 -0
  83. data/test/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  84. data/test/lib/shoulda/test_unit.rb +19 -0
  85. data/test/lib/xmlsimple.rb +1021 -0
  86. data/test/loader.rb +25 -0
  87. data/test/unit/activity.rb +26 -0
  88. data/test/unit/util.rb +39 -0
  89. metadata +198 -0
@@ -0,0 +1,85 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionController # :nodoc:
3
+ module Matchers
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_not set_the_flash }
14
+ def set_the_flash
15
+ SetTheFlashMatcher.new
16
+ end
17
+
18
+ class SetTheFlashMatcher # :nodoc:
19
+
20
+ def to(value)
21
+ @value = value
22
+ self
23
+ end
24
+
25
+ def matches?(controller)
26
+ @controller = controller
27
+ sets_the_flash? && string_value_matches? && regexp_value_matches?
28
+ end
29
+
30
+ attr_reader :failure_message, :negative_failure_message
31
+
32
+ def description
33
+ description = "set the flash"
34
+ description << " to #{@value.inspect}" unless @value.nil?
35
+ description
36
+ end
37
+
38
+ def failure_message
39
+ "Expected #{expectation}"
40
+ end
41
+
42
+ def negative_failure_message
43
+ "Did not expect #{expectation}"
44
+ end
45
+
46
+ private
47
+
48
+ def sets_the_flash?
49
+ !flash.blank?
50
+ end
51
+
52
+ def string_value_matches?
53
+ return true unless String === @value
54
+ flash.values.any? {|value| value == @value }
55
+ end
56
+
57
+ def regexp_value_matches?
58
+ return true unless Regexp === @value
59
+ flash.values.any? {|value| value =~ @value }
60
+ end
61
+
62
+ def flash
63
+ @controller.response.session['flash']
64
+ end
65
+
66
+ def expectation
67
+ expectation = "the flash to be set"
68
+ expectation << " to #{@value.inspect}" unless @value.nil?
69
+ expectation << ", but #{flash_description}"
70
+ expectation
71
+ end
72
+
73
+ def flash_description
74
+ if flash.blank?
75
+ "no flash was set"
76
+ else
77
+ "was #{flash.inspect}"
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,10 @@
1
+ require 'shoulda'
2
+ require 'shoulda/action_mailer/assertions'
3
+
4
+ module Test # :nodoc: all
5
+ module Unit
6
+ class TestCase
7
+ include Shoulda::ActionMailer::Assertions
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,38 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionMailer # :nodoc:
3
+ module Assertions
4
+ # Asserts that an email was delivered. Can take a block that can further
5
+ # narrow down the types of emails you're expecting.
6
+ #
7
+ # assert_sent_email
8
+ #
9
+ # Passes if ActionMailer::Base.deliveries has an email
10
+ #
11
+ # assert_sent_email do |email|
12
+ # email.subject =~ /hi there/ && email.to.include?('none@none.com')
13
+ # end
14
+ #
15
+ # Passes if there is an email with subject containing 'hi there' and
16
+ # 'none@none.com' as one of the recipients.
17
+ #
18
+ def assert_sent_email
19
+ emails = ::ActionMailer::Base.deliveries
20
+ assert !emails.empty?, "No emails were sent"
21
+ if block_given?
22
+ matching_emails = emails.select {|email| yield email }
23
+ assert !matching_emails.empty?, "None of the emails matched."
24
+ end
25
+ end
26
+
27
+ # Asserts that no ActionMailer mails were delivered
28
+ #
29
+ # assert_did_not_send_email
30
+ def assert_did_not_send_email
31
+ msg = "Sent #{::ActionMailer::Base.deliveries.size} emails.\n"
32
+ ::ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
33
+ assert ::ActionMailer::Base.deliveries.empty?, msg
34
+ end
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,10 @@
1
+ require 'shoulda'
2
+ require 'shoulda/action_view/macros'
3
+
4
+ module Test # :nodoc: all
5
+ module Unit
6
+ class TestCase
7
+ extend Shoulda::ActionView::Macros
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,56 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionView # :nodoc:
3
+ # = Macro test helpers for your view
4
+ #
5
+ # By using the macro helpers you can quickly and easily create concise and
6
+ # easy to read test suites.
7
+ #
8
+ # This code segment:
9
+ # context "on GET to :new" do
10
+ # setup do
11
+ # get :new
12
+ # end
13
+ #
14
+ # should_render_a_form
15
+ # should_render_page_with_metadata :title => /index/
16
+ #
17
+ # should "do something else really cool" do
18
+ # assert_select '#really_cool'
19
+ # end
20
+ # end
21
+ #
22
+ # Would produce 3 tests for the +show+ action
23
+ module Macros
24
+
25
+ # Macro that creates a test asserting that the rendered view contains a <form> element.
26
+ def should_render_a_form
27
+ should "display a form" do
28
+ assert_select "form", true, "The template doesn't contain a <form> element"
29
+ end
30
+ end
31
+
32
+ # Macro that creates a test asserting that the rendered view contains the selected metatags.
33
+ # Values can be string or Regexps.
34
+ # Example:
35
+ #
36
+ # should_render_page_with_metadata :description => "Description of this page", :keywords => /post/
37
+ #
38
+ # You can also use this method to test the rendered views title.
39
+ #
40
+ # Example:
41
+ # should_render_page_with_metadata :title => /index/
42
+ def should_render_page_with_metadata(options)
43
+ options.each do |key, value|
44
+ should "have metatag #{key}" do
45
+ if key.to_sym == :title
46
+ assert_select "title", value
47
+ else
48
+ assert_select "meta[name=?][content#{"*" if value.is_a?(Regexp)}=?]", key, value
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,16 @@
1
+ require 'shoulda'
2
+ require 'shoulda/active_record/helpers'
3
+ require 'shoulda/active_record/matchers'
4
+ require 'shoulda/active_record/assertions'
5
+ require 'shoulda/active_record/macros'
6
+
7
+ module Test # :nodoc: all
8
+ module Unit
9
+ class TestCase
10
+ include Shoulda::ActiveRecord::Helpers
11
+ include Shoulda::ActiveRecord::Matchers
12
+ include Shoulda::ActiveRecord::Assertions
13
+ extend Shoulda::ActiveRecord::Macros
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,69 @@
1
+ module Shoulda # :nodoc:
2
+ module ActiveRecord # :nodoc:
3
+ module Assertions
4
+ # Asserts that the given object can be saved
5
+ #
6
+ # assert_save User.new(params)
7
+ def assert_save(obj)
8
+ assert obj.save, "Errors: #{pretty_error_messages obj}"
9
+ obj.reload
10
+ end
11
+
12
+ # Asserts that the given object is valid
13
+ #
14
+ # assert_valid User.new(params)
15
+ def assert_valid(obj)
16
+ assert obj.valid?, "Errors: #{pretty_error_messages obj}"
17
+ end
18
+
19
+ # Asserts that an Active Record model validates with the passed
20
+ # <tt>value</tt> by making sure the <tt>error_message_to_avoid</tt> is not
21
+ # contained within the list of errors for that attribute.
22
+ #
23
+ # assert_good_value(User.new, :email, "user@example.com")
24
+ # assert_good_value(User.new, :ssn, "123456789", /length/)
25
+ #
26
+ # If a class is passed as the first argument, a new object will be
27
+ # instantiated before the assertion. If an instance variable exists with
28
+ # the same name as the class (underscored), that object will be used
29
+ # instead.
30
+ #
31
+ # assert_good_value(User, :email, "user@example.com")
32
+ #
33
+ # @product = Product.new(:tangible => false)
34
+ # assert_good_value(Product, :price, "0")
35
+ def assert_good_value(object_or_klass, attribute, value, error_message_to_avoid = nil)
36
+ object = get_instance_of(object_or_klass)
37
+ matcher = allow_value(value).
38
+ for(attribute).
39
+ with_message(error_message_to_avoid)
40
+ assert_accepts(matcher, object)
41
+ end
42
+
43
+ # Asserts that an Active Record model invalidates the passed
44
+ # <tt>value</tt> by making sure the <tt>error_message_to_expect</tt> is
45
+ # contained within the list of errors for that attribute.
46
+ #
47
+ # assert_bad_value(User.new, :email, "invalid")
48
+ # assert_bad_value(User.new, :ssn, "123", /length/)
49
+ #
50
+ # If a class is passed as the first argument, a new object will be
51
+ # instantiated before the assertion. If an instance variable exists with
52
+ # the same name as the class (underscored), that object will be used
53
+ # instead.
54
+ #
55
+ # assert_bad_value(User, :email, "invalid")
56
+ #
57
+ # @product = Product.new(:tangible => true)
58
+ # assert_bad_value(Product, :price, "0")
59
+ def assert_bad_value(object_or_klass, attribute, value,
60
+ error_message_to_expect = nil)
61
+ object = get_instance_of(object_or_klass)
62
+ matcher = allow_value(value).
63
+ for(attribute).
64
+ with_message(error_message_to_expect)
65
+ assert_rejects(matcher, object)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,40 @@
1
+ module Shoulda # :nodoc:
2
+ module ActiveRecord # :nodoc:
3
+ module Helpers
4
+ def pretty_error_messages(obj) # :nodoc:
5
+ obj.errors.map do |a, m|
6
+ msg = "#{a} #{m}"
7
+ msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
8
+ end
9
+ end
10
+
11
+ def get_instance_of(object_or_klass)
12
+ if object_or_klass.is_a?(Class)
13
+ klass = object_or_klass
14
+ instance_variable_get("@#{instance_variable_name_for(klass)}") || klass.new
15
+ else
16
+ object_or_klass
17
+ end
18
+ end
19
+
20
+ def instance_variable_name_for(klass)
21
+ klass.to_s.split('::').last.underscore
22
+ end
23
+
24
+ # Helper method that determines the default error message used by Active
25
+ # Record. Works for both existing Rails 2.1 and Rails 2.2 with the newly
26
+ # introduced I18n module used for localization.
27
+ #
28
+ # default_error_message(:blank)
29
+ # default_error_message(:too_short, :count => 5)
30
+ # default_error_message(:too_long, :count => 60)
31
+ def default_error_message(key, values = {})
32
+ if Object.const_defined?(:I18n) # Rails >= 2.2
33
+ I18n.translate("activerecord.errors.messages.#{key}", values)
34
+ else # Rails <= 2.1.x
35
+ ::ActiveRecord::Errors.default_error_messages[key] % values[:count]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,586 @@
1
+ module Shoulda # :nodoc:
2
+ module ActiveRecord # :nodoc:
3
+ # = Macro test helpers for your active record models
4
+ #
5
+ # These helpers will test most of the validations and associations for your ActiveRecord models.
6
+ #
7
+ # class UserTest < Test::Unit::TestCase
8
+ # should_validate_presence_of :name, :phone_number
9
+ # should_not_allow_values_for :phone_number, "abcd", "1234"
10
+ # should_allow_values_for :phone_number, "(123) 456-7890"
11
+ #
12
+ # should_not_allow_mass_assignment_of :password
13
+ #
14
+ # should_have_one :profile
15
+ # should_have_many :dogs
16
+ # should_have_many :messes, :through => :dogs
17
+ # should_belong_to :lover
18
+ # end
19
+ #
20
+ # For all of these helpers, the last parameter may be a hash of options.
21
+ #
22
+ module Macros
23
+ include Helpers
24
+ include Matchers
25
+
26
+ # Ensures that the model cannot be saved if one of the attributes listed is not present.
27
+ #
28
+ # If an instance variable has been created in the setup named after the
29
+ # model being tested, then this method will use that. Otherwise, it will
30
+ # create a new instance to test against.
31
+ #
32
+ # Options:
33
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
34
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.blank')</tt>
35
+ #
36
+ # Example:
37
+ # should_validate_presence_of :name, :phone_number
38
+ #
39
+ def should_validate_presence_of(*attributes)
40
+ message = get_options!(attributes, :message)
41
+ klass = model_class
42
+
43
+ attributes.each do |attribute|
44
+ matcher = validate_presence_of(attribute).with_message(message)
45
+ should matcher.description do
46
+ assert_accepts(matcher, get_instance_of(klass))
47
+ end
48
+ end
49
+ end
50
+
51
+ # Deprecated. See should_validate_presence_of
52
+ def should_require_attributes(*attributes)
53
+ warn "[DEPRECATION] should_require_attributes is deprecated. " <<
54
+ "Use should_validate_presence_of instead."
55
+ should_validate_presence_of(*attributes)
56
+ end
57
+
58
+ # Ensures that the model cannot be saved if one of the attributes listed is not unique.
59
+ # Requires an existing record
60
+ #
61
+ # Options:
62
+
63
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
64
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.taken')</tt>
65
+ # * <tt>:scoped_to</tt> - field(s) to scope the uniqueness to.
66
+ # * <tt>:case_sensitive</tt> - whether or not uniqueness is defined by an
67
+ # exact match. Ignored by non-text attributes. Default = <tt>true</tt>
68
+ #
69
+ # Examples:
70
+ # should_validate_uniqueness_of :keyword, :username
71
+ # should_validate_uniqueness_of :name, :message => "O NOES! SOMEONE STOELED YER NAME!"
72
+ # should_validate_uniqueness_of :email, :scoped_to => :name
73
+ # should_validate_uniqueness_of :address, :scoped_to => [:first_name, :last_name]
74
+ # should_validate_uniqueness_of :email, :case_sensitive => false
75
+ #
76
+ def should_validate_uniqueness_of(*attributes)
77
+ message, scope, case_sensitive = get_options!(attributes, :message, :scoped_to, :case_sensitive)
78
+ scope = [*scope].compact
79
+ case_sensitive = true if case_sensitive.nil?
80
+
81
+ klass = model_class
82
+
83
+ attributes.each do |attribute|
84
+ matcher = validate_uniqueness_of(attribute).
85
+ with_message(message).scoped_to(scope)
86
+ matcher = matcher.case_insensitive unless case_sensitive
87
+ should matcher.description do
88
+ assert_accepts(matcher, get_instance_of(klass))
89
+ end
90
+ end
91
+ end
92
+
93
+ # Deprecated. See should_validate_uniqueness_of
94
+ def should_require_unique_attributes(*attributes)
95
+ warn "[DEPRECATION] should_require_unique_attributes is deprecated. " <<
96
+ "Use should_validate_uniqueness_of instead."
97
+ should_validate_uniqueness_of(*attributes)
98
+ end
99
+
100
+ # Ensures that the attribute can be set on mass update.
101
+ #
102
+ # should_allow_mass_assignment_of :first_name, :last_name
103
+ #
104
+ def should_allow_mass_assignment_of(*attributes)
105
+ get_options!(attributes)
106
+ klass = model_class
107
+
108
+ attributes.each do |attribute|
109
+ matcher = allow_mass_assignment_of(attribute)
110
+ should matcher.description do
111
+ assert_accepts matcher, klass.new
112
+ end
113
+ end
114
+ end
115
+
116
+ # Ensures that the attribute cannot be set on mass update.
117
+ #
118
+ # should_not_allow_mass_assignment_of :password, :admin_flag
119
+ #
120
+ def should_not_allow_mass_assignment_of(*attributes)
121
+ get_options!(attributes)
122
+ klass = model_class
123
+
124
+ attributes.each do |attribute|
125
+ matcher = allow_mass_assignment_of(attribute)
126
+ should "not #{matcher.description}" do
127
+ assert_rejects matcher, klass.new
128
+ end
129
+ end
130
+ end
131
+
132
+ # Deprecated. See should_not_allow_mass_assignment_of
133
+ def should_protect_attributes(*attributes)
134
+ warn "[DEPRECATION] should_protect_attributes is deprecated. " <<
135
+ "Use should_not_allow_mass_assignment_of instead."
136
+ should_not_allow_mass_assignment_of(*attributes)
137
+ end
138
+
139
+ # Ensures that the attribute cannot be changed once the record has been created.
140
+ #
141
+ # should_have_readonly_attributes :password, :admin_flag
142
+ #
143
+ def should_have_readonly_attributes(*attributes)
144
+ get_options!(attributes)
145
+ klass = model_class
146
+
147
+ attributes.each do |attribute|
148
+ matcher = have_readonly_attribute(attribute)
149
+ should matcher.description do
150
+ assert_accepts matcher, klass.new
151
+ end
152
+ end
153
+ end
154
+
155
+ # Ensures that the attribute cannot be set to the given values
156
+ #
157
+ # If an instance variable has been created in the setup named after the
158
+ # model being tested, then this method will use that. Otherwise, it will
159
+ # create a new instance to test against.
160
+ #
161
+ # Options:
162
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
163
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.invalid')</tt>
164
+ #
165
+ # Example:
166
+ # should_not_allow_values_for :isbn, "bad 1", "bad 2"
167
+ #
168
+ def should_not_allow_values_for(attribute, *bad_values)
169
+ message = get_options!(bad_values, :message)
170
+ klass = model_class
171
+ bad_values.each do |value|
172
+ matcher = allow_value(value).for(attribute).with_message(message)
173
+ should "not #{matcher.description}" do
174
+ assert_rejects matcher, get_instance_of(klass)
175
+ end
176
+ end
177
+ end
178
+
179
+ # Ensures that the attribute can be set to the given values.
180
+ #
181
+ # If an instance variable has been created in the setup named after the
182
+ # model being tested, then this method will use that. Otherwise, it will
183
+ # create a new instance to test against.
184
+ #
185
+ # Example:
186
+ # should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
187
+ #
188
+ def should_allow_values_for(attribute, *good_values)
189
+ get_options!(good_values)
190
+ klass = model_class
191
+ klass = model_class
192
+ good_values.each do |value|
193
+ matcher = allow_value(value).for(attribute)
194
+ should matcher.description do
195
+ assert_accepts matcher, get_instance_of(klass)
196
+ end
197
+ end
198
+ end
199
+
200
+ # Ensures that the length of the attribute is in the given range
201
+ #
202
+ # If an instance variable has been created in the setup named after the
203
+ # model being tested, then this method will use that. Otherwise, it will
204
+ # create a new instance to test against.
205
+ #
206
+ # Options:
207
+ # * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
208
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.too_short') % range.first</tt>
209
+ # * <tt>:long_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
210
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.too_long') % range.last</tt>
211
+ #
212
+ # Example:
213
+ # should_ensure_length_in_range :password, (6..20)
214
+ #
215
+ def should_ensure_length_in_range(attribute, range, opts = {})
216
+ short_message, long_message = get_options!([opts],
217
+ :short_message,
218
+ :long_message)
219
+ klass = model_class
220
+
221
+ matcher = ensure_length_of(attribute).
222
+ is_at_least(range.first).
223
+ with_short_message(short_message).
224
+ is_at_most(range.last).
225
+ with_long_message(long_message)
226
+
227
+ should matcher.description do
228
+ assert_accepts matcher, get_instance_of(klass)
229
+ end
230
+ end
231
+
232
+ # Ensures that the length of the attribute is at least a certain length
233
+ #
234
+ # If an instance variable has been created in the setup named after the
235
+ # model being tested, then this method will use that. Otherwise, it will
236
+ # create a new instance to test against.
237
+ #
238
+ # Options:
239
+ # * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
240
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.too_short') % min_length</tt>
241
+ #
242
+ # Example:
243
+ # should_ensure_length_at_least :name, 3
244
+ #
245
+ def should_ensure_length_at_least(attribute, min_length, opts = {})
246
+ short_message = get_options!([opts], :short_message)
247
+ klass = model_class
248
+
249
+ matcher = ensure_length_of(attribute).
250
+ is_at_least(min_length).
251
+ with_short_message(short_message)
252
+
253
+ should matcher.description do
254
+ assert_accepts matcher, get_instance_of(klass)
255
+ end
256
+ end
257
+
258
+ # Ensures that the length of the attribute is exactly a certain length
259
+ #
260
+ # If an instance variable has been created in the setup named after the
261
+ # model being tested, then this method will use that. Otherwise, it will
262
+ # create a new instance to test against.
263
+ #
264
+ # Options:
265
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
266
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % length</tt>
267
+ #
268
+ # Example:
269
+ # should_ensure_length_is :ssn, 9
270
+ #
271
+ def should_ensure_length_is(attribute, length, opts = {})
272
+ message = get_options!([opts], :message)
273
+ klass = model_class
274
+ matcher = ensure_length_of(attribute).
275
+ is_equal_to(length).
276
+ with_message(message)
277
+
278
+ should matcher.description do
279
+ assert_accepts matcher, get_instance_of(klass)
280
+ end
281
+ end
282
+
283
+ # Ensure that the attribute is in the range specified
284
+ #
285
+ # If an instance variable has been created in the setup named after the
286
+ # model being tested, then this method will use that. Otherwise, it will
287
+ # create a new instance to test against.
288
+ #
289
+ # Options:
290
+ # * <tt>:low_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
291
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.inclusion')</tt>
292
+ # * <tt>:high_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
293
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.inclusion')</tt>
294
+ #
295
+ # Example:
296
+ # should_ensure_value_in_range :age, (0..100)
297
+ #
298
+ def should_ensure_value_in_range(attribute, range, opts = {})
299
+ message = get_options!([opts], :message)
300
+ message ||= default_error_message(:inclusion)
301
+
302
+ klass = model_class
303
+ matcher = ensure_inclusion_of(attribute).
304
+ in_range(range).
305
+ with_message(message)
306
+ should matcher.description do
307
+ assert_accepts matcher, get_instance_of(klass)
308
+ end
309
+ end
310
+
311
+ # Ensure that the attribute is numeric
312
+ #
313
+ # If an instance variable has been created in the setup named after the
314
+ # model being tested, then this method will use that. Otherwise, it will
315
+ # create a new instance to test against.
316
+ #
317
+ # Options:
318
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
319
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.not_a_number')</tt>
320
+ #
321
+ # Example:
322
+ # should_validate_numericality_of :age
323
+ #
324
+ def should_validate_numericality_of(*attributes)
325
+ message = get_options!(attributes, :message)
326
+ klass = model_class
327
+ attributes.each do |attribute|
328
+ matcher = validate_numericality_of(attribute).
329
+ with_message(message)
330
+ should matcher.description do
331
+ assert_accepts matcher, get_instance_of(klass)
332
+ end
333
+ end
334
+ end
335
+
336
+ # Deprecated. See should_validate_uniqueness_of
337
+ def should_only_allow_numeric_values_for(*attributes)
338
+ warn "[DEPRECATION] should_only_allow_numeric_values_for is " <<
339
+ "deprecated. Use should_validate_numericality_of instead."
340
+ should_validate_numericality_of(*attributes)
341
+ end
342
+
343
+ # Ensures that the has_many relationship exists. Will also test that the
344
+ # associated table has the required columns. Works with polymorphic
345
+ # associations.
346
+ #
347
+ # Options:
348
+ # * <tt>:through</tt> - association name for <tt>has_many :through</tt>
349
+ # * <tt>:dependent</tt> - tests that the association makes use of the dependent option.
350
+ #
351
+ # Example:
352
+ # should_have_many :friends
353
+ # should_have_many :enemies, :through => :friends
354
+ # should_have_many :enemies, :dependent => :destroy
355
+ #
356
+ def should_have_many(*associations)
357
+ through, dependent = get_options!(associations, :through, :dependent)
358
+ klass = model_class
359
+ associations.each do |association|
360
+ matcher = have_many(association).through(through).dependent(dependent)
361
+ should matcher.description do
362
+ assert_accepts(matcher, klass.new)
363
+ end
364
+ end
365
+ end
366
+
367
+ # Ensure that the has_one relationship exists. Will also test that the
368
+ # associated table has the required columns. Works with polymorphic
369
+ # associations.
370
+ #
371
+ # Options:
372
+ # * <tt>:dependent</tt> - tests that the association makes use of the dependent option.
373
+ #
374
+ # Example:
375
+ # should_have_one :god # unless hindu
376
+ #
377
+ def should_have_one(*associations)
378
+ dependent = get_options!(associations, :dependent)
379
+ klass = model_class
380
+ associations.each do |association|
381
+ matcher = have_one(association).dependent(dependent)
382
+ should matcher.description do
383
+ assert_accepts(matcher, klass.new)
384
+ end
385
+ end
386
+ end
387
+
388
+ # Ensures that the has_and_belongs_to_many relationship exists, and that the join
389
+ # table is in place.
390
+ #
391
+ # should_have_and_belong_to_many :posts, :cars
392
+ #
393
+ def should_have_and_belong_to_many(*associations)
394
+ get_options!(associations)
395
+ klass = model_class
396
+
397
+ associations.each do |association|
398
+ matcher = have_and_belong_to_many(association)
399
+ should matcher.description do
400
+ assert_accepts(matcher, klass.new)
401
+ end
402
+ end
403
+ end
404
+
405
+ # Ensure that the belongs_to relationship exists.
406
+ #
407
+ # should_belong_to :parent
408
+ #
409
+ def should_belong_to(*associations)
410
+ dependent = get_options!(associations, :dependent)
411
+ klass = model_class
412
+ associations.each do |association|
413
+ matcher = belong_to(association).dependent(dependent)
414
+ should matcher.description do
415
+ assert_accepts(matcher, klass.new)
416
+ end
417
+ end
418
+ end
419
+
420
+ # Ensure that the given class methods are defined on the model.
421
+ #
422
+ # should_have_class_methods :find, :destroy
423
+ #
424
+ def should_have_class_methods(*methods)
425
+ get_options!(methods)
426
+ klass = model_class
427
+ methods.each do |method|
428
+ should "respond to class method ##{method}" do
429
+ assert_respond_to klass, method, "#{klass.name} does not have class method #{method}"
430
+ end
431
+ end
432
+ end
433
+
434
+ # Ensure that the given instance methods are defined on the model.
435
+ #
436
+ # should_have_instance_methods :email, :name, :name=
437
+ #
438
+ def should_have_instance_methods(*methods)
439
+ get_options!(methods)
440
+ klass = model_class
441
+ methods.each do |method|
442
+ should "respond to instance method ##{method}" do
443
+ assert_respond_to klass.new, method, "#{klass.name} does not have instance method #{method}"
444
+ end
445
+ end
446
+ end
447
+
448
+ # Ensure that the given columns are defined on the models backing SQL table.
449
+ # Also aliased to should_have_index for readability.
450
+ # Takes the same options available in migrations:
451
+ # :type, :precision, :limit, :default, :null, and :scale
452
+ #
453
+ # Examples:
454
+ #
455
+ # should_have_db_columns :id, :email, :name, :created_at
456
+ #
457
+ # should_have_db_column :email, :type => "string", :limit => 255
458
+ # should_have_db_column :salary, :decimal, :precision => 15, :scale => 2
459
+ # should_have_db_column :admin, :default => false, :null => false
460
+ #
461
+ def should_have_db_columns(*columns)
462
+ column_type, precision, limit, default, null, scale, sql_type =
463
+ get_options!(columns, :type, :precision, :limit,
464
+ :default, :null, :scale, :sql_type)
465
+ klass = model_class
466
+ columns.each do |name|
467
+ matcher = have_db_column(name).
468
+ of_type(column_type).
469
+ with_options(:precision => precision, :limit => limit,
470
+ :default => default, :null => null,
471
+ :scale => scale, :sql_type => sql_type)
472
+ should matcher.description do
473
+ assert_accepts(matcher, klass.new)
474
+ end
475
+ end
476
+ end
477
+
478
+ alias_method :should_have_db_column, :should_have_db_columns
479
+
480
+ # Ensures that there are DB indices on the given columns or tuples of columns.
481
+ # Also aliased to should_have_index for readability
482
+ #
483
+ # Options:
484
+ # * <tt>:unique</tt> - whether or not the index has a unique
485
+ # constraint. Use <tt>true</tt> to explicitly test for a unique
486
+ # constraint. Use <tt>false</tt> to explicitly test for a non-unique
487
+ # constraint. Use <tt>nil</tt> if you don't care whether the index is
488
+ # unique or not. Default = <tt>nil</tt>
489
+ #
490
+ # Examples:
491
+ #
492
+ # should_have_indices :email, :name, [:commentable_type, :commentable_id]
493
+ # should_have_index :age
494
+ # should_have_index :ssn, :unique => true
495
+ #
496
+ def should_have_indices(*columns)
497
+ unique = get_options!(columns, :unique)
498
+ klass = model_class
499
+
500
+ columns.each do |column|
501
+ matcher = have_index(column).unique(unique)
502
+ should matcher.description do
503
+ assert_accepts(matcher, klass.new)
504
+ end
505
+ end
506
+ end
507
+
508
+ alias_method :should_have_index, :should_have_indices
509
+
510
+ # Ensures that the model cannot be saved if one of the attributes listed is not accepted.
511
+ #
512
+ # If an instance variable has been created in the setup named after the
513
+ # model being tested, then this method will use that. Otherwise, it will
514
+ # create a new instance to test against.
515
+ #
516
+ # Options:
517
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
518
+ # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.accepted')</tt>
519
+ #
520
+ # Example:
521
+ # should_validate_acceptance_of :eula
522
+ #
523
+ def should_validate_acceptance_of(*attributes)
524
+ message = get_options!(attributes, :message)
525
+ klass = model_class
526
+
527
+ attributes.each do |attribute|
528
+ matcher = validate_acceptance_of(attribute).with_message(message)
529
+ should matcher.description do
530
+ assert_accepts matcher, get_instance_of(klass)
531
+ end
532
+ end
533
+ end
534
+
535
+ # Deprecated. See should_validate_uniqueness_of
536
+ def should_require_acceptance_of(*attributes)
537
+ warn "[DEPRECATION] should_require_acceptance_of is deprecated. " <<
538
+ "Use should_validate_acceptance_of instead."
539
+ should_validate_acceptance_of(*attributes)
540
+ end
541
+
542
+ # Ensures that the model has a method named scope_name that returns a NamedScope object with the
543
+ # proxy options set to the options you supply. scope_name can be either a symbol, or a method
544
+ # call which will be evaled against the model. The eval'd method call has access to all the same
545
+ # instance variables that a should statement would.
546
+ #
547
+ # Options: Any of the options that the named scope would pass on to find.
548
+ #
549
+ # Example:
550
+ #
551
+ # should_have_named_scope :visible, :conditions => {:visible => true}
552
+ #
553
+ # Passes for
554
+ #
555
+ # named_scope :visible, :conditions => {:visible => true}
556
+ #
557
+ # Or for
558
+ #
559
+ # def self.visible
560
+ # scoped(:conditions => {:visible => true})
561
+ # end
562
+ #
563
+ # You can test lambdas or methods that return ActiveRecord#scoped calls:
564
+ #
565
+ # should_have_named_scope 'recent(5)', :limit => 5
566
+ # should_have_named_scope 'recent(1)', :limit => 1
567
+ #
568
+ # Passes for
569
+ # named_scope :recent, lambda {|c| {:limit => c}}
570
+ #
571
+ # Or for
572
+ #
573
+ # def self.recent(c)
574
+ # scoped(:limit => c)
575
+ # end
576
+ #
577
+ def should_have_named_scope(scope_call, find_options = nil)
578
+ klass = model_class
579
+ matcher = have_named_scope(scope_call).finding(find_options)
580
+ should matcher.description do
581
+ assert_accepts matcher.in_context(self), klass.new
582
+ end
583
+ end
584
+ end
585
+ end
586
+ end