Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Microsoft.SourceLink.Tools source package implementing SourceLinkMap #663

Merged
merged 2 commits into from Oct 27, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions SourceLink.sln
Expand Up @@ -58,7 +58,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.GitWeb
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.GitWeb.UnitTests", "src\SourceLink.GitWeb.UnitTests\Microsoft.SourceLink.GitWeb.UnitTests.csproj", "{50503A43-08C0-493B-B8CC-F368983644C1}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.SourceLink.Tools", "src\SourceLink.Tools\Microsoft.SourceLink.Tools.shproj", "{5DF76CC2-5F0E-45A6-AD56-6BBBCCBC1A78}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.Tools.Package", "src\SourceLink.Tools\Microsoft.SourceLink.Tools.Package.csproj", "{141E6850-B424-47AD-884A-CED362027382}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.Tools.UnitTests", "src\SourceLink.Tools.UnitTests\Microsoft.SourceLink.Tools.UnitTests.csproj", "{99D113A9-24EC-471D-9F74-D2AC2F16220B}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\SourceLink.Tools\Microsoft.SourceLink.Tools.projitems*{5df76cc2-5f0e-45a6-ad56-6bbbccbc1a78}*SharedItemsImports = 13
src\SourceLink.Tools\Microsoft.SourceLink.Tools.projitems*{99d113a9-24ec-471d-9f74-d2ac2f16220b}*SharedItemsImports = 5
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Expand Down Expand Up @@ -148,6 +158,14 @@ Global
{50503A43-08C0-493B-B8CC-F368983644C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50503A43-08C0-493B-B8CC-F368983644C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50503A43-08C0-493B-B8CC-F368983644C1}.Release|Any CPU.Build.0 = Release|Any CPU
{141E6850-B424-47AD-884A-CED362027382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{141E6850-B424-47AD-884A-CED362027382}.Debug|Any CPU.Build.0 = Debug|Any CPU
{141E6850-B424-47AD-884A-CED362027382}.Release|Any CPU.ActiveCfg = Release|Any CPU
{141E6850-B424-47AD-884A-CED362027382}.Release|Any CPU.Build.0 = Release|Any CPU
{99D113A9-24EC-471D-9F74-D2AC2F16220B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99D113A9-24EC-471D-9F74-D2AC2F16220B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99D113A9-24EC-471D-9F74-D2AC2F16220B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99D113A9-24EC-471D-9F74-D2AC2F16220B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
1 change: 1 addition & 0 deletions eng/Versions.props
Expand Up @@ -21,6 +21,7 @@
<MicrosoftDotNetPlatformAbstractionsVersion>2.1.0</MicrosoftDotNetPlatformAbstractionsVersion>
<NuGetVersioningVersion>4.9.2</NuGetVersioningVersion>
<SystemValueTupleVersion>4.5.0</SystemValueTupleVersion>
<SystemTextJsonVersion>4.7.2</SystemTextJsonVersion>
<!-- libgit2 used for integration tests -->
<LibGit2SharpVersion>0.26.0-preview-0070</LibGit2SharpVersion>
</PropertyGroup>
Expand Down
6 changes: 5 additions & 1 deletion src/Directory.Build.targets
Expand Up @@ -17,7 +17,11 @@
<ImplicitlyExpandNETStandardFacades Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">false</ImplicitlyExpandNETStandardFacades>
</PropertyGroup>

<Target Name="_UpdatePackageId" BeforeTargets="$(PackDependsOn)" >
<!--
Workaround for cyclic package reference. PackageId is set to ain invalid value above (in evaluation phase to be picked up by Restore),
then updated to the actual value before Pack target and SourceLink source package generation target.
-->
<Target Name="_UpdatePackageId" BeforeTargets="$(PackDependsOn);InitializeSourceControlInformation" >
<PropertyGroup>
<PackageId>$(_ProjectDefinedPackageId)</PackageId>
<PackageId Condition="'$(PackageId)' == ''">$(AssemblyName)</PackageId>
Expand Down
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TestUtilities\TestUtilities.csproj" />
</ItemGroup>
<Import Project="..\SourceLink.Tools\Microsoft.SourceLink.Tools.projitems" Label="Shared" />
</Project>
194 changes: 194 additions & 0 deletions src/SourceLink.Tools.UnitTests/SourceLinkMapTests.cs
@@ -0,0 +1,194 @@
// Copyright (c) Microsoft. 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;
using System.Text;
using System.Text.Json;
using TestUtilities;
using Xunit;

namespace Microsoft.SourceLink.Tools.UnitTests
{
public class SourceLinkMapTests
{
private IEnumerable<string> Inspect(SourceLinkMap map)
=> map.Entries.Select(e => $"('{e.FilePath.Path}', {(e.FilePath.IsPrefix ? "*" : "")}) -> ('{e.Uri.Prefix}', '{e.Uri.Suffix}')");

[Theory]
[InlineData(@"{}")]
[InlineData(@"{""xxx"":{}}")]
[InlineData(@"{""documents"":{}}")]
public void Empty(string json)
{
var map = SourceLinkMap.Parse(json);
Assert.Empty(map.Entries);
}

[Fact]
public void Extra()
{
var map = SourceLinkMap.Parse(@"
{
""documents"" :
{
""C:\\a*"": ""http://server/1/a*"",
},
""extra"": {}
}");
AssertEx.Equal(new[] { "('C:\\a', *) -> ('http://server/1/a', '')" }, Inspect(map));
}

[Fact]
public void Entries()
{
var map = SourceLinkMap.Parse(@"
{
""documents"" :
{
""C:\\a*"": ""http://server/[*]"",
""C:\\a*"": ""http://a/"",
""C:\\a"": ""http://a/"",
""C:\\a*"": ""http://*a"",
""C:\\b"": ""http://b"",
}
}");
AssertEx.Equal(new[]
{
@"('C:\a', *) -> ('http://server/[', ']')",
@"('C:\a', *) -> ('http://a/', '')",
@"('C:\a', ) -> ('http://a/', '')",
@"('C:\a', *) -> ('http://', 'a')",
@"('C:\b', ) -> ('http://b', '')"
}, Inspect(map));

Assert.True(map.TryGetUrl(@"C:\a", out var url));
Assert.Equal("http://server/[]", url);

Assert.True(map.TryGetUrl(@"C:\a\b\c\d\e", out url));
Assert.Equal("http://server/[/b/c/d/e]", url);

Assert.True(map.TryGetUrl(@"C:\b", out url));
Assert.Equal("http://b", url);

Assert.False(map.TryGetUrl(@"C:\b\c", out _));
}

[Fact]
public void Order1()
{
var map = SourceLinkMap.Parse(@"
{
""documents"" :
{
""C:\\a\\b*"": ""2:*"",
""C:\\a\\b\\c*"": ""1:*"",
""C:\\a*"": ""3:*"",
}
}");
AssertEx.Equal(new[]
{
@"('C:\a\b\c', *) -> ('1:', '')",
@"('C:\a\b', *) -> ('2:', '')",
@"('C:\a', *) -> ('3:', '')"
}, Inspect(map));

string? url;
Assert.True(map.TryGetUrl(@"C:\a\b\c\d\e", out url));
Assert.Equal("1:/d/e", url);

Assert.True(map.TryGetUrl(@"C:\a\b\", out url));
Assert.Equal("2:/", url);

Assert.True(map.TryGetUrl(@"C:\a\x", out url));
Assert.Equal("3:/x", url);

Assert.False(map.TryGetUrl(@"D:\x", out _));
}

[Fact]
public void Order2()
{
var map = SourceLinkMap.Parse(@"
{
""documents"" :
{
""C:\\aaa\\bbb*"": ""1:*"",
""C:\\aaa\\bb*"": ""2:*"",
}
}");
AssertEx.Equal(new[]
{
@"('C:\aaa\bbb', *) -> ('1:', '')",
@"('C:\aaa\bb', *) -> ('2:', '')",
}, Inspect(map));

string? url;
Assert.True(map.TryGetUrl(@"C:\aaa\bbbb", out url));
Assert.Equal("1:b", url);

Assert.True(map.TryGetUrl(@"C:\aaa\bbb", out url));
Assert.Equal("1:", url);

Assert.True(map.TryGetUrl(@"C:\aaa\bb", out url));
Assert.Equal("2:", url);

Assert.False(map.TryGetUrl(@"C:\aaa\b", out _));
}

[Fact]
public void TryGetUrl_Star()
{
var map = SourceLinkMap.Parse(@"{""documents"":{}}");
Assert.False(map.TryGetUrl("path*", out _));
}

[Fact]
public void TryGetUrl_InvalidArgument()
{
var map = SourceLinkMap.Parse(@"{""documents"":{}}");
Assert.Throws<ArgumentNullException>(() => map.TryGetUrl(null!, out _));
}

[Theory]
[InlineData(@"{")]
[InlineData(@"{""documents"" : { ""x"": ""y"" // comments not allowed
} }")]
[InlineData(@"{""documents"" : { 1: ""y"" } }")]
public void BadJson_Key(string json)
{
Assert.ThrowsAny<JsonException>(() => SourceLinkMap.Parse(json));
}

[Theory]
[InlineData(@"1")]
[InlineData(@"{""documents"": 1}")]
[InlineData(@"{""documents"":{""1"": 1}}")]
[InlineData(@"{""documents"":{""1"": null}}")]
[InlineData(@"{""documents"":{""1"": {}}}")]
[InlineData(@"{""documents"":{""1"": []}}")]
public void InvalidJsonTypes(string json)
{
Assert.Throws<InvalidDataException>(() => SourceLinkMap.Parse(json));
}

[Theory]
[InlineData(@"{""documents"":{"""": ""x""}}")]
[InlineData(@"{""documents"":{""1**"": ""x""}}")]
[InlineData(@"{""documents"":{""*1*"": ""x""}}")]
[InlineData(@"{""documents"":{""1*"": ""**x""}}")]
[InlineData(@"{""documents"":{""*1"": ""x*""}}")]
[InlineData(@"{""documents"":{""1"": ""x*""}}")]
public void InvalidWildcards(string json)
{
Assert.Throws<InvalidDataException>(() => SourceLinkMap.Parse(json));
}

[Fact]
public void Parse_InvalidArgument()
{
Assert.Throws<ArgumentNullException>(() => SourceLinkMap.Parse(null!));
}
}
}
24 changes: 24 additions & 0 deletions src/SourceLink.Tools/Microsoft.SourceLink.Tools.Package.csproj
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<DebugType>none</DebugType>
<GenerateDependencyFile>false</GenerateDependencyFile>

<!-- NuGet -->
<IsPackable>true</IsPackable>
<IsSourcePackage>true</IsSourcePackage>
<PackageId>Microsoft.SourceLink.Tools</PackageId>
<IncludeBuildOutput>false</IncludeBuildOutput>
<PackageDescription>
Package containing sources of tools for reading Source Link.
</PackageDescription>
<!-- Remove once https://github.com/NuGet/Home/issues/8583 is fixed -->
<NoWarn>$(NoWarn);NU5128</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
</ItemGroup>
</Project>
14 changes: 14 additions & 0 deletions src/SourceLink.Tools/Microsoft.SourceLink.Tools.projitems
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>5df76cc2-5f0e-45a6-ad56-6bbbccbc1a78</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Microsoft.SourceLink.Tools</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)SourceLinkMap.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions src/SourceLink.Tools/Microsoft.SourceLink.Tools.shproj
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>5df76cc2-5f0e-45a6-ad56-6bbbccbc1a78</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="Microsoft.SourceLink.Tools.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>