Skip to content

Commit

Permalink
Merge pull request #504 from Shane32/apiapprovals
Browse files Browse the repository at this point in the history
Add API approvals to tests
  • Loading branch information
codebude committed Apr 27, 2024
2 parents ffe2461 + 50f40ec commit c9464b8
Show file tree
Hide file tree
Showing 14 changed files with 3,932 additions and 59 deletions.
24 changes: 15 additions & 9 deletions .github/workflows/wf-build-release-ci.yml
Expand Up @@ -20,19 +20,13 @@ jobs:
1.0.x
2.0.x
5.0.x
6.0.x
6.0.x
- name: Setup MSBuild Path
uses: microsoft/setup-msbuild@v1

- name: Setup NuGet
uses: NuGet/setup-nuget@v2

- name: Restore NuGet Packages
run: nuget restore QRCoder.sln
run: dotnet restore

- name: Build library
run: msbuild QRCoder.sln /p:Configuration=Release /p:NoWarn="1182" /p:NoWarn="1701" /nr:false /t:Rebuild
run: dotnet build -c Release --no-restore

- name: Upload artifacts
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -60,28 +54,40 @@ jobs:
6.0.x
- name: Run test .NET 3.5
working-directory: QRCoderTests
run: dotnet test -c Release -f net35 --nologo --no-build # No coverage for NET3.5 because of bug in combination with Coverlet+Stronh naming

- name: Run test .NET 4.52
working-directory: QRCoderTests
run: dotnet test -c Release -f net452 --nologo --no-build # No coverage for NET4.5 because of bug in combination with Coverlet+Strong naming

- name: Run test .NET Core 1.1
working-directory: QRCoderTests
run: dotnet test -c Release -f netcoreapp1.1 --nologo # No coverage for .NETCORE 1.1 because Coverlet doesn't support it https://github.com/coverlet-coverage/coverlet/issues/466

- name: Run test .NET Core 2.0
working-directory: QRCoderTests
run: dotnet test -c Release -f netcoreapp2.0 --nologo /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 5.0
working-directory: QRCoderTests
run: dotnet test -c Release -f net5.0 --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 5.0 Windows
working-directory: QRCoderTests
run: dotnet test -c Release -f net5.0-windows --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 6.0
working-directory: QRCoderTests
run: dotnet test -c Release -f net6.0 --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 6.0 Windows
working-directory: QRCoderTests
run: dotnet test -c Release -f net6.0-windows --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run API approval tests
working-directory: QRCoderApiTests
run: dotnet test -c Release --nologo --no-build

- name: Codecov update netcoreapp2.0
uses: codecov/codecov-action@v2
Expand Down
24 changes: 15 additions & 9 deletions .github/workflows/wf-build-release.yml
Expand Up @@ -21,19 +21,13 @@ jobs:
1.0.x
2.0.x
5.0.x
6.0.x
6.0.x
- name: Setup MSBuild Path
uses: microsoft/setup-msbuild@v1

- name: Setup NuGet
uses: NuGet/setup-nuget@v2

- name: Restore NuGet Packages
run: nuget restore QRCoder.sln
run: dotnet restore

- name: Build library
run: msbuild QRCoder.sln /p:Configuration=Release /p:NoWarn="1182" /p:NoWarn="1701" /nr:false /t:Rebuild
run: dotnet build -c Release --no-restore

- name: Upload artifacts
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -61,28 +55,40 @@ jobs:
6.0.x
- name: Run test .NET 3.5
working-directory: QRCoderTests
run: dotnet test -c Release -f net35 --nologo --no-build # No coverage for NET3.5 because of bug in combination with Coverlet+Stronh naming

- name: Run test .NET 4.52
working-directory: QRCoderTests
run: dotnet test -c Release -f net452 --nologo --no-build # No coverage for NET4.5 because of bug in combination with Coverlet+Strong naming

- name: Run test .NET Core 1.1
working-directory: QRCoderTests
run: dotnet test -c Release -f netcoreapp1.1 --nologo # No coverage for .NETCORE 1.1 because Coverlet doesn't support it https://github.com/coverlet-coverage/coverlet/issues/466

- name: Run test .NET Core 2.0
working-directory: QRCoderTests
run: dotnet test -c Release -f netcoreapp2.0 --nologo /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 5.0
working-directory: QRCoderTests
run: dotnet test -c Release -f net5.0 --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 5.0 Windows
working-directory: QRCoderTests
run: dotnet test -c Release -f net5.0-windows --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 6.0
working-directory: QRCoderTests
run: dotnet test -c Release -f net6.0 --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 6.0 Windows
working-directory: QRCoderTests
run: dotnet test -c Release -f net6.0-windows --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run API approval tests
working-directory: QRCoderApiTests
run: dotnet test -c Release --nologo --no-build

- name: Codecov update netcoreapp2.0
uses: codecov/codecov-action@v2
Expand Down
26 changes: 16 additions & 10 deletions .github/workflows/wf-build-test.yml
Expand Up @@ -20,19 +20,13 @@ jobs:
1.0.x
2.0.x
5.0.x
6.0.x
- name: Setup MSBuild Path
uses: microsoft/setup-msbuild@v1

- name: Setup NuGet
uses: NuGet/setup-nuget@v2

6.0.x
- name: Restore NuGet Packages
run: nuget restore QRCoder.sln
run: dotnet restore

- name: Build library
run: msbuild QRCoder.sln /p:Configuration=Release /p:NoWarn="1182" /p:NoWarn="1701" /nr:false /t:Rebuild
run: dotnet build -c Release --no-restore

- name: Upload artifacts
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -60,29 +54,41 @@ jobs:
6.0.x
- name: Run test .NET 3.5
working-directory: QRCoderTests
run: dotnet test -c Release -f net35 --nologo --no-build # No coverage for NET3.5 because of bug in combination with Coverlet+Stronh naming

- name: Run test .NET 4.52
working-directory: QRCoderTests
run: dotnet test -c Release -f net452 --nologo --no-build # No coverage for NET4.5 because of bug in combination with Coverlet+Strong naming

- name: Run test .NET Core 1.1
working-directory: QRCoderTests
run: dotnet test -c Release -f netcoreapp1.1 --nologo # No coverage for .NETCORE 1.1 because Coverlet doesn't support it https://github.com/coverlet-coverage/coverlet/issues/466

- name: Run test .NET Core 2.0
working-directory: QRCoderTests
run: dotnet test -c Release -f netcoreapp2.0 --nologo /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 5.0
working-directory: QRCoderTests
run: dotnet test -c Release -f net5.0 --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 5.0 Windows
working-directory: QRCoderTests
run: dotnet test -c Release -f net5.0-windows --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 6.0
working-directory: QRCoderTests
run: dotnet test -c Release -f net6.0 --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run test .NET 6.0 Windows
working-directory: QRCoderTests
run: dotnet test -c Release -f net6.0-windows --nologo --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Run API approval tests
working-directory: QRCoderApiTests
run: dotnet test -c Release --nologo --no-build

clean:
needs: [build, test]
if: always()
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -219,3 +219,6 @@ pip-log.txt
*.userprefs

QRCoder/PortabilityAnalysis.html

# Unaccepted approval files
*.received.txt
18 changes: 18 additions & 0 deletions QRCoder.sln
Expand Up @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QRCoderTests", "QRCoderTest
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QRCoder.Xaml", "QRCoder.Xaml\QRCoder.Xaml.csproj", "{A7A7E073-2504-4BA2-A63B-87AC34174789}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QRCoderApiTests", "QRCoderApiTests\QRCoderApiTests.csproj", "{5FACE5F6-53C9-4B89-91D4-162677893574}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -119,6 +121,22 @@ Global
{A7A7E073-2504-4BA2-A63B-87AC34174789}.Release|x64.Build.0 = Release|Any CPU
{A7A7E073-2504-4BA2-A63B-87AC34174789}.Release|x86.ActiveCfg = Release|Any CPU
{A7A7E073-2504-4BA2-A63B-87AC34174789}.Release|x86.Build.0 = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|ARM.ActiveCfg = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|ARM.Build.0 = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|x64.ActiveCfg = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|x64.Build.0 = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|x86.ActiveCfg = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Debug|x86.Build.0 = Debug|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|Any CPU.Build.0 = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|ARM.ActiveCfg = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|ARM.Build.0 = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|x64.ActiveCfg = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|x64.Build.0 = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|x86.ActiveCfg = Release|Any CPU
{5FACE5F6-53C9-4B89-91D4-162677893574}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
117 changes: 117 additions & 0 deletions QRCoderApiTests/ApiApprovalTests.cs
@@ -0,0 +1,117 @@
using PublicApiGenerator;
using Shouldly;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Xunit;

/*********************************************
*
* This file copied from GraphQL.NET on 4/26/2024
* https://github.com/graphql-dotnet/graphql-dotnet/blob/dce3a8d9335eb2ff0674a1e48af01fdd6b942119/src/GraphQL.ApiTests/ApiApprovalTests.cs
*
* Unmodified portions of this file are subject to the following license:
* https://github.com/graphql-dotnet/graphql-dotnet/blob/dce3a8d9335eb2ff0674a1e48af01fdd6b942119/LICENSE.md
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 Joseph T. McBride, Ivan Maximov, Shane Krueger, et al. All rights reserved.
*
* 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.
*
*********************************************/

namespace QRCoderApiTests
{
/// <summary>
/// See more info about API approval tests here <see href="https://github.com/JakeGinnivan/ApiApprover"/>.
/// </summary>
public class ApiApprovalTests
{
[Theory]
[InlineData(typeof(QRCoder.QRCodeData))]
[InlineData(typeof(QRCoder.Xaml.XamlQRCode))]
public void PublicApi(Type type)
{
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string projectName = type.Assembly.GetName().Name!;
string testDir = Path.Combine(baseDir, $"..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..");
string projectDir = Path.Combine(testDir, "..");
string buildDir = Path.Combine(projectDir, projectName, "bin",
#if DEBUG
"Debug");
#else
"Release");
#endif
Debug.Assert(Directory.Exists(buildDir), $"Directory '{buildDir}' doesn't exist");
string csProject = Path.Combine(projectDir, projectName, projectName + ".csproj");
var project = XDocument.Load(csProject);
string[] tfms = project.Descendants("TargetFrameworks").Union(project.Descendants("TargetFramework")).First().Value.Split(";", StringSplitOptions.RemoveEmptyEntries);

// There may be old stuff from earlier builds like net45, netcoreapp3.0, etc. so filter it out
string[] actualTfmDirs = Directory.GetDirectories(buildDir).Where(dir => tfms.Any(tfm => dir.EndsWith(tfm))).ToArray();
Debug.Assert(actualTfmDirs.Length > 0, $"Directory '{buildDir}' doesn't contain subdirectories matching {string.Join(";", tfms)}");

(string tfm, string content)[] publicApi = actualTfmDirs.Select(tfmDir => (new DirectoryInfo(tfmDir).Name.Replace(".", ""), Assembly.LoadFile(Path.Combine(tfmDir, projectName + ".dll")).GeneratePublicApi(new ApiGeneratorOptions
{
IncludeAssemblyAttributes = false,
//AllowNamespacePrefixes = new[] { "Microsoft.Extensions.DependencyInjection" },
ExcludeAttributes = new[] { "System.Diagnostics.DebuggerDisplayAttribute", "System.Diagnostics.CodeAnalysis.AllowNullAttribute" }
}) + Environment.NewLine)).ToArray();

if (publicApi.DistinctBy(item => item.content).Count() == 1)
{
AutoApproveOrFail(publicApi[0].content, "");
}
else
{
foreach (var item in publicApi.ToLookup(item => item.content))
{
AutoApproveOrFail(item.Key, string.Join("+", item.Select(x => x.tfm).OrderBy(x => x)));
}
}

// Approval test should (re)generate approved.txt files locally if needed.
// Approval test should fail on CI.
// https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
void AutoApproveOrFail(string publicApi, string folder)
{
string file = null!;

try
{
publicApi.ShouldMatchApproved(options => options.SubFolder(folder).NoDiff().WithFilenameGenerator((testMethodInfo, discriminator, fileType, fileExtension) => file = $"{type.Assembly.GetName().Name}.{fileType}.{fileExtension}"));
}
catch (ShouldMatchApprovedException) when (Environment.GetEnvironmentVariable("CI") == null)
{
string? received = Path.Combine(testDir, folder, file);
string? approved = received.Replace(".received.txt", ".approved.txt");
if (File.Exists(received) && File.Exists(approved))
{
File.Copy(received, approved, overwrite: true);
File.Delete(received);
}
else
{
throw;
}
}
}
}
}
}
18 changes: 18 additions & 0 deletions QRCoderApiTests/QRCoder.Xaml.approved.txt
@@ -0,0 +1,18 @@
namespace QRCoder.Xaml
{
public class XamlQRCode : QRCoder.AbstractQRCode, System.IDisposable
{
public XamlQRCode() { }
public XamlQRCode(QRCoder.QRCodeData data) { }
public System.Windows.Media.DrawingImage GetGraphic(int pixelsPerModule) { }
public System.Windows.Media.DrawingImage GetGraphic(int pixelsPerModule, bool drawQuietZones) { }
public System.Windows.Media.DrawingImage GetGraphic(System.Windows.Size viewBox, bool drawQuietZones = true) { }
public System.Windows.Media.DrawingImage GetGraphic(int pixelsPerModule, string darkColorHex, string lightColorHex, bool drawQuietZones = true) { }
public System.Windows.Media.DrawingImage GetGraphic(System.Windows.Size viewBox, System.Windows.Media.Brush darkBrush, System.Windows.Media.Brush lightBrush, bool drawQuietZones = true) { }
public double GetUnitsPerModule(System.Windows.Size viewBox, bool drawQuietZones = true) { }
}
public static class XamlQRCodeHelper
{
public static System.Windows.Media.DrawingImage GetQRCode(string plainText, int pixelsPerModule, string darkColorHex, string lightColorHex, QRCoder.QRCodeGenerator.ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, QRCoder.QRCodeGenerator.EciMode eciMode = 0, int requestedVersion = -1, bool drawQuietZones = true) { }
}
}
22 changes: 22 additions & 0 deletions QRCoderApiTests/QRCoderApiTests.csproj
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\QRCoder.Xaml\QRCoder.Xaml.csproj" />
<ProjectReference Include="..\QRCoder\QRCoder.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="PublicApiGenerator" Version="11.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="shouldly" Version="4.0.3" />
</ItemGroup>

</Project>

0 comments on commit c9464b8

Please sign in to comment.