Skip to content

Commit

Permalink
Support the AssertionChain mechanism in Fluent Assertions 8. (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisdoomen authored Dec 2, 2024
1 parent 9ede640 commit daac80f
Show file tree
Hide file tree
Showing 37 changed files with 445 additions and 486 deletions.
5 changes: 4 additions & 1 deletion Build/_build.csproj.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -21,4 +23,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
5 changes: 3 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<LangVersion>11.0</LangVersion>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsNotAsErrors>NU1901; NU1902; NU1903; NU1904</WarningsNotAsErrors>
</PropertyGroup>

<!-- To reduce build times, we only enable analyzers for the newest TFM -->
Expand Down Expand Up @@ -30,11 +31,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.6.1">
<PackageReference Include="Roslynator.Analyzers" Version="4.12.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.103">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.182">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
3 changes: 3 additions & 0 deletions FluentAssertions.DataSets.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
Expand Down Expand Up @@ -154,6 +156,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UnitTesting/MsTestProvider/RunConfigurationFilename/@EntryValue">D:\Workspaces\FluentAssertions\Default.testsettings</s:String>
<s:Int64 x:Key="/Default/Environment/UnitTesting/ParallelProcessesCount/@EntryValue">4</s:Int64>
<s:Boolean x:Key="/Default/Environment/UnitTesting/ShadowCopy/@EntryValue">False</s:Boolean>
Expand Down
9 changes: 5 additions & 4 deletions Src/FluentAssertions.DataSets/AssertionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using FluentAssertions.Collections;
using FluentAssertions.DataSets;
using FluentAssertions.DataSets.Common;
using FluentAssertions.Execution;
using JetBrains.Annotations;

// ReSharper disable once CheckNamespace
Expand All @@ -21,7 +22,7 @@ public static class AssertionExtensions
public static GenericCollectionAssertions<DataTable> Should(this DataTableCollection actualValue)
{
return new GenericCollectionAssertions<DataTable>(
ReadOnlyNonGenericCollectionWrapper.Create(actualValue));
ReadOnlyNonGenericCollectionWrapper.Create(actualValue), AssertionChain.GetOrCreate());
}

/// <summary>
Expand All @@ -31,7 +32,7 @@ public static GenericCollectionAssertions<DataTable> Should(this DataTableCollec
public static GenericCollectionAssertions<DataColumn> Should(this DataColumnCollection actualValue)
{
return new GenericCollectionAssertions<DataColumn>(
ReadOnlyNonGenericCollectionWrapper.Create(actualValue));
ReadOnlyNonGenericCollectionWrapper.Create(actualValue), AssertionChain.GetOrCreate());
}

/// <summary>
Expand All @@ -41,7 +42,7 @@ public static GenericCollectionAssertions<DataColumn> Should(this DataColumnColl
public static GenericCollectionAssertions<DataRow> Should(this DataRowCollection actualValue)
{
return new GenericCollectionAssertions<DataRow>(
ReadOnlyNonGenericCollectionWrapper.Create(actualValue));
ReadOnlyNonGenericCollectionWrapper.Create(actualValue), AssertionChain.GetOrCreate());
}

/// <summary>
Expand All @@ -51,6 +52,6 @@ public static GenericCollectionAssertions<DataRow> Should(this DataRowCollection
[Pure]
public static DataColumnAssertions Should(this DataColumn actualValue)
{
return new DataColumnAssertions(actualValue);
return new DataColumnAssertions(actualValue, AssertionChain.GetOrCreate());
}
}
20 changes: 20 additions & 0 deletions Src/FluentAssertions.DataSets/Common/AssertionChainExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using FluentAssertions.Equivalency;
using FluentAssertions.Execution;

namespace FluentAssertions.DataSets.Common;

internal static class AssertionChainExtensions
{
/// <summary>
/// Updates the <see cref="AssertionChain"/> with the relevant information from the current <see cref="IEquivalencyValidationContext"/>, including the correct
/// caller identification path.
/// </summary>
public static AssertionChain For(this AssertionChain chain, IEquivalencyValidationContext context)
{
chain.OverrideCallerIdentifier(() => context.CurrentNode.Description);

return chain
.WithReportable("configuration", () => context.Options.ToString())
.BecauseOf(context.Reason);
}
}
23 changes: 4 additions & 19 deletions Src/FluentAssertions.DataSets/DataColumnAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Data;
using System.Diagnostics;
using FluentAssertions.DataSets.Common;
using FluentAssertions.Equivalency;
using FluentAssertions.Execution;
using FluentAssertions.Primitives;

Expand All @@ -15,8 +14,8 @@ namespace FluentAssertions.DataSets;
[DebuggerNonUserCode]
public class DataColumnAssertions : ReferenceTypeAssertions<DataColumn, DataColumnAssertions>
{
public DataColumnAssertions(DataColumn dataColumn)
: base(dataColumn)
public DataColumnAssertions(DataColumn dataColumn, AssertionChain assertionChain)
: base(dataColumn, assertionChain)
{
}

Expand Down Expand Up @@ -120,23 +119,9 @@ public AndConstraint<DataColumnAssertions> BeEquivalentTo(DataColumn expectation
Guard.ThrowIfArgumentIsNull(config);

var defaults = new DataEquivalencyAssertionOptions<DataColumn>(AssertionOptions.CloneDefaults<DataColumn>());
IDataEquivalencyAssertionOptions<DataColumn> options = config(defaults);
config(defaults);

var context =
new EquivalencyValidationContext(Node.From<DataColumn>(() => AssertionScope.Current.CallerIdentity), options)
{
Reason = new Reason(because, becauseArgs),
TraceWriter = options.TraceWriter
};

var comparands = new Comparands
{
Subject = Subject,
Expectation = expectation,
CompileTimeType = typeof(DataColumn)
};

new EquivalencyValidator().AssertEquality(comparands, context);
((object)Subject).Should().BeEquivalentTo(expectation, _ => defaults, because, becauseArgs);

return new AndConstraint<DataColumnAssertions>(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using FluentAssertions.Collections;
using FluentAssertions.DataSets;
using FluentAssertions.DataSets.Common;
using FluentAssertions.Execution;

// ReSharper disable once CheckNamespace
namespace FluentAssertions;
Expand Down Expand Up @@ -35,7 +34,7 @@ public static AndConstraint<GenericCollectionAssertions<DataColumn>> BeSameAs(
{
var actualSubject = wrapper.UnderlyingCollection;

Execute.Assertion
assertion.CurrentAssertionChain
.UsingLineBreaks
.ForCondition(ReferenceEquals(actualSubject, expected))
.BecauseOf(because, becauseArgs)
Expand All @@ -45,7 +44,7 @@ public static AndConstraint<GenericCollectionAssertions<DataColumn>> BeSameAs(
}
else
{
Execute.Assertion
assertion.CurrentAssertionChain
.BecauseOf(because, becauseArgs)
.FailWith(
"Invalid expectation: Expected {context:column collection} to refer to an instance of " +
Expand Down Expand Up @@ -80,15 +79,15 @@ public static AndConstraint<GenericCollectionAssertions<DataColumn>> NotBeSameAs
{
var actualSubject = wrapper.UnderlyingCollection;

Execute.Assertion
assertion.CurrentAssertionChain
.UsingLineBreaks
.ForCondition(!ReferenceEquals(actualSubject, unexpected))
.BecauseOf(because, becauseArgs)
.FailWith("Did not expect {context:column collection} to refer to {0}{reason}.", unexpected);
}
else
{
Execute.Assertion
assertion.CurrentAssertionChain
.BecauseOf(because, becauseArgs)
.FailWith(
"Invalid expectation: Expected {context:column collection} to refer to a different instance of " +
Expand Down Expand Up @@ -119,18 +118,16 @@ public static AndConstraint<GenericCollectionAssertions<DataColumn>> HaveSameCou
Guard.ThrowIfArgumentIsNull(
otherCollection, nameof(otherCollection), "Cannot verify count against a <null> collection.");

Execute.Assertion
assertion.CurrentAssertionChain
.BecauseOf(because, becauseArgs)
.WithExpectation("Expected {context:collection} to have ")
.Given(() => assertion.Subject)
.ForCondition(subject => subject is not null)
.FailWith("the same count as {0}{reason}, but found <null>.", otherCollection)
.Then
.Given(subject => (actual: subject.Count(), expected: otherCollection.Count))
.ForCondition(count => count.actual == count.expected)
.FailWith("{0} column(s){reason}, but found {1}.", count => count.expected, count => count.actual)
.Then
.ClearExpectation();
.WithExpectation("Expected {context:collection} to have ", chain => chain
.Given(() => assertion.Subject)
.ForCondition(subject => subject is not null)
.FailWith("the same count as {0}{reason}, but found <null>.", otherCollection)
.Then
.Given(subject => (actual: subject.Count(), expected: otherCollection.Count))
.ForCondition(count => count.actual == count.expected)
.FailWith("{0} column(s){reason}, but found {1}.", count => count.expected, count => count.actual));

return new AndConstraint<GenericCollectionAssertions<DataColumn>>(assertion);
}
Expand All @@ -157,18 +154,16 @@ public static AndConstraint<GenericCollectionAssertions<DataColumn>> NotHaveSame
Guard.ThrowIfArgumentIsNull(
otherCollection, nameof(otherCollection), "Cannot verify count against a <null> collection.");

Execute.Assertion
assertion.CurrentAssertionChain
.BecauseOf(because, becauseArgs)
.WithExpectation("Expected {context:collection} to not have ")
.Given(() => assertion.Subject)
.ForCondition(subject => subject is not null)
.FailWith("the same count as {0}{reason}, but found <null>.", otherCollection)
.Then
.Given(subject => (actual: subject.Count(), expected: otherCollection.Count))
.ForCondition(count => count.actual != count.expected)
.FailWith("{0} column(s){reason}, but found {1}.", count => count.expected, count => count.actual)
.Then
.ClearExpectation();
.WithExpectation("Expected {context:collection} to not have ", chain => chain
.Given(() => assertion.Subject)
.ForCondition(subject => subject is not null)
.FailWith("the same count as {0}{reason}, but found <null>.", otherCollection)
.Then
.Given(subject => (actual: subject.Count(), expected: otherCollection.Count))
.ForCondition(count => count.actual != count.expected)
.FailWith("{0} column(s){reason}, but found {1}.", count => count.expected, count => count.actual));

return new AndConstraint<GenericCollectionAssertions<DataColumn>>(assertion);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace FluentAssertions.DataSets;

internal class DataEquivalencyAssertionOptions<T> : EquivalencyAssertionOptions<T>, IDataEquivalencyAssertionOptions<T>
internal class DataEquivalencyAssertionOptions<T> : EquivalencyOptions<T>, IDataEquivalencyAssertionOptions<T>
{
private readonly HashSet<string> excludeTableNames = new();
private readonly HashSet<string> excludeColumnNames = new();
Expand All @@ -25,7 +25,7 @@ internal class DataEquivalencyAssertionOptions<T> : EquivalencyAssertionOptions<

public ISet<string> ExcludeColumnNames => excludeColumnNames;

public DataEquivalencyAssertionOptions(EquivalencyAssertionOptions<T> defaults)
public DataEquivalencyAssertionOptions(EquivalencyOptions<T> defaults)
: base(defaults)
{
}
Expand Down
3 changes: 2 additions & 1 deletion Src/FluentAssertions.DataSets/DataRowAssertionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Data;
using System.Diagnostics;
using FluentAssertions.DataSets;
using FluentAssertions.Execution;
using JetBrains.Annotations;

// ReSharper disable once CheckNamespace
Expand All @@ -20,6 +21,6 @@ public static class DataRowAssertionExtensions
public static DataRowAssertions<TDataRow> Should<TDataRow>(this TDataRow actualValue)
where TDataRow : DataRow
{
return new DataRowAssertions<TDataRow>(actualValue);
return new DataRowAssertions<TDataRow>(actualValue, AssertionChain.GetOrCreate());
}
}
Loading

0 comments on commit daac80f

Please sign in to comment.