├── .gitignore ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── circle.yml ├── lib ├── policy_assertions.rb └── policy_assertions │ ├── configuration.rb │ ├── errors.rb │ └── version.rb ├── policy-assertions.gemspec └── test ├── .rubocop.yml ├── lib ├── policy-assertions │ ├── configuration_test.rb │ └── version_test.rb └── policy_assertions_test.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - 'policy-assertions.gemspec' 4 | DisplayCopNames: true 5 | DisplayStyleGuide: true 6 | 7 | Style/Documentation: 8 | Enabled: false 9 | 10 | Style/HashSyntax: 11 | EnforcedStyle: hash_rockets -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v0.2.0 2 | * [Add support for testing policies that are not of type "#{record.class}Policy" #14](https://github.com/ProctorU/policy-assertions/pull/14) - Thanks @marceloeloelo! 3 | 4 | ## v0.1.0 5 | * [Adds support for arrays as actions in block tests](https://github.com/ProctorU/policy-assertions/pull/10) 6 | * [Adds support for `assert_not_permitted`](https://github.com/ProctorU/policy-assertions/pull/12) 7 | * [Readme updates](https://github.com/ProctorU/policy-assertions/pull/11) 8 | * Transferred ownership from @ksimmons to @proctoru 9 | 10 | ## v0.0.3 11 | 12 | * Compatibility with pundit 1.1.0 13 | 14 | ## v0.0.1 15 | 16 | * initial release 17 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in policy-assertions.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Kevin Simmons 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # policy-assertions 2 | 3 | [![Build Status](https://circleci.com/gh/ProctorU/policy-assertions.svg?style=shield&circle-token=7084a829c9e63b415f59e627d9e4ee90db7d2afa)](https://circleci.com/gh/ProctorU/policy-assertions) [![Gem Version](https://badge.fury.io/rb/policy-assertions.svg)](https://badge.fury.io/rb/policy-assertions) 4 | 5 | Minitest test assertions for [Pundit](https://github.com/elabs/pundit) policies. 6 | 7 | policy-assertions provides a test class for easy Pundit testing. The test class provides assertions and refutations for policies and strong parameters. 8 | 9 | ## Table of contents 10 | 11 | * [Installation](#installation) 12 | * [Usage](#usage) 13 | * [Available test methods](#test-method-naming) 14 | * [Configuration](#configuration) 15 | * [Developing](#developing) 16 | * [Credits](#credits) 17 | 18 | ## Installation 19 | 20 | Add this line to your application's Gemfile: 21 | 22 | ```ruby 23 | gem 'policy-assertions' 24 | 25 | # if using Rails you can add it to your test block: 26 | 27 | group :test do 28 | gem 'policy-assertions' 29 | end 30 | ``` 31 | 32 | And then execute: 33 | 34 | $ bundle 35 | 36 | Or install it yourself as: 37 | 38 | $ gem install policy-assertions 39 | 40 | **Add require policy_assertions to test_helper.rb** 41 | 42 | ```ruby 43 | require 'policy_assertions' 44 | ``` 45 | 46 | ## Usage 47 | 48 | policy-assertions is intended to make testing Pundit policies as simple as possible. The gem adds the following helpers: 49 | 50 | * PolicyAssertions::Test class 51 | * parses permissions to test from method name 52 | * assert_permit and refute_permit methods 53 | * assert_strong_parameters 54 | 55 | The following code sample illustrates the intended use of this gem. 56 | 57 | ```ruby 58 | # The class is named after the policy to be tested. 59 | class ArticlePolicyTest < PolicyAssertions::Test 60 | 61 | # Test that the Article model allows index and show 62 | # for any site visitor. nil is passed in for the user. 63 | def test_index_and_show 64 | assert_permit nil, Article 65 | end 66 | 67 | # Test that a site staff member is allowed access 68 | # to new and create 69 | def test_new_and_create 70 | assert_permit users(:staff), Article 71 | end 72 | 73 | # Test that this user cannot delete this article 74 | def test_destroy 75 | refute_permit users(:regular), articles(:instructions) 76 | # Alternate method name 77 | assert_not_permitted users(:regular), articles(:instructions) 78 | end 79 | 80 | # Test a permission by passing in an array instead of 81 | # defining it in the method name 82 | def test_name_is_not_a_permission 83 | refute_permit nil, Article, 'create?', 'new?' 84 | end 85 | 86 | # Test that a site staff member has access to the 87 | # parameters defined in the params array. 88 | # Site visitors should not have access to any Article attributes 89 | def test_strong_parameters 90 | params = [:title, :body, :tags] 91 | assert_strong_parameters(users(:staff), Article, 92 | article_attributes, params) 93 | 94 | assert_strong_parameters(nil, Article, article_attributes, []) 95 | end 96 | end 97 | ``` 98 | 99 | If policies are namespaced, the invocation of the class name should follow the same syntax as Pundit. 100 | 101 | ```ruby 102 | # Test that the Organizations::Article model allows index and show 103 | # for any site visitor. nil is passed in for the user. 104 | def test_index_and_show 105 | assert_permit nil, [:organizations, Article] 106 | end 107 | ``` 108 | 109 | ## Test method naming 110 | 111 | policy-assertions can read the permissions to test from the method name. This will only work when using the minitest def test_name syntax. When using the block syntax, you must explicitly pass the permission names. 112 | 113 | ```ruby 114 | # Good 115 | # The create permission will be parsed from this method name 116 | def test_create 117 | end 118 | 119 | # Good 120 | # multiple permissions are defined in this method name 121 | def test_show_and_index 122 | end 123 | 124 | # Good block syntax 125 | # The permission cannot be automatically read, so you must pass the policy names directly. 126 | test 'create' do 127 | refute_permit nil, Article, 'create?', 'new?' 128 | end 129 | ``` 130 | 131 | Define multiple permissions in a method name by separating the permissions using '\_and\_'. 132 | 133 | See the configuration section for changing the separator value. 134 | 135 | ### assert_permit and refute_permit 136 | 137 | These methods take the following parameters: 138 | 139 | * User to authorize 140 | * Model or instance to authorize 141 | * Optional array of permissions. They should match the permission method name exactly. 142 | 143 | #### Passing permissions to assert and refute 144 | 145 | When permissions are passed to assert or refute, the test method name is ignored and does not need to match a policy permission. 146 | 147 | ```ruby 148 | class ArticlePolicyTest < PolicyAssertions::Test 149 | # this method name is not parsed since the permissions 150 | # are passed into the method 151 | def test_that_a_user_can_do_stuff 152 | assert_permit nil, Article, 'show?', 'index?' 153 | end 154 | end 155 | ``` 156 | 157 | ### Using the rails test block helper 158 | 159 | policy-assertions will work with the rails test block helper but it cannot parse the permissions. If a test block is used and the permissions are not passed to the `assert` and `refute` methods, a PolicyAssertions::MissingBlockParameters error will be thrown. 160 | 161 | ```ruby 162 | class ArticlePolicyTest < PolicyAssertions::Test 163 | test 'index?' do 164 | assert_permit @user, Article, 'index?', 'show?' 165 | end 166 | 167 | # Actions can also be passed as an array 168 | test 'index?' do 169 | assert_permit @user, Article, %w(index? show?) 170 | end 171 | 172 | # this will result in a 173 | # PolicyAssertions::MissingBlockParameters error 174 | test 'show?' do 175 | assert_permit @user, Article 176 | end 177 | end 178 | ``` 179 | 180 | ### Strong Parameters 181 | 182 | Since Pundit offers a [permitted_attributes](https://github.com/elabs/pundit#strong-parameters) helper, policy-assertions provides an assert method for testing. 183 | 184 | ```ruby 185 | class ArticlePolicyTest < PolicyAssertions::Test 186 | # Test that a site staff member has access to the 187 | # parameters defined in the params method. 188 | # Site visitors should not have access to any Article attributes 189 | def test_strong_parameters 190 | params = [:title, :body, :tags] 191 | assert_strong_parameters(users(:staff), Article, 192 | article_attributes, params) 193 | 194 | assert_strong_parameters(nil, Article, article_attributes, []) 195 | end 196 | end 197 | ``` 198 | 199 | ## Configuration 200 | 201 | Use the following in your test helper to change the test definition permissions separator. 202 | 203 | ```ruby 204 | PolicyAssertions.config.separator = '__separator__' 205 | ``` 206 | 207 | ## Test Output Results 208 | 209 | You may find that the output of certain tests results are confusing. e.g.: 210 | 211 | ```shell 212 | Expected ProjectPolicy to grant update? on # for # but it didn't 213 | ``` 214 | 215 | What is `#`? A way to solve this problem is to simply monkey patch the `to_s` method within your tests. 216 | 217 | ```ruby 218 | # e.g. test_helper 219 | ENV['RAILS_ENV'] ||= 'test' 220 | require_relative '../config/environment' 221 | require 'rails/test_help' 222 | require 'policy_assertions' 223 | 224 | ## Add in this module 225 | module PatchUser 226 | refine User do 227 | def to_s 228 | email 229 | end 230 | end 231 | end 232 | 233 | # Apply the monkey patch only here 234 | class ActiveSupport::TestCase 235 | using PatchUser 236 | 237 | # etc etc. 238 | end 239 | ``` 240 | 241 | After doing that, you will get more meaningful test message outputs: 242 | 243 | ```shell 244 | Expected ProjectPolicy to grant update? on # for freddie@queen.com but it didn't 245 | ``` 246 | 247 | ## Developing 248 | 249 | 1. Fork it ( https://github.com/[my-github-username]/policy-assertions/fork ) 250 | 2. Create your feature branch (`git checkout -b my-new-feature`) 251 | 3. Commit your changes with tests (`git commit -am 'Add some feature'`) 252 | 4. Push to the branch (`git push origin my-new-feature`) 253 | 5. Create a new Pull Request 254 | 255 | ## Credits 256 | 257 | Policy-assertions is maintained and funded by [ProctorU](https://twitter.com/ProctorU), 258 | a simple online proctoring service that allows you to take exams or 259 | certification tests at home. 260 | 261 | We'd like to thank [@ksimmons](https://github.com/ksimmons) for being the original creator of policy-assertions and allowing us to maintain the project. 262 | 263 |
264 | 265 |

266 | 267 | 268 | 269 | 270 |

271 | ProctorU Engineering & Design 272 |

273 |

274 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/testtask' 3 | 4 | Rake::TestTask.new do |test| 5 | test.libs << 'lib' << 'test' 6 | test.pattern = 'test/**/*_test.rb' 7 | test.verbose = false 8 | end 9 | 10 | task :default => :test 11 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | override: 3 | - 'rvm-exec 2.1.10 bundle install' 4 | - 'rvm-exec 2.2.8 bundle install' 5 | - 'rvm-exec 2.3.5 bundle install' 6 | - 'rvm-exec 2.4.2 bundle install' 7 | 8 | test: 9 | override: 10 | - 'rvm-exec 2.1.10 bundle exec rake' 11 | - 'rvm-exec 2.2.8 bundle exec rake' 12 | - 'rvm-exec 2.3.5 bundle exec rake' 13 | - 'rvm-exec 2.4.2 bundle exec rake' 14 | -------------------------------------------------------------------------------- /lib/policy_assertions.rb: -------------------------------------------------------------------------------- 1 | require 'rack' 2 | require 'pundit' 3 | require 'rack/test' 4 | require 'active_support' 5 | 6 | if Gem::Specification.find_all_by_name('strong_parameters').empty? 7 | require 'action_controller/metal/strong_parameters' 8 | else 9 | require 'strong_parameters' 10 | end 11 | 12 | require 'policy_assertions/errors' 13 | require 'policy_assertions/version' 14 | require 'policy_assertions/configuration' 15 | 16 | module PolicyAssertions 17 | class Test < ActiveSupport::TestCase 18 | def assert_permit(user, record, *permissions) 19 | get_permissions(permissions.flatten).each do |permission| 20 | policy = find_policy!(user, record) 21 | assert policy.public_send(permission), 22 | "Expected #{policy.class.name} to grant #{permission} "\ 23 | "on #{record} for #{user} but it didn't" 24 | end 25 | end 26 | 27 | def refute_permit(user, record, *permissions) 28 | get_permissions(permissions.flatten).each do |permission| 29 | policy = find_policy!(user, record) 30 | refute policy.public_send(permission), 31 | "Expected #{policy.class.name} not to grant #{permission} "\ 32 | "on #{record} for #{user} but it did" 33 | end 34 | end 35 | alias assert_not_permitted refute_permit 36 | 37 | def assert_strong_parameters(user, record, params_hash, allowed_params) 38 | policy = find_policy!(user, record) 39 | 40 | param_key = find_param_key(record) 41 | 42 | params = ActionController::Parameters.new(param_key => params_hash) 43 | 44 | strong_params = params.require(param_key) 45 | .permit(*policy.permitted_attributes).keys 46 | 47 | strong_params.each do |param| 48 | assert_includes allowed_params, param.to_sym, 49 | "User #{user} should not be permitted to "\ 50 | "update parameter [#{param}]" 51 | end 52 | end 53 | 54 | private 55 | 56 | # borrowed from Pundit::PolicyFinder 57 | def find_param_key(record) 58 | if record.respond_to?(:model_name) 59 | record.model_name.param_key.to_s 60 | elsif record.is_a?(Class) 61 | record.to_s.demodulize.underscore 62 | else 63 | record.class.to_s.demodulize.underscore 64 | end 65 | end 66 | 67 | def get_permissions(permissions) 68 | return permissions if permissions.present? 69 | 70 | name = calling_method 71 | 72 | fail(MissingBlockParameters) if name.start_with?('block') 73 | 74 | # remove 'test_' and split 75 | # append ? to the permission 76 | name[5..-1].split(PolicyAssertions.config.separator).map { |a| "#{a}?" } 77 | end 78 | 79 | def calling_method 80 | if PolicyAssertions.config.ruby_version > 1 81 | caller_locations(3, 1)[0].label 82 | else 83 | caller[2][/`.*'/][1..-2] 84 | end 85 | end 86 | 87 | def find_policy!(user, record) 88 | described_policy = self.respond_to?(:described_class) ? described_class : nil 89 | described_policy ? described_policy.new(user, record) : Pundit.policy!(user, record) 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /lib/policy_assertions/configuration.rb: -------------------------------------------------------------------------------- 1 | module PolicyAssertions 2 | Configuration = Struct.new(:separator, :ruby_version) 3 | @config = Configuration.new('_and_', RUBY_VERSION.split('.')[0].to_i) 4 | 5 | # rubocop:disable Style/TrivialAccessors 6 | def self.config 7 | @config 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/policy_assertions/errors.rb: -------------------------------------------------------------------------------- 1 | module PolicyAssertions 2 | class MissingBlockParameters < StandardError 3 | def message 4 | 'PolicyTest must pass the permissions into the assert if called ' \ 5 | 'from the Rails test block method. Use def test_testname method ' \ 6 | 'to have the permissions parsed automatically.' 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/policy_assertions/version.rb: -------------------------------------------------------------------------------- 1 | module PolicyAssertions 2 | VERSION = '0.2.0' 3 | end 4 | -------------------------------------------------------------------------------- /policy-assertions.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'policy_assertions/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "policy-assertions" 8 | spec.version = PolicyAssertions::VERSION 9 | spec.authors = ['ProctorU'] 10 | spec.email = ['engineering.team@proctoru.com'] 11 | spec.summary = %q{Minitest assertions for Pundit policies.} 12 | spec.description = %q{Minitest assertions for Pundit policies.} 13 | spec.homepage = 'https://github.com/proctoru/policy-assertions' 14 | spec.license = "MIT" 15 | 16 | spec.required_ruby_version = '>= 1.9.3' 17 | 18 | spec.files = `git ls-files -z`.split("\x0") 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 21 | spec.require_paths = ["lib"] 22 | 23 | spec.add_development_dependency 'bundler', '~> 1.3' 24 | spec.add_development_dependency 'rake' 25 | spec.add_development_dependency 'minitest', '~> 5.6' 26 | spec.add_development_dependency 'actionpack', '>= 3.0.0' 27 | spec.add_development_dependency 'rack', '~> 1.6.1' 28 | spec.add_development_dependency 'rack-test', '~> 0.6.3' 29 | 30 | spec.add_dependency 'pundit', '>= 1.0.0' 31 | spec.add_dependency 'activesupport', '>= 3.0.0' 32 | end 33 | -------------------------------------------------------------------------------- /test/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | DisplayCopNames: true 3 | DisplayStyleGuide: true 4 | 5 | Style/Documentation: 6 | Enabled: false 7 | 8 | Style/HashSyntax: 9 | EnforcedStyle: hash_rockets -------------------------------------------------------------------------------- /test/lib/policy-assertions/configuration_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ConfigurationTest < Minitest::Test 4 | def test_configuration_exists 5 | refute_nil PolicyAssertions.config 6 | end 7 | 8 | def test_seperator 9 | assert_equal '_and_', PolicyAssertions.config.separator 10 | end 11 | 12 | def test_ruby_version 13 | refute_nil PolicyAssertions.config.ruby_version 14 | 15 | assert PolicyAssertions.config.ruby_version > 0 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/lib/policy-assertions/version_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class VersionTest < Minitest::Test 4 | def test_must_be_defined 5 | refute_nil PolicyAssertions::VERSION 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/lib/policy_assertions_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class MultipleAssertionsTest < Minitest::Test 4 | def test_assert_multiple_permissions_pass 5 | test_runner = policy_class do 6 | def test_index_and_create 7 | assert_permit User.new, Article 8 | end 9 | end.new :test_index_and_create 10 | 11 | test_runner.run 12 | assert test_runner.passed? 13 | end 14 | 15 | def test_assert_multiple_permissions_fail 16 | test_runner = policy_class do 17 | def test_index_and_create 18 | assert_permit nil, Article 19 | end 20 | end.new :test_index_and_create 21 | 22 | test_runner.run 23 | refute test_runner.passed? 24 | end 25 | 26 | def test_refute_multiple_permissions_pass 27 | test_runner = policy_class do 28 | def test_index_and_create 29 | refute_permit nil, Article 30 | end 31 | end.new :test_index_and_create 32 | 33 | test_runner.run 34 | refute test_runner.passed? 35 | end 36 | 37 | def test_refute_multiple_permissions_fail 38 | test_runner = policy_class do 39 | def test_index_and_create 40 | refute_permit User.new, Article 41 | end 42 | end.new :test_index_and_create 43 | 44 | test_runner.run 45 | refute test_runner.passed? 46 | end 47 | end 48 | 49 | class AssertionsTest < Minitest::Test 50 | def test_long_permission_names 51 | test_runner = policy_class do 52 | def test_long_action_and_index 53 | assert_permit nil, Article 54 | end 55 | end.new :test_long_action_and_index 56 | 57 | test_runner.run 58 | assert test_runner.passed? 59 | end 60 | 61 | def test_permission_passed 62 | test_runner = policy_class do 63 | def test_create 64 | assert_permit User.new, Article 65 | end 66 | end.new :test_create 67 | 68 | test_runner.run 69 | assert test_runner.passed? 70 | end 71 | 72 | def test_permission_failed_expected_to_pass 73 | test_runner = policy_class do 74 | def test_create 75 | assert_permit nil, Article 76 | end 77 | end.new :test_create 78 | 79 | test_runner.run 80 | refute test_runner.passed? 81 | end 82 | 83 | def test_permission_passed_expected_to_fail 84 | test_runner = policy_class do 85 | def test_create 86 | refute_permit User.new, Article 87 | end 88 | end.new :test_create 89 | 90 | test_runner.run 91 | refute test_runner.passed? 92 | end 93 | 94 | def test_permission_failed 95 | test_runner = policy_class do 96 | def test_create 97 | refute_permit nil, Article 98 | end 99 | end.new :test_create 100 | 101 | test_runner.run 102 | assert test_runner.passed? 103 | end 104 | 105 | def test_permission_failed_as_assert_not_permitted 106 | test_runner = policy_class do 107 | def test_create 108 | assert_not_permitted nil, Article 109 | end 110 | end.new :test_create 111 | 112 | test_runner.run 113 | assert test_runner.passed? 114 | end 115 | 116 | def test_destroy 117 | test_runner = policy_class do 118 | def test_destroy 119 | assert_permit User.new(100), Article.new(100) 120 | end 121 | end.new :test_destroy 122 | 123 | test_runner.run 124 | assert test_runner.passed? 125 | end 126 | 127 | def test_described_class 128 | test_runner = custom_policy_class do 129 | def described_class 130 | CustomPolicy 131 | end 132 | 133 | def test_new 134 | assert_permit User.new(100), Article.new(100) 135 | end 136 | end.new :test_new 137 | 138 | test_runner.run 139 | assert test_runner.passed? 140 | end 141 | end 142 | 143 | class StrongParametersTest < Minitest::Test 144 | def test_strong_parameters_pass 145 | test_runner = policy_class do 146 | def test_strong_parameters 147 | allowed = [:user_id, :title, :description] 148 | assert_strong_parameters User.new(1), Article, Article.params, allowed 149 | end 150 | end.new :test_strong_parameters 151 | 152 | test_runner.run 153 | assert test_runner.passed? 154 | end 155 | 156 | def test_strong_parameters_fail 157 | test_runner = policy_class do 158 | def test_strong_parameters 159 | assert_strong_parameters nil, Article, Article.params, [:user_id] 160 | end 161 | end.new :test_strong_parameters 162 | 163 | test_runner.run 164 | refute test_runner.passed? 165 | end 166 | end 167 | 168 | class DifferentClassNameTest 169 | class FakePolicyTest < PolicyAssertions::Test 170 | def test_strong_parameters 171 | allowed = [:user_id, :title, :description] 172 | assert_strong_parameters User.new(1), Article, Article.params, allowed 173 | end 174 | end 175 | end 176 | 177 | class InvalidBlockParametersTest 178 | class ArticlePolicyTest < PolicyAssertions::Test 179 | test 'index?' do 180 | assert_raises(PolicyAssertions::MissingBlockParameters) do 181 | assert_permit nil, Article 182 | end 183 | end 184 | end 185 | end 186 | 187 | class DefinedPolicyClassTest 188 | class PersonPolicyTest < PolicyAssertions::Test 189 | def test_create_and_destroy 190 | assert_permit User.new(100), User.new(101) 191 | end 192 | 193 | def test_strong_parameters 194 | assert_strong_parameters nil, User, User.params, [:user_id, :name] 195 | end 196 | end 197 | end 198 | 199 | # rubocop:disable Style/ClassAndModuleChildren: 200 | class ModularizedPolicyClassTest 201 | class Users::SessionPolicyTest < PolicyAssertions::Test 202 | def test_create_and_destroy 203 | assert_permit User.new(100), Users::Session.new(100) 204 | end 205 | 206 | def test_destroy 207 | refute_permit User.new(100), Users::Session.new(101) 208 | refute_permit nil, Users::Session.new 209 | end 210 | 211 | def test_strong_parameters 212 | assert_strong_parameters User.new, 213 | Users::Session, 214 | Users::Session.params, 215 | [:id, :user_id] 216 | end 217 | end 218 | end 219 | 220 | class ValidBlockParametersTest 221 | class ArticlePolicyTest < PolicyAssertions::Test 222 | test 'index?' do 223 | assert_permit nil, Article, 'index?', 'long_action?' 224 | end 225 | 226 | test 'assert_permit index? as array' do 227 | assert_permit nil, Article, %w(index? long_action?) 228 | end 229 | 230 | test 'destroy?' do 231 | refute_permit nil, Article, 'destroy?' 232 | end 233 | 234 | test 'destroy? with assert_not_permitted' do 235 | assert_not_permitted nil, Article, 'destroy?' 236 | end 237 | 238 | test 'refute_permit destroy? as array' do 239 | refute_permit nil, Article, %w(destroy?) 240 | end 241 | end 242 | end 243 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'minitest/pride' 3 | require 'policy_assertions' 4 | 5 | ActiveSupport::TestCase.test_order = :random 6 | 7 | # create a dynamic class using the passed in block 8 | # and names it correctly 9 | def policy_class(&block) 10 | klass = Class.new(PolicyAssertions::Test, &block) 11 | def klass.name 12 | 'ArticlePolicyTest' 13 | end 14 | 15 | klass 16 | end 17 | 18 | def custom_policy_class(&block) 19 | klass = Class.new(PolicyAssertions::Test, &block) 20 | def klass.name 21 | 'CustomPolicyTest' 22 | end 23 | 24 | klass 25 | end 26 | 27 | class User 28 | def self.policy_class 29 | PersonPolicy 30 | end 31 | 32 | attr_accessor :id 33 | 34 | def initialize(id = nil) 35 | @id = id if id 36 | end 37 | 38 | def self.params 39 | { :user_id => 1, :name => 'name', :role => 'admin' } 40 | end 41 | end 42 | 43 | class Article 44 | attr_accessor :user_id 45 | 46 | def initialize(user_id) 47 | @user_id = user_id 48 | end 49 | 50 | def self.params 51 | { :user_id => 1, :title => 'title', :description => 'test description' } 52 | end 53 | end 54 | 55 | class ArticlePolicy 56 | attr_reader :user, :record 57 | 58 | def initialize(user, record) 59 | @user = user 60 | @record = record 61 | end 62 | 63 | def index? 64 | true 65 | end 66 | 67 | def long_action? 68 | true 69 | end 70 | 71 | def create? 72 | @user 73 | end 74 | 75 | def destroy? 76 | @user && @user.id == @record.user_id 77 | end 78 | 79 | def permitted_attributes 80 | (@user && @user.id == 1) ? [:user_id, :title, :description] : [:title] 81 | end 82 | end 83 | 84 | class PersonPolicy 85 | attr_reader :user, :record 86 | 87 | def initialize(user, record) 88 | @user = user 89 | @record = record 90 | end 91 | 92 | def create? 93 | true 94 | end 95 | 96 | def destroy? 97 | @user 98 | end 99 | 100 | def permitted_attributes 101 | (@user && @user.id == 1) ? [:user_id, :name, :role] : [:user_id, :name] 102 | end 103 | end 104 | 105 | class CustomPolicy 106 | attr_reader :user, :record 107 | 108 | def initialize(user, record) 109 | @user = user 110 | @record = record 111 | end 112 | 113 | def new? 114 | record.is_a?(Article) 115 | end 116 | end 117 | 118 | module Users 119 | class Session 120 | attr_accessor :id, :user_id 121 | 122 | def initialize(user_id = nil) 123 | @id = random_id 124 | @user_id = user_id || random_id 125 | end 126 | 127 | def self.params 128 | { :id => @id, :user_id => @user_id, :name => 'session_name' } 129 | end 130 | 131 | private 132 | 133 | def random_id 134 | 100 + Random.rand(1000) 135 | end 136 | end 137 | 138 | class SessionPolicy 139 | attr_reader :user, :record 140 | 141 | def initialize(user, record) 142 | @user = user 143 | @record = record 144 | end 145 | 146 | def create? 147 | @user 148 | end 149 | 150 | def destroy? 151 | @user && @user.id == record.user_id 152 | end 153 | 154 | def permitted_attributes 155 | return [] unless @user 156 | @user.id == 1 ? [:id, :user_id, :name] : [:id, :user_id] 157 | end 158 | end 159 | end 160 | --------------------------------------------------------------------------------