ratnikov-shoulda 2.0.6.1

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 (103) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +12 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +146 -0
  4. data/Rakefile +72 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda/action_mailer/assertions.rb +38 -0
  7. data/lib/shoulda/action_mailer.rb +10 -0
  8. data/lib/shoulda/active_record/assertions.rb +90 -0
  9. data/lib/shoulda/active_record/macros.rb +748 -0
  10. data/lib/shoulda/active_record.rb +12 -0
  11. data/lib/shoulda/assertions.rb +47 -0
  12. data/lib/shoulda/context.rb +326 -0
  13. data/lib/shoulda/controller/formats/html.rb +199 -0
  14. data/lib/shoulda/controller/formats/xml.rb +168 -0
  15. data/lib/shoulda/controller/helpers.rb +62 -0
  16. data/lib/shoulda/controller/macros.rb +336 -0
  17. data/lib/shoulda/controller/resource_options.rb +233 -0
  18. data/lib/shoulda/controller.rb +30 -0
  19. data/lib/shoulda/helpers.rb +8 -0
  20. data/lib/shoulda/macros.rb +73 -0
  21. data/lib/shoulda/private_helpers.rb +20 -0
  22. data/lib/shoulda/proc_extensions.rb +14 -0
  23. data/lib/shoulda/rails.rb +19 -0
  24. data/lib/shoulda/tasks/list_tests.rake +24 -0
  25. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  26. data/lib/shoulda/tasks.rb +3 -0
  27. data/lib/shoulda.rb +21 -0
  28. data/rails/init.rb +1 -0
  29. data/test/README +36 -0
  30. data/test/fail_macros.rb +34 -0
  31. data/test/fixtures/addresses.yml +3 -0
  32. data/test/fixtures/friendships.yml +0 -0
  33. data/test/fixtures/posts.yml +5 -0
  34. data/test/fixtures/products.yml +0 -0
  35. data/test/fixtures/taggings.yml +0 -0
  36. data/test/fixtures/tags.yml +9 -0
  37. data/test/fixtures/users.yml +6 -0
  38. data/test/functional/posts_controller_test.rb +108 -0
  39. data/test/functional/users_controller_test.rb +38 -0
  40. data/test/other/context_test.rb +161 -0
  41. data/test/other/convert_to_should_syntax_test.rb +63 -0
  42. data/test/other/helpers_test.rb +183 -0
  43. data/test/other/private_helpers_test.rb +34 -0
  44. data/test/other/should_test.rb +266 -0
  45. data/test/rails_root/app/controllers/application.rb +25 -0
  46. data/test/rails_root/app/controllers/posts_controller.rb +86 -0
  47. data/test/rails_root/app/controllers/users_controller.rb +84 -0
  48. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  49. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  50. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  51. data/test/rails_root/app/models/address.rb +7 -0
  52. data/test/rails_root/app/models/flea.rb +3 -0
  53. data/test/rails_root/app/models/friendship.rb +4 -0
  54. data/test/rails_root/app/models/post.rb +12 -0
  55. data/test/rails_root/app/models/product.rb +12 -0
  56. data/test/rails_root/app/models/tag.rb +8 -0
  57. data/test/rails_root/app/models/tagging.rb +4 -0
  58. data/test/rails_root/app/models/user.rb +28 -0
  59. data/test/rails_root/app/views/layouts/posts.rhtml +19 -0
  60. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  61. data/test/rails_root/app/views/layouts/wide.html.erb +1 -0
  62. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  63. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  64. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  65. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  66. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  67. data/test/rails_root/app/views/users/index.rhtml +22 -0
  68. data/test/rails_root/app/views/users/new.rhtml +21 -0
  69. data/test/rails_root/app/views/users/show.rhtml +13 -0
  70. data/test/rails_root/config/boot.rb +109 -0
  71. data/test/rails_root/config/database.yml +4 -0
  72. data/test/rails_root/config/environment.rb +14 -0
  73. data/test/rails_root/config/environments/sqlite3.rb +0 -0
  74. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  75. data/test/rails_root/config/initializers/shoulda.rb +8 -0
  76. data/test/rails_root/config/routes.rb +6 -0
  77. data/test/rails_root/db/migrate/001_create_users.rb +19 -0
  78. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  79. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  80. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  81. data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
  82. data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
  83. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  84. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  85. data/test/rails_root/db/migrate/009_create_products.rb +17 -0
  86. data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
  87. data/test/rails_root/db/schema.rb +0 -0
  88. data/test/rails_root/public/404.html +30 -0
  89. data/test/rails_root/public/422.html +30 -0
  90. data/test/rails_root/public/500.html +30 -0
  91. data/test/rails_root/script/console +3 -0
  92. data/test/rails_root/script/generate +3 -0
  93. data/test/test_helper.rb +33 -0
  94. data/test/unit/address_test.rb +10 -0
  95. data/test/unit/dog_test.rb +10 -0
  96. data/test/unit/flea_test.rb +6 -0
  97. data/test/unit/friendship_test.rb +6 -0
  98. data/test/unit/post_test.rb +19 -0
  99. data/test/unit/product_test.rb +27 -0
  100. data/test/unit/tag_test.rb +14 -0
  101. data/test/unit/tagging_test.rb +6 -0
  102. data/test/unit/user_test.rb +60 -0
  103. metadata +189 -0
@@ -0,0 +1,233 @@
1
+ module Shoulda # :nodoc:
2
+ module Controller
3
+ # Formats tested by #should_be_restful. Defaults to [:html, :xml]
4
+ VALID_FORMATS = Dir.glob(File.join(File.dirname(__FILE__), 'formats', '*.rb')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc:
5
+ VALID_FORMATS.each {|f| require "shoulda/controller/formats/#{f}"}
6
+
7
+ # Actions tested by #should_be_restful
8
+ VALID_ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy] # :doc:
9
+
10
+ # A ResourceOptions object is passed into should_be_restful in order to configure the tests for your controller.
11
+ #
12
+ # Example:
13
+ # class UsersControllerTest < Test::Unit::TestCase
14
+ # fixtures :all
15
+ #
16
+ # def setup
17
+ # ...normal setup code...
18
+ # @user = User.find(:first)
19
+ # end
20
+ #
21
+ # should_be_restful do |resource|
22
+ # resource.identifier = :id
23
+ # resource.klass = User
24
+ # resource.object = :user
25
+ # resource.parent = []
26
+ # resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy]
27
+ # resource.formats = [:html, :xml]
28
+ #
29
+ # resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13}
30
+ # resource.update.params = { :name => "sue" }
31
+ #
32
+ # resource.create.redirect = "user_url(@user)"
33
+ # resource.update.redirect = "user_url(@user)"
34
+ # resource.destroy.redirect = "users_url"
35
+ #
36
+ # resource.create.flash = /created/i
37
+ # resource.update.flash = /updated/i
38
+ # resource.destroy.flash = /removed/i
39
+ # end
40
+ # end
41
+ #
42
+ # Whenever possible, the resource attributes will be set to sensible defaults.
43
+ #
44
+ class ResourceOptions
45
+ # Configuration options for the create, update, destroy actions under should_be_restful
46
+ class ActionOptions
47
+ # String evaled to get the target of the redirection.
48
+ # All of the instance variables set by the controller will be available to the
49
+ # evaled code.
50
+ #
51
+ # Example:
52
+ # resource.create.redirect = "user_url(@user.company, @user)"
53
+ #
54
+ # Defaults to a generated url based on the name of the controller, the action, and the resource.parents list.
55
+ attr_accessor :redirect
56
+
57
+ # String or Regexp describing a value expected in the flash. Will match against any flash key.
58
+ #
59
+ # Defaults:
60
+ # destroy:: /removed/
61
+ # create:: /created/
62
+ # update:: /updated/
63
+ attr_accessor :flash
64
+
65
+ # Hash describing the params that should be sent in with this action.
66
+ attr_accessor :params
67
+ end
68
+
69
+ # Configuration options for the denied actions under should_be_restful
70
+ #
71
+ # Example:
72
+ # context "The public" do
73
+ # setup do
74
+ # @request.session[:logged_in] = false
75
+ # end
76
+ #
77
+ # should_be_restful do |resource|
78
+ # resource.parent = :user
79
+ #
80
+ # resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy]
81
+ # resource.denied.flash = /get outta here/i
82
+ # resource.denied.redirect = 'new_session_url'
83
+ # end
84
+ # end
85
+ #
86
+ class DeniedOptions
87
+ # String evaled to get the target of the redirection.
88
+ # All of the instance variables set by the controller will be available to the
89
+ # evaled code.
90
+ #
91
+ # Example:
92
+ # resource.create.redirect = "user_url(@user.company, @user)"
93
+ attr_accessor :redirect
94
+
95
+ # String or Regexp describing a value expected in the flash. Will match against any flash key.
96
+ #
97
+ # Example:
98
+ # resource.create.flash = /created/
99
+ attr_accessor :flash
100
+
101
+ # Actions that should be denied (only used by resource.denied). <i>Note that these actions will
102
+ # only be tested if they are also listed in +resource.actions+</i>
103
+ # The special value of :all will deny all of the REST actions.
104
+ attr_accessor :actions
105
+ end
106
+
107
+ # Name of key in params that references the primary key.
108
+ # Will almost always be :id (default), unless you are using a plugin or have patched rails.
109
+ attr_accessor :identifier
110
+
111
+ # Name of the ActiveRecord class this resource is responsible for. Automatically determined from
112
+ # test class if not explicitly set. UserTest => "User"
113
+ attr_accessor :klass
114
+
115
+ # Name of the instantiated ActiveRecord object that should be used by some of the tests.
116
+ # Defaults to the underscored name of the AR class. CompanyManager => :company_manager
117
+ attr_accessor :object
118
+
119
+ # Name of the parent AR objects. Can be set as parent= or parents=, and can take either
120
+ # the name of the parent resource (if there's only one), or an array of names (if there's
121
+ # more than one).
122
+ #
123
+ # Example:
124
+ # # in the routes...
125
+ # map.resources :companies do
126
+ # map.resources :people do
127
+ # map.resources :limbs
128
+ # end
129
+ # end
130
+ #
131
+ # # in the tests...
132
+ # class PeopleControllerTest < Test::Unit::TestCase
133
+ # should_be_restful do |resource|
134
+ # resource.parent = :companies
135
+ # end
136
+ # end
137
+ #
138
+ # class LimbsControllerTest < Test::Unit::TestCase
139
+ # should_be_restful do |resource|
140
+ # resource.parents = [:companies, :people]
141
+ # end
142
+ # end
143
+ attr_accessor :parent
144
+ alias parents parent
145
+ alias parents= parent=
146
+
147
+ # Actions that should be tested. Must be a subset of VALID_ACTIONS (default).
148
+ # Tests for each actionw will only be generated if the action is listed here.
149
+ # The special value of :all will test all of the REST actions.
150
+ #
151
+ # Example (for a read-only controller):
152
+ # resource.actions = [:show, :index]
153
+ attr_accessor :actions
154
+
155
+ # Formats that should be tested. Must be a subset of VALID_FORMATS (default).
156
+ # Each action will be tested against the formats listed here. The special value
157
+ # of :all will test all of the supported formats.
158
+ #
159
+ # Example:
160
+ # resource.actions = [:html, :xml]
161
+ attr_accessor :formats
162
+
163
+ # ActionOptions object specifying options for the create action.
164
+ attr_accessor :create
165
+
166
+ # ActionOptions object specifying options for the update action.
167
+ attr_accessor :update
168
+
169
+ # ActionOptions object specifying options for the desrtoy action.
170
+ attr_accessor :destroy
171
+
172
+ # DeniedOptions object specifying which actions should return deny a request, and what should happen in that case.
173
+ attr_accessor :denied
174
+
175
+ def initialize # :nodoc:
176
+ @create = ActionOptions.new
177
+ @update = ActionOptions.new
178
+ @destroy = ActionOptions.new
179
+ @denied = DeniedOptions.new
180
+
181
+ @create.flash ||= /created/i
182
+ @update.flash ||= /updated/i
183
+ @destroy.flash ||= /removed/i
184
+ @denied.flash ||= /denied/i
185
+
186
+ @create.params ||= {}
187
+ @update.params ||= {}
188
+
189
+ @actions = VALID_ACTIONS
190
+ @formats = VALID_FORMATS
191
+ @denied.actions = []
192
+ end
193
+
194
+ def normalize!(target) # :nodoc:
195
+ @denied.actions = VALID_ACTIONS if @denied.actions == :all
196
+ @actions = VALID_ACTIONS if @actions == :all
197
+ @formats = VALID_FORMATS if @formats == :all
198
+
199
+ @denied.actions = @denied.actions.map(&:to_sym)
200
+ @actions = @actions.map(&:to_sym)
201
+ @formats = @formats.map(&:to_sym)
202
+
203
+ ensure_valid_members(@actions, VALID_ACTIONS, 'actions')
204
+ ensure_valid_members(@denied.actions, VALID_ACTIONS, 'denied.actions')
205
+ ensure_valid_members(@formats, VALID_FORMATS, 'formats')
206
+
207
+ @identifier ||= :id
208
+ @klass ||= target.name.gsub(/ControllerTest$/, '').singularize.constantize
209
+ @object ||= @klass.name.tableize.singularize
210
+ @parent ||= []
211
+ @parent = [@parent] unless @parent.is_a? Array
212
+
213
+ collection_helper = [@parent, @object.to_s.pluralize, 'url'].flatten.join('_')
214
+ collection_args = @parent.map {|n| "@#{object}.#{n}"}.join(', ')
215
+ @destroy.redirect ||= "#{collection_helper}(#{collection_args})"
216
+
217
+ member_helper = [@parent, @object, 'url'].flatten.join('_')
218
+ member_args = [@parent.map {|n| "@#{object}.#{n}"}, "@#{object}"].flatten.join(', ')
219
+ @create.redirect ||= "#{member_helper}(#{member_args})"
220
+ @update.redirect ||= "#{member_helper}(#{member_args})"
221
+ @denied.redirect ||= "new_session_url"
222
+ end
223
+
224
+ private
225
+
226
+ def ensure_valid_members(ary, valid_members, name) # :nodoc:
227
+ invalid = ary - valid_members
228
+ raise ArgumentError, "Unsupported #{name}: #{invalid.inspect}" unless invalid.empty?
229
+ end
230
+ end
231
+ end
232
+ end
233
+
@@ -0,0 +1,30 @@
1
+ require 'shoulda'
2
+ require 'shoulda/controller/helpers'
3
+ require 'shoulda/controller/resource_options'
4
+ require 'shoulda/controller/macros'
5
+
6
+ module Test # :nodoc: all
7
+ module Unit
8
+ class TestCase
9
+ extend Shoulda::Controller::Macros
10
+ include Shoulda::Controller::Helpers
11
+ Shoulda::Controller::VALID_FORMATS.each do |format|
12
+ include "Shoulda::Controller::#{format.to_s.upcase}".constantize
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ require 'shoulda/active_record/assertions'
19
+ require 'shoulda/action_mailer/assertions'
20
+
21
+ module ActionController #:nodoc: all
22
+ module Integration
23
+ class Session
24
+ include Shoulda::Assertions
25
+ include Shoulda::Helpers
26
+ include Shoulda::ActiveRecord::Assertions
27
+ include Shoulda::ActionMailer::Assertions
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ module Shoulda # :nodoc:
2
+ module Helpers
3
+ # Prints a message to stdout, tagged with the name of the calling method.
4
+ def report!(msg = "")
5
+ puts("#{caller.first}: #{msg}")
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,73 @@
1
+ require 'shoulda/private_helpers'
2
+
3
+ module Shoulda # :nodoc:
4
+ module Macros
5
+ # Macro that creates a test asserting a change between the return value
6
+ # of an expression that is run before and after the current setup block
7
+ # is run. This is similar to Active Support's <tt>assert_difference</tt>
8
+ # assertion, but supports more than just numeric values. See also
9
+ # should_not_change.
10
+ #
11
+ # Example:
12
+ #
13
+ # context "Creating a post" do
14
+ # setup { Post.create }
15
+ # should_change "Post.count", :by => 1
16
+ # end
17
+ #
18
+ # As shown in this example, the <tt>:by</tt> option expects a numeric
19
+ # difference between the before and after values of the expression. You
20
+ # may also specify <tt>:from</tt> and <tt>:to</tt> options:
21
+ #
22
+ # should_change "Post.count", :from => 0, :to => 1
23
+ # should_change "@post.title", :from => "old", :to => "new"
24
+ #
25
+ # Combinations of <tt>:by</tt>, <tt>:from</tt>, and <tt>:to</tt> are allowed:
26
+ #
27
+ # should_change "@post.title" # => assert the value changed in some way
28
+ # should_change "@post.title", :from => "old" # => assert the value changed to anything other than "old"
29
+ # should_change "@post.title", :to => "new" # => assert the value changed from anything other than "new"
30
+ def should_change(expression, options = {})
31
+ by, from, to = get_options!([options], :by, :from, :to)
32
+ stmt = "change #{expression.inspect}"
33
+ stmt << " from #{from.inspect}" if from
34
+ stmt << " to #{to.inspect}" if to
35
+ stmt << " by #{by.inspect}" if by
36
+
37
+ expression_eval = lambda { eval(expression) }
38
+ before = lambda { @_before_should_change = expression_eval.bind(self).call }
39
+ should stmt, :before => before do
40
+ old_value = @_before_should_change
41
+ new_value = expression_eval.bind(self).call
42
+ assert_operator from, :===, old_value, "#{expression.inspect} did not originally match #{from.inspect}" if from
43
+ assert_not_equal old_value, new_value, "#{expression.inspect} did not change" unless by == 0
44
+ assert_operator to, :===, new_value, "#{expression.inspect} was not changed to match #{to.inspect}" if to
45
+ assert_equal old_value + by, new_value if by
46
+ end
47
+ end
48
+
49
+ # Macro that creates a test asserting no change between the return value
50
+ # of an expression that is run before and after the current setup block
51
+ # is run. This is the logical opposite of should_change.
52
+ #
53
+ # Example:
54
+ #
55
+ # context "Updating a post" do
56
+ # setup { @post.update_attributes(:title => "new") }
57
+ # should_not_change "Post.count"
58
+ # end
59
+ def should_not_change(expression)
60
+ expression_eval = lambda { eval(expression) }
61
+ before = lambda { @_before_should_not_change = expression_eval.bind(self).call }
62
+ should "not change #{expression.inspect}", :before => before do
63
+ new_value = expression_eval.bind(self).call
64
+ assert_equal @_before_should_not_change, new_value, "#{expression.inspect} changed"
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ include Shoulda::Private
71
+ end
72
+ end
73
+
@@ -0,0 +1,20 @@
1
+ module Shoulda # :nodoc:
2
+ module Private # :nodoc:
3
+ # Returns the values for the entries in the args hash who's keys are listed in the wanted array.
4
+ # Will raise if there are keys in the args hash that aren't listed.
5
+ def get_options!(args, *wanted)
6
+ ret = []
7
+ opts = (args.last.is_a?(Hash) ? args.pop : {})
8
+ wanted.each {|w| ret << opts.delete(w)}
9
+ raise ArgumentError, "Unsupported options given: #{opts.keys.join(', ')}" unless opts.keys.empty?
10
+ return *ret
11
+ end
12
+
13
+ # Returns the model class constant, as determined by the test class name.
14
+ #
15
+ # class TestUser; model_class; end => User
16
+ def model_class
17
+ self.name.gsub(/Test$/, '').constantize
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # Stolen straight from ActiveSupport
2
+
3
+ class Proc #:nodoc:
4
+ def bind(object)
5
+ block, time = self, Time.now
6
+ (class << object; self end).class_eval do
7
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
8
+ define_method(method_name, &block)
9
+ method = instance_method(method_name)
10
+ remove_method(method_name)
11
+ method
12
+ end.bind(object)
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'shoulda'
4
+
5
+ require 'shoulda/active_record' if defined? ActiveRecord::Base
6
+ require 'shoulda/controller' if defined? ActionController::Base
7
+ require 'shoulda/action_mailer' if defined? ActionMailer::Base
8
+
9
+ if defined?(RAILS_ROOT)
10
+ # load in the 3rd party macros from vendorized plugins and gems
11
+ Dir[File.join(RAILS_ROOT, "vendor", "{plugins,gems}", "*", "shoulda_macros", "*.rb")].each do |macro_file_path|
12
+ require macro_file_path
13
+ end
14
+
15
+ # load in the local application specific macros
16
+ Dir[File.join(RAILS_ROOT, "test", "shoulda_macros", "*.rb")].each do |macro_file_path|
17
+ require macro_file_path
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ namespace :shoulda do
2
+ desc "List the names of the test methods in a specification like format"
3
+ task :list do
4
+ $LOAD_PATH.unshift("test")
5
+
6
+ require 'test/unit'
7
+ require 'rubygems'
8
+ require 'active_support'
9
+
10
+ # bug in test unit. Set to true to stop from running.
11
+ Test::Unit.run = true
12
+
13
+ test_files = Dir.glob(File.join('test', '**', '*_test.rb'))
14
+ test_files.each do |file|
15
+ load file
16
+ klass = File.basename(file, '.rb').classify.constantize
17
+
18
+ puts klass.name.gsub('Test', '')
19
+
20
+ test_methods = klass.instance_methods.grep(/^test/).map {|s| s.gsub(/^test: /, '')}.sort
21
+ test_methods.each {|m| puts " " + m }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ namespace :shoulda do
2
+ # From http://blog.internautdesign.com/2007/11/2/a-yaml_to_shoulda-rake-task
3
+ # David.Lowenfels@gmail.com
4
+ desc "Converts a YAML file (FILE=./path/to/yaml) into a Shoulda skeleton"
5
+ task :from_yaml do
6
+ require 'yaml'
7
+
8
+ def yaml_to_context(hash, indent = 0)
9
+ indent1 = ' ' * indent
10
+ indent2 = ' ' * (indent + 1)
11
+ hash.each_pair do |context, shoulds|
12
+ puts indent1 + "context \"#{context}\" do"
13
+ puts
14
+ shoulds.each do |should|
15
+ yaml_to_context( should, indent + 1 ) and next if should.is_a?( Hash )
16
+ puts indent2 + "should_eventually \"" + should.gsub(/^should +/,'') + "\" do"
17
+ puts indent2 + "end"
18
+ puts
19
+ end
20
+ puts indent1 + "end"
21
+ end
22
+ end
23
+
24
+ puts("Please pass in a FILE argument.") and exit unless ENV['FILE']
25
+
26
+ yaml_to_context( YAML.load_file( ENV['FILE'] ) )
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'tasks', '*.rake')].each do |f|
2
+ load f
3
+ end
data/lib/shoulda.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'shoulda/context'
2
+ require 'shoulda/proc_extensions'
3
+ require 'shoulda/assertions'
4
+ require 'shoulda/macros'
5
+ require 'shoulda/helpers'
6
+ require 'shoulda/rails' if defined? RAILS_ROOT
7
+
8
+ module Shoulda
9
+ VERSION = "2.0.6"
10
+ end
11
+
12
+ module Test # :nodoc: all
13
+ module Unit
14
+ class TestCase
15
+ extend Shoulda::ClassMethods
16
+ include Shoulda::Assertions
17
+ extend Shoulda::Macros
18
+ include Shoulda::Helpers
19
+ end
20
+ end
21
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'shoulda/rails'
data/test/README ADDED
@@ -0,0 +1,36 @@
1
+ The Shoulda test suite (in particular - the tests that test shoulda)
2
+
3
+ Quick overview:
4
+
5
+ The test directory contains the following files and subdirectories:
6
+
7
+ * rails_root - contains the stripped down rails application that the tests run against. The rails root contains:
8
+ ** the models, controllers, and views defined under app/
9
+ ** the sqlite3.rb environment file
10
+ ** a migration file for each model
11
+ ** a shoulda initializer that simulates loading the plugin but without relying on vendor/plugins
12
+ * fixtures - contain the sample DB data for each model
13
+ * functional - controller tests for each of the controllers under rails_root/app
14
+ * unit - model tests for each of the models under rails_root/app
15
+ * other - tests for the shoulda contexts, should statements, and assertions
16
+ * test_helper.rb - responsible for initializing the test environment
17
+ ** sets the rails_env to sqlite3
18
+ ** sets the rails_root
19
+ ** runs all the migrations against the in-memory sqlite3 db
20
+ ** adds some magic to load the right fixture files
21
+
22
+ In order to add a new model (or controller) to the test suite:
23
+
24
+ * add that model to rails_root/app/models
25
+ * add a migration for that model
26
+ * add a fixture file
27
+ * add a test for that file under test/units
28
+
29
+ Dependencies:
30
+
31
+ * Rails gem installed in the host system
32
+ * A working sqlite3 installation.
33
+
34
+ If you have problems running these tests, please notify the mailing list: shoulda@googlegroups.com
35
+
36
+ - Tammer Saleh <tsaleh@thoughtbot.com>
@@ -0,0 +1,34 @@
1
+ module Shoulda
2
+ class << self
3
+ attr_accessor :expected_exceptions
4
+ end
5
+
6
+ module ClassMethods
7
+ # Enables the core shoulda test suite to test for failure scenarios. For
8
+ # example, to ensure that a set of test macros should fail, do this:
9
+ #
10
+ # should_fail do
11
+ # should_require_attributes :comments
12
+ # should_protect_attributes :name
13
+ # end
14
+ def should_fail(&block)
15
+ context "should fail when trying to run:" do
16
+ Shoulda.expected_exceptions = [Test::Unit::AssertionFailedError]
17
+ yield block
18
+ Shoulda.expected_exceptions = nil
19
+ end
20
+ end
21
+ end
22
+
23
+ class Context
24
+ # alias_method_chain hack to allow the should_fail macro to work
25
+ def should_with_failure_scenario(name, options = {}, &block)
26
+ if Shoulda.expected_exceptions
27
+ expected_exceptions = Shoulda.expected_exceptions
28
+ failure_block = lambda { assert_raise(*expected_exceptions, &block.bind(self)) }
29
+ end
30
+ should_without_failure_scenario(name, options, &(failure_block || block))
31
+ end
32
+ alias_method_chain :should, :failure_scenario
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ first:
2
+ title: Home
3
+ addressable: first (User)
File without changes
@@ -0,0 +1,5 @@
1
+ first:
2
+ id: 1
3
+ title: My Cute Kitten!
4
+ body: This is totally a cute kitten
5
+ user_id: 1
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ first:
2
+ id: 1
3
+ name: Stuff
4
+ second:
5
+ id: 2
6
+ name: Rails
7
+ third:
8
+ id: 3
9
+ name: Nothing
@@ -0,0 +1,6 @@
1
+ first:
2
+ id: 1
3
+ name: Some dude
4
+ age: 2
5
+ email: none@none.com
6
+ ssn: 123456789