From 4aeef5b9b7fedf4ddee62ca1eb6560979ff70df6 Mon Sep 17 00:00:00 2001 From: Simon Ensslen Date: Tue, 9 Apr 2024 18:55:54 +0200 Subject: [PATCH] Add basic support for license expressions (#45) --- .github/workflows/action.yml | 8 +- .../allowedLicenses.json | 1 + .../ignorePackages.json | 1 + .../overwritePackageInformation.json | 2 + .../projectsToCheck.json | 1 + .../urlToLicenseMapping.json | 2 + NuGetUtility.sln | 30 ++- ...eferenceContainingLicenseExpression.csproj | 12 ++ src/NuGetLicenseCore/NuGetLicenseCore.csproj | 1 + .../LicenseValidator/LicenseValidator.cs | 12 +- .../LicenseValidator/UrlToLicenseMapping.cs | 56 +++--- src/NuGetUtility/NuGetUtility.csproj | 3 +- .../LicenseValidator/LicenseValidatorTest.cs | 187 ++++++++++++++++++ ...cted_License_847892e5f3e913b2.verified.txt | 21 ++ .../NuGetUtility.Test.csproj | 4 +- ...ReferencedPackagesReaderIntegrationTest.cs | 2 +- .../PackageReferenceProject.csproj | 20 +- .../ProjectWithTransitiveNuget.csproj | 20 +- .../ProjectWithTransitiveReferences.csproj | 20 +- .../ProjectWithoutNugetReferences.csproj | 14 +- 20 files changed, 341 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/allowedLicenses.json create mode 100644 .github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/ignorePackages.json create mode 100644 .github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/overwritePackageInformation.json create mode 100644 .github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/projectsToCheck.json create mode 100644 .github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/urlToLicenseMapping.json create mode 100644 integration/ProjectWithReferenceContainingLicenseExpression/ProjectWithReferenceContainingLicenseExpression.csproj create mode 100644 tests/NuGetUtility.Test/LicenseValidator/UrlToLicenseMappingTest.License_Should_Be_Available_And_Match_Expected_License_847892e5f3e913b2.verified.txt diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index a7863408..ed1945ca 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -87,7 +87,7 @@ jobs: strategy: matrix: targetFramework: [net6.0, net7.0, net8.0] - project: [App, Tests] + project: [App, Tests, ProjectWithReferenceContainingLicenseExpression] include: - targetFramework: net6.0 @@ -110,7 +110,7 @@ jobs: dotnet-version: ${{ matrix.dotnetVersion }} - name: restore - run: dotnet restore -p:TargetFramework=${{ matrix.targetFramework }} + run: dotnet restore NuGetUtility.sln - name: build run: dotnet publish ./src/NuGetLicenseCore/NuGetLicenseCore.csproj --configuration Release -o ./release -f ${{ matrix.targetFramework }} --no-restore @@ -131,7 +131,7 @@ jobs: runs-on: windows-latest strategy: matrix: - project: [App, Tests] + project: [App, Tests, ProjectWithReferenceContainingLicenseExpression] steps: - uses: actions/checkout@v4 @@ -195,7 +195,7 @@ jobs: dotnet-version: ${{ matrix.dotnetVersion }} - name: restore - run: dotnet restore -p:TargetFramework=${{ matrix.targetFramework }} + run: dotnet restore NuGetUtility.sln - uses: paulhatch/semantic-version@v5.4.0 id: version diff --git a/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/allowedLicenses.json b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/allowedLicenses.json new file mode 100644 index 00000000..790c6abc --- /dev/null +++ b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/allowedLicenses.json @@ -0,0 +1 @@ +["MIT","Apache-2.0","MS-EULA"] diff --git a/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/ignorePackages.json b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/ignorePackages.json new file mode 100644 index 00000000..6628f6d6 --- /dev/null +++ b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/ignorePackages.json @@ -0,0 +1 @@ +["NETStandard.Library"] diff --git a/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/overwritePackageInformation.json b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/overwritePackageInformation.json new file mode 100644 index 00000000..0d4f101c --- /dev/null +++ b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/overwritePackageInformation.json @@ -0,0 +1,2 @@ +[ +] diff --git a/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/projectsToCheck.json b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/projectsToCheck.json new file mode 100644 index 00000000..3201b624 --- /dev/null +++ b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/projectsToCheck.json @@ -0,0 +1 @@ +["./integration/ProjectWithReferenceContainingLicenseExpression/ProjectWithReferenceContainingLicenseExpression.csproj"] diff --git a/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/urlToLicenseMapping.json b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/urlToLicenseMapping.json new file mode 100644 index 00000000..2c63c085 --- /dev/null +++ b/.github/workflows/assets/ProjectWithReferenceContainingLicenseExpression/urlToLicenseMapping.json @@ -0,0 +1,2 @@ +{ +} diff --git a/NuGetUtility.sln b/NuGetUtility.sln index 910955a0..c49ef5ba 100644 --- a/NuGetUtility.sln +++ b/NuGetUtility.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.32112.339 MinimumVisualStudioVersion = 10.0.40219.1 @@ -31,9 +32,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleCppProject", "tests\targets\SimpleCppProject\SimpleCppProject.vcxproj", "{380FBD90-2CF0-4F83-A58E-EB98CE2EAE15}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGetLicenseCore", "src\NuGetLicenseCore\NuGetLicenseCore.csproj", "{FBA6622A-C9E3-4250-AB79-35F02CAD2419}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGetLicenseCore", "src\NuGetLicenseCore\NuGetLicenseCore.csproj", "{FBA6622A-C9E3-4250-AB79-35F02CAD2419}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGetLicenseFramework", "src\NuGetLicenseFramework\NuGetLicenseFramework.csproj", "{DE079B9C-B6BA-4D53-8B83-03D3CBD4027F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGetLicenseFramework", "src\NuGetLicenseFramework\NuGetLicenseFramework.csproj", "{DE079B9C-B6BA-4D53-8B83-03D3CBD4027F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{FFB2826C-17A3-4C18-8FFE-A34AB51592F7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectWithReferenceContainingLicenseExpression", "integration\ProjectWithReferenceContainingLicenseExpression\ProjectWithReferenceContainingLicenseExpression.csproj", "{01704839-219A-4CE2-93F4-DB3CB8773DCE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -224,6 +229,24 @@ Global {DE079B9C-B6BA-4D53-8B83-03D3CBD4027F}.TestWindows|x64.Build.0 = Debug|Any CPU {DE079B9C-B6BA-4D53-8B83-03D3CBD4027F}.TestWindows|x86.ActiveCfg = Debug|Any CPU {DE079B9C-B6BA-4D53-8B83-03D3CBD4027F}.TestWindows|x86.Build.0 = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Debug|x64.ActiveCfg = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Debug|x64.Build.0 = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Debug|x86.ActiveCfg = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Debug|x86.Build.0 = Debug|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Release|Any CPU.Build.0 = Release|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Release|x64.ActiveCfg = Release|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Release|x64.Build.0 = Release|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Release|x86.ActiveCfg = Release|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.Release|x86.Build.0 = Release|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.TestWindows|Any CPU.ActiveCfg = TestWindows|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.TestWindows|Any CPU.Build.0 = TestWindows|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.TestWindows|x64.ActiveCfg = TestWindows|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.TestWindows|x64.Build.0 = TestWindows|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.TestWindows|x86.ActiveCfg = TestWindows|Any CPU + {01704839-219A-4CE2-93F4-DB3CB8773DCE}.TestWindows|x86.Build.0 = TestWindows|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -240,6 +263,7 @@ Global {380FBD90-2CF0-4F83-A58E-EB98CE2EAE15} = {FA92392F-D895-4D1E-A5ED-E6DC3C08223E} {FBA6622A-C9E3-4250-AB79-35F02CAD2419} = {D2AB2D00-1F48-487D-BFE0-99FDB4E071CC} {DE079B9C-B6BA-4D53-8B83-03D3CBD4027F} = {D2AB2D00-1F48-487D-BFE0-99FDB4E071CC} + {01704839-219A-4CE2-93F4-DB3CB8773DCE} = {FFB2826C-17A3-4C18-8FFE-A34AB51592F7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70887D40-0182-4C32-BFA1-B5A02E405F11} diff --git a/integration/ProjectWithReferenceContainingLicenseExpression/ProjectWithReferenceContainingLicenseExpression.csproj b/integration/ProjectWithReferenceContainingLicenseExpression/ProjectWithReferenceContainingLicenseExpression.csproj new file mode 100644 index 00000000..b00b2ac1 --- /dev/null +++ b/integration/ProjectWithReferenceContainingLicenseExpression/ProjectWithReferenceContainingLicenseExpression.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + Debug;Release;TestWindows + + + + + + + diff --git a/src/NuGetLicenseCore/NuGetLicenseCore.csproj b/src/NuGetLicenseCore/NuGetLicenseCore.csproj index fcacf09c..eb14ac45 100644 --- a/src/NuGetLicenseCore/NuGetLicenseCore.csproj +++ b/src/NuGetLicenseCore/NuGetLicenseCore.csproj @@ -24,6 +24,7 @@ AnyCPU README.md A .net tool to print and validate the licenses of .net code. This tool supports .NET (Core), .NET Standard and .NET Framework projects. + NuGet;License diff --git a/src/NuGetUtility/LicenseValidator/LicenseValidator.cs b/src/NuGetUtility/LicenseValidator/LicenseValidator.cs index c2e57447..467efba0 100644 --- a/src/NuGetUtility/LicenseValidator/LicenseValidator.cs +++ b/src/NuGetUtility/LicenseValidator/LicenseValidator.cs @@ -9,6 +9,7 @@ using NuGetUtility.Wrapper.NuGetWrapper.Packaging; using NuGetUtility.Wrapper.NuGetWrapper.Packaging.Core; using NuGetUtility.Wrapper.NuGetWrapper.Versioning; +using Tethys.SPDX.ExpressionParser; namespace NuGetUtility.LicenseValidator { @@ -126,7 +127,8 @@ private void ValidateLicenseByMetadata(IPackageMetadata info, case LicenseType.Expression: case LicenseType.Overwrite: string licenseId = info.LicenseMetadata!.License; - if (IsLicenseValid(licenseId)) + SpdxExpression? licenseExpression = SpdxExpressionParser.Parse(licenseId, _ => true, _ => true); + if (IsValidLicenseExpression(licenseExpression)) { AddOrUpdateLicense(result, info, @@ -154,6 +156,14 @@ private void ValidateLicenseByMetadata(IPackageMetadata info, } } + private bool IsValidLicenseExpression(SpdxExpression? expression) => expression switch + { + SpdxAndExpression and => IsValidLicenseExpression(and.Left) && IsValidLicenseExpression(and.Right), + SpdxOrExpression or => IsValidLicenseExpression(or.Left) || IsValidLicenseExpression(or.Right), + SpdxWithExpression or SpdxLicenseExpression or SpdxLicenseReference => IsLicenseValid(expression.ToString()), + _ => false, + }; + private async Task ValidateLicenseByUrl(IPackageMetadata info, string context, ConcurrentDictionary result, diff --git a/src/NuGetUtility/LicenseValidator/UrlToLicenseMapping.cs b/src/NuGetUtility/LicenseValidator/UrlToLicenseMapping.cs index 5f88c80a..b9d613fe 100644 --- a/src/NuGetUtility/LicenseValidator/UrlToLicenseMapping.cs +++ b/src/NuGetUtility/LicenseValidator/UrlToLicenseMapping.cs @@ -17,37 +17,39 @@ public static class UrlToLicenseMapping public static IImmutableDictionary Default { get; } = ImmutableDictionary.CreateRange( new[] { - new KeyValuePair( new Uri("http://www.apache.org/licenses/LICENSE-2.0.html"), Apache20 ), - new KeyValuePair( new Uri("http://www.apache.org/licenses/LICENSE-2.0"), Apache20 ), - new KeyValuePair( new Uri("http://aws.amazon.com/apache2.0/"), Apache20 ), - new KeyValuePair( new Uri("https://github.com/owin-contrib/owin-hosting/blob/master/LICENSE.txt"), Apache20 ), - new KeyValuePair( new Uri("https://raw.githubusercontent.com/aspnet/Home/2.0.0/LICENSE.txt"), Apache20 ), - new KeyValuePair( - new Uri("https://github.com/Microsoft/Microsoft.IO.RecyclableMemoryStream/blob/master/LICENSE"), Mit + new KeyValuePair(new Uri("http://www.apache.org/licenses/LICENSE-2.0.html"), Apache20), + new KeyValuePair(new Uri("http://www.apache.org/licenses/LICENSE-2.0"), Apache20), + new KeyValuePair(new Uri("http://aws.amazon.com/apache2.0/"), Apache20), + new KeyValuePair(new Uri("https://github.com/owin-contrib/owin-hosting/blob/master/LICENSE.txt"), Apache20), + new KeyValuePair(new Uri("https://raw.githubusercontent.com/aspnet/Home/2.0.0/LICENSE.txt"), Apache20), + new KeyValuePair( + new Uri("https://github.com/Microsoft/Microsoft.IO.RecyclableMemoryStream/blob/master/LICENSE"), + Mit ), - new KeyValuePair( new Uri("https://github.com/AutoMapper/AutoMapper/blob/master/LICENSE.txt"), Mit ), - new KeyValuePair( new Uri("https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE"), Mit ), - new KeyValuePair( new Uri("https://raw.githubusercontent.com/hey-red/markdownsharp/master/LICENSE"), Mit ), - new KeyValuePair( new Uri("https://raw.github.com/JamesNK/Newtonsoft.Json/master/LICENSE.md"), Mit ), - new KeyValuePair( new Uri("https://licenses.nuget.org/MIT"), Mit ), - new KeyValuePair( new Uri("http://max.mit-license.org/"), Mit ), - new KeyValuePair( new Uri("https://github.com/dotnet/corefx/blob/master/LICENSE.TXT"), Mit ), - new KeyValuePair( new Uri("https://go.microsoft.com/fwlink/?linkid=868514"), Mit ), - new KeyValuePair( new Uri("http://go.microsoft.com/fwlink/?linkid=833178"), Mit ), - new KeyValuePair( new Uri("http://www.gnu.org/licenses/old-licenses/gpl-2.0.html"), Gpl20 ), - new KeyValuePair( new Uri("https://raw.githubusercontent.com/AArnott/Validation/8377954d86/LICENSE.txt"), MsPl ), - new KeyValuePair( new Uri("https://www.microsoft.com/web/webpi/eula/aspnetmvc3update-eula.htm"), MsEula ), - new KeyValuePair( new Uri("http://go.microsoft.com/fwlink/?LinkID=214339"), MsEula ), - new KeyValuePair( new Uri("https://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm"), MsEula ), - new KeyValuePair( new Uri("http://go.microsoft.com/fwlink/?LinkId=329770"), MsEula ), - new KeyValuePair( new Uri("http://go.microsoft.com/fwlink/?LinkId=529443"), MsEula ), - new KeyValuePair( + new KeyValuePair(new Uri("https://github.com/AutoMapper/AutoMapper/blob/master/LICENSE.txt"), Mit), + new KeyValuePair(new Uri("https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE"), Mit), + new KeyValuePair(new Uri("https://raw.githubusercontent.com/hey-red/markdownsharp/master/LICENSE"), Mit), + new KeyValuePair(new Uri("https://raw.github.com/JamesNK/Newtonsoft.Json/master/LICENSE.md"), Mit), + new KeyValuePair(new Uri("https://licenses.nuget.org/MIT"), Mit), + new KeyValuePair(new Uri("http://max.mit-license.org/"), Mit), + new KeyValuePair(new Uri("https://github.com/dotnet/corefx/blob/master/LICENSE.TXT"), Mit), + new KeyValuePair(new Uri("https://go.microsoft.com/fwlink/?linkid=868514"), Mit), + new KeyValuePair(new Uri("http://go.microsoft.com/fwlink/?linkid=833178"), Mit), + new KeyValuePair(new Uri("http://www.gnu.org/licenses/old-licenses/gpl-2.0.html"), Gpl20), + new KeyValuePair(new Uri("https://raw.githubusercontent.com/AArnott/Validation/8377954d86/LICENSE.txt"), MsPl), + new KeyValuePair(new Uri("https://www.microsoft.com/web/webpi/eula/aspnetmvc3update-eula.htm"), MsEula), + new KeyValuePair(new Uri("http://go.microsoft.com/fwlink/?LinkID=214339"), MsEula), + new KeyValuePair(new Uri("https://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm"), MsEula), + new KeyValuePair(new Uri("http://go.microsoft.com/fwlink/?LinkId=329770"), MsEula), + new KeyValuePair(new Uri("http://go.microsoft.com/fwlink/?LinkId=529443"), MsEula), + new KeyValuePair( new Uri("https://www.microsoft.com/web/webpi/eula/dotnet_library_license_non_redistributable.htm"), MsEulaNonRedistributable ), - new KeyValuePair( new Uri("http://go.microsoft.com/fwlink/?LinkId=529444"), MsEulaNonRedistributable ), - new KeyValuePair( new Uri(" http://opensource.org/licenses/mit-license.php"), Mit ), - new KeyValuePair( new Uri("https://raw.githubusercontent.com/bchavez/Bogus/master/LICENSE"), Mit) + new KeyValuePair(new Uri("http://go.microsoft.com/fwlink/?LinkId=529444"), MsEulaNonRedistributable), + new KeyValuePair(new Uri(" http://opensource.org/licenses/mit-license.php"), Mit), + new KeyValuePair(new Uri("https://raw.githubusercontent.com/bchavez/Bogus/master/LICENSE"), Mit), + new KeyValuePair(new Uri("https://github.com/Microsoft/dotnet/blob/master/LICENSE"), Mit) } ); } diff --git a/src/NuGetUtility/NuGetUtility.csproj b/src/NuGetUtility/NuGetUtility.csproj index e45108f7..1680239b 100644 --- a/src/NuGetUtility/NuGetUtility.csproj +++ b/src/NuGetUtility/NuGetUtility.csproj @@ -26,9 +26,10 @@ - + + diff --git a/tests/NuGetUtility.Test/LicenseValidator/LicenseValidatorTest.cs b/tests/NuGetUtility.Test/LicenseValidator/LicenseValidatorTest.cs index 22636dc4..5f5eefc6 100644 --- a/tests/NuGetUtility.Test/LicenseValidator/LicenseValidatorTest.cs +++ b/tests/NuGetUtility.Test/LicenseValidator/LicenseValidatorTest.cs @@ -307,6 +307,68 @@ public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_Give .Using(new LicenseValidationResultValueEqualityComparer())); } + [Test] + [ExtendedAutoData(typeof(NuGetVersionBuilder))] + public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_GiveCorrectValidatedLicenseList_When_Or_Expression( + string packageId, + INuGetVersion packageVersion, + string license1, + string license2) + { + _uut = new NuGetUtility.LicenseValidator.LicenseValidator(_licenseMapping, + Array.Empty(), + _fileDownloader, + _ignoredLicenses); + + string expression = $"{license1} OR {license2}"; + + IPackageMetadata package = SetupPackageWithExpressionLicenseInformation(packageId, packageVersion, expression); + + IEnumerable result = await _uut.Validate(CreateInput(package, _context), _token.Token); + Assert.That(result, + Is.EquivalentTo(new[] + { + new LicenseValidationResult(packageId, + packageVersion, + _projectUrl.ToString(), + expression, + null, + LicenseInformationOrigin.Expression) + }) + .Using(new LicenseValidationResultValueEqualityComparer())); + } + + [Test] + [ExtendedAutoData(typeof(NuGetVersionBuilder))] + public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_GiveCorrectValidatedLicenseList_When_And_Expression( + string packageId, + INuGetVersion packageVersion, + string license1, + string license2) + { + _uut = new NuGetUtility.LicenseValidator.LicenseValidator(_licenseMapping, + Array.Empty(), + _fileDownloader, + _ignoredLicenses); + + string expression = $"{license1} AND {license2}"; + + IPackageMetadata package = SetupPackageWithExpressionLicenseInformation(packageId, packageVersion, expression); + + IEnumerable result = await _uut.Validate(CreateInput(package, _context), _token.Token); + Assert.That(result, + Is.EquivalentTo(new[] + { + new LicenseValidationResult(packageId, + packageVersion, + _projectUrl.ToString(), + expression, + null, + LicenseInformationOrigin.Expression) + }) + .Using(new LicenseValidationResultValueEqualityComparer())); + } + [Test] [ExtendedAutoData(typeof(NuGetVersionBuilder))] public async Task ValidatingLicensesWithOverwriteLicenseInformation_Should_GiveCorrectValidatedLicenseList( @@ -502,6 +564,80 @@ public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_Give .Using(new LicenseValidationResultValueEqualityComparer())); } + [Test] + [ExtendedAutoData(typeof(NuGetVersionBuilder))] + public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_GiveCorrectResult_WithOrExpression_If_NoneAllowed( + string packageId, + INuGetVersion packageVersion, + string[] licenses) + { + string expression = licenses.Length switch + { + 0 => string.Empty, + 1 => licenses[0], + 2 => $"{licenses[0]} OR {licenses[1]}", + _ => licenses.Skip(2).Aggregate($"{licenses[0]} OR {licenses[1]}", (expression, newLicense) => $"{newLicense} OR ({expression})") + }; + + IPackageMetadata package = SetupPackageWithExpressionLicenseInformation(packageId, packageVersion, expression); + + IEnumerable result = await _uut.Validate(CreateInput(package, _context), _token.Token); + Assert.That(result, + Is.EquivalentTo(new[] + { + new LicenseValidationResult(packageId, + packageVersion, + _projectUrl.ToString(), + expression, + null, + LicenseInformationOrigin.Expression, + new List + { + new ValidationError($"License {expression} not found in list of supported licenses", + _context) + }) + }) + .Using(new LicenseValidationResultValueEqualityComparer())); + } + + [Test] + [ExtendedAutoData(typeof(NuGetVersionBuilder))] + public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_GiveCorrectResult_WithAndExpression_If_OneNotAllowed( + string packageId, + INuGetVersion packageVersion, + string unallowedLicense) + { + string[] licenses = _allowedLicenses.Shuffle(135643).Append(unallowedLicense).ToArray(); + + string expression = licenses.Length switch + { + 0 => string.Empty, + 1 => licenses[0], + 2 => $"{licenses[0]} AND {licenses[1]}", + _ => licenses.Skip(2).Aggregate($"{licenses[0]} AND {licenses[1]}", (expression, newLicense) => $"{newLicense} AND ({expression})") + }; + + IPackageMetadata package = SetupPackageWithExpressionLicenseInformation(packageId, packageVersion, expression); + + IEnumerable result = await _uut.Validate(CreateInput(package, _context), _token.Token); + Assert.That(result, + Is.EquivalentTo(new[] + { + new LicenseValidationResult(packageId, + packageVersion, + _projectUrl.ToString(), + expression, + null, + LicenseInformationOrigin.Expression, + new List + { + new ValidationError($"License {expression} not found in list of supported licenses", + _context) + }) + }) + .Using(new LicenseValidationResultValueEqualityComparer())); + } + [Test] [ExtendedAutoData(typeof(NuGetVersionBuilder))] public async Task ValidatingLicensesWithOverwriteLicenseInformation_Should_GiveCorrectResult_If_NotAllowed( @@ -555,6 +691,57 @@ public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_Give .Using(new LicenseValidationResultValueEqualityComparer())); } + [Test] + [ExtendedAutoData(typeof(NuGetVersionBuilder))] + public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_GiveCorrectResult_WithOrExpression_If_OneAllowed( + string packageId, + INuGetVersion packageVersion, + string unallowedLicense) + { + string expression = $"{_allowedLicenses.Shuffle(13563).First()} OR {unallowedLicense}"; + + IPackageMetadata package = SetupPackageWithExpressionLicenseInformation(packageId, packageVersion, expression); + + IEnumerable result = await _uut.Validate(CreateInput(package, _context), _token.Token); + Assert.That(result, + Is.EquivalentTo(new[] + { + new LicenseValidationResult(packageId, + packageVersion, + _projectUrl.ToString(), + expression, + null, + LicenseInformationOrigin.Expression) + }) + .Using(new LicenseValidationResultValueEqualityComparer())); + } + + [Test] + [ExtendedAutoData(typeof(NuGetVersionBuilder))] + public async Task ValidatingLicensesWithExpressionLicenseInformation_Should_GiveCorrectResult_WithAndExpression_If_AllAllowed( + string packageId, + INuGetVersion packageVersion) + { + string[] licenses = _allowedLicenses.Shuffle(135643).Take(2).ToArray(); + + string expression = $"{licenses[0]} AND {licenses[1]}"; + + IPackageMetadata package = SetupPackageWithExpressionLicenseInformation(packageId, packageVersion, expression); + + IEnumerable result = await _uut.Validate(CreateInput(package, _context), _token.Token); + Assert.That(result, + Is.EquivalentTo(new[] + { + new LicenseValidationResult(packageId, + packageVersion, + _projectUrl.ToString(), + expression, + null, + LicenseInformationOrigin.Expression) + }) + .Using(new LicenseValidationResultValueEqualityComparer())); + } + [Test] [ExtendedAutoData(typeof(NuGetVersionBuilder))] public async Task ValidatingLicensesWithOverwriteLicenseInformation_Should_GiveCorrectResult_If_Allowed( diff --git a/tests/NuGetUtility.Test/LicenseValidator/UrlToLicenseMappingTest.License_Should_Be_Available_And_Match_Expected_License_847892e5f3e913b2.verified.txt b/tests/NuGetUtility.Test/LicenseValidator/UrlToLicenseMappingTest.License_Should_Be_Available_And_Match_Expected_License_847892e5f3e913b2.verified.txt new file mode 100644 index 00000000..c477d6b4 --- /dev/null +++ b/tests/NuGetUtility.Test/LicenseValidator/UrlToLicenseMappingTest.License_Should_Be_Available_And_Match_Expected_License_847892e5f3e913b2.verified.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/tests/NuGetUtility.Test/NuGetUtility.Test.csproj b/tests/NuGetUtility.Test/NuGetUtility.Test.csproj index 4ac9c338..6ef94315 100644 --- a/tests/NuGetUtility.Test/NuGetUtility.Test.csproj +++ b/tests/NuGetUtility.Test/NuGetUtility.Test.csproj @@ -20,13 +20,13 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs b/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs index bd9e21df..0e4be0d3 100644 --- a/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs +++ b/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs @@ -62,7 +62,7 @@ public void GetInstalledPackagesShould_ReturnTransitiveNuGet() } [Test] - public void GetInstalledPackagesShould_ReturnEmptyEnumerableForProjectsWithoutPackages() + public void GetInstalledPackagesShould_ReturnEmptyEnumerable_For_ProjectsWithoutPackages() { string path = Path.GetFullPath( "../../../../targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj"); diff --git a/tests/targets/PackageReferenceProject/PackageReferenceProject.csproj b/tests/targets/PackageReferenceProject/PackageReferenceProject.csproj index a491bb3c..98c05136 100644 --- a/tests/targets/PackageReferenceProject/PackageReferenceProject.csproj +++ b/tests/targets/PackageReferenceProject/PackageReferenceProject.csproj @@ -1,15 +1,15 @@ - - net6.0 - enable - enable - Debug;Release;TestWindows - AnyCPU - + + net8.0 + enable + enable + Debug;Release;TestWindows + AnyCPU + - - - + + + diff --git a/tests/targets/ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj b/tests/targets/ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj index ea408f22..1a50e697 100644 --- a/tests/targets/ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj +++ b/tests/targets/ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj @@ -1,15 +1,15 @@ - - net6.0 - enable - enable - Debug;Release;TestWindows - AnyCPU - + + net8.0 + enable + enable + Debug;Release;TestWindows + AnyCPU + - - - + + + diff --git a/tests/targets/ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj b/tests/targets/ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj index 07c5d304..362e3647 100644 --- a/tests/targets/ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj +++ b/tests/targets/ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj @@ -1,15 +1,15 @@ - - net6.0 - enable - enable - Debug;Release;TestWindows - AnyCPU - + + net8.0 + enable + enable + Debug;Release;TestWindows + AnyCPU + - - - + + + diff --git a/tests/targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj b/tests/targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj index c1319926..d04a946b 100644 --- a/tests/targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj +++ b/tests/targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj @@ -1,11 +1,11 @@ - - net6.0 - enable - enable - Debug;Release;TestWindows - AnyCPU - + + net8.0 + enable + enable + Debug;Release;TestWindows + AnyCPU +