spec/authority/controller_spec.rb in authority-2.2.0 vs spec/authority/controller_spec.rb in authority-2.3.0
- old
+ new
@@ -1,147 +1,212 @@
require 'spec_helper'
-require 'support/example_model'
-require 'support/example_controllers'
+require 'support/example_classes'
require 'support/mock_rails'
-require 'support/user'
require 'active_support/core_ext/proc'
describe Authority::Controller do
- describe "the security violation callback" do
-
- it "should call whatever method on the controller that the configuration specifies" do
- # Here be dragons!
- @fake_exception = Exception.new
- @sample_controller = SampleController.new
- # If a callback is passed to a controller's `rescue_from` method as the value for
- # the `with` option (like `SomeController.rescue_from FooException, :with => some_callback`),
- # Rails will use ActiveSupport's `Proc#bind` to ensure that when the proc refers to
- # `self`, it will be the controller, not the proc itself.
- # I need this callback's `self` to be the controller for the purposes of
- # this test, so I'm stealing that behavior.
- @callback = Authority::Controller.security_violation_callback.bind(@sample_controller)
-
- Authority.configuration.security_violation_handler = :fire_ze_missiles
- @sample_controller.should_receive(:fire_ze_missiles).with(@fake_exception)
- @callback.call(@fake_exception)
- end
+ class ExampleController
+ def self.rescue_from(*args) ; end
+ def self.before_filter(*args) ; end
end
- describe "when including" do
+ # Get a fresh descendant class for each test, in case we've modified it
+ let(:controller_class) { Class.new(ExampleController) }
+ context "when including" do
+
before :each do
Authority::Controller.stub(:security_violation_callback).and_return(Proc.new {|exception| })
end
- it "should specify rescuing security violations with a standard callback" do
- SampleController.should_receive(:rescue_from).with(Authority::SecurityViolation, :with => Authority::Controller.security_violation_callback)
- SampleController.send(:include, Authority::Controller)
+ after :each do
+ controller_class.send(:include, Authority::Controller)
end
+ it "specifies rescuing security violations with a standard callback" do
+ controller_class.should_receive(:rescue_from).with(
+ Authority::SecurityViolation, :with => Authority::Controller.security_violation_callback
+ )
+ end
+
end
- describe "after including" do
+ context "after including" do
+ let(:controller_class) do
+ Class.new(ExampleController).tap do |c|
+ c.send(:include, Authority::Controller)
+ end
+ end
+
+ let(:resource_class) { ExampleResource }
+
+ describe "the security violation callback" do
+
+ it "calls whatever method on the controller that the configuration specifies" do
+ # Here be dragons!
+ fake_exception = Exception.new
+ controller_instance = controller_class.new
+ # If a callback is passed to a controller's `rescue_from` method as the value for
+ # the `with` option (like `SomeController.rescue_from FooException, :with => some_callback`),
+ # Rails will use ActiveSupport's `Proc#bind` to ensure that when the proc refers to
+ # `self`, it will be the controller, not the proc itself.
+ # I need this callback's `self` to be the controller for the purposes of
+ # this test, so I'm stealing that behavior.
+ callback = Authority::Controller.security_violation_callback.bind(controller_instance)
+
+ Authority.configuration.security_violation_handler = :fire_ze_missiles
+ controller_instance.should_receive(:fire_ze_missiles).with(fake_exception)
+ callback.call(fake_exception)
+ end
+ end
+
describe "the authority controller action map" do
- it "should be created on demand" do
- ExampleController.instance_variable_set(:@authority_action_map, nil)
- ExampleController.authority_action_map.should be_a(Hash)
- ExampleController.authority_action_map.should_not be(Authority.configuration.controller_action_map)
+ before(:each) { controller_class.instance_variable_set(:@authority_action_map, nil) }
+
+ it "is created on demand" do
+ expect(controller_class.authority_action_map).to be_a(Hash)
end
- describe "when subclassing" do
- it "should allow the child class to edit the controller action map without affecting the parent class" do
- DummyController.authority_action :erase => 'delete'
- ExampleController.authority_action_map[:erase].should be_nil
- end
+ it "is created as a copy of the configured controller action map" do
+ expect(controller_class.authority_action_map).to eq(Authority.configuration.controller_action_map)
+ expect(controller_class.authority_action_map).not_to be(Authority.configuration.controller_action_map)
end
+ it "is unique per controller" do
+ child_controller = Class.new(controller_class)
+ expect(child_controller.authority_action_map).not_to be(
+ controller_class.authority_action_map
+ )
+ end
+
end
- describe "DSL (class) methods" do
- it "should allow specifying the model to protect" do
- ExampleController.authorize_actions_for ExampleModel
- ExampleController.authority_resource.should eq(ExampleModel)
- end
+ describe "class methods" do
- it "should pass the options provided to the before filter that is set up" do
- @options = {:only => [:show, :edit, :update]}
- ExampleController.should_receive(:before_filter).with(:run_authorization_check, @options)
- ExampleController.authorize_actions_for ExampleModel, @options
- end
+ describe "authorize_actions_for" do
- it "should allow specifying the authority action map in the `authorize_actions_for` declaration" do
- ExampleController.authorize_actions_for ExampleModel, :actions => {:eat => 'delete'}
- ExampleController.authority_action_map[:eat].should eq('delete')
+ it "allows specifying the model to protect" do
+ controller_class.authorize_actions_for(resource_class)
+ expect(controller_class.authority_resource).to eq(resource_class)
+ end
+
+ it "sets up a before_filter, passing the options it was given" do
+ filter_options = {:only => [:show, :edit, :update]}
+ controller_class.should_receive(:before_filter).with(:run_authorization_check, filter_options)
+ controller_class.authorize_actions_for(resource_class, filter_options)
+ end
+
+ it "passes the action hash to the `authority_action` method" do
+ child_controller = Class.new(controller_class)
+ new_actions = {:synthesize => :create, :annihilate => 'delete'}
+ child_controller.should_receive(:authority_actions).with(new_actions)
+ child_controller.authorize_actions_for(resource_class, :actions => new_actions)
+ end
+
end
- it "should have a write into the authority actions map usuable in a DSL format" do
- ExampleController.authority_action :smite => 'delete'
- ExampleController.authority_action_map[:smite].should eq('delete')
+ describe "authority_action" do
+
+ it "modifies this controller's authority action map" do
+ new_actions = {:show => :display, :synthesize => :create, :annihilate => 'delete'}
+ controller_class.authority_actions(new_actions)
+ expect(controller_class.authority_action_map).to eq(
+ Authority.configuration.controller_action_map.merge(new_actions)
+ )
+ end
+
+ it "does not modify any other controller" do
+ child_controller = Class.new(controller_class)
+ child_controller.authority_actions(:smite => 'delete')
+ expect(controller_class.authority_action_map[:smite]).to eq(nil)
+ end
+
end
+
end
describe "instance methods" do
- before :each do
- @user = User.new
- @controller = ExampleController.new
- @controller.stub!(:action_name).and_return(:edit)
- @controller.stub!(Authority.configuration.user_method).and_return(@user)
- end
- it "should check authorization on the model specified" do
- @controller.should_receive(:authorize_action_for).with(ExampleModel)
- @controller.send(:run_authorization_check)
+ let(:controller_class) do
+ Class.new(ExampleController).tap do |c|
+ c.send(:include, Authority::Controller)
+ c.authorize_actions_for(resource_class)
+ end
end
- it "should pass the options provided to `authorize_action_for` downstream" do
- @controller.stub!(:action_name).and_return(:destroy)
- Authority.should_receive(:enforce).with('delete', ExampleModel, @user, :for => 'context')
- @controller.send(:authorize_action_for, ExampleModel, :for => 'context')
+ let(:controller_instance) do
+ controller_class.new.tap do |cc|
+ cc.stub(Authority.configuration.user_method).and_return(user)
+ end
end
- it "should raise a SecurityViolation if authorization fails" do
- expect { @controller.send(:run_authorization_check) }.to raise_error(Authority::SecurityViolation)
- end
+ let(:user) { ExampleUser.new }
- it "should raise a MissingAction if there is no corresponding action for the controller" do
- @controller.stub(:action_name).and_return('sculpt')
- expect { @controller.send(:run_authorization_check) }.to raise_error(Authority::Controller::MissingAction)
+ describe "run_authorization_check (used as a before_filter)" do
+
+ it "checks authorization on the model specified" do
+ controller_instance.should_receive(:authorize_action_for).with(resource_class)
+ controller_instance.send(:run_authorization_check)
+ end
+
+ it "raises a MissingAction if there is no corresponding action for the controller" do
+ controller_instance.stub(:action_name).and_return('sculpt')
+ expect { controller_instance.send(:run_authorization_check) }.to raise_error(
+ Authority::Controller::MissingAction
+ )
+ end
+
end
- it "should return the authority_user for the current request by using the configured user_method" do
- @controller.should_receive(Authority.configuration.user_method)
- @controller.send(:authority_user)
+ describe "authorize_action_for" do
+
+ before(:each) { controller_instance.stub(:action_name).and_return(:destroy) }
+
+ it "calls Authority.enforce to authorize the action" do
+ Authority.should_receive(:enforce)
+ controller_instance.send(:authorize_action_for, resource_class)
+ end
+
+ it "passes along any options it was given" do
+ options = {:for => 'insolence'}
+ Authority.should_receive(:enforce).with('delete', resource_class, user, options)
+ controller_instance.send(:authorize_action_for, resource_class, options)
+ end
+
end
- describe "in controllers that inherited from a controller including authority, but don't call any class method" do
- it "should automatically have a new copy of the authority_action_map" do
- @controller = InstanceController.new
- @controller.class.authority_action_map.should eq(Authority.configuration.controller_action_map)
+ describe "authority_user" do
+
+ it "gets the user for the current request from the configured user_method" do
+ controller_instance.should_receive(Authority.configuration.user_method)
+ controller_instance.send(:authority_user)
end
+
end
describe "authority_forbidden action" do
- before :each do
- @mock_error = mock(:message => 'oh noes! an error!')
- end
+ let(:mock_error) { mock(:message => 'oh noes! an error!') }
- it "should log an error" do
+ it "logs an error" do
Authority.configuration.logger.should_receive(:warn)
- @controller.stub(:render)
- @controller.send(:authority_forbidden, @mock_error)
+ controller_instance.stub(:render)
+ controller_instance.send(:authority_forbidden, mock_error)
end
- it "should render the public/403.html file" do
+ it "renders the public/403.html file" do
forbidden_page = Rails.root.join('public/403.html')
Authority.configuration.logger.stub(:warn)
- @controller.should_receive(:render).with(:file => forbidden_page, :status => 403, :layout => false)
- @controller.send(:authority_forbidden, @mock_error)
+ controller_instance.should_receive(:render).with(:file => forbidden_page, :status => 403, :layout => false)
+ controller_instance.send(:authority_forbidden, mock_error)
end
+
end
+
end
+
end
end