require_relative './test_helper' require File.expand_path('../../lib/attr_comparable', __FILE__) class ComparableTestOneParameter include AttrComparable attr_reader :last_name attr_compare :last_name def initialize(last_name) @last_name = last_name end end class ComparableTestManyParameters include AttrComparable attr_reader :last_name, :first_name attr_compare :last_name, :first_name def initialize(last_name, first_name) @last_name = last_name @first_name = first_name end end describe 'AttrComparable' do describe "one parameter" do before do @d1 = ComparableTestOneParameter.new('Jones') @d2 = ComparableTestOneParameter.new('Jones') @d3 = ComparableTestOneParameter.new('Kelley') end it "should define <=>" do assert_equal 0, @d1 <=> @d2 assert_equal -1, @d1 <=> @d3 assert_equal 1, @d3 <=> @d1 end it "should define relative operators like Comparable" do assert @d1.is_a?(Comparable) assert @d1 < @d3 assert @d3 >= @d2 assert @d1 == @d2 assert @d2 != @d3 end end describe "many parameters" do before do @d1 = ComparableTestManyParameters.new('Jones', 'S') @d2 = ComparableTestManyParameters.new('Jones', 'T') @d3 = ComparableTestManyParameters.new('Jones', 'S') @d4 = ComparableTestManyParameters.new('Kelley', 'C') end it "should define <=>" do assert_equal 0, @d1 <=> @d3 assert_equal -1, @d1 <=> @d2 assert_equal 1, @d4 <=> @d1 end it "should be Comparable" do assert @d1.is_a?(Comparable) end it "should define relative operators from Comparable" do assert @d1 < @d2 assert @d2 >= @d3 assert @d1 == @d3 assert @d2 != @d3 end end describe "many parameters with nil" do before do # sort order @d1 = ComparableTestManyParameters.new(nil, 'S') # 1 @d2 = ComparableTestManyParameters.new('Jones', nil) # 2 @d3 = ComparableTestManyParameters.new(nil, nil) # 0 @d4 = ComparableTestManyParameters.new('Jones', 'S') # 3 end it "should define <=> with nil first" do assert_equal 0, @d1 <=> @d1 assert_equal 0, @d3 <=> @d3 assert_equal -1, @d1 <=> @d2 assert_equal 1, @d2 <=> @d3 assert_equal -1, @d2 <=> @d4 end it "should define relative operators from Comparable" do assert @d1 == @d1 assert @d2 > @d3 assert @d2 != @d3 end end describe "parameters that are incompatible to order" do it "should return nil when the objects contain incompatible attributes" do d1 = ComparableTestOneParameter.new(false) d2 = ComparableTestOneParameter.new(true) d3 = ComparableTestManyParameters.new(false, 'D') d4 = ComparableTestManyParameters.new(true, 'D') d5 = ComparableTestManyParameters.new('Kelly', false) d6 = ComparableTestManyParameters.new('Kelly', true) assert_nil d1 <=> d2 assert_nil d3 <=> d4 assert_nil d5 <=> d6 end # For ComparableTestManyParameters the objects are compared by last_name then first_name # If the comparison of last_names returns nil, that should immediately return nil, # and not compare the remaining attributes. This code tests that by raising a runtime error # if the first_name attribute (later in the compare order) is acessed it "should return immediately return nils, not evaulate further attributes" do incompatible_first_attribute = ComparableTestManyParameters.new('Kelly', false) compatible_first_and_second_attribute = ComparableTestManyParameters.new(true, 'D') d7 = Minitest::Mock.new d8 = Minitest::Mock.new 2.times { d7.expect :last_name, false, [] } # :last_name is used exactly twice per <=> call d7.expect :nil?, false, [] # :nil? is used exactly once per <=> call assert_nil incompatible_first_attribute <=> d7 2.times { d8.expect :last_name, true, [] } 2.times { d8.expect :first_name, 'D', [] } d8.expect :nil?, false, [] assert_equal 0, compatible_first_and_second_attribute <=> d8 d7.verify d8.verify end it "should return nil if the rhs is nil" do d1 = ComparableTestOneParameter.new(false) d2 = ComparableTestManyParameters.new('Kelly', false) assert_nil d1 <=> nil assert_nil d2 <=> nil end end end