Skip to content

Commit

Permalink
chore: simplify integration tests versioning (#693)
Browse files Browse the repository at this point in the history
  • Loading branch information
latonz authored Aug 28, 2023
1 parent 0084deb commit f89e77a
Show file tree
Hide file tree
Showing 73 changed files with 194 additions and 158 deletions.
10 changes: 10 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
charset = utf-8

# Generated code
[*{_AssemblyInfo.cs,.notsupported.cs,AsmOffsets.cs}]
Expand Down Expand Up @@ -210,3 +211,12 @@ indent_size = 2
# markdown
[*.{md,mdx}]
indent_size = unset

# Verify settings
[*.{received,verified}.*]
end_of_line = lf
indent_size = unset
indent_style = unset
insert_final_newline = false
tab_width = unset
trim_trailing_whitespace = false
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.verified.txt text eol=lf working-tree-encoding=UTF-8
*.verified.json text eol=lf working-tree-encoding=UTF-8
*.verified.cs text eol=lf working-tree-encoding=UTF-8
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ jobs:
- uses: actions/[email protected]
with:
dotnet-version: ${{ matrix.dotnet }}
- run: dotnet --list-sdks
- uses: actions/download-artifact@v3
with:
name: mapperly-nupkg
Expand Down Expand Up @@ -113,6 +114,7 @@ jobs:
- uses: actions/checkout@v3
# delete global.json since we want to use custom versions here
- run: rm global.json
- run: dotnet --list-sdks
- uses: actions/download-artifact@v3
with:
name: mapperly-nupkg
Expand Down
9 changes: 5 additions & 4 deletions docs/docs/contributing/common-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ To support a new roslyn version via multi targeting follow these steps (see also
2. Create a new file `Riok.Mapperly.Roslyn$(Version).props` in `src/Riok.Mapperly` similar to the existing ones
and define constants and include dependencies as needed.
3. Update the default `ROSLYN_VERSION` in `src/Riok.Mapperly/Riok.Mapperly.csproj`.
4. Update the `Microsoft.CodeAnalysis.CSharp` dependency version in `test/Riok.Mapperly.Tests/Riok.Mapperly.Tests.csproj`.
4. Update the `Microsoft.CodeAnalysis.CSharp` dependency version.
5. Adjust the .NET version matrix of the `integration-test` GitHub Actions job (defined in `.github/workflows/test.yml`)
to include a dotnet version which is based on the added Roslyn version.
6. Adjust the .NET version in the `global.json` file as needed.
7. If generated code changes based on the new Roslyn version,
introduce a new `roslynVersionName` in `Riok.Mapperly.IntegrationTests.BaseMapperTest.GetRoslynVersion()` and generate the new snapshots.
8. Adjust the documentation as needed.
7. Add the new version in `Riok.Mapperly.IntegrationTests.Helpers.Versions` and `Riok.Mapperly.IntegrationTests.BaseMapperTest.GetCurrentVersion`.
8. If generated code changes based on the new Roslyn version,
adjust the `VersionedSnapshotAttribute`s as needed.
9. Adjust the documentation as needed.

## Mapping syntax

Expand Down
10 changes: 9 additions & 1 deletion docs/docs/contributing/tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ These tests run locally by referencing the source generator as an analyzer.
In the CI pipeline, the integration tests reference the built NuGet package and
are run on several supported target frameworks (including .NET 7.0 but also .NET Framework).

Snapshots of the generated code are stored per Roslyn version.
If the content of the snapshot is different depending on the target framework used,
`[VersionedSnapshot(...)]` can be applied on a test class or method.
The version of each version,
which produces a changed snapshot content should be passed to the `VersionedSnapshotAttribute`.
Eg.
if a snapshots content is different for .NET 6.0, .NET 7.0 and .NET Framework 4.8 but .NET 8.0 is the same as .NET 7.0,
`[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]` can be applied.
The resulting snapshot is then stored three times:
in `default` for .NET Framework 4.8, in `NET6_0` for .NET 6.0 and in `NET7_0` for .NET 7.0 and later.
You may need to manually update older versions.
The received snapshots of the tests are saved in the GitHub Actions as artifacts
and can be downloaded.
Expand Down
55 changes: 49 additions & 6 deletions test/Riok.Mapperly.IntegrationTests/BaseMapperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Riok.Mapperly.IntegrationTests.Dto;
using Riok.Mapperly.IntegrationTests.Helpers;
using Riok.Mapperly.IntegrationTests.Models;
using VerifyTests;
using VerifyXunit;
Expand All @@ -30,7 +33,11 @@ static BaseMapperTest()

Verifier.DerivePathInfo(
(file, _, type, method) =>
new PathInfo(Path.Combine(Path.GetDirectoryName(file)!, "_snapshots", GetPlatformVersion()), type.Name, method.Name)
new PathInfo(
Path.Combine(Path.GetDirectoryName(file)!, "_snapshots"),
type.Name,
method.Name + GetSnapshotVersionSuffix(type, method)
)
);
}

Expand Down Expand Up @@ -120,14 +127,50 @@ public static TestObject NewTestObj()
};
}

private static string GetPlatformVersion()
/// <summary>
/// Gets the version of the snapshot.
/// If the test is not a <see cref="VersionedSnapshotAttribute"/>, empty string is returned.
/// Otherwise either the current version, or the latest version of the <see cref="VersionedSnapshotAttribute"/> prefixed with a _ is returned.
/// </summary>
/// <param name="type">The type of the test method.</param>
/// <param name="method">The test method.</param>
/// <returns>Either an empty string or the name of the version.</returns>
private static string GetSnapshotVersionSuffix(Type type, MethodInfo method)
{
var versionedSnapshot =
method.GetCustomAttribute<VersionedSnapshotAttribute>() ?? type.GetCustomAttribute<VersionedSnapshotAttribute>();
if (versionedSnapshot == null)
return string.Empty;

var currentVersion = GetCurrentVersion();
if (versionedSnapshot.VersionsWithChanges.HasFlag(currentVersion))
return "_" + currentVersion;

var supportedVersions = Enum.GetValues(typeof(Versions))
.Cast<Versions>()
.Where(x => x < currentVersion)
.OrderByDescending(x => x);
foreach (var supportedVersion in supportedVersions)
{
if (versionedSnapshot.VersionsWithChanges.HasFlag(supportedVersion))
return "_" + supportedVersion;
}

return string.Empty;
}

private static Versions GetCurrentVersion()
{
#if NET48_OR_GREATER
return "NET_48";
#if NET8_0_OR_GREATER
return Versions.NET8_0;
#elif NET7_0_OR_GREATER
return "Roslyn_4_5";
return Versions.NET7_0;
#elif NET6_0_OR_GREATER
return Versions.NET6_0;
#elif NET48_OR_GREATER
return Versions.NETFRAMEWORK4_8;
#else
return "Roslyn_4_4_OR_LOWER";
throw new InvalidOperationException("Target framework is not supported");
#endif
}
}
Expand Down
3 changes: 3 additions & 0 deletions test/Riok.Mapperly.IntegrationTests/DeepCloningMapperTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using FluentAssertions;
using Riok.Mapperly.IntegrationTests.Helpers;
using Riok.Mapperly.IntegrationTests.Mapper;
using Riok.Mapperly.IntegrationTests.Models;
using VerifyXunit;
Expand All @@ -11,13 +12,15 @@ namespace Riok.Mapperly.IntegrationTests
public class DeepCloningMapperTest : BaseMapperTest
{
[Fact]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public Task SnapshotGeneratedSource()
{
var path = GetGeneratedMapperFilePath(nameof(DeepCloningMapper));
return Verifier.VerifyFile(path);
}

[Fact]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public Task RunMappingShouldWork()
{
var model = NewTestObj();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;

namespace Riok.Mapperly.IntegrationTests.Helpers
{
/// <summary>
/// Uses different paths for snapshots of each version with expected changes.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class VersionedSnapshotAttribute : Attribute
{
/// <summary>
/// Uses different paths for snapshots of each version with expected changes.
/// </summary>
/// <param name="versionsWithChanges">The versions which result in different snapshot content than the previous version.</param>
public VersionedSnapshotAttribute(Versions versionsWithChanges)
{
VersionsWithChanges = versionsWithChanges;
}

public Versions VersionsWithChanges { get; }
}
}
12 changes: 12 additions & 0 deletions test/Riok.Mapperly.IntegrationTests/Helpers/Versions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Riok.Mapperly.IntegrationTests.Helpers
{
[Flags]
public enum Versions
{
NETFRAMEWORK4_8 = 1 << 0,
NET6_0 = 1 << 1,
NET7_0 = 1 << 2,
}
}
2 changes: 2 additions & 0 deletions test/Riok.Mapperly.IntegrationTests/MapperTest.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System.Threading.Tasks;
using Riok.Mapperly.IntegrationTests.Helpers;
using Riok.Mapperly.IntegrationTests.Mapper;
using VerifyXunit;
using Xunit;

namespace Riok.Mapperly.IntegrationTests
{
[UsesVerify]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public class MapperTest : BaseMapperTest
{
[Fact]
Expand Down
32 changes: 24 additions & 8 deletions test/Riok.Mapperly.IntegrationTests/ProjectionMapperTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Riok.Mapperly.IntegrationTests.Helpers;
using Riok.Mapperly.IntegrationTests.Mapper;
using Riok.Mapperly.IntegrationTests.Models;
using VerifyXunit;
Expand All @@ -16,6 +17,7 @@ namespace Riok.Mapperly.IntegrationTests
public class ProjectionMapperTest : BaseMapperTest
{
[Fact]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public Task SnapshotGeneratedSource()
{
var path = GetGeneratedMapperFilePath(nameof(ProjectionMapper));
Expand All @@ -26,26 +28,40 @@ public Task SnapshotGeneratedSource()
[Fact]
public Task ProjectionShouldTranslateToQuery()
{
return RunWithDatabase(async ctx =>
return RunWithDatabase(ctx =>
{
var query = ctx.Objects.ProjectToDto();
await Verifier.Verify(query.ToQueryString(), "sql").UseTextForParameters("query");
return Verifier.Verify(query.ToQueryString(), "sql");
});
}

var objects = await query.ToListAsync();
await Verifier.Verify(objects).UseTextForParameters("result");
[Fact]
public Task ProjectionShouldTranslateToResult()
{
return RunWithDatabase(async ctx =>
{
var objects = await ctx.Objects.ProjectToDto().ToListAsync();
await Verifier.Verify(objects);
});
}

[Fact]
public Task DerivedTypesProjectionShouldTranslateToQuery()
{
return RunWithDatabase(async ctx =>
return RunWithDatabase(ctx =>
{
var query = ctx.BaseTypeObjects.OrderBy(x => x.BaseValue).ProjectToDto();
await Verifier.Verify(query.ToQueryString(), "sql").UseTextForParameters("query");
return Verifier.Verify(query.ToQueryString(), "sql");
});
}

var objects = await query.ToListAsync();
await Verifier.Verify(objects).UseTextForParameters("result");
[Fact]
public Task DerivedTypesProjectionShouldTranslateToResult()
{
return RunWithDatabase(async ctx =>
{
var objects = await ctx.BaseTypeObjects.OrderBy(x => x.BaseValue).ProjectToDto().ToListAsync();
await Verifier.Verify(objects);
});
}

Expand Down
4 changes: 4 additions & 0 deletions test/Riok.Mapperly.IntegrationTests/StaticMapperTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using FluentAssertions;
using Riok.Mapperly.IntegrationTests.Dto;
using Riok.Mapperly.IntegrationTests.Helpers;
using Riok.Mapperly.IntegrationTests.Mapper;
using Riok.Mapperly.IntegrationTests.Models;
using VerifyXunit;
Expand All @@ -12,13 +13,15 @@ namespace Riok.Mapperly.IntegrationTests
public class StaticMapperTest : BaseMapperTest
{
[Fact]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public Task SnapshotGeneratedSource()
{
var path = GetGeneratedMapperFilePath(nameof(StaticTestMapper));
return Verifier.VerifyFile(path);
}

[Fact]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public Task RunMappingShouldWork()
{
var model = NewTestObj();
Expand All @@ -27,6 +30,7 @@ public Task RunMappingShouldWork()
}

[Fact]
[VersionedSnapshot(Versions.NET6_0 | Versions.NET7_0)]
public Task RunExtensionMappingShouldWork()
{
var model = NewTestObj();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,4 @@
},
DateTimeValueTargetDateOnly: 2020-01-03 15:10:05 Utc,
DateTimeValueTargetTimeOnly: 2020-01-03 15:10:05 Utc
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,4 @@
},
DateTimeValueTargetDateOnly: 2020-01-03 15:10:05 Utc,
DateTimeValueTargetTimeOnly: 2020-01-03 15:10:05 Utc
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,4 @@
},
DateTimeValueTargetDateOnly: 2020-01-03 15:10:05 Utc,
DateTimeValueTargetTimeOnly: 2020-01-03 15:10:05 Utc
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,4 @@ private static (string A, string) MapToValueTuple((string A, string) source)
return target;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,4 @@
},
DateTimeValueTargetDateOnly: 2020-01-03,
DateTimeValueTargetTimeOnly: 3:10 PM
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,4 @@
},
DateTimeValueTargetDateOnly: 2020-01-03,
DateTimeValueTargetTimeOnly: 3:10 PM
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,4 @@
},
DateTimeValueTargetDateOnly: 2020-01-03,
DateTimeValueTargetTimeOnly: 3:10 PM
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -492,4 +492,4 @@ private string MapToString1(global::Riok.Mapperly.IntegrationTests.Dto.TestEnumD
return target;
}
}
}
}
Loading

0 comments on commit f89e77a

Please sign in to comment.