socialcast_shoulda_ext 0.1.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 (78) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +13 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +126 -0
  5. data/Rakefile +12 -0
  6. data/lib/shoulda_ext.rb +7 -0
  7. data/lib/shoulda_ext/assertions.rb +14 -0
  8. data/lib/shoulda_ext/integrations/test_unit.rb +13 -0
  9. data/lib/shoulda_ext/matchers.rb +9 -0
  10. data/lib/shoulda_ext/matchers/record_count_change.rb +127 -0
  11. data/lib/shoulda_ext/matchers/respond_with_json.rb +99 -0
  12. data/lib/shoulda_ext/matchers/trigger_callback.rb +131 -0
  13. data/lib/shoulda_ext/shoulda_patches/context_with_matcher_before_hooks.rb +32 -0
  14. data/lib/shoulda_ext/version.rb +4 -0
  15. data/socialcast_shoulda_ext.gemspec +22 -0
  16. data/test/helper.rb +30 -0
  17. data/test/rails3_root/.gitignore +4 -0
  18. data/test/rails3_root/Rakefile +7 -0
  19. data/test/rails3_root/app/controllers/application_controller.rb +3 -0
  20. data/test/rails3_root/app/controllers/blogs_controller.rb +11 -0
  21. data/test/rails3_root/app/controllers/comments_controller.rb +2 -0
  22. data/test/rails3_root/app/helpers/application_helper.rb +2 -0
  23. data/test/rails3_root/app/helpers/blogs_helper.rb +2 -0
  24. data/test/rails3_root/app/helpers/comments_helper.rb +2 -0
  25. data/test/rails3_root/app/models/blog.rb +3 -0
  26. data/test/rails3_root/app/models/comment.rb +3 -0
  27. data/test/rails3_root/app/views/blogs/index.html.erb +6 -0
  28. data/test/rails3_root/app/views/layouts/application.html.erb +14 -0
  29. data/test/rails3_root/config.ru +4 -0
  30. data/test/rails3_root/config/application.rb +17 -0
  31. data/test/rails3_root/config/boot.rb +6 -0
  32. data/test/rails3_root/config/database.yml +22 -0
  33. data/test/rails3_root/config/environment.rb +5 -0
  34. data/test/rails3_root/config/environments/development.rb +26 -0
  35. data/test/rails3_root/config/environments/production.rb +49 -0
  36. data/test/rails3_root/config/environments/test.rb +35 -0
  37. data/test/rails3_root/config/initializers/backtrace_silencers.rb +7 -0
  38. data/test/rails3_root/config/initializers/inflections.rb +10 -0
  39. data/test/rails3_root/config/initializers/mime_types.rb +5 -0
  40. data/test/rails3_root/config/initializers/secret_token.rb +7 -0
  41. data/test/rails3_root/config/initializers/session_store.rb +8 -0
  42. data/test/rails3_root/config/locales/en.yml +5 -0
  43. data/test/rails3_root/config/routes.rb +4 -0
  44. data/test/rails3_root/db/migrate/20110411025326_create_blogs.rb +12 -0
  45. data/test/rails3_root/db/migrate/20110411025332_create_comments.rb +13 -0
  46. data/test/rails3_root/db/seeds.rb +7 -0
  47. data/test/rails3_root/lib/tasks/.gitkeep +0 -0
  48. data/test/rails3_root/public/404.html +26 -0
  49. data/test/rails3_root/public/422.html +26 -0
  50. data/test/rails3_root/public/500.html +26 -0
  51. data/test/rails3_root/public/favicon.ico +0 -0
  52. data/test/rails3_root/public/images/rails.png +0 -0
  53. data/test/rails3_root/public/index.html +239 -0
  54. data/test/rails3_root/public/javascripts/application.js +2 -0
  55. data/test/rails3_root/public/javascripts/controls.js +965 -0
  56. data/test/rails3_root/public/javascripts/dragdrop.js +974 -0
  57. data/test/rails3_root/public/javascripts/effects.js +1123 -0
  58. data/test/rails3_root/public/javascripts/prototype.js +6001 -0
  59. data/test/rails3_root/public/javascripts/rails.js +191 -0
  60. data/test/rails3_root/public/robots.txt +5 -0
  61. data/test/rails3_root/public/stylesheets/.gitkeep +0 -0
  62. data/test/rails3_root/script/rails +6 -0
  63. data/test/rails3_root/test/fixtures/blogs.yml +5 -0
  64. data/test/rails3_root/test/fixtures/comments.yml +0 -0
  65. data/test/rails3_root/test/functional/blogs_controller_test.rb +8 -0
  66. data/test/rails3_root/test/functional/comments_controller_test.rb +8 -0
  67. data/test/rails3_root/test/shoulda_ext.sqlite3 +0 -0
  68. data/test/rails3_root/test/test_helper.rb +13 -0
  69. data/test/rails3_root/test/unit/blog_test.rb +8 -0
  70. data/test/rails3_root/test/unit/comment_test.rb +8 -0
  71. data/test/rails3_root/test/unit/helpers/blogs_helper_test.rb +4 -0
  72. data/test/rails3_root/test/unit/helpers/comments_helper_test.rb +4 -0
  73. data/test/rails3_root/vendor/plugins/.gitkeep +0 -0
  74. data/test/test_assertions.rb +14 -0
  75. data/test/test_record_count_change_matcher.rb +150 -0
  76. data/test/test_respond_with_json.rb +42 -0
  77. data/test/test_trigger_callback_matcher.rb +38 -0
  78. metadata +362 -0
@@ -0,0 +1,6 @@
1
+ .bundle
2
+ Gemfile.lock
3
+ test/debug.log
4
+ test/rails3_root/db/*.sqlite3
5
+ test/rails3_root/tmp
6
+ test/rails3_root/log
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rails', "~> 3.0.0"
7
+ gem 'shoulda', '>= 2.11.3'
8
+ gem 'json', ">= 0"
9
+ gem 'bundler', ">= 0"
10
+ gem 'mocha', ">= 0"
11
+ gem 'sqlite3-ruby', "~> 1.3.2"
12
+ gem 'ruby-debug', ">= 0"
13
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2011, Geoffrey Hichborn, Socialcast, 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.
@@ -0,0 +1,126 @@
1
+
2
+ = Socialcast Shoulda Extensions
3
+ Adds new matchers and functionality to the shoulda test library
4
+
5
+ = Installation
6
+
7
+ In your Gemfile:
8
+
9
+ group :test do
10
+ gem 'socialcast_shoulda_ext', :git => 'git@github.com:socialcast/socialcast-shoulda-ext.git', :require => 'shoulda_ext'
11
+ end
12
+
13
+ If you want to include the trigger_callbacks matcher, also add the following to your test helper:
14
+
15
+ ShouldaExt::Matchers::TriggerCallbackMatcher.attach_active_record_callback_hooks!
16
+
17
+ = Matchers
18
+
19
+ == RecordCountChangeMatcher
20
+ Test if the count for a model has changed, and by how much. Requires the context_with_matcher_before_hooks patch, which is included by default.
21
+
22
+ Provides the following matcher methods:
23
+
24
+ - create_record(klass_or_symbol)
25
+ Alias for change_record_count.for(klass_or_symbol).by(1)
26
+
27
+ - create_records(klass_or_symbol, amount)
28
+ Alias for change_record_count.for(klass_or_symbol).by(amount)
29
+
30
+ - destroy_record(klass_or_symbol)
31
+ Alias for change_record_count.for(klass_or_symbol).by(-1)
32
+
33
+ - destroy_records(klass_or_symbol, amount)
34
+ Alias for change_record_count.for(klass_or_symbol).by(-amount)
35
+
36
+ - change_record_count
37
+ Tests the difference in record count before and after the current setup/subject block
38
+ Can be used with the follow methods:
39
+ - for(klass_or_symbol)
40
+ Provides the class which the test is being performed on. Can be a constant or a symbol
41
+
42
+ - by(amount)
43
+ Provides an expected difference for the number of records for the specified class.
44
+ Excluding this number will allow the matcher to check for any difference
45
+
46
+ Examples:
47
+
48
+ context "creating a blog article" do
49
+
50
+ context "with good parameters" do
51
+ setup do
52
+ post :create, :blog => {:title => 'my blog post', :body => 'Ipsum lorem...'}
53
+ end
54
+ should create_record :blog
55
+ end
56
+
57
+ context "without a body" do
58
+ setup do
59
+ post :create, :blog => {:title => 'my blog post' }
60
+ end
61
+ should_not create_record Blog
62
+ end
63
+
64
+ end
65
+
66
+ == RespondWithJson
67
+ Check if the controller's response is json
68
+
69
+ Examples:
70
+
71
+ context ":index.json" do
72
+ setup do
73
+ get :index, :format => 'json'
74
+ end
75
+ # Just check to see that the response was json
76
+ should respond_with_json
77
+
78
+ # Evaluate the hash produced by the json yourself
79
+ should respond_with_json { |json| json.first['blog']['title'] == 'blog post 1'}
80
+
81
+ # Provide an exact match
82
+ should respond_with_json.exactly(['blog' => {'id' => 1, 'title' => 'blog post 1'}])
83
+
84
+ # Provide an exact match with a block
85
+ should response_with_json.exactly{ |json| JSON.parse(Blog.all.to_json)}
86
+ end
87
+
88
+ context ":index.html" do
89
+ setup do
90
+ get :index
91
+ end
92
+
93
+ # or the negation
94
+ should_not respond_with_json
95
+ end
96
+
97
+ == TriggerCallbackMatcher
98
+
99
+ Test if create, update, destroy, or save callbacks were triggered.
100
+
101
+ Requires running
102
+ ShouldaExt::Matchers::TriggerCallbackMatcher.attach_active_record_callback_hooks!
103
+ in your test suite in order to work properly.
104
+
105
+ Examples:
106
+
107
+ context "doing nothing to a record" do
108
+ subject { Blog.new :title => 'blog title' }
109
+ should_not trigger_callbacks
110
+ end
111
+
112
+ context "creating a record" do
113
+ subject { Blog.create! :title => 'blog title' }
114
+ should trigger_callbacks.for :create
115
+ should_not trigger_callbacks.for :update, :destroy
116
+ end
117
+
118
+ = Integrations
119
+
120
+ Currently only integrates with test/unit. RSpec support to come.
121
+
122
+ = Shoulda Extensions
123
+
124
+ == ContextWithMatcherBeforeHooks
125
+
126
+ Adds the ability to define a 'before' method on any method which will be run before each context's setup/subject block. Used by RecordCountChangeMatcher to record the number of records before the tested operation takes place.
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake'
5
+
6
+ require 'rake/testtask'
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << 'lib' << 'test'
9
+ test.pattern = 'test/**/test_*.rb'
10
+ test.verbose = true
11
+ end
12
+ task :default => :test
@@ -0,0 +1,7 @@
1
+ require 'shoulda_ext/version'
2
+
3
+ require 'shoulda'
4
+ require 'shoulda_ext/assertions'
5
+ require 'shoulda_ext/matchers'
6
+
7
+ require 'shoulda_ext/integrations/test_unit'
@@ -0,0 +1,14 @@
1
+
2
+ module ShouldaExt
3
+ module Assertions
4
+ # Asserts the result of object.blank?
5
+ def assert_blank(object, message = nil)
6
+ assert(object.blank?, message || "Expected object to be blank")
7
+ end
8
+
9
+ # Asserts the result of !object.blank?
10
+ def assert_not_blank(object, message = nil)
11
+ assert(!object.blank?, message || "Expected object to not be blank")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+
2
+ require 'shoulda_ext/assertions'
3
+ require 'shoulda_ext/matchers'
4
+ require 'test/unit'
5
+
6
+ module Test # :nodoc: all
7
+ module Unit
8
+ class TestCase
9
+ extend ShouldaExt::Matchers
10
+ include ShouldaExt::Assertions
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+
2
+ require 'shoulda_ext/matchers/record_count_change'
3
+ require 'shoulda_ext/matchers/trigger_callback'
4
+ require 'shoulda_ext/matchers/respond_with_json'
5
+
6
+ module ShouldaExt # :nodoc:
7
+ module Matchers # :nodoc:
8
+ end
9
+ end
@@ -0,0 +1,127 @@
1
+
2
+ require 'shoulda_ext/shoulda_patches/context_with_matcher_before_hooks'
3
+
4
+ module ShouldaExt # :nodoc:
5
+ module Matchers # :nodoc:
6
+
7
+ # Test if a record of klass is created during the current setup/subject block
8
+ # Equivilent to change_record_count.for(klass).by(1)
9
+ def create_record(klass)
10
+ RecordCountChangeMatcher.new.for(klass).by(1)
11
+ end
12
+
13
+ # Test if a record of klass is destroyed during the current setup/subject block
14
+ # Equivilent to change_record_count.for(klass).by(-1)
15
+ def destroy_record(klass)
16
+ RecordCountChangeMatcher.new.for(klass).by(-1)
17
+ end
18
+
19
+ # Test if 'count' records of 'klass' are created during the current setup/subject block
20
+ # Equivilent to change_record_count.for(klass).by(count)
21
+ def create_records(klass, count)
22
+ RecordCountChangeMatcher.new.for(klass).by(count)
23
+ end
24
+
25
+ # Test if 'count' records of 'klass' are destroyed during the current setup/subject block
26
+ # Equivilent to change_record_count.for(klass).by(-count)
27
+ def destroy_records(klass, count)
28
+ RecordCountChangeMatcher.new.for(klass).by(-count)
29
+ end
30
+
31
+ # Tests the difference in record count before and after the current setup/subject block
32
+ # Can be used with the follow methods:
33
+ # - for(klass)
34
+ # Provides the class which the test is being performed on. Can be a constant or a symbol
35
+ #
36
+ # - by(count)
37
+ # Provides an expected difference for the number of records for the specified class. If
38
+ # this count is not specified, the matcher will test for any difference.
39
+ #
40
+ # Examples:
41
+ #
42
+ # context "creating a blog article" do
43
+ #
44
+ # context "with good parameters" do
45
+ # setup do
46
+ # post :create, :blog => {:title => 'my blog post', :body => 'Ipsum lorem...'}
47
+ # end
48
+ #
49
+ # # All of the below are synonomous
50
+ # should create_record Blog
51
+ # should create_record :blog
52
+ # should change_record_count.for(Blog).by(1)
53
+ # end
54
+ #
55
+ # context "without a body" do
56
+ # setup do
57
+ # post :create, :blog => {:title => 'my blog post' }
58
+ # end
59
+ #
60
+ # # All of the below are synonomous
61
+ # should_not create_record Blog
62
+ # should_not change_record_count.for(Blog)
63
+ # end
64
+ #
65
+ # end
66
+ def change_record_count
67
+ RecordCountChangeMatcher.new
68
+ end
69
+
70
+ class RecordCountChangeMatcher # :nodoc:
71
+
72
+ def before
73
+ @triggered_before = true
74
+ @previous_count = @klass.count
75
+ end
76
+
77
+ def for(klass)
78
+ klass = klass.to_s.classify.constantize if klass.is_a? Symbol
79
+ @klass = klass
80
+ self
81
+ end
82
+
83
+ def by(expected_change)
84
+ @expected_change = expected_change
85
+ self
86
+ end
87
+
88
+ def matches?(*)
89
+ @new_count = @klass.count
90
+ found_expected?
91
+ end
92
+
93
+ def description
94
+ "expect #{@klass.name}.count to change#{" by #{@expected_change} records" if @expected_change }"
95
+ end
96
+
97
+ def failure_message
98
+ "Expected #{errors.join("\n")}"
99
+ end
100
+
101
+ def negative_failure_message
102
+ "Did not expect #{errors.join("\n")}"
103
+ end
104
+
105
+ def errors
106
+ @errors = []
107
+ @errors << "Never received :before call. Please make sure you are running this with a setup/subject block in the current context and the ContextWithMatcherBeforeHooks patch is installed" if !@triggered_before
108
+ @errors << "#{expected_count} #{@klass.name} records, but found #{@new_count}" if !found_expected? && @expected_change
109
+ @errors << "#{@klass.name}.count to change" if !found_expected? && !@expected_change
110
+ @errors
111
+ end
112
+
113
+ def expected_count
114
+ @previous_count + @expected_change
115
+ end
116
+
117
+ def found_expected?
118
+ if @expected_change
119
+ expected_count == @new_count
120
+ else
121
+ @new_count != @previous_count
122
+ end
123
+ end
124
+
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,99 @@
1
+ module ShouldaExt # :nodoc:
2
+ module Matchers # :nodoc:
3
+
4
+ # Check if the controller's response is json
5
+ #
6
+ # Example uses:
7
+ # context ":index.json" do
8
+ # setup do
9
+ # get :index, :format => 'json'
10
+ # end
11
+ # # Just check to see that the response was json
12
+ # should respond_with_json
13
+ #
14
+ # # Evaluate the hash produced by the json yourself
15
+ # should respond_with_json { |json| json.first['blog']['title'] == 'blog post 1'}
16
+ #
17
+ # # Provide an exact match
18
+ # should respond_with_json.exactly(['blog' => {'id' => 1, 'title' => 'blog post 1'}])
19
+ #
20
+ # # Provide an exact match with a block
21
+ # should response_with_json.exactly{ |json| JSON.parse(Blog.all.to_json)}
22
+ # end
23
+ #
24
+ # context ":index.html" do
25
+ # setup do
26
+ # get :index
27
+ # end
28
+ #
29
+ # # or the negation
30
+ # should_not respond_with_json
31
+ # end
32
+ def respond_with_json(description = nil, &block)
33
+ RespondWithJsonMatcher.new(self, description, &block)
34
+ end
35
+
36
+ class RespondWithJsonMatcher
37
+ def initialize(context, description = nil, &block)
38
+ @block = block || lambda{|*| true }
39
+ @description = description
40
+ @exactly = false
41
+ end
42
+
43
+ # Provide an exact result directly or using a block argument
44
+ def exactly(expected_json = nil, &block)
45
+ @exactly = true
46
+ @expected_value = expected_json
47
+ @block = block
48
+ self
49
+ end
50
+
51
+ def in_context(context)
52
+ @context = context
53
+ self
54
+ end
55
+
56
+ def description
57
+ @description ||= "respond with JSON"
58
+ end
59
+
60
+ def failure_message
61
+ "Expected to respond with json, but: #{errors.join("\n")}"
62
+ end
63
+
64
+ def negative_failure_message
65
+ "Expected not to respond with json, but: #{errors.join("\n")}"
66
+ end
67
+
68
+ def errors
69
+ @errors = []
70
+ @errors << 'Failed to parse the response as JSON' unless @parsable
71
+ @errors << "Failed to #{'exactly ' if @exactly}match json: expected #{@exactly ? @expected_value.inspect : true}, but found #{@exactly ? @response_json.inspect : @block_result} " unless @json_matched
72
+ @errors
73
+ end
74
+
75
+ def json_matched?
76
+ @expected_value ||= run_block
77
+ @json_matched ||= @exactly ? @response_json == @expected_value : !!@block_result
78
+ end
79
+
80
+ def run_block
81
+ @block_result = @context.instance_exec(@response_json, &@block)
82
+ end
83
+
84
+ def parsable?
85
+ @parsable = true
86
+ @response_json = JSON.parse(@subject.response.body)
87
+ rescue
88
+ @parsable = false
89
+ end
90
+
91
+ def matches?(subject)
92
+ @subject = subject
93
+ parsable? and json_matched?
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+