mirror of
https://github.com/thoughtbot/shoulda-matchers.git
synced 2022-11-09 12:01:38 -05:00
Fix habtm matcher to support symbols for join_table (#1323)
The fix is simple but required slightly rewriting the tests, as it turns out the existing tests weren't exercising all of the possible checks that join_table makes.
This commit is contained in:
parent
97810e6154
commit
39f1dd7c93
3 changed files with 338 additions and 75 deletions
|
@ -920,21 +920,21 @@ module Shoulda
|
||||||
# asserts that the table you're referring to actually exists.
|
# asserts that the table you're referring to actually exists.
|
||||||
#
|
#
|
||||||
# class Person < ActiveRecord::Base
|
# class Person < ActiveRecord::Base
|
||||||
# has_and_belongs_to_many :issues, join_table: 'people_tickets'
|
# has_and_belongs_to_many :issues, join_table: :people_tickets
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# # RSpec
|
# # RSpec
|
||||||
# RSpec.describe Person, type: :model do
|
# RSpec.describe Person, type: :model do
|
||||||
# it do
|
# it do
|
||||||
# should have_and_belong_to_many(:issues).
|
# should have_and_belong_to_many(:issues).
|
||||||
# join_table('people_tickets')
|
# join_table(:people_tickets)
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# # Minitest (Shoulda)
|
# # Minitest (Shoulda)
|
||||||
# class PersonTest < ActiveSupport::TestCase
|
# class PersonTest < ActiveSupport::TestCase
|
||||||
# should have_and_belong_to_many(:issues).
|
# should have_and_belong_to_many(:issues).
|
||||||
# join_table('people_tickets')
|
# join_table(:people_tickets)
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# ##### validate
|
# ##### validate
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Shoulda
|
||||||
if option_verifier.correct_for_string?(:join_table, options[:join_table_name])
|
if option_verifier.correct_for_string?(:join_table, options[:join_table_name])
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
@failure_message = "#{name} should use '#{options[:join_table_name]}' for :join_table option"
|
@failure_message = "#{name} should use #{options[:join_table_name].inspect} for :join_table option"
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -38,7 +38,7 @@ module Shoulda
|
||||||
end
|
end
|
||||||
|
|
||||||
def join_table_exists?
|
def join_table_exists?
|
||||||
if RailsShim.tables_and_views(connection).include?(join_table_name)
|
if RailsShim.tables_and_views(connection).include?(join_table_name.to_s)
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
@failure_message = missing_table_message
|
@failure_message = missing_table_message
|
||||||
|
|
|
@ -1570,96 +1570,359 @@ Expected Parent to have a has_many association called children through conceptio
|
||||||
end.to fail_with_message_including('missing columns: person_id, relative_id')
|
end.to fail_with_message_including('missing columns: person_id, relative_id')
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the association is declared with a :join_table option' do
|
context 'when qualified with join_table' do
|
||||||
it 'accepts when testing with the same :join_table option' do
|
context 'and it is a symbol' do
|
||||||
join_table_name = 'people_and_their_families'
|
context 'and the association has been declared with a :join_table option' do
|
||||||
|
context 'which is the same as the matcher' do
|
||||||
|
context 'and the join table exists' do
|
||||||
|
context 'and the join table has the appropriate foreign key columns' do
|
||||||
|
it 'matches' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
define_model :relative
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: :people_and_their_families
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
define_model :person do
|
create_table(:people_and_their_families, id: false) do |t|
|
||||||
has_and_belongs_to_many(:relatives, join_table: join_table_name)
|
t.references :person
|
||||||
|
t.references :relative
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).
|
||||||
|
join_table(:people_and_their_families)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
to match_against(Person.new).
|
||||||
|
or_fail_with(<<-MESSAGE)
|
||||||
|
Did not expect Person to have a has_and_belongs_to_many association called relatives
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and the join table is missing columns' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: :people_and_their_families
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:people_and_their_families)
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).
|
||||||
|
join_table(:people_and_their_families)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families missing columns: person_id, relative_id)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and the join table does not exist' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: :people_and_their_families
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).
|
||||||
|
join_table(:family_tree)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use :family_tree for :join_table option)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'which is the not the same as the matcher' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: :people_and_their_families
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:people_and_their_families, id: false) do |t|
|
||||||
|
t.references :person
|
||||||
|
t.references :relative
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).join_table(:family_tree)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use :family_tree for :join_table option)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table(join_table_name, id: false) do |t|
|
context 'and the association has not been declared with a :join_table option' do
|
||||||
t.references :person
|
it 'does not match, producing an appropriate failure message' do
|
||||||
t.references :relative
|
define_model :relative
|
||||||
end
|
|
||||||
|
|
||||||
expect(Person.new).
|
define_model :person do
|
||||||
to have_and_belong_to_many(:relatives).
|
has_and_belongs_to_many(:relatives)
|
||||||
join_table(join_table_name)
|
end
|
||||||
|
|
||||||
|
create_table(:people_relatives, id: false) do |t|
|
||||||
|
t.references :person
|
||||||
|
t.references :relative
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).join_table(:family_tree)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use :family_tree for :join_table option)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accepts even when not explicitly testing with a :join_table option' do
|
context 'and it is a string' do
|
||||||
join_table_name = 'people_and_their_families'
|
context 'and the association has been declared with a :join_table option' do
|
||||||
|
context 'which is the same as the matcher' do
|
||||||
|
context 'and the join table exists' do
|
||||||
|
context 'and the join table has the appropriate foreign key columns' do
|
||||||
|
it 'matches' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
define_model :relative
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: 'people_and_their_families'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
define_model :person do
|
create_table(:people_and_their_families, id: false) do |t|
|
||||||
has_and_belongs_to_many(:relatives,
|
t.references :person
|
||||||
join_table: join_table_name
|
t.references :relative
|
||||||
)
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).
|
||||||
|
join_table('people_and_their_families')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
to match_against(Person.new).
|
||||||
|
or_fail_with(<<-MESSAGE)
|
||||||
|
Did not expect Person to have a has_and_belongs_to_many association called relatives
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and the join table is missing columns' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: 'people_and_their_families'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:people_and_their_families)
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).
|
||||||
|
join_table('people_and_their_families')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families missing columns: person_id, relative_id)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and the join table does not exist' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: 'people_and_their_families'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).
|
||||||
|
join_table('family_tree')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use "family_tree" for :join_table option)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'which is the not the same as the matcher' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: 'people_and_their_families'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:people_and_their_families, id: false) do |t|
|
||||||
|
t.references :person
|
||||||
|
t.references :relative
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).join_table('family_tree')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use "family_tree" for :join_table option)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table(join_table_name, id: false) do |t|
|
context 'and the association has not been declared with a :join_table option' do
|
||||||
t.references :person
|
it 'does not match, producing an appropriate failure message' do
|
||||||
t.references :relative
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(:relatives)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:people_relatives, id: false) do |t|
|
||||||
|
t.references :person
|
||||||
|
t.references :relative
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> do
|
||||||
|
have_and_belong_to_many(:relatives).join_table('family_tree')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (relatives should use "family_tree" for :join_table option)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Person.new).to have_and_belong_to_many(:relatives)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'rejects when testing with a different :join_table option' do
|
|
||||||
join_table_name = 'people_and_their_families'
|
|
||||||
|
|
||||||
define_model :relative
|
|
||||||
|
|
||||||
define_model :person do
|
|
||||||
has_and_belongs_to_many(
|
|
||||||
:relatives,
|
|
||||||
join_table: join_table_name
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table(join_table_name, id: false) do |t|
|
|
||||||
t.references :person
|
|
||||||
t.references :relative
|
|
||||||
end
|
|
||||||
|
|
||||||
assertion = lambda do
|
|
||||||
expect(Person.new).
|
|
||||||
to have_and_belong_to_many(:relatives).
|
|
||||||
join_table('family_tree')
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(&assertion).to fail_with_message_including(
|
|
||||||
"relatives should use 'family_tree' for :join_table option"
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the association is not declared with a :join_table option' do
|
context 'when the matcher is not qualified with join_table but the association has still been declared with a :join_table option' do
|
||||||
it 'rejects when testing with a :join_table option' do
|
context 'and the join table exists' do
|
||||||
define_model :relative
|
context 'and the join table has the appropriate foreign key columns' do
|
||||||
|
it 'matches' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
define_model :person do
|
define_model :person do
|
||||||
has_and_belongs_to_many(:relatives)
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: :people_and_their_families
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:people_and_their_families, id: false) do |t|
|
||||||
|
t.references :person
|
||||||
|
t.references :relative
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> { have_and_belong_to_many(:relatives) }
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
to match_against(Person.new).
|
||||||
|
or_fail_with(<<-MESSAGE)
|
||||||
|
Did not expect Person to have a has_and_belongs_to_many association called relatives
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table('people_relatives', id: false) do |t|
|
context 'and the join table is missing columns' do
|
||||||
t.references :person
|
it 'does not match, producing an appropriate failure message' do
|
||||||
t.references :relative
|
define_model :relative
|
||||||
end
|
|
||||||
|
|
||||||
assertion = lambda do
|
define_model :person do
|
||||||
expect(Person.new).
|
has_and_belongs_to_many(
|
||||||
to have_and_belong_to_many(:relatives).
|
:relatives,
|
||||||
join_table('family_tree')
|
join_table: :people_and_their_families
|
||||||
end
|
)
|
||||||
|
end
|
||||||
|
|
||||||
expect(&assertion).to fail_with_message_including(
|
create_table(:people_and_their_families)
|
||||||
"relatives should use 'family_tree' for :join_table option"
|
|
||||||
)
|
build_matcher = -> { have_and_belong_to_many(:relatives) }
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families missing columns: person_id, relative_id)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and the join table does not exist' do
|
||||||
|
it 'does not match, producing an appropriate failure message' do
|
||||||
|
define_model :relative
|
||||||
|
|
||||||
|
define_model :person do
|
||||||
|
has_and_belongs_to_many(
|
||||||
|
:relatives,
|
||||||
|
join_table: :people_and_their_families
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
build_matcher = -> { have_and_belong_to_many(:relatives) }
|
||||||
|
|
||||||
|
expect(&build_matcher).
|
||||||
|
not_to match_against(Person.new).
|
||||||
|
and_fail_with(<<-MESSAGE)
|
||||||
|
Expected Person to have a has_and_belongs_to_many association called relatives (join table people_and_their_families doesn't exist)
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue