remockable 0.1.1 → 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 (38) hide show
  1. data/.gitignore +6 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +1 -1
  6. data/README.markdown +50 -36
  7. data/Rakefile +1 -0
  8. data/lib/remockable/active_model/helpers.rb +2 -0
  9. data/lib/remockable/active_record/helpers.rb +2 -0
  10. data/lib/remockable/version.rb +1 -1
  11. data/remockable.gemspec +23 -0
  12. data/spec/active_model/allow_mass_assignment_of_spec.rb +86 -0
  13. data/spec/active_model/allow_values_for_spec.rb +46 -0
  14. data/spec/active_model/validate_acceptance_of_spec.rb +16 -0
  15. data/spec/active_model/validate_confirmation_of_spec.rb +14 -0
  16. data/spec/active_model/validate_exclusion_of_spec.rb +16 -0
  17. data/spec/active_model/validate_format_of_spec.rb +18 -0
  18. data/spec/active_model/validate_inclusion_of_spec.rb +16 -0
  19. data/spec/active_model/validate_length_of_spec.rb +26 -0
  20. data/spec/active_model/validate_numericality_of_spec.rb +23 -0
  21. data/spec/active_model/validate_presence_of_spec.rb +14 -0
  22. data/spec/active_record/accept_nested_attributes_for_spec.rb +47 -0
  23. data/spec/active_record/belong_to_spec.rb +62 -0
  24. data/spec/active_record/have_and_belong_to_many_spec.rb +67 -0
  25. data/spec/active_record/have_column_spec.rb +109 -0
  26. data/spec/active_record/have_default_scope_spec.rb +169 -0
  27. data/spec/active_record/have_index_spec.rb +89 -0
  28. data/spec/active_record/have_many_spec.rb +70 -0
  29. data/spec/active_record/have_one_spec.rb +61 -0
  30. data/spec/active_record/have_scope_spec.rb +229 -0
  31. data/spec/active_record/validate_associated_spec.rb +27 -0
  32. data/spec/active_record/validate_uniqueness_of_spec.rb +23 -0
  33. data/spec/spec_helper.rb +17 -0
  34. data/spec/support/active_record_example_group.rb +22 -0
  35. data/spec/support/class_builder.rb +39 -0
  36. data/spec/support/shared/a_validation_matcher.rb +130 -0
  37. data/spec/support/shared/an_active_record_matcher.rb +53 -0
  38. metadata +134 -40
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.swp
2
+ .bundle
3
+ .rvmrc
4
+ Gemfile.lock
5
+ bin
6
+ pkg
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ script: bundle exec rspec
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2011 Tyler Hunt
1
+ Copyright (c) 2010-2012 Tyler Hunt
2
2
 
3
3
  MIT License
4
4
 
data/README.markdown CHANGED
@@ -1,5 +1,10 @@
1
1
  # Remockable
2
2
 
3
+ [![Build Status][travis-image]][travis]
4
+
5
+ [travis]: http://travis-ci.org/tylerhunt/remockable
6
+ [travis-image]: https://secure.travis-ci.org/tylerhunt/remockable.png
7
+
3
8
  A collection of RSpec 2 matchers to simplify your web app specs.
4
9
 
5
10
 
@@ -7,7 +12,7 @@ A collection of RSpec 2 matchers to simplify your web app specs.
7
12
 
8
13
  The goal of this project is to provide a modern replacement to the now
9
14
  unmaintained Remarkable project. Remarkable was a great asset when Rails 2.3
10
- was current, but now that Rails 3.0 has become mainstream, a gap has been left
15
+ was current, but now that Rails 3 has become mainstream, a gap has been left
11
16
  by still unreleased Remarkable 4.0.
12
17
 
13
18
  In looking at the code for Remarkable to determine the feasibility of continuing
@@ -17,58 +22,67 @@ Remockable was born. It's an attempt to start with a clean slate but maintain
17
22
  the original goal of Remarkable in spirit.
18
23
 
19
24
 
20
- ## Active Model Matchers
25
+ ## Installation
21
26
 
22
- The following Active Model matchers are supported:
27
+ Add this line to your application's Gemfile:
23
28
 
24
- * allow_mass_assignment_of
25
- * validate_acceptance_of
26
- * validate_confirmation_of
27
- * validate_exclusion_of
28
- * validate_format_of
29
- * validate_inclusion_of
30
- * validate_length_of
31
- * validate_numericality_of
32
- * validate_presence_of
29
+ ``` ruby
30
+ gem 'remockable'
31
+ ```
33
32
 
33
+ And then execute:
34
34
 
35
- ## Active Record Matchers
35
+ $ bundle
36
36
 
37
- The following Active Record matchers are supported:
37
+ Or install it yourself as:
38
38
 
39
- * have_column
40
- * have_index
41
- * have_scope
42
- * have_default_scope
43
- * belong_to
44
- * have_one
45
- * have_many
46
- * have_and_belong_to_many
47
- * validate_associated
48
- * validate_uniqueness_of
39
+ $ gem install remockable
49
40
 
50
41
 
51
- ## Installation
42
+ ## Usage
43
+
44
+ Remockable provides matchers for use with Active Model and Active Record
45
+ classes.
52
46
 
53
- Add the `remockable` gem to your `Gemfile`:
47
+ ### Active Model Matchers
54
48
 
55
- gem 'remockable'
49
+ The following Active Model matchers are supported:
56
50
 
57
- Then run `bundle install` to install the gem.
51
+ * `allow_mass_assignment_of`
52
+ * `validate_acceptance_of`
53
+ * `validate_confirmation_of`
54
+ * `validate_exclusion_of`
55
+ * `validate_format_of`
56
+ * `validate_inclusion_of`
57
+ * `validate_length_of`
58
+ * `validate_numericality_of`
59
+ * `validate_presence_of`
58
60
 
59
- You'll also want to make sure the library is required by RSpec, so add the
60
- following to your `spec_helper.rb` or someone else where it will get loaded
61
- when your specs do:
61
+ ### Active Record Matchers
62
+
63
+ The following Active Record matchers are supported:
62
64
 
63
- require 'remockable'
65
+ * `have_column`
66
+ * `have_index`
67
+ * `have_scope`
68
+ * `have_default_scope`
69
+ * `belong_to`
70
+ * `have_one`
71
+ * `have_many`
72
+ * `have_and_belong_to_many`
73
+ * `validate_associated`
74
+ * `validate_uniqueness_of`
64
75
 
65
76
 
66
- ## Compatibility
77
+ ## Contributing
67
78
 
68
- Remockable is compatible with Rails 3.0, but it has also been tested against
69
- 3.1 and appears to be working fine there, too.
79
+ 1. Fork it.
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
81
+ 3. Commit your changes (`git commit -am 'Added some feature'`).
82
+ 4. Push to the branch (`git push origin my-new-feature`).
83
+ 5. Create a new Pull Request.
70
84
 
71
85
 
72
86
  ## Copyright
73
87
 
74
- Copyright © 2010-2011 Tyler Hunt. See LICENSE for details.
88
+ Copyright © 2010-2012 Tyler Hunt. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -1,3 +1,5 @@
1
+ require 'remockable/helpers'
2
+
1
3
  module Remockable
2
4
  module ActiveModel
3
5
  module Helpers
@@ -1,3 +1,5 @@
1
+ require 'remockable/helpers'
2
+
1
3
  module Remockable
2
4
  module ActiveRecord
3
5
  module Helpers
@@ -1,3 +1,3 @@
1
1
  module Remockable
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -0,0 +1,23 @@
1
+ require './lib/remockable/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'remockable'
5
+ spec.version = Remockable::VERSION
6
+ spec.authors = ['Tyler Hunt']
7
+ spec.summary = 'A collection of RSpec matchers for web apps.'
8
+ spec.homepage = 'http://github.com/tylerhunt/remockable'
9
+ spec.license = 'MIT'
10
+
11
+ spec.add_dependency 'activemodel', '~> 3.0'
12
+ spec.add_dependency 'activerecord', '~> 3.0'
13
+ spec.add_dependency 'activesupport', '~> 3.0'
14
+ spec.add_dependency 'rspec-core', '~> 2.0'
15
+ spec.add_dependency 'rspec-expectations', '~> 2.0'
16
+ spec.add_dependency 'rspec-mocks', '~> 2.0'
17
+ spec.add_development_dependency 'sqlite3', '~> 1.3.4'
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |file| File.basename(file) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe :allow_mass_assignment_of do
4
+ let(:attribute) { :one }
5
+ let(:options) { {} }
6
+ let(:matcher_name) { self.class.parent.description }
7
+
8
+ let(:model) do
9
+ build_class(:User) { include ActiveModel::MassAssignmentSecurity }
10
+ end
11
+
12
+ subject { model.new }
13
+
14
+ context 'description' do
15
+ it 'has a custom description' do
16
+ matcher = allow_mass_assignment_of(attribute)
17
+ matcher.description.should == "allow mass-assignment of #{attribute}"
18
+ end
19
+ end
20
+
21
+ context 'failure messages' do
22
+ let(:matcher) { allow_mass_assignment_of(attribute) }
23
+
24
+ before { matcher.matches?(subject) }
25
+
26
+ it 'has a custom failure message' do
27
+ matcher.failure_message_for_should.should ==
28
+ "Expected #{subject.class.name} to #{matcher.description}"
29
+ end
30
+
31
+ it 'has a custom negative failure message' do
32
+ matcher.failure_message_for_should_not.should ==
33
+ "Did not expect #{subject.class.name} to #{matcher.description}"
34
+ end
35
+ end
36
+
37
+ context 'for accessible' do
38
+ before { model.attr_accessible(attribute, options) }
39
+
40
+ it 'matches if the attribute is accessible' do
41
+ should allow_mass_assignment_of(:one)
42
+ end
43
+
44
+ it 'does not match if the attribute is protected' do
45
+ should_not allow_mass_assignment_of(:two)
46
+ end
47
+
48
+ context 'with a role' do
49
+ let(:options) { { :as => :admin } }
50
+
51
+ it 'matches if the attribute is accessible' do
52
+ should allow_mass_assignment_of(:one, :as => :admin)
53
+ end
54
+
55
+ it 'does not match if the attribute is protected' do
56
+ should_not allow_mass_assignment_of(:two, :as => :admin)
57
+ end
58
+ end
59
+ end
60
+
61
+ context 'for protected' do
62
+ let(:attribute) { :two }
63
+
64
+ before { model.attr_protected(attribute, options) }
65
+
66
+ it 'matches if the attribute is accessible' do
67
+ should allow_mass_assignment_of(:one)
68
+ end
69
+
70
+ it 'does not match if the attribute is protected' do
71
+ should_not allow_mass_assignment_of(:two)
72
+ end
73
+
74
+ context 'with a role' do
75
+ let(:options) { { :as => :admin } }
76
+
77
+ it 'matches if the attribute is accessible' do
78
+ should allow_mass_assignment_of(:one, :as => :admin)
79
+ end
80
+
81
+ it 'does not match if the attribute is protected' do
82
+ should_not allow_mass_assignment_of(:two, :as => :admin)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe :allow_values_for do
4
+ let(:attribute) { :one }
5
+ let(:values) { ['123'] }
6
+ let(:matcher_name) { self.class.parent.description }
7
+
8
+ let(:model) do
9
+ build_class(:User) { include ActiveModel::Validations }
10
+ end
11
+
12
+ before { model.validates(attribute, :format => /^\d+$/) }
13
+
14
+ subject { model.new }
15
+
16
+ context 'description' do
17
+ it 'has a custom description' do
18
+ matcher = allow_values_for(attribute, *values)
19
+ matcher.description.should == "allow the values #{values.collect(&:inspect).to_sentence} for #{attribute}"
20
+ end
21
+ end
22
+
23
+ context 'failure messages' do
24
+ let(:matcher) { allow_values_for(attribute, *values) }
25
+
26
+ before { matcher.matches?(subject) }
27
+
28
+ it 'has a custom failure message' do
29
+ matcher.failure_message_for_should.should ==
30
+ "Expected #{subject.class.name} to #{matcher.description}"
31
+ end
32
+
33
+ it 'has a custom negative failure message' do
34
+ matcher.failure_message_for_should_not.should ==
35
+ "Did not expect #{subject.class.name} to #{matcher.description}"
36
+ end
37
+ end
38
+
39
+ it 'matches if the values are valid' do
40
+ should allow_values_for(:one, '123', '4567890')
41
+ end
42
+
43
+ it 'does not match if the values are invalid' do
44
+ should_not allow_values_for(:one, 'abc', 'abc123')
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_acceptance_of do
4
+ let(:validator_name) { :acceptance }
5
+ let(:default_options) { true }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:accept, 'TRUE', 'FALSE')
9
+ with_option(:allow_nil, true, false)
10
+ with_option(:message, 'must agree!', 'invalid')
11
+ with_option(:on, :create, :update)
12
+
13
+ with_conditional_option(:if)
14
+ with_conditional_option(:unless)
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_confirmation_of do
4
+ let(:validator_name) { :confirmation }
5
+ let(:default_options) { true }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:message, 'must match!', 'invalid')
9
+ with_option(:on, :create, :update)
10
+
11
+ with_conditional_option(:if)
12
+ with_conditional_option(:unless)
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_exclusion_of do
4
+ let(:validator_name) { :exclusion }
5
+ let(:default_options) { { :in => [true, false] } }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:allow_blank, true, false)
9
+ with_option(:allow_nil, true, false)
10
+ with_option(:in, [true, false], %w(male female))
11
+ with_option(:message, 'is in list!', 'invalid')
12
+
13
+ with_conditional_option(:if)
14
+ with_conditional_option(:unless)
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_format_of do
4
+ let(:validator_name) { :format }
5
+ let(:default_options) { { :with => /\d+/ } }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:allow_blank, true, false)
9
+ with_option(:allow_nil, true, false)
10
+ with_option(:message, 'is the wrong format!', 'invalid')
11
+ with_option(:on, :create, :update)
12
+ with_option!(:with, /\d+/, /\w+/)
13
+ with_option!(:without, /\d+/, /\w+/)
14
+
15
+ with_conditional_option(:if)
16
+ with_conditional_option(:unless)
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_inclusion_of do
4
+ let(:validator_name) { :inclusion }
5
+ let(:default_options) { { :in => [true, false] } }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:allow_blank, true, false)
9
+ with_option(:allow_nil, true, false)
10
+ with_option(:in, [true, false], %w(male female))
11
+ with_option(:message, 'is not in list!', 'invalid')
12
+
13
+ with_conditional_option(:if)
14
+ with_conditional_option(:unless)
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_length_of do
4
+ let(:validator_name) { :length }
5
+ let(:default_options) { { :is => 5 } }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:allow_blank, true, false)
9
+ with_option(:allow_nil, true, false)
10
+ with_option(:in, 1..10, 1..5)
11
+ with_option(:is, 5, 10)
12
+ with_option(:maximum, 5, 10)
13
+ with_option(:message, 'is the wrong length!', 'invalid')
14
+ with_option(:minimum, 5, 10)
15
+ with_option(:on, :create, :update)
16
+ with_option(:too_long, 'is too long!', 'invalid')
17
+ with_option(:too_short, 'is too short!', 'invalid')
18
+ with_option(:within, 1..10, 1..5)
19
+ with_option(:wrong_length, 'is not five!', 'invalid')
20
+
21
+ with_conditional_option(:if)
22
+ with_conditional_option(:unless)
23
+
24
+ with_unsupported_option(:tokenizer, lambda { |string| string.scan(/\w+/) })
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_numericality_of do
4
+ let(:validator_name) { :numericality }
5
+ let(:default_options) { { :only_integer => true } }
6
+
7
+ it_behaves_like 'a validation matcher' do
8
+ with_option(:allow_nil, true, false)
9
+ with_option(:equal_to, 5, 10)
10
+ with_option(:even, true, false)
11
+ with_option(:greater_than, 5, 10)
12
+ with_option(:greater_than_or_equal_to, 5, 10)
13
+ with_option(:less_than, 5, 10)
14
+ with_option(:less_than_or_equal_to, 5, 10)
15
+ with_option(:message, 'is the wrong numericality!', 'invalid')
16
+ with_option(:odd, true, false)
17
+ with_option(:on, :create, :update)
18
+ with_option(:only_integer, true, false)
19
+
20
+ with_conditional_option(:if)
21
+ with_conditional_option(:unless)
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe :validate_presence_of do
4
+ let(:validator_name) { :presence }
5
+ let(:default_options) { true }
6
+
7
+ it_behaves_like 'a validation matcher', :presence do
8
+ with_option(:message, 'is required!', 'invalid')
9
+ with_option(:on, :create, :update)
10
+
11
+ with_conditional_option(:if)
12
+ with_conditional_option(:unless)
13
+ end
14
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe :accept_nested_attributes_for do
4
+ let(:macro) { :accepts_nested_attributes_for }
5
+ let(:options) { [:company, { :allow_destroy => true }] }
6
+
7
+ it_behaves_like 'an Active Record matcher' do
8
+ let(:matcher_name) { :accept_nested_attributes_for }
9
+
10
+ let(:model) do
11
+ build_class(:User, ActiveRecord::Base) { belongs_to :company }
12
+ end
13
+
14
+ before { create_table(:users) }
15
+
16
+ subject { model.new }
17
+
18
+ context 'description' do
19
+ let(:matcher) { send(matcher_name, *options) }
20
+
21
+ it 'has a custom description' do
22
+ association = matcher.instance_variable_get(:@association)
23
+ with = " with #{matcher.expected.inspect}" if matcher.expected.any?
24
+ matcher.description.should == "accept nested attributes for #{association}#{with}"
25
+ end
26
+ end
27
+
28
+ context 'with no options' do
29
+ let(:options) { :company }
30
+
31
+ it 'matches if the model accepts the nested attributes' do
32
+ model.accepts_nested_attributes_for(*options)
33
+ model.should accept_nested_attributes_for(*options)
34
+ end
35
+
36
+ it 'does not match if the model does not accept the nested attributes' do
37
+ model.should_not accept_nested_attributes_for(*options)
38
+ end
39
+ end
40
+
41
+ with_option(:allow_destroy, true, false)
42
+ with_option(:limit, 1, 2)
43
+ with_option(:update_only, true, false)
44
+
45
+ with_unsupported_option(:reject_if, :all_blank)
46
+ end
47
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe :belong_to do
4
+ let(:macro) { :belongs_to }
5
+ let(:options) { [:company, { :dependent => :destroy }] }
6
+
7
+ it_behaves_like 'an Active Record matcher' do
8
+ let(:model) { build_class(:User, ActiveRecord::Base) }
9
+
10
+ before do
11
+ create_table(:users) { |table| table.integer(:company_id) }
12
+ end
13
+
14
+ subject { model.new }
15
+
16
+ context 'description' do
17
+ let(:matcher) { send(matcher_name, *options) }
18
+
19
+ it 'has a custom description' do
20
+ name = matcher.instance_variable_get(:@name).to_s.gsub(/_/, ' ')
21
+ association = matcher.instance_variable_get(:@association)
22
+ with = " with #{matcher.expected.inspect}" if matcher.expected.any?
23
+ matcher.description.should == "#{name} #{association}#{with}"
24
+ end
25
+ end
26
+
27
+ context 'with no options' do
28
+ let(:options) { :company }
29
+
30
+ it 'matches if the association exists' do
31
+ model.belongs_to(*options)
32
+ model.should belong_to(*options)
33
+ end
34
+
35
+ it 'does not match if the association does not exist' do
36
+ model.should_not belong_to(*options)
37
+ end
38
+
39
+ it 'does not match if the association is of the wrong type' do
40
+ model.has_many(*options)
41
+ model.should_not belong_to(*options)
42
+ end
43
+ end
44
+
45
+ with_option(:class_name, 'Company', 'Organization')
46
+ with_option(:conditions, { :id => 1 }, { :id => 2 })
47
+ with_option(:select, %w(id), %w(name))
48
+ with_option(:foreign_key, :company_id, :organization_id)
49
+ with_option(:primary_key, :id, :company_id)
50
+ with_option(:dependent, :destroy, :nullify)
51
+ with_option(:counter_cache, true, false)
52
+ with_option(:include, :users, :employees)
53
+ with_option(:polymorphic, true, false)
54
+ with_option(:readonly, true, false)
55
+ with_option(:validate, true, false)
56
+ with_option(:autosave, true, false)
57
+ with_option(:touch, true, false)
58
+ with_option(:inverse_of, :users, :employees)
59
+
60
+ with_unsupported_option(:extend, Module.new)
61
+ end
62
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe :have_and_belong_to_many do
4
+ let(:macro) { :has_and_belongs_to_many }
5
+ let(:options) { [:tags, { :order => :name }] }
6
+
7
+ it_behaves_like 'an Active Record matcher' do
8
+ let(:model) { build_class(:User, ActiveRecord::Base) }
9
+
10
+ before do
11
+ create_table(:users) { |table| table.string(:name) }
12
+ end
13
+
14
+ subject { model.new }
15
+
16
+ context 'description' do
17
+ let(:matcher) { send(matcher_name, *options) }
18
+
19
+ it 'has a custom description' do
20
+ association = matcher.instance_variable_get(:@association)
21
+ with = " with #{matcher.expected.inspect}" if matcher.expected.any?
22
+ matcher.description.should == "have and belong to #{association}#{with}"
23
+ end
24
+ end
25
+
26
+ context 'with no options' do
27
+ let(:options) { :tags }
28
+
29
+ it 'matches if the association exists' do
30
+ model.has_and_belongs_to_many(*options)
31
+ model.should have_and_belong_to_many(*options)
32
+ end
33
+
34
+ it 'does not match if the association does not exist' do
35
+ model.should_not have_and_belong_to_many(*options)
36
+ end
37
+
38
+ it 'does not match if the association is of the wrong type' do
39
+ model.has_many(*options)
40
+ model.should_not have_and_belong_to_many(*options)
41
+ end
42
+ end
43
+
44
+ with_option(:class_name, 'Tag', 'Role')
45
+ with_option(:join_table, 'tags_users', 'user_tags')
46
+ with_option(:foreign_key, :user_id, :tagged_id)
47
+ with_option(:association_foreign_key, :tag_id, :role_id)
48
+ with_option(:conditions, { :active => true }, { :active => false })
49
+ with_option(:order, :name, :created_at)
50
+ with_option(:uniq, true, false)
51
+ with_option(:finder_sql, 'SELECT * FROM user_tags', 'SELECT * FROM tags_users')
52
+ with_option(:counter_sql, 'SELECT COUNT(*) FROM user_tags', 'SELECT COUNT(*) FROM tags_users')
53
+ with_option(:delete_sql, 'DELETE FROM user_tags', 'DELETE FROM tags_users')
54
+ with_option(:insert_sql, 'INSERT INTO user_tags', 'INSERT INTO tags_users')
55
+ with_option(:include, :statistics, :changes)
56
+ with_option(:group, 'usage_count', 'changes_count')
57
+ with_option(:having, 'usage_count > 5', 'changes_count > 5')
58
+ with_option(:limit, 5, 10)
59
+ with_option(:offset, 10, 20)
60
+ with_option(:select, %w(id), %w(name))
61
+ with_option(:readonly, true, false)
62
+ with_option(:validate, true, false)
63
+ with_option(:autosave, true, false)
64
+
65
+ with_unsupported_option(:extend, Module.new)
66
+ end
67
+ end