Skip to content
This repository has been archived by the owner on Mar 16, 2021. It is now read-only.

[C2R 3] Add unit tests for RegistrationComparer core logic #730

Merged
merged 1 commit into from
Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions NuGet.Services.Metadata.sln
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.V3.Tests", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Jobs.RegistrationComparer", "src\NuGet.Jobs.RegistrationComparer\NuGet.Jobs.RegistrationComparer.csproj", "{4CE6C864-DB4D-4262-A2DD-80BB932F6E8C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Jobs.RegistrationComparer.Tests", "tests\NuGet.Jobs.RegistrationComparer.Tests\NuGet.Jobs.RegistrationComparer.Tests.csproj", "{A0E0698A-1161-4DEA-81A9-06D30FB16538}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -391,6 +393,18 @@ Global
{4CE6C864-DB4D-4262-A2DD-80BB932F6E8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4CE6C864-DB4D-4262-A2DD-80BB932F6E8C}.Release|x64.ActiveCfg = Release|Any CPU
{4CE6C864-DB4D-4262-A2DD-80BB932F6E8C}.Release|x64.Build.0 = Release|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Debug|x64.ActiveCfg = Debug|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Debug|x64.Build.0 = Debug|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Release|Any CPU.Build.0 = Release|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Release|x64.ActiveCfg = Release|Any CPU
{A0E0698A-1161-4DEA-81A9-06D30FB16538}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -422,6 +436,7 @@ Global
{296703A3-67BA-4876-8C1D-ACE13DF901EF} = {F1C83FD9-A498-483E-ADFA-B55D82A14965}
{CCB4D5EF-AC84-449D-AC6E-0A0AD295483A} = {F1C83FD9-A498-483E-ADFA-B55D82A14965}
{4CE6C864-DB4D-4262-A2DD-80BB932F6E8C} = {C86C6DEE-84E1-4E4E-8868-6755D7A8E0E4}
{A0E0698A-1161-4DEA-81A9-06D30FB16538} = {F1C83FD9-A498-483E-ADFA-B55D82A14965}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D3AB83E9-02B4-4FFA-A2D0-637F0B97E626}
Expand Down
2 changes: 1 addition & 1 deletion src/NuGet.Jobs.RegistrationComparer/Normalizers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ private static bool IsPropertyName(string path, string name)
return path == name || path.EndsWith("." + name);
}

private Normalizers(
public Normalizers(
IReadOnlyList<ValueNormalizer> scalarNormalizers,
IReadOnlyList<ShouldNormalizeByPath> unsortedObjects,
IReadOnlyList<ArrayNormalizer> unsortedArrays)
Expand Down
3 changes: 2 additions & 1 deletion test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ Function Run-Tests {
"tests\NuGet.Protocol.Catalog.Tests\bin\$Configuration\NuGet.Protocol.Catalog.Tests.dll", `
"tests\NuGet.Services.AzureSearch.Tests\bin\$Configuration\NuGet.Services.AzureSearch.Tests.dll", `
"tests\NuGet.Services.SearchService.Tests\bin\$Configuration\NuGet.Services.SearchService.Tests.dll", `
"tests\NuGet.Jobs.Catalog2Registration.Tests\bin\$Configuration\NuGet.Jobs.Catalog2Registration.Tests.dll"
"tests\NuGet.Jobs.Catalog2Registration.Tests\bin\$Configuration\NuGet.Jobs.Catalog2Registration.Tests.dll", `
"tests\NuGet.Jobs.RegistrationComparer.Tests\bin\$Configuration\NuGet.Jobs.RegistrationComparer.Tests.dll"

$TestCount = 0

Expand Down
6 changes: 6 additions & 0 deletions tests/NuGet.Jobs.RegistrationComparer.Tests/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>
206 changes: 206 additions & 0 deletions tests/NuGet.Jobs.RegistrationComparer.Tests/JsonComparerFacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// 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 Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
using ValueNormalizer = System.Collections.Generic.KeyValuePair<NuGet.Jobs.RegistrationComparer.ShouldNormalizeByPath, NuGet.Jobs.RegistrationComparer.NormalizeToken>;
using ArrayNormalizer = System.Collections.Generic.KeyValuePair<NuGet.Jobs.RegistrationComparer.ShouldNormalizeByArray, System.Comparison<Newtonsoft.Json.Linq.JToken>>;

namespace NuGet.Jobs.RegistrationComparer
{
public class JsonComparerFacts
{
[Fact]
public void AcceptsSameObject()
{
var a = Json(new { array = new[] { 0, 1, 3 } });
var b = Json(new { array = new[] { 0, 1, 3 } });

Target.Compare(a, b, Context);

Assert.NotSame(a, b);
}

[Fact]
public void DetectsMissingItemInArray()
{
var a = Json(new { array = new[] { 0, 1, 3 } });
var b = Json(new { array = new[] { 0, 1, 2, 3 } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The JSON array item count is different.", ex.Message);
}

[Fact]
public void DetectsDifferentItemsInArray()
{
var a = Json(new { array = new[] { 0, 1, 3 } });
var b = Json(new { array = new[] { 0, 1, 2 } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The value of the JSON scalar is different.", ex.Message);
}

[Fact]
public void DetectsOutOfOrderItemsInArray()
{
var a = Json(new { array = new[] { 0, 2, 1 } });
var b = Json(new { array = new[] { 0, 1, 2 } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The value of the JSON scalar is different.", ex.Message);
}

[Theory]
[InlineData("2", 2)]
[InlineData(true, 1)]
[InlineData("false", false)]
[InlineData("null", null)]
[InlineData(0, null)]
public void DetectsDifferentTypesInArray(object valueA, object valueB)
{
var a = Json(new { array = new object[] { 0, 1, valueA } });
var b = Json(new { array = new object[] { 0, 1, valueB } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The type of the JSON value is different.", ex.Message);
}

[Fact]
public void DetectsDifferentProperties()
{
var a = Json(new { arrayA = new[] { 0, 1, 2 } });
var b = Json(new { arrayB = new[] { 0, 1, 2 } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The JSON object property names are disjoint.", ex.Message);
}

[Fact]
public void DetectsOutOfOrderProperties()
{
var a = Json(new { inner = new { a = "a", b = "b" } });
var b = Json(new { inner = new { b = "b", a = "a" } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The JSON object property names are in a different order.", ex.Message);
}

[Fact]
public void DetectsDifferentCaseOfPropertyNames()
{
var a = Json(new { array = new[] { 0, 1, 2 } });
var b = Json(new { Array = new[] { 0, 1, 2 } });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The JSON object property names are disjoint.", ex.Message);
}

[Fact]
public void DetectsExtraProperty()
{
var a = Json(new { array = new[] { 0, 1, 2 } });
var b = Json(new { array = new[] { 0, 1, 2 }, somethingElse = 2 });

var ex = Assert.Throws<InvalidOperationException>(() => Target.Compare(a, b, Context));

Assert.Contains("The JSON object property names are disjoint.", ex.Message);
}

[Fact]
public void AllowsValueToBeNormalized()
{
var normalizers = new Normalizers(
scalarNormalizers: new List<ValueNormalizer>
{
new ValueNormalizer(
(path) => path == "random",
(token, isLeft, context) => "999"),
},
unsortedObjects: new List<ShouldNormalizeByPath>(),
unsortedArrays: new List<ArrayNormalizer>());
var a = Json(new { array = new[] { 0, 1, 2 }, random = 23 });
var b = Json(new { array = new[] { 0, 1, 2 }, random = 42 });

Target.Compare(a, b, GetContext(normalizers));
}

[Fact]
public void AllowsObjectPropertyOrderToBeIgnored()
{
var normalizers = new Normalizers(
scalarNormalizers: new List<ValueNormalizer>(),
unsortedObjects: new List<ShouldNormalizeByPath>
{
(path) => path == "inner",
},
unsortedArrays: new List<ArrayNormalizer>());
var a = Json(new { inner = new { a = "a", b = "b" } });
var b = Json(new { inner = new { b = "b", a = "a" } });

Target.Compare(a, b, GetContext(normalizers));
}

[Fact]
public void AllowsArrayItemOrderToBeIgnored()
{
var normalizers = new Normalizers(
scalarNormalizers: new List<ValueNormalizer>(),
unsortedObjects: new List<ShouldNormalizeByPath>(),
unsortedArrays: new List<ArrayNormalizer>
{
new ArrayNormalizer(
array => array.Path == "array",
(x, y) => Comparer<JToken>.Default.Compare(x, y)),
});
var a = Json(new { array = new[] { 0, 2, 1 } });
var b = Json(new { array = new[] { 0, 1, 2 } });

Target.Compare(a, b, GetContext(normalizers));
}

public JsonComparerFacts()
{
Context = GetContext();
Target = new JsonComparer();
}

private ComparisonContext GetContext(Normalizers normalizers)
{
return new ComparisonContext(
"NuGet.Versioning",
"https://example/api/a",
"https://example/api/b",
"https://example/api/a/index.json",
"https://example/api/b/index.json",
normalizers);
}

private ComparisonContext GetContext()
{
return GetContext(
new Normalizers(
new List<ValueNormalizer>(),
new List<ShouldNormalizeByPath>(),
new List<ArrayNormalizer>()));
}

public ComparisonContext Context { get; }
public JsonComparer Target { get; }

private JToken Json<T>(T obj)
{
return JsonConvert.DeserializeObject<JToken>(JsonConvert.SerializeObject(obj));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A0E0698A-1161-4DEA-81A9-06D30FB16538}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NuGet.Jobs.RegistrationComparer</RootNamespace>
<AssemblyName>NuGet.Jobs.RegistrationComparer.Tests</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Moq">
<Version>4.10.1</Version>
</PackageReference>
<PackageReference Include="xunit">
<Version>2.4.1</Version>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio">
<Version>2.4.1</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="JsonComparerFacts.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NuGet.Jobs.RegistrationComparer\NuGet.Jobs.RegistrationComparer.csproj">
<Project>{4ce6c864-db4d-4262-a2dd-80bb932f6e8c}</Project>
<Name>NuGet.Jobs.RegistrationComparer</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<SignPath>..\..\build</SignPath>
<SignPath Condition="'$(BUILD_SOURCESDIRECTORY)' != ''">$(BUILD_SOURCESDIRECTORY)\build</SignPath>
<SignPath Condition="'$(NuGetBuildPath)' != ''">$(NuGetBuildPath)</SignPath>
</PropertyGroup>
<Import Project="$(SignPath)\sign.targets" Condition="Exists('$(SignPath)\sign.targets')" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("NuGet.Jobs.RegistrationComparer.Tests")]
[assembly: ComVisible(false)]
[assembly: Guid("a83b83d0-4f95-4e1e-bb46-8c4ce547bd67")]