tpitale-shoulda 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +171 -0
- data/Rakefile +71 -0
- data/bin/convert_to_should_syntax +42 -0
- data/lib/shoulda.rb +11 -0
- data/lib/shoulda/action_controller.rb +26 -0
- data/lib/shoulda/action_controller/macros.rb +240 -0
- data/lib/shoulda/action_controller/matchers.rb +37 -0
- data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
- data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
- data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
- data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +74 -0
- data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
- data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
- data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +87 -0
- data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
- data/lib/shoulda/action_mailer.rb +10 -0
- data/lib/shoulda/action_mailer/assertions.rb +38 -0
- data/lib/shoulda/action_view.rb +10 -0
- data/lib/shoulda/action_view/macros.rb +61 -0
- data/lib/shoulda/active_record.rb +16 -0
- data/lib/shoulda/active_record/assertions.rb +69 -0
- data/lib/shoulda/active_record/helpers.rb +27 -0
- data/lib/shoulda/active_record/macros.rb +512 -0
- data/lib/shoulda/active_record/matchers.rb +43 -0
- data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
- data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
- data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
- data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
- data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
- data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
- data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +112 -0
- data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +128 -0
- data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
- data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
- data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +67 -0
- data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
- data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
- data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
- data/lib/shoulda/active_record/matchers/validation_matcher.rb +57 -0
- data/lib/shoulda/assertions.rb +71 -0
- data/lib/shoulda/autoload_macros.rb +46 -0
- data/lib/shoulda/context.rb +413 -0
- data/lib/shoulda/helpers.rb +8 -0
- data/lib/shoulda/macros.rb +133 -0
- data/lib/shoulda/minitest.rb +24 -0
- data/lib/shoulda/private_helpers.rb +13 -0
- data/lib/shoulda/proc_extensions.rb +14 -0
- data/lib/shoulda/rails.rb +13 -0
- data/lib/shoulda/rspec.rb +11 -0
- data/lib/shoulda/tasks.rb +3 -0
- data/lib/shoulda/tasks/list_tests.rake +29 -0
- data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
- data/lib/shoulda/test_unit.rb +22 -0
- data/rails/init.rb +7 -0
- data/test/README +36 -0
- data/test/fail_macros.rb +39 -0
- data/test/fixtures/addresses.yml +3 -0
- data/test/fixtures/friendships.yml +0 -0
- data/test/fixtures/posts.yml +5 -0
- data/test/fixtures/products.yml +0 -0
- data/test/fixtures/taggings.yml +0 -0
- data/test/fixtures/tags.yml +9 -0
- data/test/fixtures/users.yml +6 -0
- data/test/functional/posts_controller_test.rb +121 -0
- data/test/functional/users_controller_test.rb +19 -0
- data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +68 -0
- data/test/matchers/active_record/allow_value_matcher_test.rb +64 -0
- data/test/matchers/active_record/association_matcher_test.rb +263 -0
- data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +80 -0
- data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
- data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
- data/test/matchers/active_record/have_db_index_matcher_test.rb +91 -0
- data/test/matchers/active_record/have_named_scope_matcher_test.rb +65 -0
- data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
- data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
- data/test/matchers/active_record/validate_format_of_matcher_test.rb +39 -0
- data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
- data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
- data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
- data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
- data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
- data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
- data/test/matchers/controller/respond_with_content_type_matcher_test.rb +32 -0
- data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
- data/test/matchers/controller/route_matcher_test.rb +58 -0
- data/test/matchers/controller/set_session_matcher_test.rb +38 -0
- data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
- data/test/model_builder.rb +106 -0
- data/test/other/autoload_macro_test.rb +18 -0
- data/test/other/context_test.rb +203 -0
- data/test/other/convert_to_should_syntax_test.rb +63 -0
- data/test/other/helpers_test.rb +340 -0
- data/test/other/private_helpers_test.rb +32 -0
- data/test/other/should_test.rb +271 -0
- data/test/rails_root/app/controllers/application_controller.rb +25 -0
- data/test/rails_root/app/controllers/posts_controller.rb +87 -0
- data/test/rails_root/app/controllers/users_controller.rb +84 -0
- data/test/rails_root/app/helpers/application_helper.rb +3 -0
- data/test/rails_root/app/helpers/posts_helper.rb +2 -0
- data/test/rails_root/app/helpers/users_helper.rb +2 -0
- data/test/rails_root/app/models/address.rb +7 -0
- data/test/rails_root/app/models/flea.rb +3 -0
- data/test/rails_root/app/models/friendship.rb +4 -0
- data/test/rails_root/app/models/pets/cat.rb +7 -0
- data/test/rails_root/app/models/pets/dog.rb +10 -0
- data/test/rails_root/app/models/post.rb +12 -0
- data/test/rails_root/app/models/product.rb +12 -0
- data/test/rails_root/app/models/profile.rb +2 -0
- data/test/rails_root/app/models/registration.rb +2 -0
- data/test/rails_root/app/models/tag.rb +8 -0
- data/test/rails_root/app/models/tagging.rb +4 -0
- data/test/rails_root/app/models/treat.rb +3 -0
- data/test/rails_root/app/models/user.rb +32 -0
- data/test/rails_root/app/views/layouts/posts.rhtml +19 -0
- data/test/rails_root/app/views/layouts/users.rhtml +17 -0
- data/test/rails_root/app/views/layouts/wide.html.erb +1 -0
- data/test/rails_root/app/views/posts/edit.rhtml +27 -0
- data/test/rails_root/app/views/posts/index.rhtml +25 -0
- data/test/rails_root/app/views/posts/new.rhtml +26 -0
- data/test/rails_root/app/views/posts/show.rhtml +18 -0
- data/test/rails_root/app/views/users/edit.rhtml +22 -0
- data/test/rails_root/app/views/users/index.rhtml +22 -0
- data/test/rails_root/app/views/users/new.rhtml +21 -0
- data/test/rails_root/app/views/users/show.rhtml +13 -0
- data/test/rails_root/config/boot.rb +110 -0
- data/test/rails_root/config/database.yml +4 -0
- data/test/rails_root/config/environment.rb +18 -0
- data/test/rails_root/config/environments/test.rb +0 -0
- data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
- data/test/rails_root/config/initializers/shoulda.rb +8 -0
- data/test/rails_root/config/routes.rb +6 -0
- data/test/rails_root/db/migrate/001_create_users.rb +19 -0
- data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
- data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
- data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
- data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
- data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
- data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
- data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
- data/test/rails_root/db/migrate/009_create_products.rb +17 -0
- data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
- data/test/rails_root/db/migrate/011_create_treats.rb +12 -0
- data/test/rails_root/db/migrate/20090506203502_create_profiles.rb +12 -0
- data/test/rails_root/db/migrate/20090506203536_create_registrations.rb +14 -0
- data/test/rails_root/db/migrate/20090513104502_create_cats.rb +12 -0
- data/test/rails_root/db/schema.rb +0 -0
- data/test/rails_root/log/test.log +1 -0
- data/test/rails_root/public/404.html +30 -0
- data/test/rails_root/public/422.html +30 -0
- data/test/rails_root/public/500.html +30 -0
- data/test/rails_root/script/console +3 -0
- data/test/rails_root/script/generate +3 -0
- data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
- data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
- data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
- data/test/rspec_test.rb +207 -0
- data/test/test_helper.rb +28 -0
- data/test/unit/address_test.rb +10 -0
- data/test/unit/cat_test.rb +7 -0
- data/test/unit/dog_test.rb +9 -0
- data/test/unit/flea_test.rb +6 -0
- data/test/unit/friendship_test.rb +6 -0
- data/test/unit/post_test.rb +19 -0
- data/test/unit/product_test.rb +23 -0
- data/test/unit/tag_test.rb +15 -0
- data/test/unit/tagging_test.rb +6 -0
- data/test/unit/user_test.rb +80 -0
- metadata +226 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
We're using GitHub[http://github.com/thoughtbot/shoulda/tree/master], and we've been getting any combination of github pull requests, tickets, patches, emails, etc. We need to normalize this workflow to make sure we don't miss any fixes.
|
2
|
+
|
3
|
+
* Make sure you're accessing the source from the {official repository}[http://github.com/thoughtbot/shoulda/tree/master].
|
4
|
+
* We prefer git branches over patches, but we can take either.
|
5
|
+
* If you're using git, please make a branch for each separate contribution. We can cherry pick your commits, but pulling from a branch is easier.
|
6
|
+
* If you're submitting patches, please cut each fix or feature into a separate patch.
|
7
|
+
* There should be an issue[http://github.com/thoughtbot/shoulda/issues] for any submission. If you've found a bug and want to fix it, open a new ticket at the same time.
|
8
|
+
* Please <b>don't send pull requests</b> Just update the issue with the url for your fix (or attach the patch) when it's ready. The github pull requests pretty much get dropped on the floor until someone with commit rights notices them in the mailbox.
|
9
|
+
* Contributions without tests won't be accepted. The file <tt>/test/README</tt> explains the testing system pretty thoroughly.
|
10
|
+
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2007, Tammer Saleh, Thoughtbot, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
= Shoulda - Making tests easy on the fingers and eyes
|
2
|
+
|
3
|
+
Shoulda makes it easy to write elegant, understandable, and maintainable tests. Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework. It's fully compatible with your existing tests, and requires no retooling to use.
|
4
|
+
|
5
|
+
Helpers:: #context and #should give you RSpec like test blocks.
|
6
|
+
In addition, you get nested contexts and a much more readable syntax.
|
7
|
+
Macros:: Generate hundreds of lines of Controller and ActiveRecord tests with these powerful macros.
|
8
|
+
They get you started quickly, and can help you ensure that your application is conforming to best practices.
|
9
|
+
Assertions:: Many common rails testing idioms have been distilled into a set of useful assertions.
|
10
|
+
Matchers:: Rspec-compatible matchers providing the same tests as Shoulda macros.
|
11
|
+
|
12
|
+
= Usage
|
13
|
+
|
14
|
+
=== Context Helpers (Shoulda::Context)
|
15
|
+
|
16
|
+
Stop killing your fingers with all of those underscores... Name your tests with plain sentences!
|
17
|
+
|
18
|
+
class UserTest < Test::Unit::TestCase
|
19
|
+
context "A User instance" do
|
20
|
+
setup do
|
21
|
+
@user = User.find(:first)
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return its full name" do
|
25
|
+
assert_equal 'John Doe', @user.full_name
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with a profile" do
|
29
|
+
setup do
|
30
|
+
@user.profile = Profile.find(:first)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "return true when sent #has_profile?" do
|
34
|
+
assert @user.has_profile?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Produces the following test methods:
|
41
|
+
|
42
|
+
"test: A User instance should return its full name."
|
43
|
+
"test: A User instance with a profile should return true when sent #has_profile?."
|
44
|
+
|
45
|
+
So readable!
|
46
|
+
|
47
|
+
=== ActiveRecord Tests (Shoulda::ActiveRecord::Macros)
|
48
|
+
|
49
|
+
Quick macro tests for your ActiveRecord associations and validations:
|
50
|
+
|
51
|
+
class PostTest < Test::Unit::TestCase
|
52
|
+
fixtures :all
|
53
|
+
|
54
|
+
should_belong_to :user
|
55
|
+
should_have_many :tags, :through => :taggings
|
56
|
+
|
57
|
+
should_validate_uniqueness_of :title
|
58
|
+
should_validate_presence_of :body, :message => /wtf/
|
59
|
+
should_validate_presence_of :title
|
60
|
+
should_validate_numericality_of :user_id
|
61
|
+
end
|
62
|
+
|
63
|
+
class UserTest < Test::Unit::TestCase
|
64
|
+
should_have_many :posts
|
65
|
+
|
66
|
+
should_not_allow_values_for :email, "blah", "b lah"
|
67
|
+
should_allow_values_for :email, "a@b.com", "asdf@asdf.com"
|
68
|
+
should_ensure_length_in_range :email, 1..100
|
69
|
+
should_ensure_value_in_range :age, 1..100
|
70
|
+
should_not_allow_mass_assignment_of :password
|
71
|
+
end
|
72
|
+
|
73
|
+
Makes TDD so much easier.
|
74
|
+
|
75
|
+
=== Controller Tests (Shoulda::Controller::Macros)
|
76
|
+
|
77
|
+
Macros to test the most common controller patterns...
|
78
|
+
|
79
|
+
class PostsControllerTest < ActionController::TestCase
|
80
|
+
context "on GET to :show for first record" do
|
81
|
+
setup do
|
82
|
+
get :show, :id => 1
|
83
|
+
end
|
84
|
+
|
85
|
+
should_assign_to :user
|
86
|
+
should_respond_with :success
|
87
|
+
should_render_template :show
|
88
|
+
should_not_set_the_flash
|
89
|
+
|
90
|
+
should "do something else really cool" do
|
91
|
+
assert_equal 1, assigns(:user).id
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
=== Helpful Assertions (Shoulda::Assertions)
|
97
|
+
|
98
|
+
More to come here, but have fun with what's there.
|
99
|
+
|
100
|
+
assert_same_elements([:a, :b, :c], [:c, :a, :b])
|
101
|
+
assert_contains(['a', '1'], /\d/)
|
102
|
+
assert_contains(['a', '1'], 'a')
|
103
|
+
|
104
|
+
=== 3rd Party and Application Specific Macros
|
105
|
+
|
106
|
+
Any *.rb file under RAILS_ROOT/test/shoulda_macros/ or vendor/(plugins|gems)/gem_name/shoulda_macros/ will be automatically required when you run your tests. This allows you to distribute macros with your plugins, or to organize the macros inside your application. Remember to add your macro to Test::Unit::TestCase in the macro file:
|
107
|
+
|
108
|
+
# test/shoulda_macros/security.rb
|
109
|
+
class Test::Unit::TestCase
|
110
|
+
def self.should_be_denied(opts = {})
|
111
|
+
should_set_the_flash_to(opts[:flash] || /Please log in/i)
|
112
|
+
should_redirect_to(opts[:redirect] || 'login_url')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
= Rails Installation (Test::Unit)
|
117
|
+
|
118
|
+
=== As a Gem
|
119
|
+
|
120
|
+
Use this if you prefer to use versioned releases of shoulda. Specify the gem dependency in your config/environment.rb file:
|
121
|
+
|
122
|
+
Rails::Initializer.run do |config|
|
123
|
+
config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com"
|
124
|
+
end
|
125
|
+
|
126
|
+
Then:
|
127
|
+
|
128
|
+
$ rake gems:install
|
129
|
+
$ rake gems:unpack
|
130
|
+
|
131
|
+
=== As a Plugin
|
132
|
+
|
133
|
+
Use this if you prefer to use the edge version of shoulda:
|
134
|
+
|
135
|
+
$ script/plugin install git://github.com/thoughtbot/shoulda.git
|
136
|
+
|
137
|
+
=== As a Plugin (using git submodules)
|
138
|
+
|
139
|
+
Use this if you prefer the idea of being able to easily switch between using edge or a tagged version of shoulda:
|
140
|
+
|
141
|
+
$ git submodule add git://github.com/thoughtbot/shoulda.git vendor/plugins/shoulda
|
142
|
+
|
143
|
+
= Rails Installation (RSpec)
|
144
|
+
|
145
|
+
If you're using Shoulda with RSpec, we recommend that you add config.gem lines
|
146
|
+
for RSpec and Shoulda in your config/environment/test.rb file, but do not ask
|
147
|
+
Rails to load the RSpec and Shoulda libraries:
|
148
|
+
|
149
|
+
config.gem 'rspec', :lib => false
|
150
|
+
config.gem 'rspec-rails', :lib => false
|
151
|
+
config.gem 'thoughtbot-shoulda',
|
152
|
+
:lib => false,
|
153
|
+
:source => 'http://gems.github.com'
|
154
|
+
|
155
|
+
Then require shoulda from your spec/spec_helper.rb file, before Spec::Runner is
|
156
|
+
configured:
|
157
|
+
|
158
|
+
# requires for RSpec
|
159
|
+
require 'shoulda'
|
160
|
+
Spec::Runner.configure do |config|
|
161
|
+
# ...
|
162
|
+
|
163
|
+
You should not need to require anything besides the top-level shoulda library.
|
164
|
+
|
165
|
+
= Credits
|
166
|
+
|
167
|
+
Shoulda is maintained by {Tammer Saleh}[mailto:tsaleh@thoughtbot.com], and is funded by Thoughtbot[http://www.thoughtbot.com], inc.
|
168
|
+
|
169
|
+
= License
|
170
|
+
|
171
|
+
Shoulda is Copyright © 2006-2008 Tammer Saleh, Thoughtbot. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift("lib")
|
7
|
+
require 'shoulda'
|
8
|
+
load 'tasks/shoulda.rake'
|
9
|
+
|
10
|
+
# Test::Unit::UI::VERBOSE
|
11
|
+
test_files_pattern = 'test/{unit,functional,other,matchers}/**/*_test.rb'
|
12
|
+
Rake::TestTask.new do |t|
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.pattern = test_files_pattern
|
15
|
+
t.verbose = false
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::RDocTask.new { |rdoc|
|
19
|
+
rdoc.rdoc_dir = 'doc'
|
20
|
+
rdoc.title = "Shoulda -- Making tests easy on the fingers and eyes"
|
21
|
+
rdoc.options << '--line-numbers'
|
22
|
+
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
23
|
+
rdoc.rdoc_files.include('README.rdoc', 'CONTRIBUTION_GUIDELINES.rdoc', 'lib/**/*.rb')
|
24
|
+
}
|
25
|
+
|
26
|
+
desc "Run code-coverage analysis using rcov"
|
27
|
+
task :coverage do
|
28
|
+
rm_rf "coverage"
|
29
|
+
files = Dir[test_files_pattern]
|
30
|
+
system "rcov --rails --sort coverage -Ilib #{files.join(' ')}"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Update documentation on website'
|
34
|
+
task :sync_docs => 'rdoc' do
|
35
|
+
`rsync -ave ssh doc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/shoulda`
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'Default: run tests.'
|
39
|
+
task :default => ['test']
|
40
|
+
|
41
|
+
spec = Gem::Specification.new do |s|
|
42
|
+
s.name = "tpitale-shoulda"
|
43
|
+
s.version = Shoulda::VERSION
|
44
|
+
s.summary = "Making tests easy on the fingers and eyes"
|
45
|
+
s.homepage = "http://thoughtbot.com/projects/shoulda"
|
46
|
+
|
47
|
+
s.files = FileList["[A-Z]*", "{bin,lib,rails,test}/**/*"]
|
48
|
+
s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
|
49
|
+
|
50
|
+
s.has_rdoc = true
|
51
|
+
s.extra_rdoc_files = ["README.rdoc", "CONTRIBUTION_GUIDELINES.rdoc"]
|
52
|
+
s.rdoc_options = ["--line-numbers", "--main", "README.rdoc"]
|
53
|
+
|
54
|
+
s.authors = ["Tammer Saleh"]
|
55
|
+
s.email = "tsaleh@thoughtbot.com"
|
56
|
+
end
|
57
|
+
|
58
|
+
Rake::GemPackageTask.new spec do |pkg|
|
59
|
+
pkg.need_tar = true
|
60
|
+
pkg.need_zip = true
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "Clean files generated by rake tasks"
|
64
|
+
task :clobber => [:clobber_rdoc, :clobber_package]
|
65
|
+
|
66
|
+
desc "Generate a gemspec file for GitHub"
|
67
|
+
task :gemspec do
|
68
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
69
|
+
f.write spec.to_ruby
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
TMP = Dir::tmpdir
|
6
|
+
|
7
|
+
def usage(msg = nil)
|
8
|
+
puts "Error: #{msg}" if msg
|
9
|
+
puts if msg
|
10
|
+
puts "Usage: #{File.basename(__FILE__)} normal_test_file.rb"
|
11
|
+
puts
|
12
|
+
puts "Will convert an existing test file with names like "
|
13
|
+
puts
|
14
|
+
puts " def test_should_do_stuff"
|
15
|
+
puts " ..."
|
16
|
+
puts " end"
|
17
|
+
puts
|
18
|
+
puts "to one using the new syntax: "
|
19
|
+
puts
|
20
|
+
puts " should \"be super cool\" do"
|
21
|
+
puts " ..."
|
22
|
+
puts " end"
|
23
|
+
puts
|
24
|
+
puts "A copy of the old file will be left under #{TMP} in case\nthis script just seriously screws up"
|
25
|
+
puts
|
26
|
+
exit (msg ? 2 : 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
usage("Wrong number of arguments.") unless ARGV.size == 1
|
30
|
+
usage("Temp directory '#{TMP}' is not valid. Set TMPDIR environment variable to a writeable directory.") unless File.directory?(TMP) && File.writable?(TMP)
|
31
|
+
|
32
|
+
file = ARGV.shift
|
33
|
+
tmpfile = File.join(TMP, File.basename(file))
|
34
|
+
usage("File '#{file}' doesn't exist") unless File.exists?(file)
|
35
|
+
|
36
|
+
FileUtils.cp(file, tmpfile)
|
37
|
+
contents = File.read(tmpfile)
|
38
|
+
contents.gsub!(/def test_should_(\S+)/) {|line| "should \"#{$1.tr('_', ' ')}\" do"}
|
39
|
+
contents.gsub!(/def test_(\S+)/) {|line| "should \"RENAME ME: test #{$1.tr('_', ' ')}\" do"}
|
40
|
+
File.open(file, 'w') { |f| f.write(contents) }
|
41
|
+
|
42
|
+
puts "File '#{file}' has been converted to 'should' syntax. Old version has been stored in '#{tmpfile}'"
|
data/lib/shoulda.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'shoulda'
|
2
|
+
require 'shoulda/action_controller/matchers'
|
3
|
+
require 'shoulda/action_controller/macros'
|
4
|
+
|
5
|
+
module Test # :nodoc: all
|
6
|
+
module Unit
|
7
|
+
class TestCase
|
8
|
+
include Shoulda::ActionController::Matchers
|
9
|
+
extend Shoulda::ActionController::Macros
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'shoulda/active_record/assertions'
|
15
|
+
require 'shoulda/action_mailer/assertions'
|
16
|
+
|
17
|
+
module ActionController #:nodoc: all
|
18
|
+
module Integration
|
19
|
+
class Session
|
20
|
+
include Shoulda::Assertions
|
21
|
+
include Shoulda::Helpers
|
22
|
+
include Shoulda::ActiveRecord::Assertions
|
23
|
+
include Shoulda::ActionMailer::Assertions
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
module Shoulda # :nodoc:
|
2
|
+
module ActionController # :nodoc:
|
3
|
+
# = Macro test helpers for your controllers
|
4
|
+
#
|
5
|
+
# By using the macro helpers you can quickly and easily create concise and easy to read test suites.
|
6
|
+
#
|
7
|
+
# This code segment:
|
8
|
+
# context "on GET to :show for first record" do
|
9
|
+
# setup do
|
10
|
+
# get :show, :id => 1
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# should_assign_to :user
|
14
|
+
# should_respond_with :success
|
15
|
+
# should_render_template :show
|
16
|
+
# should_not_set_the_flash
|
17
|
+
#
|
18
|
+
# should "do something else really cool" do
|
19
|
+
# assert_equal 1, assigns(:user).id
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Would produce 5 tests for the +show+ action
|
24
|
+
module Macros
|
25
|
+
include Matchers
|
26
|
+
|
27
|
+
# Macro that creates a test asserting that the flash contains the given
|
28
|
+
# value. Expects a +String+ or +Regexp+.
|
29
|
+
#
|
30
|
+
# If the argument is +nil+, it will assert that the flash is not set.
|
31
|
+
# This behavior is deprecated.
|
32
|
+
#
|
33
|
+
# Example:
|
34
|
+
#
|
35
|
+
# should_set_the_flash_to "Thank you for placing this order."
|
36
|
+
# should_set_the_flash_to /created/i
|
37
|
+
def should_set_the_flash_to(val)
|
38
|
+
if val
|
39
|
+
matcher = set_the_flash.to(val)
|
40
|
+
should matcher.description do
|
41
|
+
assert_accepts matcher, @controller
|
42
|
+
end
|
43
|
+
else
|
44
|
+
warn "[DEPRECATION] should_set_the_flash_to nil is deprecated. " <<
|
45
|
+
"Use should_not_set_the_flash instead."
|
46
|
+
should_not_set_the_flash
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Macro that creates a test asserting that the flash is empty.
|
51
|
+
def should_not_set_the_flash
|
52
|
+
matcher = set_the_flash
|
53
|
+
should "not #{matcher.description}" do
|
54
|
+
assert_rejects matcher, @controller
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Macro that creates a test asserting that filter_parameter_logging
|
59
|
+
# is set for the specified keys
|
60
|
+
#
|
61
|
+
# Example:
|
62
|
+
#
|
63
|
+
# should_filter_params :password, :ssn
|
64
|
+
def should_filter_params(*keys)
|
65
|
+
keys.each do |key|
|
66
|
+
matcher = filter_param(key)
|
67
|
+
should matcher.description do
|
68
|
+
assert_accepts matcher, @controller
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Macro that creates a test asserting that the controller assigned to
|
74
|
+
# each of the named instance variable(s).
|
75
|
+
#
|
76
|
+
# Options:
|
77
|
+
# * <tt>:class</tt> - The expected class of the instance variable being checked.
|
78
|
+
#
|
79
|
+
# If a block is passed, the assigned variable is expected to be equal to
|
80
|
+
# the return value of that block.
|
81
|
+
#
|
82
|
+
# Example:
|
83
|
+
#
|
84
|
+
# should_assign_to :user, :posts
|
85
|
+
# should_assign_to :user, :class => User
|
86
|
+
# should_assign_to(:user) { @user }
|
87
|
+
def should_assign_to(*names, &block)
|
88
|
+
klass = get_options!(names, :class)
|
89
|
+
names.each do |name|
|
90
|
+
matcher = assign_to(name).with_kind_of(klass)
|
91
|
+
should matcher.description do
|
92
|
+
if block
|
93
|
+
expected_value = instance_eval(&block)
|
94
|
+
matcher = matcher.with(expected_value)
|
95
|
+
end
|
96
|
+
|
97
|
+
assert_accepts matcher, @controller
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Macro that creates a test asserting that the controller did not assign to
|
103
|
+
# any of the named instance variable(s).
|
104
|
+
#
|
105
|
+
# Example:
|
106
|
+
#
|
107
|
+
# should_not_assign_to :user, :posts
|
108
|
+
def should_not_assign_to(*names)
|
109
|
+
names.each do |name|
|
110
|
+
matcher = assign_to(name)
|
111
|
+
should "not #{matcher.description}" do
|
112
|
+
assert_rejects matcher, @controller
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Macro that creates a test asserting that the controller responded with a 'response' status code.
|
118
|
+
# Example:
|
119
|
+
#
|
120
|
+
# should_respond_with :success
|
121
|
+
def should_respond_with(response)
|
122
|
+
should "respond with #{response}" do
|
123
|
+
matcher = respond_with(response)
|
124
|
+
assert_accepts matcher, @controller
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Macro that creates a test asserting that the response content type was 'content_type'.
|
129
|
+
# Example:
|
130
|
+
#
|
131
|
+
# should_respond_with_content_type 'application/rss+xml'
|
132
|
+
# should_respond_with_content_type :rss
|
133
|
+
# should_respond_with_content_type /rss/
|
134
|
+
def should_respond_with_content_type(content_type)
|
135
|
+
matcher = respond_with_content_type(content_type)
|
136
|
+
should matcher.description do
|
137
|
+
assert_accepts matcher, @controller
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Macro that creates a test asserting that a value returned from the
|
142
|
+
# session is correct. Expects the session key as a parameter, and a block
|
143
|
+
# that returns the expected value.
|
144
|
+
#
|
145
|
+
# Example:
|
146
|
+
#
|
147
|
+
# should_set_session(:user_id) { @user.id }
|
148
|
+
# should_set_session(:message) { "Free stuff" }
|
149
|
+
def should_set_session(key, &block)
|
150
|
+
matcher = set_session(key)
|
151
|
+
should matcher.description do
|
152
|
+
expected_value = instance_eval(&block)
|
153
|
+
matcher = matcher.to(expected_value)
|
154
|
+
assert_accepts matcher, @controller
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Macro that creates a test asserting that the controller rendered the given template.
|
159
|
+
# Example:
|
160
|
+
#
|
161
|
+
# should_render_template :new
|
162
|
+
def should_render_template(template)
|
163
|
+
should "render template #{template.inspect}" do
|
164
|
+
assert_template template.to_s
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Macro that creates a test asserting that the controller rendered with the given layout.
|
169
|
+
# Example:
|
170
|
+
#
|
171
|
+
# should_render_with_layout 'special'
|
172
|
+
def should_render_with_layout(expected_layout = 'application')
|
173
|
+
matcher = render_with_layout(expected_layout)
|
174
|
+
if expected_layout
|
175
|
+
should matcher.description do
|
176
|
+
assert_accepts matcher, @controller
|
177
|
+
end
|
178
|
+
else
|
179
|
+
should "render without layout" do
|
180
|
+
assert_rejects matcher, @controller
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Macro that creates a test asserting that the controller rendered without a layout.
|
186
|
+
# Same as @should_render_with_layout false@
|
187
|
+
def should_render_without_layout
|
188
|
+
should_render_with_layout nil
|
189
|
+
end
|
190
|
+
|
191
|
+
# Macro that creates a test asserting that the controller returned a
|
192
|
+
# redirect to the given path. The passed description will be used when
|
193
|
+
# generating a test name. Expects a block that returns the expected path
|
194
|
+
# for the redirect.
|
195
|
+
#
|
196
|
+
# Example:
|
197
|
+
#
|
198
|
+
# should_redirect_to("the user's profile") { user_url(@user) }
|
199
|
+
def should_redirect_to(description, &block)
|
200
|
+
should "redirect to #{description}" do
|
201
|
+
expected_url = instance_eval(&block)
|
202
|
+
assert_redirected_to expected_url
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Macro that creates a routing test. It tries to use the given HTTP
|
207
|
+
# +method+ on the given +path+, and asserts that it routes to the
|
208
|
+
# given +options+.
|
209
|
+
#
|
210
|
+
# If you don't specify a :controller, it will try to guess the controller
|
211
|
+
# based on the current test.
|
212
|
+
#
|
213
|
+
# +to_param+ is called on the +options+ given.
|
214
|
+
#
|
215
|
+
# Examples:
|
216
|
+
#
|
217
|
+
# should_route :get, "/posts", :controller => :posts, :action => :index
|
218
|
+
# should_route :get, "/posts/new", :action => :new
|
219
|
+
# should_route :post, "/posts", :action => :create
|
220
|
+
# should_route :get, "/posts/1", :action => :show, :id => 1
|
221
|
+
# should_route :edit, "/posts/1", :action => :show, :id => 1
|
222
|
+
# should_route :put, "/posts/1", :action => :update, :id => 1
|
223
|
+
# should_route :delete, "/posts/1", :action => :destroy, :id => 1
|
224
|
+
# should_route :get, "/users/1/posts/1",
|
225
|
+
# :action => :show, :id => 1, :user_id => 1
|
226
|
+
#
|
227
|
+
def should_route(method, path, options)
|
228
|
+
unless options[:controller]
|
229
|
+
options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
|
230
|
+
end
|
231
|
+
|
232
|
+
matcher = route(method, path).to(options)
|
233
|
+
|
234
|
+
should matcher.description do
|
235
|
+
assert_accepts matcher.in_context(self), self
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|