Berryl Hesh
unread,Sep 22, 2010, 7:41:53 PM9/22/10Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to NUnit-Discuss
Below is code for an abstract generic range class based on code
written by Jon Skeet in his C# In Depth book, a DateTime
implementation of same, and a test that at first glance I would expect
to pass using NUnit equals constraints (latest version). As you can
see, a major part of the class design is to provide support for
enumeration, although it is obviously not a collection class.
Is there some way to use the equals constraint in this situation?
Cheers,
Berryl
public abstract class Range<T> : ValueObject, IEnumerable<T> where
T : IComparable<T>, IEquatable<T>
{
private readonly T _end;
private readonly T _start;
/// <summary> The start of the range. </summary>
public T Start { get { return _start; } }
/// <summary> The end of the range. </summary>
public T End { get { return _end; } }
protected Range(T start, T end)
{
if (start.CompareTo(end) > 0)
throw new ArgumentOutOfRangeException();
_start = start;
_end = end;
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
var value = _start;
while (value.CompareTo(_end) < 0)
{
yield return value;
value = GetNextValue(value);
}
if (value.CompareTo(_end) == 0)
yield return value;
}
IEnumerator IEnumerable.GetEnumerator() { return
GetEnumerator(); }
#endregion
/// <summary> True if the first range includes the passed
point.</summary>
public bool Contains(T value)
{
return value.CompareTo(_start) >= 0 &&
value.CompareTo(_end) <= 0;
}
protected abstract T GetNextValue(T current);
#region Equality
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return ReferenceEquals(this, obj) || Equals(obj as
Range<T>);
}
public bool Equals(Range<T> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.Start.Equals(Start) && other.End.Equals(End);
}
public override int GetHashCode()
{
unchecked
{
var result = 17;
result = (result * 397) ^ Start.GetHashCode();
result = (result * 397) ^ End.GetHashCode();
return result;
}
}
public static bool operator ==(Range<T> left, Range<T> right)
{ return Equals(left, right); }
public static bool operator !=(Range<T> left, Range<T> right)
{ return !Equals(left, right); }
#endregion
}
public class DateTimeRange : Range<DateTime>
{
readonly TimeSpan _step;
public DateTimeRange(DateTime start, DateTime end)
: this(start, end, TimeSpan.FromDays(1)) { }
public DateTimeRange(DateTime start, DateTime end, TimeSpan
step)
: base(start, end) { this._step = step; }
protected override DateTime GetNextValue(DateTime current)
{ return current + _step; }
}
[Test]
public void DateTime_EndOfRange_EffectsEquality()
{
var start = DateTime.Now;
var end = start.AddDays(1);
var r1 = new DateTimeRange(start, end);
var r2 = new DateTimeRange(start, end);
Assert.That(r1, Is.EqualTo(r2));
Assert.That(r1.GetHashCode(),
Is.EqualTo(r2.GetHashCode()));
Assert.That(r1 == r2);
Assert.That(r1.Equals(r2));
r2 = new DateTimeRange(start, end.AddTicks(1));
//Assert.That(r1,
Is.Not.EqualTo(r2));==============================> FALSE <==
Assert.That(r1.GetHashCode(),
Is.Not.EqualTo(r2.GetHashCode()));
Assert.That(r1 != r2);
Assert.That(!r1.Equals(r2));
}
public T Start { get { return _start; } }
public T End { get { return _end; } }
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator() {
var value = _start;
while (value.CompareTo(_end) < 0) {
yield return value;
value = GetNextValue(value);
}
if (value.CompareTo(_end) == 0)
yield return value;
}
IEnumerator IEnumerable.GetEnumerator() { return
GetEnumerator(); }
#endregion
public bool Contains(T value) {
return value.CompareTo(_start) >= 0 &&
value.CompareTo(_end) <= 0;
}
protected abstract T GetNextValue(T current);
}