Skip to content

Commit

Permalink
Merge pull request #88 from NuGet/dev
Browse files Browse the repository at this point in the history
Merge branch 'dev' into master
  • Loading branch information
joelverhagen authored Aug 13, 2019
2 parents 03597a6 + 55f68e9 commit 3d8f707
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.IO;
using System.Linq;
Expand All @@ -18,7 +19,8 @@ public class JsonNetPackagesSerializer
private readonly JsonSerializer _serializer = new JsonSerializer
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore
NullValueHandling = NullValueHandling.Ignore,
Converters = { new AbsoluteUriConverter() },
};

public void Serialize(IEnumerable<ServerPackage> packages, Stream stream)
Expand Down Expand Up @@ -51,5 +53,54 @@ public IEnumerable<ServerPackage> Deserialize(Stream stream)
return packages.Packages;
}
}

/// <summary>
/// This is necessary because Newtonsoft.Json creates <see cref="Uri"/> instances with
/// <see cref="UriKind.RelativeOrAbsolute"/> which treats UNC paths as relative. NuGet.Core uses
/// <see cref="UriKind.Absolute"/> which treats UNC paths as absolute. For more details, see:
/// https://github.com/JamesNK/Newtonsoft.Json/issues/2128
/// </summary>
private class AbsoluteUriConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Uri);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
else if (reader.TokenType == JsonToken.String)
{
return new Uri((string)reader.Value, UriKind.Absolute);
}

throw new JsonSerializationException("The JSON value must be a string.");
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}

if (!(value is Uri uriValue))
{
throw new JsonSerializationException("The value must be a URI.");
}

if (!uriValue.IsAbsoluteUri)
{
throw new JsonSerializationException("The URI value must be an absolute Uri. Relative URI instances are not allowed.");
}

writer.WriteValue(uriValue.OriginalString);
}
}
}
}
52 changes: 47 additions & 5 deletions test/NuGet.Server.Core.Tests/JsonNetPackagesSerializerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,37 @@ namespace NuGet.Server.Core.Tests
{
public class JsonNetPackagesSerializerTests
{
[Fact]
public void RoundTripsUncPaths()
{
var originalPackages = GenerateServerPackages(1);
var originalPackage = originalPackages.Single();
originalPackage.IconUrl = new Uri("//testunc/test/a", UriKind.Absolute);
originalPackage.LicenseUrl = new Uri("//testunc/test/b", UriKind.Absolute);
originalPackage.ProjectUrl = new Uri("//testunc/test/c", UriKind.Absolute);
originalPackage.ReportAbuseUrl = new Uri("//testunc/test/d", UriKind.Absolute);
var serializer = new JsonNetPackagesSerializer();

// Act
var deserializedPackages = new List<ServerPackage>();
using (var memoryStream = new MemoryStream())
{
serializer.Serialize(originalPackages, memoryStream);

memoryStream.Position = 0;

deserializedPackages.AddRange(serializer.Deserialize(memoryStream));
}

// Assert
AssertPackagesAreEqual(originalPackages, deserializedPackages);
var deserializedPackage = deserializedPackages.Single();
Assert.True(deserializedPackage.IconUrl.IsAbsoluteUri, "The icon URL should still be absolute.");
Assert.True(deserializedPackage.LicenseUrl.IsAbsoluteUri, "The license URL should still be absolute.");
Assert.True(deserializedPackage.ProjectUrl.IsAbsoluteUri, "The project URL should still be absolute.");
Assert.True(deserializedPackage.ReportAbuseUrl.IsAbsoluteUri, "The report abuse URL should still be absolute.");
}

[Fact]
public void TestSerializationRoundTrip()
{
Expand All @@ -33,14 +64,25 @@ public void TestSerializationRoundTrip()
}

// Assert
AssertPackagesAreEqual(originalPackages, deserializedPackages);
}

private static void AssertPackagesAreEqual(List<ServerPackage> originalPackages, List<ServerPackage> deserializedPackages)
{
Assert.Equal(originalPackages.Count, deserializedPackages.Count);
for (var i = 0; i < originalPackages.Count; i++)
{
Assert.True(PublicPropertiesEqual(originalPackages[i], deserializedPackages[i], "DependencySets", "FrameworkAssemblies", "PackageAssemblyReferences", "AssemblyReferences"));
AssertPublicPropertiesEqual(
originalPackages[i],
deserializedPackages[i],
"DependencySets",
"FrameworkAssemblies",
"PackageAssemblyReferences",
"AssemblyReferences");
}
}

private static bool PublicPropertiesEqual<T>(T a, T b, params string[] ignoreProperties) where T : class
private static void AssertPublicPropertiesEqual<T>(T a, T b, params string[] ignoreProperties) where T : class
{
if (a != null && b != null)
{
Expand All @@ -55,15 +97,15 @@ private static bool PublicPropertiesEqual<T>(T a, T b, params string[] ignorePro

if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)) && !(selfValue is IEnumerable))
{
return false;
Assert.False(true, $"The property '{pi.Name}' is not equal.");
}
}
}

return true;
return;
}

return a == b;
Assert.Equal(a, b);
}

private static List<ServerPackage> GenerateServerPackages(int count)
Expand Down

0 comments on commit 3d8f707

Please sign in to comment.