Add strong and weak ETag comparisons

This commit is contained in:
John Luo 2016-08-29 17:55:20 -07:00
parent e2a0e887af
commit e4afd782e8
2 changed files with 127 additions and 1 deletions

View File

@ -93,6 +93,15 @@ namespace Microsoft.Net.Http.Headers
return _tag;
}
/// <summary>
/// Check against another <see cref="EntityTagHeaderValue"/> for equality.
/// This equality check should not be used to determine if two values match under the RFC specifications (https://tools.ietf.org/html/rfc7232#section-2.3.2).
/// </summary>
/// <param name="obj">The other value to check against for equality.</param>
/// <returns>
/// <c>true</c> if the strength and tag of the two values match,
/// <c>false</c> if the other value is null, is not an <see cref="EntityTagHeaderValue"/>, or if there is a mismatch of strength or tag between the two values.
/// </returns>
public override bool Equals(object obj)
{
var other = obj as EntityTagHeaderValue;
@ -103,7 +112,7 @@ namespace Microsoft.Net.Http.Headers
}
// Since the tag is a quoted-string we treat it case-sensitive.
return ((_isWeak == other._isWeak) && (string.CompareOrdinal(_tag, other._tag) == 0));
return _isWeak == other._isWeak && string.Equals(_tag, other._tag, StringComparison.Ordinal);
}
public override int GetHashCode()
@ -112,6 +121,32 @@ namespace Microsoft.Net.Http.Headers
return _tag.GetHashCode() ^ _isWeak.GetHashCode();
}
/// <summary>
/// Compares against another <see cref="EntityTagHeaderValue"/> to see if they match under the RFC specifications (https://tools.ietf.org/html/rfc7232#section-2.3.2).
/// </summary>
/// <param name="other">The other <see cref="EntityTagHeaderValue"/> to compare against.</param>
/// <param name="useStrongComparison"><c>true</c> to use a strong comparison, <c>false</c> to use a weak comparison</param>
/// <returns>
/// <c>true</c> if the <see cref="EntityTagHeaderValue"/> match for the given comparison type,
/// <c>false</c> if the other value is null or the comparison failed.
/// </returns>
public bool Compare(EntityTagHeaderValue other, bool useStrongComparison)
{
if (other == null)
{
return false;
}
if (useStrongComparison)
{
return !IsWeak && !other.IsWeak && string.Equals(Tag, other.Tag, StringComparison.Ordinal);
}
else
{
return string.Equals(Tag, other.Tag, StringComparison.Ordinal);
}
}
public static EntityTagHeaderValue Parse(string input)
{
var index = 0;

View File

@ -99,6 +99,97 @@ namespace Microsoft.Net.Http.Headers
Assert.True(etag1.Equals(etag5), "tag vs. tag..");
}
[Fact]
public void Compare_WithNull_ReturnsFalse()
{
Assert.False(EntityTagHeaderValue.Any.Compare(null, useStrongComparison: true));
Assert.False(EntityTagHeaderValue.Any.Compare(null, useStrongComparison: false));
}
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> NotEquivalentUnderStrongComparison
{
get
{
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
{
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"TAG\"") },
{ new EntityTagHeaderValue("\"tag\"", true), new EntityTagHeaderValue("\"tag\"", true) },
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"", true) },
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag1\"") },
{ new EntityTagHeaderValue("\"tag\""), EntityTagHeaderValue.Any },
};
}
}
[Theory]
[MemberData(nameof(NotEquivalentUnderStrongComparison))]
public void CompareUsingStrongComparison_NonEquivalentPairs_ReturnFalse(EntityTagHeaderValue left, EntityTagHeaderValue right)
{
Assert.False(left.Compare(right, useStrongComparison: true));
Assert.False(right.Compare(left, useStrongComparison: true));
}
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> EquivalentUnderStrongComparison
{
get
{
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
{
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"") },
};
}
}
[Theory]
[MemberData(nameof(EquivalentUnderStrongComparison))]
public void CompareUsingStrongComparison_EquivalentPairs_ReturnTrue(EntityTagHeaderValue left, EntityTagHeaderValue right)
{
Assert.True(left.Compare(right, useStrongComparison: true));
Assert.True(right.Compare(left, useStrongComparison: true));
}
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> NotEquivalentUnderWeakComparison
{
get
{
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
{
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"TAG\"") },
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag1\"") },
{ new EntityTagHeaderValue("\"tag\""), EntityTagHeaderValue.Any },
};
}
}
[Theory]
[MemberData(nameof(NotEquivalentUnderWeakComparison))]
public void CompareUsingWeakComparison_NonEquivalentPairs_ReturnFalse(EntityTagHeaderValue left, EntityTagHeaderValue right)
{
Assert.False(left.Compare(right, useStrongComparison: false));
Assert.False(right.Compare(left, useStrongComparison: false));
}
public static TheoryData<EntityTagHeaderValue, EntityTagHeaderValue> EquivalentUnderWeakComparison
{
get
{
return new TheoryData<EntityTagHeaderValue, EntityTagHeaderValue>
{
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"") },
{ new EntityTagHeaderValue("\"tag\"", true), new EntityTagHeaderValue("\"tag\"", true) },
{ new EntityTagHeaderValue("\"tag\""), new EntityTagHeaderValue("\"tag\"", true) },
};
}
}
[Theory]
[MemberData(nameof(EquivalentUnderWeakComparison))]
public void CompareUsingWeakComparison_EquivalentPairs_ReturnTrue(EntityTagHeaderValue left, EntityTagHeaderValue right)
{
Assert.True(left.Compare(right, useStrongComparison: false));
Assert.True(right.Compare(left, useStrongComparison: false));
}
[Fact]
public void Parse_SetOfValidValueStrings_ParsedCorrectly()
{