Skip to content

Commit

Permalink
Add api approvals
Browse files Browse the repository at this point in the history
  • Loading branch information
Shane32 committed Apr 26, 2024
1 parent 6ec439e commit 99488f6
Show file tree
Hide file tree
Showing 10 changed files with 3,847 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,6 @@ pip-log.txt
*.userprefs

QRCoder/PortabilityAnalysis.html

# Approval files
*.received.txt
18 changes: 18 additions & 0 deletions QRCoder.sln
Original file line number Diff line number Diff line change
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
1 change: 0 additions & 1 deletion QRCoder/ASCIIQRCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public AsciiQRCode() { }

public AsciiQRCode(QRCodeData data) : base(data) { }


/// <summary>
/// Returns a strings that contains the resulting QR code as textual representation.
/// </summary>
Expand Down
80 changes: 80 additions & 0 deletions QRCoderApiTests/ApiApprovalTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using PublicApiGenerator;
using Shouldly;
using System.Diagnostics;
using System.Reflection;
using System.Xml.Linq;
using Xunit;

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", "Debug");
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
Original file line number Diff line number Diff line change
@@ -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) { }
}
}
23 changes: 23 additions & 0 deletions QRCoderApiTests/QRCoderApiTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<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>
Loading

0 comments on commit 99488f6

Please sign in to comment.