jcnetdev-shoulda 4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +12 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +123 -0
  4. data/Rakefile +32 -0
  5. data/bin/convert_to_should_syntax +40 -0
  6. data/init.rb +1 -0
  7. data/lib/shoulda.rb +43 -0
  8. data/lib/shoulda/active_record_helpers.rb +670 -0
  9. data/lib/shoulda/color.rb +77 -0
  10. data/lib/shoulda/controller_tests/controller_tests.rb +467 -0
  11. data/lib/shoulda/controller_tests/formats/html.rb +201 -0
  12. data/lib/shoulda/controller_tests/formats/xml.rb +170 -0
  13. data/lib/shoulda/gem/proc_extensions.rb +14 -0
  14. data/lib/shoulda/gem/shoulda.rb +246 -0
  15. data/lib/shoulda/general.rb +118 -0
  16. data/lib/shoulda/private_helpers.rb +22 -0
  17. data/rails/init.rb +1 -0
  18. data/shoulda.gemspec +109 -0
  19. data/tasks/list_tests.rake +23 -0
  20. data/tasks/yaml_to_shoulda.rake +28 -0
  21. data/test/README +36 -0
  22. data/test/fixtures/addresses.yml +3 -0
  23. data/test/fixtures/posts.yml +5 -0
  24. data/test/fixtures/taggings.yml +0 -0
  25. data/test/fixtures/tags.yml +9 -0
  26. data/test/fixtures/users.yml +6 -0
  27. data/test/functional/posts_controller_test.rb +43 -0
  28. data/test/functional/users_controller_test.rb +36 -0
  29. data/test/other/context_test.rb +115 -0
  30. data/test/other/helpers_test.rb +80 -0
  31. data/test/other/private_helpers_test.rb +26 -0
  32. data/test/rails_root/app/controllers/application.rb +25 -0
  33. data/test/rails_root/app/controllers/posts_controller.rb +78 -0
  34. data/test/rails_root/app/controllers/users_controller.rb +81 -0
  35. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  36. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  37. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  38. data/test/rails_root/app/models/address.rb +4 -0
  39. data/test/rails_root/app/models/dog.rb +4 -0
  40. data/test/rails_root/app/models/flea.rb +3 -0
  41. data/test/rails_root/app/models/post.rb +11 -0
  42. data/test/rails_root/app/models/tag.rb +8 -0
  43. data/test/rails_root/app/models/tagging.rb +4 -0
  44. data/test/rails_root/app/models/user.rb +17 -0
  45. data/test/rails_root/app/views/layouts/posts.rhtml +17 -0
  46. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  47. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  48. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  49. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  50. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  51. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  52. data/test/rails_root/app/views/users/index.rhtml +22 -0
  53. data/test/rails_root/app/views/users/new.rhtml +21 -0
  54. data/test/rails_root/app/views/users/show.rhtml +13 -0
  55. data/test/rails_root/config/boot.rb +109 -0
  56. data/test/rails_root/config/database.yml +4 -0
  57. data/test/rails_root/config/environment.rb +18 -0
  58. data/test/rails_root/config/environments/sqlite3.rb +0 -0
  59. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  60. data/test/rails_root/config/routes.rb +6 -0
  61. data/test/rails_root/db/migrate/001_create_users.rb +17 -0
  62. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  63. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  64. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  65. data/test/rails_root/db/migrate/005_create_dogs.rb +11 -0
  66. data/test/rails_root/db/migrate/006_create_addresses.rb +13 -0
  67. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  68. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  69. data/test/rails_root/db/migrate/009_add_ssn_to_users.rb +9 -0
  70. data/test/rails_root/db/schema.rb +0 -0
  71. data/test/rails_root/log/.keep +0 -0
  72. data/test/rails_root/public/.htaccess +40 -0
  73. data/test/rails_root/public/404.html +30 -0
  74. data/test/rails_root/public/422.html +30 -0
  75. data/test/rails_root/public/500.html +30 -0
  76. data/test/rails_root/script/console +3 -0
  77. data/test/rails_root/script/generate +3 -0
  78. data/test/rails_root/vendor/plugins/.keep +0 -0
  79. data/test/test_helper.rb +35 -0
  80. data/test/unit/address_test.rb +7 -0
  81. data/test/unit/dog_test.rb +7 -0
  82. data/test/unit/flea_test.rb +7 -0
  83. data/test/unit/post_test.rb +14 -0
  84. data/test/unit/tag_test.rb +12 -0
  85. data/test/unit/tagging_test.rb +8 -0
  86. data/test/unit/user_test.rb +32 -0
  87. metadata +148 -0
@@ -0,0 +1,118 @@
1
+ module ThoughtBot # :nodoc:
2
+ module Shoulda # :nodoc:
3
+ module General
4
+ def self.included(other) # :nodoc:
5
+ other.class_eval do
6
+ extend ThoughtBot::Shoulda::General::ClassMethods
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+ # Loads all fixture files (<tt>test/fixtures/*.yml</tt>)
12
+ def load_all_fixtures
13
+ all_fixtures = Dir.glob(File.join(Test::Unit::TestCase.fixture_path, "*.yml")).collect do |f|
14
+ File.basename(f, '.yml').to_sym
15
+ end
16
+ fixtures *all_fixtures
17
+ end
18
+ end
19
+
20
+ # Prints a message to stdout, tagged with the name of the calling method.
21
+ def report!(msg = "")
22
+ puts("#{caller.first}: #{msg}")
23
+ end
24
+
25
+ # Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
26
+ #
27
+ # assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
28
+ def assert_same_elements(a1, a2, msg = nil)
29
+ [:select, :inject, :size].each do |m|
30
+ [a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") }
31
+ end
32
+
33
+ assert a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h }
34
+ assert a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h }
35
+
36
+ assert_equal(a1h, a2h, msg)
37
+ end
38
+
39
+ # Asserts that the given collection contains item x. If x is a regular expression, ensure that
40
+ # at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails.
41
+ #
42
+ # assert_contains(['a', '1'], /\d/) => passes
43
+ # assert_contains(['a', '1'], 'a') => passes
44
+ # assert_contains(['a', '1'], /not there/) => fails
45
+ def assert_contains(collection, x, extra_msg = "")
46
+ collection = [collection] unless collection.is_a?(Array)
47
+ msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}"
48
+ case x
49
+ when Regexp: assert(collection.detect { |e| e =~ x }, msg)
50
+ else assert(collection.include?(x), msg)
51
+ end
52
+ end
53
+
54
+ # Asserts that the given collection does not contain item x. If x is a regular expression, ensure that
55
+ # none of the elements from the collection match x.
56
+ def assert_does_not_contain(collection, x, extra_msg = "")
57
+ collection = [collection] unless collection.is_a?(Array)
58
+ msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg
59
+ case x
60
+ when Regexp: assert(!collection.detect { |e| e =~ x }, msg)
61
+ else assert(!collection.include?(x), msg)
62
+ end
63
+ end
64
+
65
+ # Asserts that the given object can be saved
66
+ #
67
+ # assert_save User.new(params)
68
+ def assert_save(obj)
69
+ assert obj.save, "Errors: #{pretty_error_messages obj}"
70
+ obj.reload
71
+ end
72
+
73
+ # Asserts that the given object is valid
74
+ #
75
+ # assert_valid User.new(params)
76
+ def assert_valid(obj)
77
+ assert obj.valid?, "Errors: #{pretty_error_messages obj}"
78
+ end
79
+
80
+ # Asserts that an email was delivered. Can take a block that can further
81
+ # narrow down the types of emails you're expecting.
82
+ #
83
+ # assert_sent_email
84
+ #
85
+ # Passes if ActionMailer::Base.deliveries has an email
86
+ #
87
+ # assert_sent_email do |email|
88
+ # email.subject =~ /hi there/ && email.to.include?('none@none.com')
89
+ # end
90
+ #
91
+ # Passes if there is an email with subject containing 'hi there' and
92
+ # 'none@none.com' as one of the recipients.
93
+ #
94
+ def assert_sent_email
95
+ emails = ActionMailer::Base.deliveries
96
+ assert !emails.empty?, "No emails were sent"
97
+ if block_given?
98
+ matching_emails = emails.select {|email| yield email }
99
+ assert !matching_emails.empty?, "None of the emails matched."
100
+ end
101
+ end
102
+
103
+ # Asserts that no ActionMailer mails were delivered
104
+ #
105
+ # assert_did_not_send_email
106
+ def assert_did_not_send_email
107
+ msg = "Sent #{ActionMailer::Base.deliveries.size} emails.\n"
108
+ ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
109
+ assert ActionMailer::Base.deliveries.empty?, msg
110
+ end
111
+
112
+ def pretty_error_messages(obj)
113
+ obj.errors.map { |a, m| "#{a} #{m} (#{obj.send(a).inspect})" }
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,22 @@
1
+ module ThoughtBot # :nodoc:
2
+ module Shoulda # :nodoc:
3
+ module Private # :nodoc:
4
+ # Returns the values for the entries in the args hash who's keys are listed in the wanted array.
5
+ # Will raise if there are keys in the args hash that aren't listed.
6
+ def get_options!(args, *wanted)
7
+ ret = []
8
+ opts = (args.last.is_a?(Hash) ? args.pop : {})
9
+ wanted.each {|w| ret << opts.delete(w)}
10
+ raise ArgumentError, "Unsupported options given: #{opts.keys.join(', ')}" unless opts.keys.empty?
11
+ return *ret
12
+ end
13
+
14
+ # Returns the model class constant, as determined by the test class name.
15
+ #
16
+ # class TestUser; model_class; end => User
17
+ def model_class
18
+ self.name.gsub(/Test$/, '').constantize
19
+ end
20
+ end
21
+ end
22
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'shoulda'
data/shoulda.gemspec ADDED
@@ -0,0 +1,109 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'shoulda'
3
+ s.version = '4.2'
4
+ s.date = '2008-07-04'
5
+
6
+ s.summary = "Makes tests easy on the fingers and the eyes"
7
+ s.description = "Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework"
8
+
9
+ s.authors = ['Tammer Saleh']
10
+ s.email = 'tsaleh@thoughtbot.com'
11
+ s.homepage = 'http://github.com/thoughtbot/shoulda'
12
+
13
+ s.has_rdoc = true
14
+ s.rdoc_options = ["--main", "README.rdoc"]
15
+ s.extra_rdoc_files = ["README.rdoc"]
16
+
17
+ s.add_dependency 'rails', ['>= 2.1']
18
+
19
+ s.files = ["CONTRIBUTION_GUIDELINES.rdoc",
20
+ "MIT-LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "bin/convert_to_should_syntax",
24
+ "init.rb",
25
+ "lib/shoulda/active_record_helpers.rb",
26
+ "lib/shoulda/color.rb",
27
+ "lib/shoulda/controller_tests",
28
+ "lib/shoulda/controller_tests/controller_tests.rb",
29
+ "lib/shoulda/controller_tests/formats",
30
+ "lib/shoulda/controller_tests/formats/html.rb",
31
+ "lib/shoulda/controller_tests/formats/xml.rb",
32
+ "lib/shoulda/gem/proc_extensions.rb",
33
+ "lib/shoulda/gem/shoulda.rb",
34
+ "lib/shoulda/general.rb",
35
+ "lib/shoulda/private_helpers.rb",
36
+ "lib/shoulda.rb",
37
+ "rails/init.rb",
38
+ "shoulda.gemspec",
39
+ "tasks/list_tests.rake",
40
+ "tasks/yaml_to_shoulda.rake"]
41
+
42
+ s.test_files = ["test/fixtures/addresses.yml",
43
+ "test/fixtures/posts.yml",
44
+ "test/fixtures/taggings.yml",
45
+ "test/fixtures/tags.yml",
46
+ "test/fixtures/users.yml",
47
+ "test/functional/posts_controller_test.rb",
48
+ "test/functional/users_controller_test.rb",
49
+ "test/other/context_test.rb",
50
+ "test/other/helpers_test.rb",
51
+ "test/other/private_helpers_test.rb",
52
+ "test/rails_root/app/controllers/application.rb",
53
+ "test/rails_root/app/controllers/posts_controller.rb",
54
+ "test/rails_root/app/controllers/users_controller.rb",
55
+ "test/rails_root/app/helpers/application_helper.rb",
56
+ "test/rails_root/app/helpers/posts_helper.rb",
57
+ "test/rails_root/app/helpers/users_helper.rb",
58
+ "test/rails_root/app/models/address.rb",
59
+ "test/rails_root/app/models/dog.rb",
60
+ "test/rails_root/app/models/flea.rb",
61
+ "test/rails_root/app/models/post.rb",
62
+ "test/rails_root/app/models/tag.rb",
63
+ "test/rails_root/app/models/tagging.rb",
64
+ "test/rails_root/app/models/user.rb",
65
+ "test/rails_root/app/views/layouts/posts.rhtml",
66
+ "test/rails_root/app/views/layouts/users.rhtml",
67
+ "test/rails_root/app/views/posts/edit.rhtml",
68
+ "test/rails_root/app/views/posts/index.rhtml",
69
+ "test/rails_root/app/views/posts/new.rhtml",
70
+ "test/rails_root/app/views/posts/show.rhtml",
71
+ "test/rails_root/app/views/users/edit.rhtml",
72
+ "test/rails_root/app/views/users/index.rhtml",
73
+ "test/rails_root/app/views/users/new.rhtml",
74
+ "test/rails_root/app/views/users/show.rhtml",
75
+ "test/rails_root/config/boot.rb",
76
+ "test/rails_root/config/database.yml",
77
+ "test/rails_root/config/environment.rb",
78
+ "test/rails_root/config/environments/sqlite3.rb",
79
+ "test/rails_root/config/initializers/new_rails_defaults.rb",
80
+ "test/rails_root/config/routes.rb",
81
+ "test/rails_root/db/migrate/001_create_users.rb",
82
+ "test/rails_root/db/migrate/002_create_posts.rb",
83
+ "test/rails_root/db/migrate/003_create_taggings.rb",
84
+ "test/rails_root/db/migrate/004_create_tags.rb",
85
+ "test/rails_root/db/migrate/005_create_dogs.rb",
86
+ "test/rails_root/db/migrate/006_create_addresses.rb",
87
+ "test/rails_root/db/migrate/007_create_fleas.rb",
88
+ "test/rails_root/db/migrate/008_create_dogs_fleas.rb",
89
+ "test/rails_root/db/migrate/009_add_ssn_to_users.rb",
90
+ "test/rails_root/db/schema.rb",
91
+ "test/rails_root/log/.keep",
92
+ "test/rails_root/public/.htaccess",
93
+ "test/rails_root/public/404.html",
94
+ "test/rails_root/public/422.html",
95
+ "test/rails_root/public/500.html",
96
+ "test/rails_root/script/console",
97
+ "test/rails_root/script/generate",
98
+ "test/rails_root/vendor/plugins/.keep",
99
+ "test/README",
100
+ "test/test_helper.rb",
101
+ "test/unit/address_test.rb",
102
+ "test/unit/dog_test.rb",
103
+ "test/unit/flea_test.rb",
104
+ "test/unit/post_test.rb",
105
+ "test/unit/tag_test.rb",
106
+ "test/unit/tagging_test.rb",
107
+ "test/unit/user_test.rb"]
108
+
109
+ end
@@ -0,0 +1,23 @@
1
+ namespace :shoulda do
2
+ desc "List the names of the test methods in a specification like format"
3
+ task :list do
4
+
5
+ require 'test/unit'
6
+ require 'rubygems'
7
+ require 'active_support'
8
+
9
+ # bug in test unit. Set to true to stop from running.
10
+ Test::Unit.run = true
11
+
12
+ test_files = Dir.glob(File.join('test', '**', '*_test.rb'))
13
+ test_files.each do |file|
14
+ load file
15
+ klass = File.basename(file, '.rb').classify.constantize
16
+
17
+ puts klass.name.gsub('Test', '')
18
+
19
+ test_methods = klass.instance_methods.grep(/^test/).map {|s| s.gsub(/^test: /, '')}.sort
20
+ test_methods.each {|m| puts " " + m }
21
+ end
22
+ end
23
+ 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
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
+ * fixtures - contain the sample DB data for each model
12
+ * functional - controller tests for each of the controllers under rails_root/app
13
+ * unit - model tests for each of the models under rails_root/app
14
+ * other - tests for the shoulda contexts, should statements, and assertions
15
+ * test_helper.rb - responsible for initializing the test environment
16
+ ** sets the rails_env to sqlite3
17
+ ** sets the rails_root
18
+ ** creates the rails_root/vendor/plugins/shoulda symlink
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,3 @@
1
+ first:
2
+ title: Home
3
+ addressable: first (User)
@@ -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
@@ -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
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'posts_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class PostsController; def rescue_action(e) raise e end; end
6
+
7
+ class PostsControllerTest < Test::Unit::TestCase
8
+ load_all_fixtures
9
+
10
+ def setup
11
+ @controller = PostsController.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ @post = Post.find(:first)
15
+ end
16
+
17
+ context "The public" do
18
+ setup do
19
+ @request.session[:logged_in] = false
20
+ end
21
+
22
+ should_be_restful do |resource|
23
+ resource.parent = :user
24
+
25
+ resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy]
26
+ resource.denied.flash = /what/i
27
+ resource.denied.redirect = '"/"'
28
+ end
29
+ end
30
+
31
+ context "Logged in" do
32
+ setup do
33
+ @request.session[:logged_in] = true
34
+ end
35
+
36
+ should_be_restful do |resource|
37
+ resource.parent = :user
38
+
39
+ resource.create.params = { :title => "first post", :body => 'blah blah blah'}
40
+ resource.update.params = { :title => "changed" }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'users_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class UsersController; def rescue_action(e) raise e end; end
6
+
7
+ class UsersControllerTest < Test::Unit::TestCase
8
+ load_all_fixtures
9
+
10
+ def setup
11
+ @controller = UsersController.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ @user = User.find(:first)
15
+ end
16
+
17
+ should_be_restful do |resource|
18
+ resource.identifier = :id
19
+ resource.klass = User
20
+ resource.object = :user
21
+ resource.parent = []
22
+ resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy]
23
+ resource.formats = [:html, :xml]
24
+
25
+ resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13, :ssn => "123456789"}
26
+ resource.update.params = { :name => "sue" }
27
+
28
+ resource.create.redirect = "user_url(@user)"
29
+ resource.update.redirect = "user_url(@user)"
30
+ resource.destroy.redirect = "users_url"
31
+
32
+ resource.create.flash = /created/i
33
+ resource.update.flash = /updated/i
34
+ resource.destroy.flash = /removed/i
35
+ end
36
+ end