riot-rails 0.1.0 → 0.2.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG +150 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +31 -0
- data/Rakefile +32 -10
- data/VERSION +1 -1
- data/lib/riot/action_controller/context_macros/asserts_response.rb +15 -0
- data/lib/riot/action_controller/context_middleware.rb +48 -0
- data/lib/riot/action_controller/http_methods.rb +19 -0
- data/lib/riot/action_controller.rb +4 -0
- data/lib/riot/active_record/assertion_macros.rb +3 -0
- data/lib/riot/active_record/context_middleware.rb +17 -0
- data/lib/riot/active_record/database_macros.rb +58 -0
- data/lib/riot/active_record/reflection_macros.rb +106 -0
- data/lib/riot/active_record/transactional_middleware.rb +28 -0
- data/lib/riot/active_record/validation_macros.rb +187 -0
- data/lib/riot/active_record.rb +4 -0
- data/lib/riot/rails.rb +1 -0
- data/rails/init.rb +1 -0
- data/riot-rails.gemspec +130 -0
- data/test/action_controller/context_macros/asserts_response_test.rb +35 -0
- data/test/action_controller/context_middleware_test.rb +66 -0
- data/test/action_controller/delete_request_test.rb +45 -0
- data/test/action_controller/get_request_test.rb +37 -0
- data/test/action_controller/post_request_test.rb +45 -0
- data/test/action_controller/put_request_test.rb +45 -0
- data/test/action_controller/restful_delete_request_test.rb +28 -0
- data/test/action_controller/restful_get_request_test.rb +25 -0
- data/test/action_controller/restful_post_request_test.rb +25 -0
- data/test/action_controller/restful_put_request_test.rb +28 -0
- data/test/active_record/allowing_values_test.rb +64 -0
- data/test/active_record/attribute_is_invalid_test.rb +20 -0
- data/test/active_record/belongs_to_test.rb +22 -0
- data/test/active_record/context_middleware_test.rb +18 -0
- data/test/active_record/has_and_belongs_to_many_test.rb +22 -0
- data/test/active_record/has_database_index_on_test.rb +73 -0
- data/test/active_record/has_many_test.rb +22 -0
- data/test/active_record/has_one_test.rb +22 -0
- data/test/active_record/validates_length_of_test.rb +31 -0
- data/test/active_record/validates_presence_of_test.rb +14 -0
- data/test/active_record/validates_uniqueness_of_test.rb +23 -0
- data/test/rails_root/app/controllers/gremlins_controller.rb +21 -0
- data/test/rails_root/app/controllers/parties_controller.rb +17 -0
- data/test/rails_root/app/controllers/rooms_controller.rb +22 -0
- data/{README.md → test/rails_root/app/views/rendered_templates/foo_bar.html.erb} +0 -0
- data/test/rails_root/config/database.yml +4 -0
- data/test/rails_root/config/environment.rb +46 -0
- data/test/rails_root/config/routes.rb +7 -0
- data/test/rails_root/db/schema.rb +8 -0
- data/test/teststrap.rb +84 -0
- data/test/transactional_middleware_test.rb +27 -0
- metadata +154 -26
- data/init.rb +0 -0
- data/install.rb +0 -0
- data/lib/generators/riot_rails/model/model_generator.rb +0 -22
- data/lib/generators/riot_rails/model/templates/fixtures.yml +0 -23
- data/lib/generators/riot_rails/model/templates/riot_test.rb +0 -5
- data/lib/generators/riot_rails.rb +0 -10
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
*0.2.0.pre*
|
2
|
+
|
3
|
+
* Using latest middleware construct from Riot 0.11.1. Also using eigen-class for hijacking local_run in the transactional, active record middleware. [jaknowlden]
|
4
|
+
|
5
|
+
* Bumping version up arbitrarily in order to move it past the previous 0.1.0 that we hijacked from @dasch :) [jaknowlden]
|
6
|
+
|
7
|
+
*0.0.10.pre.3*
|
8
|
+
|
9
|
+
* Renamed to riot-rails and am hoping @dasch is kind of enough to let me be an owner on the gem he originally pushed. The ol' bait and and switch. [jaknowlden]
|
10
|
+
|
11
|
+
* Added asserts_response context macro. You can also provide method names to be called against the response. [jaknowlden]
|
12
|
+
|
13
|
+
context FoosController do
|
14
|
+
setup { get "/foos" }
|
15
|
+
|
16
|
+
asserts_response.exists
|
17
|
+
asserts_response(:status).equals(200)
|
18
|
+
asserts_response(:body).matches(/Bar baz/)
|
19
|
+
end # FoosController
|
20
|
+
|
21
|
+
* Added GET support for ActionController testing, a la Rack testing methods. [jaknowlden]
|
22
|
+
|
23
|
+
context MyController do
|
24
|
+
setup { get "/my/dashboard", "foo" => "bar" }
|
25
|
+
end # MyController
|
26
|
+
|
27
|
+
* Redoing support for ActionController. Dropped everything started from scratch. Also, moved the context-helper stuff into Riot and called it ContextMiddleware. Reimplemented helpers as middleware here. [jaknowlden]
|
28
|
+
|
29
|
+
*0.0.9.pre*
|
30
|
+
|
31
|
+
* To accommodate the last change, added concept of context helpers. It's so simple you can define your own. [jaknowlden]
|
32
|
+
|
33
|
+
module RiotRails
|
34
|
+
register_context_helper do
|
35
|
+
def prepare_context(original_description, context)
|
36
|
+
# ...
|
37
|
+
context.<do-something-before-the-context-runs-if-you-want-to>
|
38
|
+
# ...
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
* Well. Aren't we special? We don't have include ActiveRecord or ActionController code if we don't want to. But if you do: [jaknowlden]
|
44
|
+
|
45
|
+
# teststrap.rb
|
46
|
+
require 'riot/activerecord' # implicit riot/rails require
|
47
|
+
require 'riot/actioncontroller' # also an implicit riot/rails require
|
48
|
+
|
49
|
+
* Added asserts_request and asserts_response context macros. They also take a possible method to call.
|
50
|
+
[jaknowlden]
|
51
|
+
|
52
|
+
rails_context UsersController do
|
53
|
+
hookup { get :show, :id => 1 }
|
54
|
+
|
55
|
+
asserts_response.kind_of(ActionController::TestResponse)
|
56
|
+
asserts_response(:body).kind_of(String)
|
57
|
+
|
58
|
+
asserts_request.kind_of(ActionController::TestRequest)
|
59
|
+
asserts_request(:cookies).kind_of(Hash)
|
60
|
+
end
|
61
|
+
|
62
|
+
* Controller assertions now no longer assume the actual value is a controller instance. Instead, the actual
|
63
|
+
value is something that should quack like a response. [jaknowlden]
|
64
|
+
|
65
|
+
* Added asserts_assigned context macro [jaknowlden]
|
66
|
+
|
67
|
+
rails_context UsersController do
|
68
|
+
hookup { get :show, :id => 1 }
|
69
|
+
|
70
|
+
asserts_assigned(:user).kind_of(User)
|
71
|
+
end
|
72
|
+
|
73
|
+
* rails_context now recognizes controllers [jaknowlden]
|
74
|
+
|
75
|
+
rails_context RoomsController do
|
76
|
+
hookup { get :index }
|
77
|
+
asserts_controller.reponse_status :ok
|
78
|
+
end
|
79
|
+
|
80
|
+
Plus, you can only use controlling within a rails_context now
|
81
|
+
|
82
|
+
rails_context "rooms" do
|
83
|
+
controlling :rooms
|
84
|
+
hookup { get :index }
|
85
|
+
asserts_controller.reponse_status :ok
|
86
|
+
end
|
87
|
+
|
88
|
+
* controlling now lets you pass a controller class reference in [jaknowlden]
|
89
|
+
|
90
|
+
rails_context "rooms" do
|
91
|
+
controlling RoomsController
|
92
|
+
end
|
93
|
+
|
94
|
+
* Reflection macros now test the options [emschwar]
|
95
|
+
|
96
|
+
rails_context Room do
|
97
|
+
asserts_topic.has_one :floor, :class_name => "Surface"
|
98
|
+
asserts_topic.has_many :walls, :join_table => "foos"
|
99
|
+
end
|
100
|
+
|
101
|
+
* Added the has_one reflection macro [emschwar]
|
102
|
+
|
103
|
+
rails_context Room do
|
104
|
+
asserts_topic.has_one :floor
|
105
|
+
end
|
106
|
+
|
107
|
+
* Added the attribute_is_invalid validation macro [jaknowlden]
|
108
|
+
|
109
|
+
rails_context Room do
|
110
|
+
hookup { topic.location = nil }
|
111
|
+
asserts_topic.attribute_is_invalid(:location, "can't be blank")
|
112
|
+
end
|
113
|
+
|
114
|
+
* Added validates_length_of assertion macro (minimalistic) [jaknowlden]
|
115
|
+
|
116
|
+
rails_context Room do
|
117
|
+
asserts_topic.validates_length_of :name, (2..36)
|
118
|
+
end
|
119
|
+
|
120
|
+
* Added transactional support to RailsContext. Disabled by default [jaknowlden]
|
121
|
+
|
122
|
+
rails_context Room do
|
123
|
+
set :transactional, true
|
124
|
+
end
|
125
|
+
|
126
|
+
* Added option enabling to RailsContext [jaknowlden]
|
127
|
+
|
128
|
+
rails_context Room do
|
129
|
+
set :this, "that"
|
130
|
+
end
|
131
|
+
|
132
|
+
* Added initial #rails_context. Assumes ActiveRecord class for now [jaknowlden]
|
133
|
+
|
134
|
+
class Room < ActiveRecord::Base
|
135
|
+
# ...
|
136
|
+
end
|
137
|
+
|
138
|
+
# TEST
|
139
|
+
|
140
|
+
rails_context Room do
|
141
|
+
asserts_topic.belongs_to(:house)
|
142
|
+
asserts_topic.validates_presence_of(:house_id)
|
143
|
+
end
|
144
|
+
|
145
|
+
* Added the #belongs_to ActiveRecord assertion macro [jaknowlden]
|
146
|
+
|
147
|
+
context "a Room" do
|
148
|
+
setup { Room.new }
|
149
|
+
asserts_topic.belongs_to(:house)
|
150
|
+
end
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Justin Knowlden, Thumble Monks
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Riot Rails
|
2
|
+
|
3
|
+
[Riot](http://github.com/thumblemonks/riot) macros for Rails application testing.
|
4
|
+
|
5
|
+
LOTS more to come ...
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
We're a gem! Install per the normal course of installing gems.
|
10
|
+
|
11
|
+
gem install riot_rails
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Tons of documentation to come. Try looking at the [RDoc](http://rdoc.info/projects/thumblemonks/riot_rails) for now. As a note, you will likely put this in your `teststrap.rb` or `test_helper.rb`:
|
16
|
+
|
17
|
+
require 'riot/rails'
|
18
|
+
|
19
|
+
### ActiveRecord
|
20
|
+
|
21
|
+
Awesome stuff in the works. Doc coming soon.
|
22
|
+
|
23
|
+
### ActionController
|
24
|
+
|
25
|
+
Awesome stuff in the works. Doc coming soon.
|
26
|
+
|
27
|
+
### ActionMailer
|
28
|
+
|
29
|
+
Awesome stuff coming soon. See [Shoulda Action Mailer](http://github.com/thumblemonks/shoulda_action_mailer) - which is also by us - in the meantime.
|
30
|
+
|
31
|
+
I told you we liked Shoulda.
|
data/Rakefile
CHANGED
@@ -1,19 +1,41 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
task :default => [:test]
|
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 = false
|
5
11
|
end
|
6
12
|
|
13
|
+
desc "Run Flog against library (except tests)"
|
14
|
+
task :flog do
|
15
|
+
puts %x[find ./lib -name *.rb | xargs flog]
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Run Roodi against library (except tests)"
|
19
|
+
task :roodi do
|
20
|
+
puts %x[find ./lib -name *.rb | xargs roodi]
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Some monks like diamonds. I like gems.
|
25
|
+
|
7
26
|
begin
|
8
27
|
require 'jeweler'
|
9
28
|
Jeweler::Tasks.new do |gem|
|
10
29
|
gem.name = "riot-rails"
|
11
|
-
gem.summary = "
|
12
|
-
gem.description = "
|
13
|
-
gem.email = "
|
14
|
-
gem.homepage = "http://github.com/
|
15
|
-
gem.authors = ["
|
16
|
-
gem.add_dependency
|
30
|
+
gem.summary = "Riot specific test support for Rails apps"
|
31
|
+
gem.description = "Riot specific test support for Rails apps. Protest the slow app."
|
32
|
+
gem.email = "gus@gusg.us"
|
33
|
+
gem.homepage = "http://github.com/thumblemonks/riot-rails"
|
34
|
+
gem.authors = ["Justin 'Gus' Knowlden"]
|
35
|
+
gem.add_dependency("riot", ">= 0.11.0")
|
36
|
+
gem.add_dependency("rack-test", ">= 0.5.3")
|
37
|
+
gem.add_development_dependency("activerecord", ">= 3.0.0.beta3")
|
38
|
+
gem.add_development_dependency("actionpack", ">= 3.0.0.beta3")
|
17
39
|
end
|
18
40
|
Jeweler::GemcutterTasks.new
|
19
41
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0.pre
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RiotRails
|
2
|
+
module ActionController
|
3
|
+
module AssertsResponse
|
4
|
+
|
5
|
+
def asserts_response(method_name=nil)
|
6
|
+
if method_name
|
7
|
+
asserts("response ##{method_name.to_s}") { response.send(method_name) }
|
8
|
+
else
|
9
|
+
asserts("response") { response }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end # AssertsResponse
|
14
|
+
end # ActionController
|
15
|
+
end # RiotRails
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RiotRails
|
2
|
+
class ActionControllerMiddleware < Riot::ContextMiddleware
|
3
|
+
register
|
4
|
+
|
5
|
+
def call(context)
|
6
|
+
if handle?(context)
|
7
|
+
setup_context_macros(context)
|
8
|
+
setup_situation(context)
|
9
|
+
end
|
10
|
+
middleware.call(context)
|
11
|
+
end
|
12
|
+
private
|
13
|
+
def handle?(context)
|
14
|
+
description = context.description
|
15
|
+
description.kind_of?(Class) && description.ancestors.include?(::ActionController::Base)
|
16
|
+
end
|
17
|
+
|
18
|
+
def setup_context_macros(context)
|
19
|
+
context.class_eval do
|
20
|
+
include RiotRails::ActionController::AssertsResponse
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup_situation(context)
|
25
|
+
context.helper(:app) { @app }
|
26
|
+
context.helper(:env) { @env }
|
27
|
+
context.helper(:controller) { env["action_controller.instance"] }
|
28
|
+
|
29
|
+
context.helper(:request) do
|
30
|
+
return controller.request if controller
|
31
|
+
raise Exception, "No request made yet"
|
32
|
+
end
|
33
|
+
|
34
|
+
context.helper(:response) do
|
35
|
+
return controller.response if controller
|
36
|
+
raise Exception, "No response since no request made yet"
|
37
|
+
end
|
38
|
+
|
39
|
+
context.setup(true) do
|
40
|
+
self.class_eval { include RiotRails::ActionController::HttpMethods }
|
41
|
+
@app = ::Rails.application
|
42
|
+
http_reset
|
43
|
+
context.description
|
44
|
+
end # context.setup(true)
|
45
|
+
end # call
|
46
|
+
|
47
|
+
end # ActionControllerMiddleware
|
48
|
+
end # RiotRails
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RiotRails
|
2
|
+
module ActionController
|
3
|
+
module HttpMethods
|
4
|
+
def http_reset; @env = {}; end
|
5
|
+
def get(uri, params={}) perform_request("GET", uri, params); end
|
6
|
+
def post(uri, params={}) perform_request("POST", uri, params); end
|
7
|
+
def put(uri, params={}); perform_request("PUT", uri, params); end
|
8
|
+
def delete(uri, params={}); perform_request("DELETE", uri, params); end
|
9
|
+
private
|
10
|
+
def perform_request(request_method, uri, params)
|
11
|
+
http_reset
|
12
|
+
params = params.inject({}) { |acc,(key,val)| acc[key] = val.to_s; acc }
|
13
|
+
@env = ::Rack::MockRequest.env_for(uri, {:params => params, :method => request_method}).merge(@env)
|
14
|
+
@env['action_dispatch.show_exceptions'] = false
|
15
|
+
@app.call(@env)
|
16
|
+
end
|
17
|
+
end # HttpMethods
|
18
|
+
end # ActionController
|
19
|
+
end # RiotRails
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RiotRails
|
2
|
+
class ActiveRecordMiddleware < Riot::ContextMiddleware
|
3
|
+
register
|
4
|
+
|
5
|
+
def call(context)
|
6
|
+
if handle?(context)
|
7
|
+
context.setup(true) { context.description.new }
|
8
|
+
end
|
9
|
+
middleware.call(context)
|
10
|
+
end
|
11
|
+
private
|
12
|
+
def handle?(context)
|
13
|
+
description = context.description
|
14
|
+
description.kind_of?(Class) && description.ancestors.include?(::ActiveRecord::Base)
|
15
|
+
end
|
16
|
+
end # ActiveRecordMiddleware
|
17
|
+
end # RiotRails
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module RiotRails
|
2
|
+
module ActiveRecord
|
3
|
+
|
4
|
+
# An ActiveRecord assertion macro that looks for an index on a given set of attributes in the table
|
5
|
+
# used by the model under test (aka: topic).
|
6
|
+
#
|
7
|
+
# asserts_topic.has_database_index_on :name
|
8
|
+
# asserts_topic.has_database_index_on :email, :group_name
|
9
|
+
#
|
10
|
+
# In the form used above, the assertion will pass if any index is found with the attributes listed
|
11
|
+
# (unique or not). To be specific about uniqueness, provide the +:unique+ option.
|
12
|
+
#
|
13
|
+
# asserts_topic.has_database_index_on :email, :unique => true
|
14
|
+
# asserts_topic.has_database_index_on :name, :unique => false
|
15
|
+
#
|
16
|
+
# The last example will require that the index not be a unique one.
|
17
|
+
class HasDatabaseIndexOnMacro < Riot::AssertionMacro
|
18
|
+
register :has_database_index_on
|
19
|
+
|
20
|
+
def initialize(database_connection=nil) # Good for testing :)
|
21
|
+
@database_connection = database_connection
|
22
|
+
end
|
23
|
+
|
24
|
+
def evaluate(actual, *attributes_and_options)
|
25
|
+
attributes, options = extract_options_from(attributes_and_options)
|
26
|
+
unique = options[:unique]
|
27
|
+
|
28
|
+
index = find_index(actual, attributes, unique)
|
29
|
+
|
30
|
+
static_message = "#{unique ? "unique" : ""} index on #{attributes.inspect}".strip
|
31
|
+
index.nil? ? fail("expected #{static_message}") : pass("has #{static_message}")
|
32
|
+
end
|
33
|
+
private
|
34
|
+
def database_connection; @database_connection || ::ActiveRecord::Base.connection; end
|
35
|
+
|
36
|
+
def find_index(model, attributes, uniqueness, &block)
|
37
|
+
database_connection.indexes(model.class.table_name).find do |the_index|
|
38
|
+
unique_enough?(uniqueness, the_index) && attributes_match?(attributes, the_index)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def unique_enough?(uniqueness, index)
|
43
|
+
return true if uniqueness.nil?
|
44
|
+
index.unique == uniqueness
|
45
|
+
end
|
46
|
+
|
47
|
+
def attributes_match?(attributes, index)
|
48
|
+
Set.new(attributes.map(&:to_s)) == Set.new(index.columns)
|
49
|
+
end
|
50
|
+
|
51
|
+
def extract_options_from(attributes)
|
52
|
+
options = attributes.last.kind_of?(Hash) ? attributes.pop : {}
|
53
|
+
[attributes, options]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end # ActiveRecord
|
58
|
+
end # RiotRails
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module RiotRails
|
2
|
+
module ActiveRecord
|
3
|
+
protected
|
4
|
+
|
5
|
+
class ReflectionAssertionMacro < Riot::AssertionMacro
|
6
|
+
private
|
7
|
+
def reflection_match?(expected, reflection)
|
8
|
+
!reflection.nil? && (expected == reflection.macro.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
def options_match_for_reflection?(reflection, options)
|
12
|
+
options.all? { |k, v| reflection.options[k] == v }
|
13
|
+
end
|
14
|
+
|
15
|
+
def assert_reflection(expected, record, attribute, options=nil)
|
16
|
+
options ||= {}
|
17
|
+
reflection = record.class.reflect_on_association(attribute)
|
18
|
+
if reflection_match?(expected, reflection)
|
19
|
+
if options_match_for_reflection?(reflection, options)
|
20
|
+
pass new_message(attribute).is_a.push(expected).association
|
21
|
+
else
|
22
|
+
fail expected_message.push("#{expected} #{attribute.inspect}").with(options)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
fail new_message(attribute).is_not_a.push(expected).association
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
public
|
31
|
+
|
32
|
+
# An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a +has_many+
|
33
|
+
# association. Will fail if an association is not defined for the attribute or if the association is
|
34
|
+
# not +has_many+.
|
35
|
+
#
|
36
|
+
# context "a Room" do
|
37
|
+
# setup { Room.new }
|
38
|
+
#
|
39
|
+
# asserts_topic.has_many(:doors)
|
40
|
+
# asserts_topic.has_many(:floors) # should probably fail given our current universe :)
|
41
|
+
# end
|
42
|
+
class HasManyMacro < ReflectionAssertionMacro
|
43
|
+
register :has_many
|
44
|
+
|
45
|
+
def evaluate(actual, *expectings)
|
46
|
+
attribute, options = *expectings
|
47
|
+
assert_reflection("has_many", actual, attribute, options)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a
|
52
|
+
# +has_one+ association. Will fail if an association is not defined for the attribute or if the
|
53
|
+
# association is not +has_one+.
|
54
|
+
#
|
55
|
+
# context "a Room" do
|
56
|
+
# setup { Room.new }
|
57
|
+
#
|
58
|
+
# asserts_topic.has_one(:floor)
|
59
|
+
# end
|
60
|
+
class HasOneMacro < ReflectionAssertionMacro
|
61
|
+
register :has_one
|
62
|
+
|
63
|
+
def evaluate(actual, *expectings)
|
64
|
+
attribute, options = *expectings
|
65
|
+
assert_reflection("has_one", actual, attribute, options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a
|
70
|
+
# +belongs_to+ association. Will fail if an association is not defined for the attribute or if the
|
71
|
+
# association is not +belongs_to+.
|
72
|
+
#
|
73
|
+
# context "a Room" do
|
74
|
+
# setup { Room.new }
|
75
|
+
#
|
76
|
+
# asserts_topic.belongs_to(:house)
|
77
|
+
# end
|
78
|
+
class BelongsToMacro < ReflectionAssertionMacro
|
79
|
+
register :belongs_to
|
80
|
+
|
81
|
+
def evaluate(actual, *expectings)
|
82
|
+
attribute, options = *expectings
|
83
|
+
assert_reflection("belongs_to", actual, attribute, options)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a
|
88
|
+
# +has_and_belongs_to_many+ association. Will fail if an association is not defined for the attribute or
|
89
|
+
# if the association is not +has_and_belongs_to_many+.
|
90
|
+
#
|
91
|
+
# context "a Room" do
|
92
|
+
# setup { Room.new }
|
93
|
+
#
|
94
|
+
# asserts_topic.has_and_belongs_to_many(:walls)
|
95
|
+
# end
|
96
|
+
class HasAndBelongsToManyMacro < ReflectionAssertionMacro
|
97
|
+
register :has_and_belongs_to_many
|
98
|
+
|
99
|
+
def evaluate(actual, *expectings)
|
100
|
+
attribute, options = *expectings
|
101
|
+
assert_reflection("has_and_belongs_to_many", actual, attribute, options)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end # ActiveRecord
|
106
|
+
end # RiotRails
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RiotRails
|
2
|
+
class TransactionalMiddleware < Riot::ContextMiddleware
|
3
|
+
register
|
4
|
+
|
5
|
+
def call(context)
|
6
|
+
middleware.call(context)
|
7
|
+
hijack_local_run(context) if handle?(context)
|
8
|
+
end
|
9
|
+
private
|
10
|
+
def handle?(context)
|
11
|
+
context.option(:transactional) == true
|
12
|
+
end
|
13
|
+
|
14
|
+
# Don't you just love mr. metaclass?
|
15
|
+
def hijack_local_run(context)
|
16
|
+
(class << context; self; end).class_eval do
|
17
|
+
alias_method :transactionless_local_run, :local_run
|
18
|
+
def local_run(*args)
|
19
|
+
::ActiveRecord::Base.transaction do
|
20
|
+
transactionless_local_run(*args)
|
21
|
+
raise ::ActiveRecord::Rollback
|
22
|
+
end
|
23
|
+
end # local_run
|
24
|
+
end # metaclass
|
25
|
+
end # hijack_local_run
|
26
|
+
|
27
|
+
end # TransactionalMiddleware
|
28
|
+
end # RiotRails
|