test/unit/relationship_test.rb in rails-erd-0.2.0 vs test/unit/relationship_test.rb in rails-erd-0.3.0
- old
+ new
@@ -1,16 +1,21 @@
require File.expand_path("../test_helper", File.dirname(__FILE__))
class RelationshipTest < ActiveSupport::TestCase
+ N = Relationship::N
+
+ def domain_cardinalities
+ Domain.generate.relationships.map(&:cardinality)
+ end
+
# Relationship =============================================================
test "inspect should show source and destination" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar"
- domain = Domain.generate
- assert_match %r{#<RailsERD::Relationship:.* @source=Bar @destination=Foo>}, domain.relationships.first.inspect
+ assert_match %r{#<RailsERD::Relationship:.* @source=Bar @destination=Foo>}, Domain.generate.relationships.first.inspect
end
test "source should return relationship source" do
create_model "Foo", :bar => :references do
belongs_to :bar
@@ -33,62 +38,61 @@
test "mutual should return false for one way relationship" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar"
- domain = Domain.generate
- assert_equal [false], domain.relationships.map(&:mutual?)
+ assert_equal [false], Domain.generate.relationships.map(&:mutual?)
end
test "mutual should return true for mutual relationship" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar" do
has_many :foos
end
- domain = Domain.generate
- assert_equal [true], domain.relationships.map(&:mutual?)
+ assert_equal [true], Domain.generate.relationships.map(&:mutual?)
end
+ test "mutual should return true for mutual many to many relationship" do
+ create_many_to_many_assoc_domain
+ assert_equal [true], Domain.generate.relationships.map(&:mutual?)
+ end
+
test "recursive should return false for ordinary relationship" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar" do
has_many :foos
end
- domain = Domain.generate
- assert_equal [false], domain.relationships.map(&:recursive?)
+ assert_equal [false], Domain.generate.relationships.map(&:recursive?)
end
test "recursive should return true for self referencing relationship" do
create_model "Foo", :foo => :references do
belongs_to :foo
end
- domain = Domain.generate
- assert_equal [true], domain.relationships.map(&:recursive?)
+ assert_equal [true], Domain.generate.relationships.map(&:recursive?)
end
test "indirect should return false for ordinary relationship" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar" do
has_many :foos
end
- domain = Domain.generate
- assert_equal [false], domain.relationships.map(&:indirect?)
+ assert_equal [false], Domain.generate.relationships.map(&:indirect?)
end
test "indirect should return false for non mutual ordinary relationship" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar"
- domain = Domain.generate
- assert_equal [false], domain.relationships.map(&:indirect?)
+ assert_equal [false], Domain.generate.relationships.map(&:indirect?)
end
test "indirect should return true if relationship is a through association" do
create_model "Foo", :baz => :references, :bar => :references do
belongs_to :baz
@@ -99,33 +103,30 @@
has_many :bazs, :through => :foos
end
create_model "Baz" do
has_many :foos
end
- domain = Domain.generate
- assert_equal true, domain.relationships.find { |rel|
+ assert_equal true, Domain.generate.relationships.find { |rel|
rel.source.model == Bar and rel.destination.model == Baz }.indirect?
end
test "strength should return one for relationship with one association" do
create_model "Foo", :bar => :references
create_model "Bar" do
has_many :foos
end
- domain = Domain.generate
- assert_equal [1], domain.relationships.map(&:strength)
+ assert_equal [1], Domain.generate.relationships.map(&:strength)
end
test "strength should return two for relationship with two associations" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar" do
has_many :foos
end
- domain = Domain.generate
- assert_equal [2], domain.relationships.map(&:strength)
+ assert_equal [2], Domain.generate.relationships.map(&:strength)
end
test "strength should return number of associations that make up the relationship" do
create_model "Foo", :bar => :references do
belongs_to :bar
@@ -133,185 +134,285 @@
end
create_model "Bar" do
has_many :foos
has_many :special_foos, :class_name => "Foo", :foreign_key => :bar_id
end
- domain = Domain.generate
- assert_equal [4], domain.relationships.map(&:strength)
+ assert_equal [4], Domain.generate.relationships.map(&:strength)
end
- # Cardinality ==============================================================
- test "cardinality should return one to one for has_one associations" do
- create_model "Foo", :bar => :references
- create_model "Bar" do
- has_one :foo
+ # Cardinalities ============================================================
+ test "cardinality should be zero-one to zero-one for optional one to one associations" do
+ create_one_to_one_assoc_domain
+ assert_equal [Relationship::Cardinality.new(0..1, 0..1)], domain_cardinalities
+ end
+
+ test "cardinality should be one to one for mutually mandatory one to one associations" do
+ create_one_to_one_assoc_domain
+ One.class_eval do
+ validates_presence_of :other
end
- domain = Domain.generate
- assert_equal [Relationship::Cardinality::OneToOne], domain.relationships.map(&:cardinality)
+ Other.class_eval do
+ validates_presence_of :one
+ end
+ assert_equal [Relationship::Cardinality.new(1, 1)], domain_cardinalities
end
+
+ test "cardinality should be zero-one to zero-many for optional one to many associations" do
+ create_one_to_many_assoc_domain
+ assert_equal [Relationship::Cardinality.new(0..1, 0..N)], domain_cardinalities
+ end
+
+ test "cardinality should be one to zero-many for one to many associations with not null foreign key" do
+ create_model "One" do
+ has_many :many
+ end
+ create_model "Many" do
+ belongs_to :one
+ end
+ add_column :manies, :one_id, :integer, :null => false, :default => 0
+ assert_equal [Relationship::Cardinality.new(1, 0..N)], domain_cardinalities
+ end
+
+ test "cardinality should be one to one-many for mutually mandatory one to many associations" do
+ create_one_to_many_assoc_domain
+ One.class_eval do
+ validates_presence_of :many
+ end
+ Many.class_eval do
+ validates_presence_of :one
+ end
+ assert_equal [Relationship::Cardinality.new(1, 1..N)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to one-n for maximised one to many associations" do
+ create_one_to_many_assoc_domain
+ One.class_eval do
+ validates_presence_of :many
+
+ # This kind of validation is bizarre, but we support it.
+ validates_length_of :many, :maximum => 5
+ validates_length_of :many, :maximum => 2 # The lowest maximum should be used.
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 1..2)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to n-many for minimised one to many associations" do
+ create_one_to_many_assoc_domain
+ One.class_eval do
+ validates_presence_of :many
+ validates_length_of :many, :minimum => 2
+ validates_length_of :many, :minimum => 5 # The highest minimum should be used.
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 5..N)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to n-m for limited one to many associations with single validation" do
+ create_one_to_many_assoc_domain
+ One.class_eval do
+ validates_length_of :many, :minimum => 5, :maximum => 17
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 5..17)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to n-m for limited one to many associations with multiple validations" do
+ create_one_to_many_assoc_domain
+ One.class_eval do
+ validates_presence_of :many
+ validates_length_of :many, :maximum => 17
+ validates_length_of :many, :minimum => 5
+ validates_length_of :many, :minimum => 2, :maximum => 28
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 5..17)], domain_cardinalities
+ end
- test "cardinality should return one to many for has_many associations" do
- create_model "Foo", :bar => :references
- create_model "Bar" do
- has_many :foos
+ test "cardinality should be zero-many to zero-many for optional many to many associations" do
+ create_many_to_many_assoc_domain
+ assert_equal [Relationship::Cardinality.new(0..N, 0..N)], domain_cardinalities
+ end
+
+ test "cardinality should be one-many to one-many for mutually mandatory many to many associations" do
+ create_many_to_many_assoc_domain
+ Many.class_eval do
+ validates_presence_of :more
end
- domain = Domain.generate
- assert_equal [Relationship::Cardinality::OneToMany], domain.relationships.map(&:cardinality)
+ More.class_eval do
+ validates_presence_of :many
+ end
+ assert_equal [Relationship::Cardinality.new(1..N, 1..N)], domain_cardinalities
end
- test "cardinality should return many to many for has_and_belongs_to_many associations" do
- create_table "bars_foos", :foo_id => :integer, :bar_id => :integer
- create_model "Foo" do
- has_and_belongs_to_many :bars
+ test "cardinality should be n-m to n-m for limited many to many associations with single validations" do
+ create_many_to_many_assoc_domain
+ Many.class_eval do
+ validates_length_of :more, :minimum => 3, :maximum => 18
end
- create_model "Bar" do
- has_and_belongs_to_many :foos
+ More.class_eval do
+ validates_length_of :many, :maximum => 29, :minimum => 7
end
+ assert_equal [Relationship::Cardinality.new(3..18, 7..29)], domain_cardinalities
+ end
+
+ test "cardinality should be n-m to n-m for limited many to many associations with multiple validations" do
+ create_many_to_many_assoc_domain
+ Many.class_eval do
+ validates_presence_of :more
+ validates_length_of :more, :minimum => 3
+ validates_length_of :more, :maximum => 20
+ validates_length_of :more, :maximum => 33
+ end
+ More.class_eval do
+ validates_presence_of :many
+ validates_length_of :many, :minimum => 2
+ validates_length_of :many, :minimum => 9
+ validates_length_of :many, :maximum => 17
+ end
+ assert_equal [Relationship::Cardinality.new(3..20, 9..17)], domain_cardinalities
+ end
+
+ # Cardinality for non-mutual relationships =================================
+ test "cardinality should be zero-one to zero-many for non mutual relationship with belongs_to association" do
+ create_model "One"
+ create_model "Many", :one => :references do
+ belongs_to :one
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 0..N)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to zero-many for non mutual relationship with has_many association" do
+ create_model "One" do
+ has_many :many
+ end
+ create_model "Many", :one => :references
+ assert_equal [Relationship::Cardinality.new(0..1, 0..N)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to zero-one for non mutual relationship with has_one association" do
+ create_model "One" do
+ has_one :other
+ end
+ create_model "Other", :one => :references
+ assert_equal [Relationship::Cardinality.new(0..1, 0..1)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-many to zero-many for non mutual relationship with has_and_belongs_to_many association" do
+ create_table "many_more", :many_id => :integer, :more_id => :integer
+ create_model "Many"
+ create_model "More" do
+ has_and_belongs_to_many :many
+ end
+ assert_equal [Relationship::Cardinality.new(0..N, 0..N)], domain_cardinalities
+ end
+
+ # Cardinality for multiple associations ====================================
+ test "cardinality should be zero-one to zero-many for conflicting one to many associations" do
+ create_model "CreditCard", :person => :references do
+ belongs_to :person
+ end
+ create_model "Person" do
+ has_many :credit_cards
+
+ # A person may have a preferred card, but they are still able to have
+ # many cards. The association has an infinite maximum cardinality.
+ has_one :preferred_credit_card, :class_name => "CreditCard"
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 0..N)], domain_cardinalities
+ end
+
+ test "cardinality should be zero-one to one-many for conflicting validations in one to many associations" do
+ create_model "Book", :author => :references do
+ belongs_to :author
+ end
+ create_model "Author" do
+ has_many :books
+ has_many :published_books, :class_name => "Book"
+
+ # The author certainly has books, therefore, this association has a
+ # minimum cardinality of one.
+ validates_presence_of :books
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 1..N)], domain_cardinalities
+ end
+
+ test "cardinality should be n-m to n-m for conflicting validations in one to many associations" do
+ create_model "Spell", :wizard => :references do
+ end
+ create_model "Wizard" do
+ has_many :ice_spells, :class_name => "Spell"
+ has_many :fire_spells, :class_name => "Spell"
+
+ # Well, this can make sense, based on the conditions for the associations.
+ # We don't go that far yet. We ignore the lower values and opt for the
+ # higher values. It'll be okay. Really... You'll never need this.
+ validates_length_of :ice_spells, :in => 10..20
+ validates_length_of :fire_spells, :in => 50..100
+ end
+ assert_equal [Relationship::Cardinality.new(0..1, 50..100)], domain_cardinalities
+ end
+
+ # Cardinality classes ======================================================
+ test "cardinality should be one to one for has_one associations" do
+ create_one_to_one_assoc_domain
domain = Domain.generate
- assert_equal [Relationship::Cardinality::ManyToMany], domain.relationships.map(&:cardinality)
+
+ # In these test, we are liberal with the number of assertions per test.
+ assert_equal [:one_to_one], domain.relationships.map(&:cardinality).map(&:name)
+
+ assert_equal [true], domain.relationships.map(&:one_to_one?)
+ assert_equal [false], domain.relationships.map(&:one_to_many?)
+ assert_equal [false], domain.relationships.map(&:many_to_many?)
+
+ assert_equal [true], domain.relationships.map(&:one_to?)
+ assert_equal [false], domain.relationships.map(&:many_to?)
+ assert_equal [true], domain.relationships.map(&:to_one?)
+ assert_equal [false], domain.relationships.map(&:to_many?)
end
- test "cardinality should return one to many for multiple associations with maximum cardinality of has_many" do
+ test "cardinality should be one to many for has_many associations" do
+ create_one_to_many_assoc_domain
+ domain = Domain.generate
+
+ assert_equal [:one_to_many], domain.relationships.map(&:cardinality).map(&:name)
+ assert_equal [false], domain.relationships.map(&:one_to_one?)
+ assert_equal [true], domain.relationships.map(&:one_to_many?)
+ assert_equal [false], domain.relationships.map(&:many_to_many?)
+
+ assert_equal [true], domain.relationships.map(&:one_to?)
+ assert_equal [false], domain.relationships.map(&:many_to?)
+ assert_equal [false], domain.relationships.map(&:to_one?)
+ assert_equal [true], domain.relationships.map(&:to_many?)
+ end
+
+ test "cardinality should be many to many for has_and_belongs_to_many associations" do
+ create_many_to_many_assoc_domain
+ domain = Domain.generate
+
+ assert_equal [:many_to_many], domain.relationships.map(&:cardinality).map(&:name)
+
+ assert_equal [false], domain.relationships.map(&:one_to_one?)
+ assert_equal [false], domain.relationships.map(&:one_to_many?)
+ assert_equal [true], domain.relationships.map(&:many_to_many?)
+
+ assert_equal [false], domain.relationships.map(&:one_to?)
+ assert_equal [true], domain.relationships.map(&:many_to?)
+ assert_equal [false], domain.relationships.map(&:to_one?)
+ assert_equal [true], domain.relationships.map(&:to_many?)
+ end
+
+ test "cardinality should be one to many for multiple associations with maximum cardinality of has_many" do
create_model "Foo", :bar => :references
create_model "Bar" do
has_one :foo
has_many :foos
end
domain = Domain.generate
- assert_equal [Relationship::Cardinality::OneToMany], domain.relationships.map(&:cardinality)
+ assert_equal [:one_to_many], domain.relationships.map(&:cardinality).map(&:name)
end
- test "cardinality should return one to many if forward association is missing" do
+ test "cardinality should be one to many if forward association is missing" do
create_model "Foo", :bar => :references do
belongs_to :bar
end
create_model "Bar"
domain = Domain.generate
- assert_equal [Relationship::Cardinality::OneToMany], domain.relationships.map(&:cardinality)
+ assert_equal [:one_to_many], domain.relationships.map(&:cardinality).map(&:name)
end
-
- # test "cardinality should return zero or more for has_many association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # end
- # create_model "Bar" do
- # has_many :foos
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ZeroOrMore, domain.relationships.first.cardinality
- # end
- #
- # test "cardinality should return one or more for validated has_many association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # end
- # create_model "Bar" do
- # has_many :foos
- # validates :foos, :presence => true
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::OneOrMore, domain.relationships.first.cardinality
- # end
- #
- # test "cardinality should return zero or more for has_many association with foreign database constraint" do
- # create_model "Foo" do
- # belongs_to :bar
- # end
- # add_column :foos, :bar_id, :integer, :null => false, :default => 0
- # create_model "Bar" do
- # has_many :foos
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ZeroOrMore, domain.relationships.first.cardinality
- # end
- #
- # test "cardinality should return zero or one for has_one association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # end
- # create_model "Bar" do
- # has_one :foo
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ZeroOrOne, domain.relationships.first.cardinality
- # end
- #
- # test "cardinality should return exactly one for validated has_one association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # end
- # create_model "Bar" do
- # has_one :foo
- # validates :foo, :presence => true
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ExactlyOne, domain.relationships.first.cardinality
- # end
- #
- # test "cardinality should return exactly one for has_one association with foreign database constraint" do
- # create_model "Foo" do
- # belongs_to :bar
- # end
- # add_column :foos, :bar_id, :integer, :null => false, :default => 0
- # create_model "Bar" do
- # has_one :foo
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ZeroOrOne, domain.relationships.first.cardinality
- # end
- #
- # # Reverse cardinality ======================================================
- # test "reverse_cardinality should return nil if reverse association is missing" do
- # create_model "Foo", :bar => :references
- # create_model "Bar" do
- # has_many :foos
- # end
- # domain = Domain.generate
- # assert_nil domain.relationships.first.reverse_cardinality
- # end
- #
- # test "reverse_cardinality should return zero or one for has_many association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # end
- # create_model "Bar" do
- # has_many :foos
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ZeroOrOne, domain.relationships.first.reverse_cardinality
- # end
- #
- # test "reverse_cardinality should return exactly one for validated has_many association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # validates :bar, :presence => true
- # end
- # create_model "Bar" do
- # has_many :foos
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ExactlyOne, domain.relationships.first.reverse_cardinality
- # end
- #
- # test "reverse_cardinality should return zero or one for has_one association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # end
- # create_model "Bar" do
- # has_one :foo
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ZeroOrOne, domain.relationships.first.reverse_cardinality
- # end
- #
- # test "reverse_cardinality should return exactly one for validated has_one association" do
- # create_model "Foo", :bar => :references do
- # belongs_to :bar
- # validates :bar, :presence => true
- # end
- # create_model "Bar" do
- # has_one :foo
- # end
- # domain = Domain.generate
- # assert_equal Cardinality::ExactlyOne, domain.relationships.first.reverse_cardinality
- # end
end