Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ jobs:
all:
if: github.run_id != 1
name: Build & Tests
uses: dailydevops/pipelines/.github/workflows/cicd-dotnet.yml@0.14.82
uses: dailydevops/pipelines/.github/workflows/cicd-dotnet.yml@0.14.86
with:
enableSonarQube: true
dotnet-logging: ${{ inputs.dotnet-logging }}
dotnet-logging: ${{ inputs.dotnet-logging || 'minimal' }}
dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
solution: ./FluentValue.sln
secrets: inherit
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<CopyrightYearStart>2024</CopyrightYearStart>
</PropertyGroup>
<PropertyGroup>
<NetEvolve_ProjectTargetFrameworks>net6.0;net8.0;net9.0</NetEvolve_ProjectTargetFrameworks>
<NetEvolve_TestTargetFrameworks>net6.0;net7.0;net8.0;net9.0</NetEvolve_TestTargetFrameworks>
<NetEvolve_ProjectTargetFrameworks>net8.0;net9.0</NetEvolve_ProjectTargetFrameworks>
<NetEvolve_TestTargetFrameworks>net8.0;net9.0</NetEvolve_TestTargetFrameworks>
</PropertyGroup>
<PropertyGroup>
<!-- Workaround, until https://github.com/GitTools/GitVersion/pull/4206 is released -->
Expand Down
10 changes: 4 additions & 6 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,24 @@
</PropertyGroup>
<ItemGroup>
<GlobalPackageReference Include="CSharpier.MSBuild" Version="1.0.1" />
<GlobalPackageReference Include="GitVersion.MsBuild" Version="6.1.0" />
<GlobalPackageReference Include="GitVersion.MsBuild" Version="6.3.0" />
<GlobalPackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
<GlobalPackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<GlobalPackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.13.61" />
<GlobalPackageReference Include="NetEvolve.Defaults" Version="1.3.80" />
<GlobalPackageReference
Include="SonarAnalyzer.CSharp"
Version="10.6.0.109712"
Version="10.9.0.115408"
Condition=" '$(BuildingInsideVisualStudio)' == 'true' "
/>
</ItemGroup>
<ItemGroup>
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="coverlet.msbuild" Version="6.0.4" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.14.2" />
<PackageVersion Include="NetEvolve.Arguments" Version="1.3.84" />
<PackageVersion Include="NetEvolve.Extensions.XUnit" Version="2.6.9" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.2" />
<PackageVersion Include="NetEvolve.Extensions.TUnit" Version="2.6.9" />
<PackageVersion Include="TUnit" Version="0.19.143" />
</ItemGroup>
</Project>
7 changes: 0 additions & 7 deletions FluentValue.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AE6A68C3
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.FluentValue.Tests.Unit", "tests\NetEvolve.FluentValue.Tests.Unit\NetEvolve.FluentValue.Tests.Unit.csproj", "{93D85E57-7EB9-4CDD-836E-301A58BF3312}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.FluentValue.Tests.Architecture", "tests\NetEvolve.FluentValue.Tests.Architecture\NetEvolve.FluentValue.Tests.Architecture.csproj", "{6C599754-9C81-494C-9136-98259711B6C8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2FF9F0BF-A46C-4C74-BD17-25B38E8D85EE}"
ProjectSection(SolutionItems) = preProject
.commitlintrc = .commitlintrc
Expand Down Expand Up @@ -46,17 +44,12 @@ Global
{93D85E57-7EB9-4CDD-836E-301A58BF3312}.Debug|Any CPU.Build.0 = Debug|Any CPU
{93D85E57-7EB9-4CDD-836E-301A58BF3312}.Release|Any CPU.ActiveCfg = Release|Any CPU
{93D85E57-7EB9-4CDD-836E-301A58BF3312}.Release|Any CPU.Build.0 = Release|Any CPU
{6C599754-9C81-494C-9136-98259711B6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C599754-9C81-494C-9136-98259711B6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C599754-9C81-494C-9136-98259711B6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C599754-9C81-494C-9136-98259711B6C8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7B62BC70-8970-4D45-A86C-CB6C7E64A5D9} = {BB2B11D1-1E37-4333-9E07-E6709C1796F5}
{93D85E57-7EB9-4CDD-836E-301A58BF3312} = {AE6A68C3-E24A-45BC-B7A6-4D527AF3BF99}
{6C599754-9C81-494C-9136-98259711B6C8} = {AE6A68C3-E24A-45BC-B7A6-4D527AF3BF99}
EndGlobalSection
EndGlobal
26 changes: 26 additions & 0 deletions src/NetEvolve.FluentValue/Constraints/ConstraintBase.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
namespace NetEvolve.FluentValue.Constraints;

using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using NetEvolve.FluentValue;

[SuppressMessage("Info Code Smell", "S1133:Deprecated code should be removed", Justification = "As designed.")]
[SuppressMessage(
"Blocker Code Smell",
"S3877:Exceptions should not be thrown from unexpected methods",
Justification = "As designed."
)]
internal abstract class ConstraintBase : IConstraint
{
[ThreadStatic]
private static StringBuilder? _builder;

private const int DefaultCapacity = 1024;

/// <inheritdoc />
public abstract bool IsSatisfiedBy(object? value);

/// <inheritdoc />
public abstract void SetDescription(StringBuilder builder);

/// <inhertdoc />
[Obsolete("This is base `object` method that should not be called.", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DebuggerHidden]
public new bool Equals(object? obj) =>
throw new NotSupportedException("This is base `object` method that should not be called.");

/// <inheritdoc/>
[Obsolete("This is base `object` method that should not be called.", true)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DebuggerHidden]
public new int GetHashCode() =>
throw new NotSupportedException("This is base `object` method that should not be called.");

public override string ToString()
{
var builder = _builder ?? new StringBuilder(capacity: DefaultCapacity);
Expand Down
13 changes: 2 additions & 11 deletions src/NetEvolve.FluentValue/Constraints/DefaultConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,16 @@

using System;
using System.Text;
using NetEvolve.FluentValue;

internal sealed class DefaultConstraint : ConstraintBase
{
public override bool IsSatisfiedBy(object? value) =>
value?.GetType() switch
{
{ IsValueType: true } valueType => GetDefault(valueType).Equals(value),
{ IsValueType: true } valueType => TypeExtensions.GetDefault(valueType)?.Equals(value) ?? false,
_ => false,
};

public override void SetDescription(StringBuilder builder) => builder.Append(" is <default>");

private static object GetDefault(Type value)
{
var underlying = Nullable.GetUnderlyingType(value);
if (underlying is not null)
{
return Activator.CreateInstance(underlying)!;
}
return Activator.CreateInstance(value)!;
}
}
16 changes: 16 additions & 0 deletions src/NetEvolve.FluentValue/Constraints/NotDefaultConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace NetEvolve.FluentValue.Constraints;

using System.Text;
using NetEvolve.FluentValue;

internal sealed class NotDefaultConstraint : ConstraintBase
{
public override bool IsSatisfiedBy(object? value) =>
value?.GetType() switch
{
{ IsValueType: true } valueType => !TypeExtensions.GetDefault(valueType)?.Equals(value) ?? false,
_ => true,
};

public override void SetDescription(StringBuilder builder) => builder.Append(" is not <default>");
}
20 changes: 20 additions & 0 deletions src/NetEvolve.FluentValue/Constraints/NotEmptyConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace NetEvolve.FluentValue.Constraints;

using System;
using System.Collections;
using System.Text;

internal sealed class NotEmptyConstraint : ConstraintBase
{
public override bool IsSatisfiedBy(object? value) =>
value switch
{
string stringValue => stringValue.Length > 0,
Guid guidValue => guidValue != Guid.Empty,
ICollection collection => collection.Count > 0,
IEnumerable enumerable => enumerable.GetEnumerator().MoveNext(),
_ => false,
};

public override void SetDescription(StringBuilder builder) => builder.Append(" is not <empty>");
}
10 changes: 10 additions & 0 deletions src/NetEvolve.FluentValue/Constraints/NotNullConstraint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace NetEvolve.FluentValue.Constraints;

using System.Text;

internal sealed class NotNullConstraint : ConstraintBase
{
public override bool IsSatisfiedBy(object? value) => value is not null;

public override void SetDescription(StringBuilder builder) => builder.Append(" is not <null>");
}
22 changes: 17 additions & 5 deletions src/NetEvolve.FluentValue/IOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,8 @@ IConstraint EqualTo(string compareValue, StringComparison comparison = default)
/// <returns>
/// The current instance.
/// </returns>
IConstraint Matches(
#if NET7_0_OR_GREATER
[StringSyntax(StringSyntaxAttribute.Regex)]
#endif
string pattern, RegexOptions? options = null) => SetConstraint(new MatchesConstraint(pattern, options));
IConstraint Matches([StringSyntax(StringSyntaxAttribute.Regex)] string pattern, RegexOptions? options = null) =>
SetConstraint(new MatchesConstraint(pattern, options));

/// <summary>
/// Appends a negation operator.
Expand All @@ -165,6 +162,21 @@ IOperator Not
}
}

/// <summary>
/// Appends a constraint that the value is <see langword="not"/> the <see langword="default"/> value.
/// </summary>
IConstraint NotDefault => SetConstraint(new NotDefaultConstraint());

/// <summary>
/// Appends a constraint that the value is <see langword="not"/> empty.
/// </summary>
IConstraint NotEmpty => SetConstraint(new NotEmptyConstraint());

/// <summary>
/// Appends a constraint that the value is <see langword="not"/> <see langword="null"/>.
/// </summary>
IConstraint NotNull => SetConstraint(new NotNullConstraint());

/// <summary>
/// Appends a constraint that the value is <see langword="null"/>.
/// </summary>
Expand Down
5 changes: 3 additions & 2 deletions src/NetEvolve.FluentValue/Operators/AndOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
using System.Text;
using NetEvolve.Arguments;
using NetEvolve.FluentValue;
using NetEvolve.FluentValue.Constraints;

internal sealed class AndOperator : OperatorBase
internal sealed class AndOperator : ConstraintBase, IOperator
{
private readonly IConstraint _left;
private IConstraint? _right;
Expand All @@ -27,7 +28,7 @@ public override bool IsSatisfiedBy(object? value)
return _left.IsSatisfiedBy(value) && _right.IsSatisfiedBy(value);
}

public override IConstraint SetConstraint(IConstraint constraint)
public IConstraint SetConstraint(IConstraint constraint)
{
Argument.ThrowIfNull(constraint);

Expand Down
5 changes: 3 additions & 2 deletions src/NetEvolve.FluentValue/Operators/NotOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
using System.Text;
using NetEvolve.Arguments;
using NetEvolve.FluentValue;
using NetEvolve.FluentValue.Constraints;

internal sealed class NotOperator : OperatorBase
internal sealed class NotOperator : ConstraintBase, IOperator
{
internal IConstraint? _constraint;

Expand All @@ -21,7 +22,7 @@ public override bool IsSatisfiedBy(object? value)
return !_constraint.IsSatisfiedBy(value);
}

public override IConstraint SetConstraint(IConstraint constraint)
public IConstraint SetConstraint(IConstraint constraint)
{
Argument.ThrowIfNull(constraint);

Expand Down
9 changes: 0 additions & 9 deletions src/NetEvolve.FluentValue/Operators/OperatorBase.cs

This file was deleted.

5 changes: 3 additions & 2 deletions src/NetEvolve.FluentValue/Operators/OrOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
using System.Text;
using NetEvolve.Arguments;
using NetEvolve.FluentValue;
using NetEvolve.FluentValue.Constraints;

internal sealed class OrOperator : OperatorBase
internal sealed class OrOperator : ConstraintBase, IOperator
{
private readonly IConstraint _left;
private IConstraint? _right;
Expand All @@ -27,7 +28,7 @@ public override bool IsSatisfiedBy(object? value)
return _left.IsSatisfiedBy(value) || _right.IsSatisfiedBy(value);
}

public override IConstraint SetConstraint(IConstraint constraint)
public IConstraint SetConstraint(IConstraint constraint)
{
Argument.ThrowIfNull(constraint);

Expand Down
5 changes: 3 additions & 2 deletions src/NetEvolve.FluentValue/Operators/XorOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
using System.Text;
using NetEvolve.Arguments;
using NetEvolve.FluentValue;
using NetEvolve.FluentValue.Constraints;

internal sealed class XorOperator : OperatorBase
internal sealed class XorOperator : ConstraintBase, IOperator
{
private readonly IConstraint _left;
private IConstraint? _right;
Expand All @@ -27,7 +28,7 @@ public override bool IsSatisfiedBy(object? value)
return _left.IsSatisfiedBy(value) ^ _right.IsSatisfiedBy(value);
}

public override IConstraint SetConstraint(IConstraint constraint)
public IConstraint SetConstraint(IConstraint constraint)
{
Argument.ThrowIfNull(constraint);

Expand Down
21 changes: 21 additions & 0 deletions src/NetEvolve.FluentValue/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace NetEvolve.FluentValue;

using System;

internal static class TypeExtensions
{
internal static object? GetDefault(this Type value)
{
if (!value.IsValueType)
{
return null;
}

var underlying = Nullable.GetUnderlyingType(value);
if (underlying is not null)
{
return null;
}
return Activator.CreateInstance(value)!;
}
}
Loading
Loading