Skip to content

Commit

Permalink
Refactored parts of AssertionScope into AssertionChain and used that …
Browse files Browse the repository at this point in the history
…to improve the identifier in .Which constructs.
  • Loading branch information
dennisdoomen committed Sep 28, 2024
1 parent 6cadca1 commit 29a0a25
Show file tree
Hide file tree
Showing 215 changed files with 6,220 additions and 5,941 deletions.
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ dotnet_diagnostic.SA1116.severity = none
dotnet_diagnostic.SA1117.severity = none
# SA1200: Using directive should appear within a namespace declaration
dotnet_diagnostic.SA1200.severity = none

# Purpose: Use string. Empty for empty strings
# Reason: There's no performance difference. See https://medium.com/@dk.kravtsov/string-empty-vs-in-c-70c64971161f
dotnet_diagnostic.SA1122.severity = none

# SA1124: Do not use regions
dotnet_diagnostic.SA1124.severity = none
# SA1201: A property should not follow a method
Expand Down
4 changes: 0 additions & 4 deletions Build/Build.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using LibGit2Sharp;
using Microsoft.Build.Tasks;
using Nuke.Common;
using Nuke.Common.CI.GitHubActions;
using Nuke.Common.Execution;
Expand Down
1 change: 1 addition & 0 deletions Build/_build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<NukeRootDirectory>..\</NukeRootDirectory>
<NukeScriptDirectory>..\</NukeScriptDirectory>
<NukeVersion>8.1.0</NukeVersion>
<NukeTelemetryVersion>1</NukeTelemetryVersion>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<DefineConstants>OS_WINDOWS</DefineConstants>
Expand Down
1 change: 0 additions & 1 deletion FluentAssertions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
Tests\Default.testsettings = Tests\Default.testsettings
Directory.Build.props = Directory.Build.props
Src\JetBrainsAnnotations.cs = Src\JetBrainsAnnotations.cs
nuget.config = nuget.config
README.md = README.md
docs\_pages\releases.md = docs\_pages\releases.md
Expand Down
14 changes: 7 additions & 7 deletions FluentAssertions.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/AutoCompleteBasicCompletion/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/LookupWindow/ShowSignatures/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeEditing/TypingAssist/FormatBlockOnRBrace/@EntryValue">False</s:Boolean>
Expand Down Expand Up @@ -143,7 +143,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=NAMESPACE_005FALIAS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FRESOURCE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>

<s:String x:Key="/Default/Environment/Editor/MatchingBraceHighlighting/Style/@EntryValue">OUTLINE</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/PsiConfigurationSettingsKey/LocationType/@EntryValue">SOLUTION_FOLDER</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EDaemon_002ESettings_002EMigration_002ESwaWarningsModeSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -161,17 +161,17 @@
<s:Int64 x:Key="/Default/Environment/UnitTesting/ParallelProcessesCount/@EntryValue">4</s:Int64>
<s:Boolean x:Key="/Default/Environment/UnitTesting/ShadowCopy/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Field/=behavior/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Field/=behavior/Order/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Field/=scenario/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Field/=scenario/Order/@EntryValue">0</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Field/=behavior/@KeyIndexDefined">False</s:Boolean>

<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Field/=scenario/@KeyIndexDefined">False</s:Boolean>

<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Shortcut/@EntryValue">aaa</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Description/@EntryValue">Arrange-Act-Assert</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=012E3B0572DEF2448B0B5D9AA88E6210/Text/@EntryValue">[Fact]
public void $END$()
{
// Arrange


// Act

Expand Down
100 changes: 75 additions & 25 deletions Src/FluentAssertions/AndWhichConstraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,84 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions.Common;
using FluentAssertions.Execution;
using FluentAssertions.Formatting;

namespace FluentAssertions;

/// <summary>
/// Constraint which can be returned from an assertion which matches a condition and which will allow
/// further matches to be performed on the matched condition as well as the parent constraint.
/// Provides a <see cref="Which"/> property that can be used in chained assertions where the prior assertions returns a
/// single object that the assertion continues on.
/// </summary>
/// <typeparam name="TParentConstraint">The type of the original constraint that was matched</typeparam>
/// <typeparam name="TMatchedElement">The type of the matched object which the parent constraint matched</typeparam>
public class AndWhichConstraint<TParentConstraint, TMatchedElement> : AndConstraint<TParentConstraint>
public class AndWhichConstraint<TParent, TSubject> : AndConstraint<TParent>
{
private readonly Lazy<TMatchedElement> matchedConstraint;
private readonly AssertionChain assertionChain;
private readonly string pathPostfix;
private readonly Lazy<TSubject> getSubject;

public AndWhichConstraint(TParentConstraint parentConstraint, TMatchedElement matchedConstraint)
: base(parentConstraint)
/// <summary>
/// Creates an object that allows continuing an assertion executed through <paramref name="parent"/> and
/// which resulted in a single <paramref name="subject"/>.
/// </summary>
public AndWhichConstraint(TParent parent, TSubject subject)
: base(parent)
{
getSubject = new Lazy<TSubject>(() => subject);
}

/// <summary>
/// Creates an object that allows continuing an assertion executed through <paramref name="parent"/> and
/// which resulted in a single <paramref name="subject"/> on an existing <paramref name="assertionChain"/>, but where
/// the previous caller identifier is post-fixed with <paramref name="pathPostfix"/>.
/// </summary>
public AndWhichConstraint(TParent parent, TSubject subject, AssertionChain assertionChain, string pathPostfix = "")
: base(parent)
{
this.matchedConstraint =
new Lazy<TMatchedElement>(() => matchedConstraint);
getSubject = new Lazy<TSubject>(() => subject);

this.assertionChain = assertionChain;
this.pathPostfix = pathPostfix;
}

public AndWhichConstraint(TParentConstraint parentConstraint, IEnumerable<TMatchedElement> matchedConstraint)
: base(parentConstraint)
/// <summary>
/// Creates an object that allows continuing an assertion executed through <paramref name="parent"/> and
/// which resulted in a potential collection of objects through <paramref name="subjects"/>.
/// </summary>
/// <remarks>
/// If <paramref name="subjects"/> contains more than one object, a clear exception is thrown.
/// </remarks>
public AndWhichConstraint(TParent parent, IEnumerable<TSubject> subjects)
: base(parent)
{
this.matchedConstraint =
new Lazy<TMatchedElement>(
() => SingleOrDefault(matchedConstraint));
getSubject = new Lazy<TSubject>(() => Single(subjects));
}

private static TMatchedElement SingleOrDefault(
IEnumerable<TMatchedElement> matchedConstraint)
/// <summary>
/// Creates an object that allows continuing an assertion executed through <paramref name="parent"/> and
/// which resulted in a potential collection of objects through <paramref name="subjects"/> on an
/// existing <paramref name="assertionChain"/>, but where
/// the previous caller identifier is post-fixed with <paramref name="pathPostfix"/>.
/// </summary>
/// <remarks>
/// If <paramref name="subjects"/> contains more than one object, a clear exception is thrown.
/// </remarks>
public AndWhichConstraint(TParent parent, IEnumerable<TSubject> subjects, AssertionChain assertionChain, string pathPostfix)
: base(parent)
{
TMatchedElement[] matchedElements = matchedConstraint.ToArray();
getSubject = new Lazy<TSubject>(() => Single(subjects));

this.assertionChain = assertionChain;
this.pathPostfix = pathPostfix;
}

private static TSubject Single(IEnumerable<TSubject> subjects)
{
TSubject[] matchedElements = subjects.ToArray();

if (matchedElements.Length > 1)
{
string foundObjects = string.Join(Environment.NewLine,
matchedElements.Select(
ele => "\t" + Formatter.ToString(ele)));
matchedElements.Select(ele => "\t" + Formatter.ToString(ele)));

string message = "More than one object found. FluentAssertions cannot determine which object is meant."
+ $" Found objects:{Environment.NewLine}{foundObjects}";
Expand All @@ -54,13 +93,24 @@ private static TMatchedElement SingleOrDefault(
/// <summary>
/// Returns the single result of a prior assertion that is used to select a nested or collection item.
/// </summary>
public TMatchedElement Which => matchedConstraint.Value;
/// <remarks>
/// Just a convenience property that returns the same value as <see cref="Which"/>.
/// </remarks>
public TSubject Subject => Which;

/// <summary>
/// Returns the single result of a prior assertion that is used to select a nested or collection item.
/// </summary>
/// <remarks>
/// Just a convenience property that returns the same value as <see cref="Which"/>.
/// </remarks>
public TMatchedElement Subject => Which;
public TSubject Which
{
get
{
if (pathPostfix is not null and not "")
{
assertionChain.WithCallerPostfix(pathPostfix).ReuseOnce();
}

return getSubject.Value;
}
}
}
Loading

0 comments on commit 29a0a25

Please sign in to comment.