-
Notifications
You must be signed in to change notification settings - Fork 238
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'refs/remotes/origin/master' into release
- Loading branch information
Showing
9 changed files
with
259 additions
and
7 deletions.
There are no files selected for viewing
This file contains 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
43 changes: 43 additions & 0 deletions
43
src/NuGet.Server/DataServices/IgnoreCaseForPackageIdInterceptor.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
|
||
namespace NuGet.Server.DataServices | ||
{ | ||
public class IgnoreCaseForPackageIdInterceptor : ExpressionVisitor | ||
{ | ||
private static readonly MemberInfo _idMember = typeof(ODataPackage).GetProperty("Id"); | ||
private static readonly Expression<Func<string, string, int>> _ordinalIgnoreCaseComparer = (a, b) => StringComparer.OrdinalIgnoreCase.Compare(a, b); | ||
|
||
protected override Expression VisitBinary(BinaryExpression node) | ||
{ | ||
// Change equality comparisons on Version to normalized comparisons on NormalizedVersion | ||
if (node.NodeType == ExpressionType.Equal) | ||
{ | ||
// Figure out which side is the target | ||
ConstantExpression constSide = (node.Left as ConstantExpression) ?? (node.Right as ConstantExpression); | ||
if (constSide != null && constSide.Type == typeof(string)) | ||
{ | ||
MemberExpression memberSide = (node.Right as MemberExpression) ?? (node.Left as MemberExpression); | ||
if (memberSide != null && memberSide.Member == _idMember) | ||
{ | ||
// We have a "Package.Id == <constant>" expression! | ||
|
||
// Rewrite it to StringComparer.OrdinalIgnoreCase.Compare(a, b) == 0 | ||
return Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Invoke(_ordinalIgnoreCaseComparer, | ||
Expression.MakeMemberAccess(memberSide.Expression, _idMember), | ||
constSide | ||
), | ||
Expression.Constant(0)); | ||
} | ||
} | ||
} | ||
return node; | ||
} | ||
} | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
112 changes: 112 additions & 0 deletions
112
test/NuGet.Server.Tests/IgnoreCaseForPackageIdInterceptorTest.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using NuGet.Server.DataServices; | ||
using Xunit; | ||
|
||
namespace NuGet.Server.Tests | ||
{ | ||
public class IgnoreCaseForPackageIdInterceptorTest | ||
{ | ||
private static readonly MemberInfo _idMember = typeof(ODataPackage).GetProperty("Id"); | ||
private static readonly Expression<Func<string, string, int>> _ordinalIgnoreCaseComparer = (a, b) => StringComparer.OrdinalIgnoreCase.Compare(a, b); | ||
|
||
public static IEnumerable<object[]> TheoryData | ||
{ | ||
get | ||
{ | ||
return new[] | ||
{ | ||
new object[] | ||
{ | ||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Constant("NEWTONSOFT.JSON"), | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _idMember)), | ||
|
||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Invoke(_ordinalIgnoreCaseComparer, | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _idMember), | ||
Expression.Constant("NEWTONSOFT.JSON") | ||
), | ||
Expression.Constant(0)) | ||
}, | ||
|
||
new object[] | ||
{ | ||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _idMember), | ||
Expression.Constant("NEWTONSOFT.JSON")), | ||
|
||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Invoke(_ordinalIgnoreCaseComparer, | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _idMember), | ||
Expression.Constant("NEWTONSOFT.JSON") | ||
), | ||
Expression.Constant(0)) | ||
} | ||
}; | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData("TheoryData")] | ||
public void RewritesIdComparisonToIgnoreCaseComparison(Expression originalExpression, Expression expectedExpression) | ||
{ | ||
// Arrange | ||
var interceptor = new IgnoreCaseForPackageIdInterceptor(); | ||
|
||
// Act | ||
var rewrittenExpression = interceptor.Visit(originalExpression); | ||
|
||
// Assert | ||
Assert.Equal(rewrittenExpression.ToString(), expectedExpression.ToString()); | ||
} | ||
|
||
[Fact] | ||
public void FindsPackagesIgnoringCase() | ||
{ | ||
// Arrange | ||
var data = new List<ODataPackage>(); | ||
data.Add(new ODataPackage { Id = "foo" }); | ||
data.Add(new ODataPackage { Id = "BAR" }); | ||
data.Add(new ODataPackage { Id = "bAz" }); | ||
|
||
var queryable = data.AsQueryable().InterceptWith(new IgnoreCaseForPackageIdInterceptor()); | ||
|
||
// Act | ||
var result1 = queryable.FirstOrDefault(p => p.Id == "foo"); | ||
var result2 = queryable.FirstOrDefault(p => p.Id == "FOO"); | ||
var result3 = queryable.FirstOrDefault(p => p.Id == "Foo"); | ||
|
||
var result4 = queryable.FirstOrDefault(p => p.Id == "bar"); | ||
var result5 = queryable.FirstOrDefault(p => p.Id == "BAR"); | ||
var result6 = queryable.FirstOrDefault(p => p.Id == "baR"); | ||
|
||
var result7 = queryable.FirstOrDefault(p => p.Id == "baz"); | ||
var result8 = queryable.FirstOrDefault(p => p.Id == "BAZ"); | ||
var result9 = queryable.FirstOrDefault(p => p.Id == "bAz"); | ||
|
||
// Assert | ||
Assert.Equal(result1.Id, data[0].Id); | ||
Assert.Equal(result2.Id, data[0].Id); | ||
Assert.Equal(result3.Id, data[0].Id); | ||
|
||
Assert.Equal(result4.Id, data[1].Id); | ||
Assert.Equal(result5.Id, data[1].Id); | ||
Assert.Equal(result6.Id, data[1].Id); | ||
|
||
Assert.Equal(result7.Id, data[2].Id); | ||
Assert.Equal(result8.Id, data[2].Id); | ||
Assert.Equal(result9.Id, data[2].Id); | ||
} | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
test/NuGet.Server.Tests/NormalizeVersionInterceptorTest.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using NuGet.Server.DataServices; | ||
using Xunit; | ||
|
||
namespace NuGet.Server.Tests | ||
{ | ||
public class NormalizeVersionInterceptorTest | ||
{ | ||
private static readonly MemberInfo _versionMember = typeof(ODataPackage).GetProperty("Version"); | ||
private static readonly MemberInfo _normalizedVersionMember = typeof(ODataPackage).GetProperty("NormalizedVersion"); | ||
|
||
public static IEnumerable<object[]> TheoryData | ||
{ | ||
get | ||
{ | ||
return new[] | ||
{ | ||
new object[] | ||
{ | ||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Constant("1.0.0.0"), | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _versionMember)), | ||
|
||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Constant("1.0.0"), | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _normalizedVersionMember)) | ||
}, | ||
|
||
new object[] | ||
{ | ||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _versionMember), | ||
Expression.Constant("1.0.0.0")), | ||
|
||
Expression.MakeBinary( | ||
ExpressionType.Equal, | ||
Expression.Constant("1.0.0"), | ||
Expression.MakeMemberAccess(Expression.Parameter(typeof(ODataPackage)), _normalizedVersionMember)) | ||
} | ||
}; | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData("TheoryData")] | ||
public void RewritesVersionPropertyNameToNormalizedVersionPropertyName(Expression originalExpression, Expression expectedExpression) | ||
{ | ||
// Arrange | ||
var interceptor = new NormalizeVersionInterceptor(); | ||
|
||
// Act | ||
var rewrittenExpression = interceptor.Visit(originalExpression); | ||
|
||
// Assert | ||
Assert.Equal(rewrittenExpression.ToString(), expectedExpression.ToString()); | ||
} | ||
|
||
[Fact] | ||
public void FindsPackagesUsingNormalizedVersion() | ||
{ | ||
// Arrange | ||
var data = new List<ODataPackage>(); | ||
data.Add(new ODataPackage { Id = "foo", Version = "1.0.0.0.0.0", NormalizedVersion = "1.0.0"}); | ||
|
||
var queryable = data.AsQueryable().InterceptWith(new NormalizeVersionInterceptor()); | ||
|
||
// Act | ||
var result1 = queryable.FirstOrDefault(p => p.Version == "1.0"); | ||
var result2 = queryable.FirstOrDefault(p => p.Version == "1.0.0"); | ||
var result3 = queryable.FirstOrDefault(p => p.Version == "1.0.0.0"); | ||
|
||
// Assert | ||
Assert.Equal(result1, data[0]); | ||
Assert.Equal(result2, data[0]); | ||
Assert.Equal(result3, data[0]); | ||
} | ||
} | ||
} |
This file contains 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