Created
May 31, 2010 20:29
-
-
Save agross/420249 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace Crimson.NHibernateSupport | |
{ | |
public interface IEntity | |
{ | |
int Id | |
{ | |
get; | |
} | |
} | |
public abstract class Entity : IEntity, IEquatable<Entity> | |
{ | |
readonly int _id; | |
protected Entity() | |
{ | |
} | |
protected Entity(int id) | |
{ | |
_id = id; | |
} | |
public virtual int Id | |
{ | |
get { return _id; } | |
} | |
public virtual bool Equals(Entity other) | |
{ | |
if (ReferenceEquals(null, other)) | |
{ | |
return false; | |
} | |
if (ReferenceEquals(this, other)) | |
{ | |
return true; | |
} | |
return Id.Equals(default(int)) ? base.Equals(other) : other.Id.Equals(Id); | |
} | |
public override bool Equals(object obj) | |
{ | |
return Equals(obj as Entity); | |
} | |
public override int GetHashCode() | |
{ | |
return Id.Equals(default(int)) ? base.GetHashCode() : Id.GetHashCode(); | |
} | |
public static bool operator ==(Entity left, Entity right) | |
{ | |
return Equals(left, right); | |
} | |
public static bool operator !=(Entity left, Entity right) | |
{ | |
return !Equals(left, right); | |
} | |
} | |
} | |
using System; | |
using System.Collections.Generic; | |
using System.Reflection; | |
namespace Crimson.NHibernateSupport | |
{ | |
public abstract class ValueObject<T> : IEquatable<T> where T : ValueObject<T> | |
{ | |
public virtual bool Equals(T other) | |
{ | |
if (other == null) | |
{ | |
return false; | |
} | |
Type leftType = GetType(); | |
Type otherType = other.GetType(); | |
if (leftType != otherType) | |
{ | |
return false; | |
} | |
IEnumerable<FieldInfo> fields = GetFieldsFromTypeHierarchy(); | |
foreach (FieldInfo field in fields) | |
{ | |
object value1 = field.GetValue(this); | |
object value2 = field.GetValue(other); | |
if (value1 == null) | |
{ | |
if (value2 != null) | |
{ | |
return false; | |
} | |
} | |
else if (!value1.Equals(value2)) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
public override bool Equals(object obj) | |
{ | |
if (obj == null) | |
{ | |
return false; | |
} | |
return Equals(obj as T); | |
} | |
public override int GetHashCode() | |
{ | |
IEnumerable<FieldInfo> fields = GetFieldsFromTypeHierarchy(); | |
const int StartValue = 17; | |
const int Multiplier = 59; | |
int hashCode = StartValue; | |
foreach (FieldInfo field in fields) | |
{ | |
object value = field.GetValue(this); | |
hashCode = (hashCode * Multiplier) + (value != null ? value.GetHashCode() : StartValue); | |
} | |
return hashCode; | |
} | |
IEnumerable<FieldInfo> GetFieldsFromTypeHierarchy() | |
{ | |
Type t = GetType(); | |
List<FieldInfo> fields = new List<FieldInfo>(); | |
while (t != typeof(object)) | |
{ | |
fields.AddRange(t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)); | |
t = t.BaseType; | |
} | |
return fields; | |
} | |
public static bool operator ==(ValueObject<T> left, ValueObject<T> right) | |
{ | |
return Equals(left, right); | |
} | |
public static bool operator !=(ValueObject<T> left, ValueObject<T> right) | |
{ | |
return !Equals(left, right); | |
} | |
} | |
} | |
using System; | |
using Machine.Specifications; | |
namespace Crimson.NHibernateSupport.Tests | |
{ | |
public class Person : Entity | |
{ | |
public Person(string name) | |
{ | |
Name = name; | |
} | |
public Person(int id, string name) : base(id) | |
{ | |
Name = name; | |
} | |
public string Name | |
{ | |
get; | |
private set; | |
} | |
} | |
[Behaviors] | |
internal class EntityInequality | |
{ | |
protected static Person Person1; | |
protected static Person Person2; | |
It should_be_considered_as_unequal = () => ((Object) Person1).Equals(Person2).ShouldBeFalse(); | |
It should_be_considered_as_unequal_with_equality_operator = () => (Person1 == Person2).ShouldBeFalse(); | |
It should_be_considered_as_unequal_with_inequality_operator = () => (Person1 != Person2).ShouldBeTrue(); | |
It should_have_symmetric_inequality = () => ((Object) Person2).Equals(Person1).ShouldBeFalse(); | |
It should_compute_a_different_hash = () => Person1.GetHashCode().ShouldNotEqual(Person2.GetHashCode()); | |
} | |
[Behaviors] | |
internal class EntityEquality | |
{ | |
protected static Person Person1; | |
protected static Person Person2; | |
It should_be_considered_as_equal = () => ((Object) Person1).Equals(Person2).ShouldBeTrue(); | |
It should_be_considered_as_equal_with_equality_operator = () => (Person1 == Person2).ShouldBeTrue(); | |
It should_be_considered_as_equal_with_inequality_operator = () => (Person1 != Person2).ShouldBeFalse(); | |
It should_have_symmetric_inequality = () => ((Object) Person2).Equals(Person1).ShouldBeTrue(); | |
It should_compute_the_same_hash = () => Person1.GetHashCode().ShouldEqual(Person2.GetHashCode()); | |
} | |
[Subject(typeof(Entity))] | |
public class When_comparing_unsaved_entities_with_identical_values | |
{ | |
protected static Person Person1; | |
protected static Person Person2; | |
Establish context = () => | |
{ | |
Person1 = new Person("Darth Vader"); | |
Person2 = new Person("Darth Vader"); | |
}; | |
Behaves_like<EntityInequality> inequal_entities; | |
} | |
[Subject(typeof(Entity))] | |
public class When_comparing_unsaved_entities_with_different_values | |
{ | |
protected static Person Person1; | |
protected static Person Person2; | |
Establish context = () => | |
{ | |
Person1 = new Person("Darth Vader"); | |
Person2 = new Person("Senator Palpatine"); | |
}; | |
Behaves_like<EntityInequality> inequal_entities; | |
} | |
[Subject(typeof(Entity))] | |
public class When_comparing_saved_entities_with_different_IDs | |
{ | |
protected static Person Person1; | |
protected static Person Person2; | |
Establish context = () => | |
{ | |
Person1 = new Person(42, "Darth Vader"); | |
Person2 = new Person(43, "Senator Palpatine"); | |
}; | |
Behaves_like<EntityInequality> inequal_entities; | |
} | |
[Subject(typeof(Entity))] | |
public class When_comparing_saved_entities_with_identical_IDs | |
{ | |
protected static Person Person1; | |
protected static Person Person2; | |
Establish context = () => | |
{ | |
Person1 = new Person(42, "Darth Vader"); | |
Person2 = new Person(42, "Senator Palpatine"); | |
}; | |
Behaves_like<EntityEquality> equal_entities; | |
} | |
[Subject(typeof(Entity))] | |
public class When_comparing_the_same_entity_with_itself | |
{ | |
static Person Person; | |
Establish context = () => { Person = new Person("Darth Vader"); }; | |
It should_have_reflexive_equality = () => Person.Equals(Person).ShouldBeTrue(); | |
} | |
} | |
using System; | |
using Machine.Specifications; | |
namespace Crimson.NHibernateSupport.Tests | |
{ | |
#region Test Types | |
public class StreetAddress : ValueObject<StreetAddress> | |
{ | |
readonly string _city; | |
readonly string _state; | |
readonly string _street; | |
public StreetAddress(string street, string city, string state) | |
{ | |
_street = street; | |
_city = city; | |
_state = state; | |
} | |
public string Street | |
{ | |
get { return _street; } | |
} | |
public string City | |
{ | |
get { return _city; } | |
} | |
public string State | |
{ | |
get { return _state; } | |
} | |
} | |
public class StreetAddressWithStreetNumber : StreetAddress | |
{ | |
readonly string _streetNumber; | |
public StreetAddressWithStreetNumber(string street, string streetNumber, string city, string state) | |
: base(street, city, state) | |
{ | |
_streetNumber = streetNumber; | |
} | |
public string StreetNumber | |
{ | |
get { return _streetNumber; } | |
} | |
} | |
#endregion | |
[Behaviors] | |
internal class ValueObjectInequality | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddress Address2; | |
It should_be_considered_as_unequal = () => ((Object) Address1).Equals(Address2).ShouldBeFalse(); | |
It should_be_considered_as_unequal_with_equality_operator = () => (Address1 == Address2).ShouldBeFalse(); | |
It should_be_considered_as_unequal_with_inequality_operator = () => (Address1 != Address2).ShouldBeTrue(); | |
It should_have_symmetric_unequality = () => ((Object) Address2).Equals(Address1).ShouldBeFalse(); | |
It should_compute_a_different_hash = () => Address1.GetHashCode().ShouldNotEqual(Address2.GetHashCode()); | |
} | |
[Behaviors] | |
internal class ValueObjectEquality | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddress Address2; | |
It should_be_considered_as_equal = () => ((Object) Address1).Equals(Address2).ShouldBeTrue(); | |
It should_be_considered_as_equal_with_equality_operator = () => (Address1 == Address2).ShouldBeTrue(); | |
It should_be_considered_as_equal_with_inequality_operator = () => (Address1 != Address2).ShouldBeFalse(); | |
It should_have_symmetric_equality = () => ((Object) Address2).Equals(Address1).ShouldBeTrue(); | |
It should_compute_the_same_hash = () => Address1.GetHashCode().ShouldEqual(Address2.GetHashCode()); | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_value_objects_with_identical_values | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddress Address2; | |
Establish context = () => | |
{ | |
Address1 = new StreetAddress("Street", "Austin", "TX"); | |
Address2 = new StreetAddress("Street", "Austin", "TX"); | |
}; | |
Behaves_like<ValueObjectEquality> equal_value_objects; | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_value_objects_with_different_values | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddress Address2; | |
Establish context = () => | |
{ | |
Address1 = new StreetAddress("Street", "Austin", "TX"); | |
Address2 = new StreetAddress("Foo", "Austin", "TX"); | |
}; | |
Behaves_like<ValueObjectInequality> unequal_value_objects; | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_different_value_objects_with_null_values_on_one_object | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddress Address2; | |
Establish context = () => | |
{ | |
Address1 = new StreetAddress(null, "Austin", "TX"); | |
Address2 = new StreetAddress("Street", "Austin", "TX"); | |
}; | |
Behaves_like<ValueObjectInequality> unequal_value_objects; | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_a_value_object_against_null | |
{ | |
static StreetAddress StreetAddress; | |
Establish context = () => { StreetAddress = new StreetAddress("Street", "Austin", "TX"); }; | |
It should_be_considered_as_unequal = () => StreetAddress.Equals(null).ShouldBeFalse(); | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_the_same_value_object_with_itself | |
{ | |
static StreetAddress StreetAddress; | |
Establish context = () => { StreetAddress = new StreetAddress("StreetAddress", "Austin", "TX"); }; | |
It should_have_reflexive_equality = () => StreetAddress.Equals(StreetAddress).ShouldBeTrue(); | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_three_value_objects_with_identical_values | |
{ | |
static StreetAddress Address1; | |
static StreetAddress Address2; | |
static StreetAddress Address3; | |
Establish context = () => | |
{ | |
Address1 = new StreetAddress("StreetAddress", "Austin", "TX"); | |
Address2 = new StreetAddress("StreetAddress", "Austin", "TX"); | |
Address3 = new StreetAddress("StreetAddress", "Austin", "TX"); | |
}; | |
It should_have_transitive_equality_for_A_and_B = () => ((Object) Address1).Equals(Address2).ShouldBeTrue(); | |
It should_have_transitive_equality_for_B_and_C = () => ((Object) Address2).Equals(Address3).ShouldBeTrue(); | |
It should_have_transitive_equality_for_A_and_C = () => ((Object) Address1).Equals(Address3).ShouldBeTrue(); | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_value_objects_with_transposed_field_values | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddress Address2; | |
Establish context = () => | |
{ | |
Address1 = new StreetAddress(null, "Austin", "TX"); | |
Address2 = new StreetAddress("TX", "Austin", null); | |
}; | |
Behaves_like<ValueObjectInequality> unequal_value_objects; | |
} | |
[Subject(typeof(ValueObject<>))] | |
public class When_comparing_a_value_object_against_a_derived_one_with_the_same_values | |
{ | |
protected static StreetAddress Address1; | |
protected static StreetAddressWithStreetNumber Address2; | |
Establish context = () => | |
{ | |
Address1 = new StreetAddress("Street", "Austin", "TX"); | |
Address2 = new StreetAddressWithStreetNumber("Street", "StreetNumber", "Austin", "TX"); | |
}; | |
Behaves_like<ValueObjectInequality> unequal_value_objects; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment