Skip to content

Commit

Permalink
Merge pull request #96 from feO2x/dev
Browse files Browse the repository at this point in the history
v11.0.0 Release
  • Loading branch information
feO2x committed Nov 16, 2023
2 parents a067d91 + ee447b0 commit 9d994da
Show file tree
Hide file tree
Showing 43 changed files with 200 additions and 63 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore ./Code/Light.GuardClauses.AllProjects.sln
- name: Build Analyzer
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-on-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
dotnetVersion:
description: "The version of .NET to use"
required: false
default: "7.0.x"
default: "8.0.x"

jobs:
release-to-nuget:
Expand All @@ -20,7 +20,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ github.event.inputs.dotnetVersion || '7.0.x' }}
dotnet-version: ${{ github.event.inputs.dotnetVersion || '8.0.x' }}
- name: Prepare SNK file
env:
LIGHT_GUARDCLAUSES_SNK: ${{ secrets.LIGHT_GUARDCLAUSES_SNK }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public ConsoleColor NoFlagsBaseVersion()

public static class MustBeValidEnumValueExtensionMethods
{
public static T OldMustBeValidEnumValue<T>(this T parameter, string parameterName = null, string message = null, Func<Exception> exception = null) where T : Enum
public static T OldMustBeValidEnumValue<T>(this T parameter, string parameterName = null, string message = null, Func<Exception> exception = null) where T : struct, Enum
{
if (parameter.IsValidEnumValue())
return parameter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net7.0;net48</TargetFrameworks>
<TargetFrameworks>net8.0;net48</TargetFrameworks>
<LangVersion>11</LangVersion>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class IsValidEnumValueTests
[InlineData(UInt64Enum.AllLow | UInt64Enum.High1)]
[InlineData(UInt64Enum.AllHigh)]
[InlineData(UInt64Enum.MaxValue)]
public static void EnumValueValid<T>(T enumValue) where T : Enum, IComparable
public static void EnumValueValid<T>(T enumValue) where T : struct, Enum, IComparable
{
if (enumValue is BindingFlags)
{
Expand All @@ -42,6 +42,7 @@ public static class IsValidEnumValueTests
[InlineData(int.MinValue)]
[InlineData(2048)]
[InlineData(2055)]
[InlineData(4096)]
[InlineData(int.MaxValue)]
public static void InvalidNumberStyles(int invalidValue) => ((NumberStyles) invalidValue).IsValidEnumValue().Should().BeFalse();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,28 @@ public static void CallerArgumentExpression()
act.Should().Throw<EmptyGuidException>()
.WithParameterName(nameof(emptyGuid));
}
}

public class Entity(Guid id)
{
public Guid Id { get; } = id.MustNotBeEmpty();
}

[Fact]
public static void PrimaryConstructorValidArgument()
{
var guid = Guid.NewGuid();
var entity = new Entity(guid);

entity.Id.Should().Be(guid);
}

[Fact]
public static void PrimaryConstructorInvalidArgument()
{
var act = () => new Entity(Guid.Empty);

act.Should().Throw<EmptyGuidException>()
.And.Message.Should().StartWith("id must be a valid GUID, but it actually is an empty one.");
}
}

12 changes: 6 additions & 6 deletions Code/Light.GuardClauses.Tests/Light.GuardClauses.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
<Import Project="TargetFrameworks.props" Condition="Exists('TargetFrameworks.props')" />

<PropertyGroup>
<TargetFrameworks Condition="'$(TargetFrameworks)' == ''">net7.0</TargetFrameworks>
<TargetFrameworks Condition="'$(TargetFrameworks)' == ''">net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<LangVersion>11.0</LangVersion>
<LangVersion>12</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="xunit" Version="2.5.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.1" />
<ProjectReference Include="..\Light.GuardClauses\Light.GuardClauses.csproj" />
</ItemGroup>

Expand Down
6 changes: 4 additions & 2 deletions Code/Light.GuardClauses/CallerArgumentExpressionAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// ReSharper disable once CheckNamespace -- CallerArgumentExpression must be in exactly this namespace
#if !NET8_0
// ReSharper disable once CheckNamespace -- CallerArgumentExpression must be in exactly this namespace
namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
Expand All @@ -10,4 +11,5 @@ public CallerArgumentExpressionAttribute(string parameterName)
}

public string ParameterName { get; }
}
}
#endif
6 changes: 3 additions & 3 deletions Code/Light.GuardClauses/Check.CommonAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public static T MustBeOfType<T>([ValidatedNotNull, NoEnumeration] this object? p
/// <typeparam name="T">The type of the enum.</typeparam>
/// <param name="parameter">The enum value to be checked.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsValidEnumValue<T>(this T parameter) where T : Enum
public static bool IsValidEnumValue<T>(this T parameter) where T : struct, Enum
=> EnumInfo<T>.IsValidEnumValue(parameter);

/// <summary>
Expand All @@ -189,7 +189,7 @@ public static T MustBeOfType<T>([ValidatedNotNull, NoEnumeration] this object? p
/// <param name="message">The message that will be passed to the resulting exception (optional).</param>
/// <exception cref="EnumValueNotDefinedException">Thrown when <paramref name="parameter" /> is no valid enum value.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T MustBeValidEnumValue<T>(this T parameter, [CallerArgumentExpression("parameter")] string? parameterName = null, string? message = null) where T : Enum
public static T MustBeValidEnumValue<T>(this T parameter, [CallerArgumentExpression("parameter")] string? parameterName = null, string? message = null) where T : struct, Enum
{
if (!EnumInfo<T>.IsValidEnumValue(parameter))
Throw.EnumValueNotDefined(parameter, parameterName, message);
Expand All @@ -207,7 +207,7 @@ public static T MustBeOfType<T>([ValidatedNotNull, NoEnumeration] this object? p
/// <exception cref="Exception">Your custom exception thrown when <paramref name="parameter" /> is no valid enum value, or when <typeparamref name="T" /> is no enum type.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("exceptionFactory:null => halt")]
public static T MustBeValidEnumValue<T>(this T parameter, Func<T, Exception> exceptionFactory) where T : Enum
public static T MustBeValidEnumValue<T>(this T parameter, Func<T, Exception> exceptionFactory) where T : struct, Enum
{
if (!EnumInfo<T>.IsValidEnumValue(parameter))
Throw.CustomException(exceptionFactory, parameter);
Expand Down
91 changes: 72 additions & 19 deletions Code/Light.GuardClauses/Check.TypeAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
#if NET8_0
using System.Diagnostics.CodeAnalysis;
#endif

namespace Light.GuardClauses;

Expand Down Expand Up @@ -41,11 +44,19 @@ private static bool CheckTypeEquivalency(Type type, Type other)
/// <param name="interfaceType">The interface type that <paramref name="type" /> should implement.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" /> or <paramref name="interfaceType" /> is null.</exception>
[ContractAnnotation("type:null => halt; interfaceType:null => halt")]
public static bool Implements([ValidatedNotNull] this Type type, [ValidatedNotNull] Type interfaceType)
public static bool Implements(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull]
this Type type,
[ValidatedNotNull] Type interfaceType
)
{
interfaceType.MustNotBeNull(nameof(interfaceType));
var implementedInterfaces = type.MustNotBeNull(nameof(type)).GetInterfaces();
type.MustNotBeNull();
interfaceType.MustNotBeNull();

var implementedInterfaces = type.GetInterfaces();
for (var i = 0; i < implementedInterfaces.Length; ++i)
{
if (interfaceType.IsEquivalentTypeTo(implementedInterfaces[i]))
Expand All @@ -64,12 +75,21 @@ public static bool Implements([ValidatedNotNull] this Type type, [ValidatedNotNu
/// <param name="typeComparer">The equality comparer used to compare the interface types.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" />, or <paramref name="interfaceType" />, or <paramref name="typeComparer" /> is null.</exception>
[ContractAnnotation("type:null => halt; interfaceType:null => halt; typeComparer:null => halt")]
public static bool Implements([ValidatedNotNull] this Type type, [ValidatedNotNull] Type interfaceType, [ValidatedNotNull] IEqualityComparer<Type> typeComparer)
public static bool Implements(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull]
this Type type,
[ValidatedNotNull] Type interfaceType,
[ValidatedNotNull] IEqualityComparer<Type> typeComparer
)
{
interfaceType.MustNotBeNull(nameof(interfaceType));
typeComparer.MustNotBeNull(nameof(typeComparer));
type.MustNotBeNull();
interfaceType.MustNotBeNull();
typeComparer.MustNotBeNull();

var implementedInterfaces = type.MustNotBeNull(nameof(type)).GetInterfaces();
var implementedInterfaces = type.GetInterfaces();
for (var i = 0; i < implementedInterfaces.Length; ++i)
{
if (typeComparer.Equals(implementedInterfaces[i], interfaceType))
Expand All @@ -88,7 +108,12 @@ public static bool Implements([ValidatedNotNull] this Type type, [ValidatedNotNu
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" /> or <paramref name="otherType" /> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("type:null => halt; otherType:null => halt")]
public static bool IsOrImplements([ValidatedNotNull] this Type type, [ValidatedNotNull] Type otherType) =>
public static bool IsOrImplements(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull] this Type type,
[ValidatedNotNull] Type otherType) =>
type.IsEquivalentTypeTo(otherType.MustNotBeNull(nameof(otherType))) || type.Implements(otherType);

/// <summary>
Expand All @@ -102,7 +127,13 @@ public static bool Implements([ValidatedNotNull] this Type type, [ValidatedNotNu
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" /> or <paramref name="otherType" /> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("type:null => halt; otherType:null => halt")]
public static bool IsOrImplements([ValidatedNotNull] this Type type, [ValidatedNotNull] Type otherType, [ValidatedNotNull] IEqualityComparer<Type> typeComparer) =>
public static bool IsOrImplements(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull] this Type type,
[ValidatedNotNull] Type otherType,
[ValidatedNotNull] IEqualityComparer<Type> typeComparer) =>
typeComparer.MustNotBeNull(nameof(typeComparer)).Equals(type.MustNotBeNull(nameof(type)), otherType.MustNotBeNull(nameof(otherType))) || type.Implements(otherType, typeComparer);

/// <summary>
Expand Down Expand Up @@ -190,11 +221,16 @@ public static bool DerivesFrom([ValidatedNotNull] this Type type, [ValidatedNotN
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" /> or <paramref name="baseClassOrInterfaceType" /> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("type:null => halt; baseClassOrInterfaceType:null => halt")]
public static bool InheritsFrom([ValidatedNotNull] this Type type, [ValidatedNotNull] Type baseClassOrInterfaceType) =>
public static bool InheritsFrom(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull] this Type type,
[ValidatedNotNull] Type baseClassOrInterfaceType) =>
baseClassOrInterfaceType.MustNotBeNull(nameof(baseClassOrInterfaceType))
.IsInterface
? type.Implements(baseClassOrInterfaceType)
: type.DerivesFrom(baseClassOrInterfaceType);
.IsInterface ?
type.Implements(baseClassOrInterfaceType) :
type.DerivesFrom(baseClassOrInterfaceType);

/// <summary>
/// Checks if the given type derives from the specified base class or interface type. This overload uses the specified <paramref name="typeComparer" />
Expand All @@ -206,11 +242,17 @@ public static bool DerivesFrom([ValidatedNotNull] this Type type, [ValidatedNotN
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" />, or <paramref name="baseClassOrInterfaceType" />, or <paramref name="typeComparer" /> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("type:null => halt; baseClassOrInterfaceType:null => halt; typeComparer:null => halt")]
public static bool InheritsFrom([ValidatedNotNull] this Type type, [ValidatedNotNull] Type baseClassOrInterfaceType, [ValidatedNotNull] IEqualityComparer<Type> typeComparer) =>
public static bool InheritsFrom(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull] this Type type,
[ValidatedNotNull] Type baseClassOrInterfaceType,
[ValidatedNotNull] IEqualityComparer<Type> typeComparer) =>
baseClassOrInterfaceType.MustNotBeNull(nameof(baseClassOrInterfaceType))
.IsInterface
? type.Implements(baseClassOrInterfaceType, typeComparer)
: type.DerivesFrom(baseClassOrInterfaceType, typeComparer);
.IsInterface ?
type.Implements(baseClassOrInterfaceType, typeComparer) :
type.DerivesFrom(baseClassOrInterfaceType, typeComparer);

/// <summary>
/// Checks if the given <paramref name="type" /> is equal to the specified <paramref name="otherType" /> or if it derives from it or implements it.
Expand All @@ -222,7 +264,12 @@ public static bool DerivesFrom([ValidatedNotNull] this Type type, [ValidatedNotN
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" /> or <paramref name="otherType" /> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("type:null => halt; otherType:null => halt")]
public static bool IsOrInheritsFrom([ValidatedNotNull] this Type type, [ValidatedNotNull] Type otherType) =>
public static bool IsOrInheritsFrom(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull] this Type type,
[ValidatedNotNull] Type otherType) =>
type.IsEquivalentTypeTo(otherType.MustNotBeNull(nameof(otherType))) || type.InheritsFrom(otherType);


Expand All @@ -236,7 +283,13 @@ public static bool DerivesFrom([ValidatedNotNull] this Type type, [ValidatedNotN
/// <exception cref="ArgumentNullException">Thrown when <paramref name="type" /> or <paramref name="otherType" /> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ContractAnnotation("type:null => halt; otherType:null => halt; typeComparer:null => halt")]
public static bool IsOrInheritsFrom([ValidatedNotNull] this Type type, [ValidatedNotNull] Type otherType, [ValidatedNotNull] IEqualityComparer<Type> typeComparer) =>
public static bool IsOrInheritsFrom(
#if NET8_0
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#endif
[ValidatedNotNull] this Type type,
[ValidatedNotNull] Type otherType,
[ValidatedNotNull] IEqualityComparer<Type> typeComparer) =>
typeComparer.MustNotBeNull(nameof(typeComparer)).Equals(type, otherType.MustNotBeNull(nameof(otherType))) || type.InheritsFrom(otherType, typeComparer);


Expand Down
16 changes: 6 additions & 10 deletions Code/Light.GuardClauses/EnumInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Light.GuardClauses;
/// Can be used to validate that an enum value is valid.
/// </summary>
/// <typeparam name="T">The type of the enum.</typeparam>
public static class EnumInfo<T> where T : Enum
public static class EnumInfo<T> where T : struct, Enum
{
// ReSharper disable StaticMemberInGenericType

Expand All @@ -28,23 +28,19 @@ public static class EnumInfo<T> where T : Enum
private static readonly int EnumSize = Unsafe.SizeOf<T>();
private static readonly T[] EnumConstantsArray;

/// <summary>
/// Gets the underlying type that is used for the enum (<see cref="int" /> for default enums).
/// </summary>
public static readonly Type UnderlyingType;

/// <summary>
/// Gets the values of the enum as a read-only collection.
/// </summary>
public static ReadOnlyMemory<T> EnumConstants { get; }

static EnumInfo()
{
#if NET8_0
EnumConstantsArray = Enum.GetValues<T>();
#else
EnumConstantsArray = (T[]) Enum.GetValues(typeof(T));
var fields = typeof(T).GetFields();

UnderlyingType = fields[0].FieldType;
EnumConstants = new ReadOnlyMemory<T>(EnumConstantsArray);
#endif
EnumConstants = new (EnumConstantsArray);

if (!IsFlagsEnum)
return;
Expand Down
2 changes: 2 additions & 0 deletions Code/Light.GuardClauses/Exceptions/AbsoluteUriException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class AbsoluteUriException : UriException
/// <param name="message">The message of the exception (optional).</param>
public AbsoluteUriException(string? parameterName = null, string? message = null) : base(parameterName, message) { }

#if !NET8_0
/// <inheritdoc />
protected AbsoluteUriException(SerializationInfo info, StreamingContext context) : base(info, context) { }
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class ArgumentDefaultException : ArgumentException
/// <param name="message">The message of the exception (optional).</param>
public ArgumentDefaultException(string? parameterName = null, string? message = null) : base(message, parameterName) { }

#if !NET8_0
/// <inheritdoc />
protected ArgumentDefaultException(SerializationInfo info, StreamingContext context) : base(info, context) { }
#endif
}
2 changes: 2 additions & 0 deletions Code/Light.GuardClauses/Exceptions/CollectionException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class CollectionException : ArgumentException
/// <param name="message">The message of the exception (optional).</param>
public CollectionException(string? parameterName = null, string? message = null) : base(message, parameterName) { }

#if !NET8_0
/// <inheritdoc />
protected CollectionException(SerializationInfo info, StreamingContext context) : base(info, context) { }
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class EmptyCollectionException : InvalidCollectionCountException
/// <param name="message">The message of the exception (optional).</param>
public EmptyCollectionException(string? parameterName = null, string? message = null) : base(parameterName, message) { }

#if !NET8_0
/// <inheritdoc />
protected EmptyCollectionException(SerializationInfo info, StreamingContext context) : base(info, context) { }
#endif
}
Loading

0 comments on commit 9d994da

Please sign in to comment.