remockable 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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