Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/master' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
maartenba committed Apr 15, 2016
2 parents 1b7a1fd + 866ddb9 commit a39bc60
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/CommonAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

[assembly: ComVisible(false)]

[assembly: AssemblyVersion("2.10.0.0")]
[assembly: AssemblyFileVersion("2.10.0.0")]
[assembly: AssemblyVersion("2.10.3.0")]
[assembly: AssemblyFileVersion("2.10.3.0")]

[assembly: NeutralResourcesLanguage("en-US")]
43 changes: 43 additions & 0 deletions src/NuGet.Server/DataServices/IgnoreCaseForPackageIdInterceptor.cs
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;
}
}
}
2 changes: 1 addition & 1 deletion src/NuGet.Server/DataServices/PackageContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public IQueryable<ODataPackage> Packages
.GetPackages()
.Select(package => package.AsODataPackage())
.AsQueryable()
.InterceptWith(new NormalizeVersionInterceptor());
.InterceptWith(new IgnoreCaseForPackageIdInterceptor(), new NormalizeVersionInterceptor());
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/NuGet.Server/Infrastructure/ServerPackageRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Threading;
using System.Threading.Tasks;
using System.Web.Configuration;
using NuGet.Resources;
using NuGet.Server.Logging;

namespace NuGet.Server.Infrastructure
Expand Down
14 changes: 11 additions & 3 deletions src/NuGet.Server/Infrastructure/ServerPackageStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace NuGet.Server.Infrastructure
{
Expand Down Expand Up @@ -53,10 +54,17 @@ private void Load()
}
}
}
catch (SerializationException)
catch (Exception ex)
{
// In case this happens, remove the file
_fileSystem.DeleteFile(_fileName);
if (ex is JsonReaderException || ex is SerializationException)
{
// In case this happens, remove the file
_fileSystem.DeleteFile(_fileName);
}
else
{
throw;
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/NuGet.Server/NuGet.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<Compile Include="Core\FrameworkNameExtensions.cs" />
<Compile Include="Core\IServiceResolver.cs" />
<Compile Include="Core\PackageExtensions.cs" />
<Compile Include="DataServices\IgnoreCaseForPackageIdInterceptor.cs" />
<Compile Include="DataServices\ODataPackage.cs" />
<Compile Include="DataServices\PackageContext.cs" />
<Compile Include="DataServices\PackageExtensions.cs" />
Expand Down
112 changes: 112 additions & 0 deletions test/NuGet.Server.Tests/IgnoreCaseForPackageIdInterceptorTest.cs
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 test/NuGet.Server.Tests/NormalizeVersionInterceptorTest.cs
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]);
}
}
}
2 changes: 2 additions & 0 deletions test/NuGet.Server.Tests/NuGet.Server.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<ItemGroup>
<Compile Include="IgnoreCaseForPackageIdInterceptorTest.cs" />
<Compile Include="JsonNetPackagesSerializerTests.cs" />
<Compile Include="FeedPackageTest.cs" />
<Compile Include="Infrastructure\TemporaryDirectory.cs" />
<Compile Include="NormalizeVersionInterceptorTest.cs" />
<Compile Include="PackageAuthenticationServiceTests.cs" />
<Compile Include="PackageSvcFacts.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down

0 comments on commit a39bc60

Please sign in to comment.