Skip to content

Commit

Permalink
chore: replace PublicApiAnalyzer with snapshot test (#1497)
Browse files Browse the repository at this point in the history
Replaces the PublicApiAnalyzer with a snapshot test.
This simplifies the handling and detection of public api changes.
There is no need to keep separate files for unshipped and shipped apis,
no need to move generated api changes from one file to another,
and regular c# syntax is used (including syntax highlighting of editors).
  • Loading branch information
latonz authored Sep 29, 2024
1 parent 35fbd7c commit 6cf2df6
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 213 deletions.
8 changes: 4 additions & 4 deletions docs/docs/contributing/common-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Step by step guides for common tasks one may encounter when contrib

# Common tasks

This page provides to-do lists for some common tasks one may encounter while contributing to Mapperly.
This page provides todo lists for some common tasks one may encounter while contributing to Mapperly.

## New diagnostic

Expand All @@ -25,9 +25,9 @@ as it is generated automatically on the basis of the `AnalyzerReleases.Shipped.m

## New public API

If new public API surface is introduced in `Riok.Mapperly.Abstractions`,
add the new API to the `PublicAPI.Shipped.txt` file directly.
Mapperly does not use the `PublicAPI.Unshipped.txt` file.
If new public API surface is introduced in `Riok.Mapperly.Abstractions` or existing API surface is modified,
the `PublicApiTest` snapshot test needs to be updated.
See also [VerifyTests](./tests.md#verifytests).

## Add support for a new roslyn version

Expand Down
204 changes: 0 additions & 204 deletions src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion src/Riok.Mapperly.Abstractions/PublicAPI.Unshipped.txt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,4 @@
<ItemGroup>
<Using Include="Riok.Mapperly.Abstractions" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>
</Project>
17 changes: 17 additions & 0 deletions test/Riok.Mapperly.Abstractions.Tests/ModuleInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Runtime.CompilerServices;
using VerifyTests.DiffPlex;

namespace Riok.Mapperly.Abstractions.Tests;

public static class ModuleInitializer
{
// ModuleInitializer should only be used in apps
#pragma warning disable CA2255
[ModuleInitializer]
#pragma warning restore CA2255
public static void Init()
{
DerivePathInfo((file, _, type, method) => new(Path.Join(Path.GetDirectoryName(file), "_snapshots"), type.Name, method.Name));
VerifyDiffPlex.Initialize(OutputType.Compact);
}
}
14 changes: 14 additions & 0 deletions test/Riok.Mapperly.Abstractions.Tests/PublicApiTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using PublicApiGenerator;

namespace Riok.Mapperly.Abstractions.Tests;

public class PublicApiTest
{
[Fact]
public Task PublicApiHasNotChanged()
{
var assembly = typeof(MapperAttribute).Assembly;
var api = assembly.GeneratePublicApi();
return Verify(api, "cs");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<ItemGroup>
<PackageReference Include="NetArchTest.Rules" Version="1.3.2" />
<PackageReference Include="PublicApiGenerator" Version="11.1.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
[assembly: System.Runtime.Versioning.TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")]
namespace Riok.Mapperly.Abstractions
{
public enum EnumMappingStrategy
{
ByValue = 0,
ByName = 1,
ByValueCheckDefined = 2,
}
public enum EnumNamingStrategy
{
MemberName = 0,
CamelCase = 1,
PascalCase = 2,
SnakeCase = 3,
UpperSnakeCase = 4,
KebabCase = 5,
UpperKebabCase = 6,
ComponentModelDescriptionAttribute = 7,
SerializationEnumMemberAttribute = 8,
}
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class FormatProviderAttribute : System.Attribute
{
public FormatProviderAttribute() { }
public bool Default { get; set; }
}
[System.Flags]
public enum IgnoreObsoleteMembersStrategy
{
None = 0,
Both = -1,
Source = 1,
Target = 2,
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapDerivedTypeAttribute : System.Attribute
{
public MapDerivedTypeAttribute(System.Type sourceType, System.Type targetType) { }
public System.Type SourceType { get; }
public System.Type TargetType { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapDerivedTypeAttribute<TSource, TTarget> : System.Attribute
{
public MapDerivedTypeAttribute() { }
}
[System.AttributeUsage(System.AttributeTargets.Method)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapEnumAttribute : System.Attribute
{
public MapEnumAttribute(Riok.Mapperly.Abstractions.EnumMappingStrategy strategy) { }
public object? FallbackValue { get; set; }
public bool IgnoreCase { get; set; }
public Riok.Mapperly.Abstractions.EnumNamingStrategy NamingStrategy { get; set; }
public Riok.Mapperly.Abstractions.EnumMappingStrategy Strategy { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapEnumValueAttribute : System.Attribute
{
public MapEnumValueAttribute(object source, object target) { }
public object Source { get; }
public object Target { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapNestedPropertiesAttribute : System.Attribute
{
public MapNestedPropertiesAttribute(string source) { }
public MapNestedPropertiesAttribute(string[] source) { }
public System.Collections.Generic.IReadOnlyCollection<string> Source { get; }
public string SourceFullName { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapPropertyAttribute : System.Attribute
{
public MapPropertyAttribute(string source, string target) { }
public MapPropertyAttribute(string[] source, string target) { }
public MapPropertyAttribute(string source, string[] target) { }
[System.Obsolete("Use MapPropertyAttribute(string[], string) or MapPropertyAttribute(string, string" +
"[]) instead.")]
public MapPropertyAttribute(string[] source, string[] target) { }
public string? FormatProvider { get; set; }
public System.Collections.Generic.IReadOnlyCollection<string> Source { get; }
public string SourceFullName { get; }
public string? StringFormat { get; set; }
public System.Collections.Generic.IReadOnlyCollection<string> Target { get; }
public string TargetFullName { get; }
public string? Use { get; set; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapPropertyFromSourceAttribute : System.Attribute
{
public MapPropertyFromSourceAttribute(string target) { }
public MapPropertyFromSourceAttribute(string[] target) { }
public string? FormatProvider { get; set; }
public string? StringFormat { get; set; }
public System.Collections.Generic.IReadOnlyCollection<string> Target { get; }
public string TargetFullName { get; }
public string? Use { get; set; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapValueAttribute : System.Attribute
{
public MapValueAttribute(string target) { }
public MapValueAttribute(string[] target) { }
public MapValueAttribute(string target, object? value) { }
public MapValueAttribute(string[] target, object? value) { }
public System.Collections.Generic.IReadOnlyCollection<string> Target { get; }
public string TargetFullName { get; }
public string? Use { get; set; }
public object? Value { get; }
}
[System.AttributeUsage(System.AttributeTargets.Class)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public class MapperAttribute : System.Attribute
{
public MapperAttribute() { }
public bool AllowNullPropertyAssignment { get; set; }
public bool AutoUserMappings { get; set; }
public Riok.Mapperly.Abstractions.MappingConversionType EnabledConversions { get; set; }
public bool EnumMappingIgnoreCase { get; set; }
public Riok.Mapperly.Abstractions.EnumMappingStrategy EnumMappingStrategy { get; set; }
public Riok.Mapperly.Abstractions.EnumNamingStrategy EnumNamingStrategy { get; set; }
public Riok.Mapperly.Abstractions.IgnoreObsoleteMembersStrategy IgnoreObsoleteMembersStrategy { get; set; }
public Riok.Mapperly.Abstractions.MemberVisibility IncludedConstructors { get; set; }
public Riok.Mapperly.Abstractions.MemberVisibility IncludedMembers { get; set; }
public bool PreferParameterlessConstructors { get; set; }
public Riok.Mapperly.Abstractions.PropertyNameMappingStrategy PropertyNameMappingStrategy { get; set; }
public Riok.Mapperly.Abstractions.RequiredMappingStrategy RequiredMappingStrategy { get; set; }
public bool ThrowOnMappingNullMismatch { get; set; }
public bool ThrowOnPropertyMappingNullMismatch { get; set; }
public bool UseDeepCloning { get; set; }
public bool UseReferenceHandling { get; set; }
}
[System.AttributeUsage(System.AttributeTargets.Constructor)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperConstructorAttribute : System.Attribute
{
public MapperConstructorAttribute() { }
}
[System.AttributeUsage(System.AttributeTargets.Assembly)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperDefaultsAttribute : Riok.Mapperly.Abstractions.MapperAttribute
{
public MapperDefaultsAttribute() { }
}
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperIgnoreAttribute : System.Attribute
{
public MapperIgnoreAttribute() { }
}
[System.AttributeUsage(System.AttributeTargets.Method)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperIgnoreObsoleteMembersAttribute : System.Attribute
{
public MapperIgnoreObsoleteMembersAttribute(Riok.Mapperly.Abstractions.IgnoreObsoleteMembersStrategy ignoreObsoleteStrategy = -1) { }
public Riok.Mapperly.Abstractions.IgnoreObsoleteMembersStrategy IgnoreObsoleteStrategy { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperIgnoreSourceAttribute : System.Attribute
{
public MapperIgnoreSourceAttribute(string source) { }
public string Source { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperIgnoreSourceValueAttribute : System.Attribute
{
public MapperIgnoreSourceValueAttribute(object source) { }
public System.Enum? SourceValue { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperIgnoreTargetAttribute : System.Attribute
{
public MapperIgnoreTargetAttribute(string target) { }
public string Target { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperIgnoreTargetValueAttribute : System.Attribute
{
public MapperIgnoreTargetValueAttribute(object target) { }
public System.Enum? TargetValue { get; }
}
[System.AttributeUsage(System.AttributeTargets.Method)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MapperRequiredMappingAttribute : System.Attribute
{
public MapperRequiredMappingAttribute(Riok.Mapperly.Abstractions.RequiredMappingStrategy requiredMappingStrategy) { }
public Riok.Mapperly.Abstractions.RequiredMappingStrategy RequiredMappingStrategy { get; }
}
[System.Flags]
public enum MappingConversionType
{
None = 0,
Constructor = 1,
ImplicitCast = 2,
ExplicitCast = 4,
ParseMethod = 8,
ToStringMethod = 16,
StringToEnum = 32,
EnumToString = 64,
EnumToEnum = 128,
DateTimeToDateOnly = 256,
DateTimeToTimeOnly = 512,
Queryable = 1024,
Enumerable = 2048,
Dictionary = 4096,
Span = 8192,
Memory = 16384,
Tuple = 32768,
EnumUnderlyingType = 65536,
All = -1,
}
[System.AttributeUsage(System.AttributeTargets.Parameter)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MappingTargetAttribute : System.Attribute
{
public MappingTargetAttribute() { }
}
[System.Flags]
public enum MemberVisibility
{
AllAccessible = 31,
All = 30,
Accessible = 1,
Public = 2,
Internal = 4,
Protected = 8,
Private = 16,
}
[System.AttributeUsage(System.AttributeTargets.Method)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class ObjectFactoryAttribute : System.Attribute
{
public ObjectFactoryAttribute() { }
}
public enum PropertyNameMappingStrategy
{
CaseSensitive = 0,
CaseInsensitive = 1,
}
[System.Flags]
public enum RequiredMappingStrategy
{
None = 0,
Both = -1,
Source = 1,
Target = 2,
}
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class UseMapperAttribute : System.Attribute
{
public UseMapperAttribute() { }
}
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class UseStaticMapperAttribute : System.Attribute
{
public UseStaticMapperAttribute(System.Type mapperType) { }
}
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=true)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class UseStaticMapperAttribute<T> : System.Attribute
{
public UseStaticMapperAttribute() { }
}
[System.AttributeUsage(System.AttributeTargets.Method)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class UserMappingAttribute : System.Attribute
{
public UserMappingAttribute() { }
public bool Default { get; set; }
public bool Ignore { get; set; }
}
}
namespace Riok.Mapperly.Abstractions.ReferenceHandling
{
public interface IReferenceHandler
{
void SetReference<TSource, TTarget>(TSource source, TTarget target)
where TSource : notnull
where TTarget : notnull;
bool TryGetReference<TSource, TTarget>(TSource source, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out TTarget? target)
where TSource : notnull
where TTarget : notnull;
}
public sealed class PreserveReferenceHandler : Riok.Mapperly.Abstractions.ReferenceHandling.IReferenceHandler
{
public PreserveReferenceHandler() { }
public void SetReference<TSource, TTarget>(TSource source, TTarget target)
where TSource : notnull
where TTarget : notnull { }
public bool TryGetReference<TSource, TTarget>(TSource source, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out TTarget? target)
where TSource : notnull
where TTarget : notnull { }
}
[System.AttributeUsage(System.AttributeTargets.Parameter)]
[System.Diagnostics.Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class ReferenceHandlerAttribute : System.Attribute
{
public ReferenceHandlerAttribute() { }
}
}

0 comments on commit 6cf2df6

Please sign in to comment.