Skip to content

Commit 2c7f001

Browse files
authored
feat: add API tests (#1212)
Add API tests, that ensure that no accidental changes on the public API are made. All changes have to be accepted by executing the explict `AcceptApiChanges` unit test and are included in the repo/pull request.
1 parent f5db2e2 commit 2c7f001

20 files changed

+8110
-4
lines changed

Directory.Packages.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
<PackageVersion Include="NUnit.Analyzers" Version="4.6.0" />
1919
<PackageVersion Include="NUnit3TestAdapter" Version="5.0.0" />
2020
<PackageVersion Include="Snapshooter.NUnit" Version="1.0.1" />
21+
<PackageVersion Include="PublicApiGenerator" Version="11.4.2"/>
22+
<PackageVersion Include="aweXpect" Version="1.0.0"/>
2123
</ItemGroup>
2224
<ItemGroup>
2325
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.7.115" />

System.IO.Abstractions.sln

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Abstractions.Test
88
EndProject
99
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableIO.System.IO.Abstractions.Benchmarks", "benchmarks\TestableIO.System.IO.Abstractions.Benchmarks\TestableIO.System.IO.Abstractions.Benchmarks.csproj", "{015B3812-E01D-479C-895D-BDDF16E798CA}"
1010
EndProject
11-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{BCEC61BD-4941-41EC-975A-ACEFC7AC1780}"
11+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BCEC61BD-4941-41EC-975A-ACEFC7AC1780}"
1212
EndProject
1313
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableIO.System.IO.Abstractions.Wrappers.Tests", "tests\TestableIO.System.IO.Abstractions.Wrappers.Tests\TestableIO.System.IO.Abstractions.Wrappers.Tests.csproj", "{7105D748-1253-409F-A624-4879412EF3C2}"
1414
EndProject
1515
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableIO.System.IO.Abstractions", "src\TestableIO.System.IO.Abstractions\TestableIO.System.IO.Abstractions.csproj", "{1B8388D2-58A7-47B8-89EC-C5A94A0FEED5}"
1616
EndProject
1717
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableIO.System.IO.Abstractions.Wrappers", "src\TestableIO.System.IO.Abstractions.Wrappers\TestableIO.System.IO.Abstractions.Wrappers.csproj", "{3698BB93-B031-4140-BAEF-D3480A94F531}"
1818
EndProject
19-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{C078E0B6-9747-475F-A999-B9E775DF6643}"
19+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{C078E0B6-9747-475F-A999-B9E775DF6643}"
2020
EndProject
2121
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableIO.System.IO.Abstractions.TestingHelpers", "src\TestableIO.System.IO.Abstractions.TestingHelpers\TestableIO.System.IO.Abstractions.TestingHelpers.csproj", "{DE22AA55-408F-4041-B85D-26D6D6A158A4}"
2222
EndProject
@@ -44,6 +44,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B66A0B3F-6A0
4444
ProjectSection(SolutionItems) = preProject
4545
src\Directory.Build.props = src\Directory.Build.props
4646
EndProjectSection
47+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{10F39E91-97F2-4812-9D2F-79BE18EC6B08}"
48+
EndProject
49+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestableIO.System.IO.Abstractions.Api.Tests", "tests\TestableIO.System.IO.Abstractions.Api.Tests\TestableIO.System.IO.Abstractions.Api.Tests.csproj", "{7DE6AD74-E2B3-498E-90C5-DDF3188F333A}"
4750
EndProject
4851
Global
4952
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -83,20 +86,25 @@ Global
8386
{919888D2-E37D-40E7-8AD0-600F9429316D}.Debug|Any CPU.Build.0 = Debug|Any CPU
8487
{919888D2-E37D-40E7-8AD0-600F9429316D}.Release|Any CPU.ActiveCfg = Release|Any CPU
8588
{919888D2-E37D-40E7-8AD0-600F9429316D}.Release|Any CPU.Build.0 = Release|Any CPU
89+
{7DE6AD74-E2B3-498E-90C5-DDF3188F333A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
90+
{7DE6AD74-E2B3-498E-90C5-DDF3188F333A}.Debug|Any CPU.Build.0 = Debug|Any CPU
91+
{7DE6AD74-E2B3-498E-90C5-DDF3188F333A}.Release|Any CPU.ActiveCfg = Release|Any CPU
92+
{7DE6AD74-E2B3-498E-90C5-DDF3188F333A}.Release|Any CPU.Build.0 = Release|Any CPU
8693
EndGlobalSection
8794
GlobalSection(SolutionProperties) = preSolution
8895
HideSolutionNode = FALSE
8996
EndGlobalSection
9097
GlobalSection(NestedProjects) = preSolution
9198
{B7DA254D-496F-4C50-969C-CF925758E2ED} = {C078E0B6-9747-475F-A999-B9E775DF6643}
9299
{0103D32A-6124-4A1A-AD6C-30EB957F09B0} = {C078E0B6-9747-475F-A999-B9E775DF6643}
93-
{015B3812-E01D-479C-895D-BDDF16E798CA} = {BCEC61BD-4941-41EC-975A-ACEFC7AC1780}
94100
{7105D748-1253-409F-A624-4879412EF3C2} = {BCEC61BD-4941-41EC-975A-ACEFC7AC1780}
95101
{919888D2-E37D-40E7-8AD0-600F9429316D} = {BCEC61BD-4941-41EC-975A-ACEFC7AC1780}
96102
{2BE9161B-A3F3-4511-81DB-DB1DCB6375C9} = {BBF7AD8D-5522-48C0-A906-00CBB72308A0}
97103
{D905E09D-6DC3-4F7C-8E83-82FADAE2C9E5} = {2BE9161B-A3F3-4511-81DB-DB1DCB6375C9}
98104
{1B8388D2-58A7-47B8-89EC-C5A94A0FEED5} = {C078E0B6-9747-475F-A999-B9E775DF6643}
99105
{B66A0B3F-6A00-482E-99E2-27D8DECB075E} = {BBF7AD8D-5522-48C0-A906-00CBB72308A0}
106+
{015B3812-E01D-479C-895D-BDDF16E798CA} = {10F39E91-97F2-4812-9D2F-79BE18EC6B08}
107+
{7DE6AD74-E2B3-498E-90C5-DDF3188F333A} = {BCEC61BD-4941-41EC-975A-ACEFC7AC1780}
100108
EndGlobalSection
101109
GlobalSection(ExtensibilityGlobals) = postSolution
102110
SolutionGuid = {8885C59C-F6A0-4C2F-A3BC-B720E9BD161F}

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<PropertyGroup>
11-
<PublishRepositoryUrl>true</PublishRepositoryUrl>
11+
<RepositoryUrl>https://github.com/TestableIO/System.IO.Abstractions.git</RepositoryUrl>
1212
<IncludeSymbols>true</IncludeSymbols>
1313
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1414
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using aweXpect;
2+
3+
namespace TestableIO.System.IO.Abstractions.Api.Tests;
4+
5+
public sealed class ApiAcceptance
6+
{
7+
/// <summary>
8+
/// Execute this test to update the expected public API to the current API surface.
9+
/// </summary>
10+
[TestCase]
11+
[Explicit]
12+
public async Task AcceptApiChanges()
13+
{
14+
string[] assemblyNames =
15+
[
16+
"TestableIO.System.IO.Abstractions.Wrappers",
17+
"TestableIO.System.IO.Abstractions.TestingHelpers",
18+
];
19+
20+
foreach (string assemblyName in assemblyNames)
21+
{
22+
foreach (string framework in Helper.GetTargetFrameworks())
23+
{
24+
string publicApi = Helper.CreatePublicApi(framework, assemblyName)
25+
.Replace("\n", Environment.NewLine);
26+
Helper.SetExpectedApi(framework, assemblyName, publicApi);
27+
}
28+
}
29+
30+
await Expect.That(assemblyNames).IsNotEmpty();
31+
}
32+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
using aweXpect;
3+
4+
namespace TestableIO.System.IO.Abstractions.Api.Tests;
5+
6+
/// <summary>
7+
/// Whenever a test fails, this means that the public API surface changed.
8+
/// If the change was intentional, execute the <see cref="ApiAcceptance.AcceptApiChanges()" /> test to take over the
9+
/// current public API surface. The changes will become part of the pull request and will be reviewed accordingly.
10+
/// </summary>
11+
public sealed class ApiApprovalTests
12+
{
13+
[TestCaseSource(nameof(TargetFrameworksTheoryData))]
14+
public async Task VerifyPublicApiForWrappers(string framework)
15+
{
16+
const string assemblyName = "TestableIO.System.IO.Abstractions.Wrappers";
17+
18+
var publicApi = Helper.CreatePublicApi(framework, assemblyName);
19+
var expectedApi = Helper.GetExpectedApi(framework, assemblyName);
20+
21+
await Expect.That(publicApi).IsEqualTo(expectedApi);
22+
}
23+
24+
[TestCaseSource(nameof(TargetFrameworksTheoryData))]
25+
public async Task VerifyPublicApiForTestingHelpers(string framework)
26+
{
27+
const string assemblyName = "TestableIO.System.IO.Abstractions.TestingHelpers";
28+
29+
var publicApi = Helper.CreatePublicApi(framework, assemblyName);
30+
var expectedApi = Helper.GetExpectedApi(framework, assemblyName);
31+
32+
await Expect.That(publicApi).IsEqualTo(expectedApi);
33+
}
34+
35+
private static IEnumerable<string> TargetFrameworksTheoryData()
36+
{
37+
List<string> theoryData = new();
38+
foreach (var targetFramework in Helper.GetTargetFrameworks())
39+
{
40+
theoryData.Add(targetFramework);
41+
}
42+
43+
return theoryData;
44+
}
45+
}

0 commit comments

Comments
 (0)