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
35 changes: 35 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,38 @@ resharper_blank_lines_before_multiline_statements = 1

resharper_parentheses_non_obvious_operations = arithmetic, multiplicative, equality, relational, additive
resharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence

dotnet_analyzer_diagnostic.category-roslynator.severity = error

# Remove suffix 'Async' from non-asynchronous method name. Disabled because we like that suffix for now.
dotnet_diagnostic.RCS1047.severity = none

# Combine 'Enumerable.Where' method chain. It doesn't make it more readable in all cases.
dotnet_diagnostic.RCS1112.severity = suggestion

# Inline local variable.
dotnet_diagnostic.RCS1124.severity = suggestion

# Add exception to documentation comment. Nice suggestion, but we don't want to document exceptions for internal code.
dotnet_diagnostic.RCS1140.severity = suggestion

# Use conditional access. Suggestion because it doesn't always improve readability
dotnet_diagnostic.RCS1146.severity = suggestion

# Enum should declare explicit values. Disabled because we're not storing them.
dotnet_diagnostic.RCS1161.severity = none

# Static member in generic type should use a type parameter. Disabled because it's not always applicable.
dotnet_diagnostic.RCS1158.severity = none

# Add region name to #endregion.
dotnet_diagnostic.RCS1189.severity = none

# Convert comment to documentation comment. Disabled because it also complains about SMELL/REFACTOR comments
dotnet_diagnostic.RCS1181.severity = none

# Use Regex instance instead of static method. Disabled because it's not always worth it.
dotnet_diagnostic.RCS1186.severity = none

# Use bit shift operator.
dotnet_diagnostic.RCS1237.severity = none
5 changes: 3 additions & 2 deletions Src/FluentAssertions/CallerIdentification/IParsingStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ namespace FluentAssertions.CallerIdentification;

/// <summary>
/// Represents a stateful parsing strategy that is used to help identify the "caller" to use in an assertion message.
///
/// </summary>
/// <remarks>
/// The strategies will be instantiated at the beginning of a "caller identification" task, and will live until
/// the statement can be identified (and thus some are stateful).
/// </summary>
/// </remarks>
internal interface IParsingStrategy
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3347,9 +3347,7 @@ private static string GetExpressionOrderString<TSelector>(Expression<Func<T, TSe
{
string orderString = propertyExpression.GetMemberPath().ToString();

orderString = orderString is "\"\"" ? string.Empty : "by " + orderString;

return orderString;
return orderString is "\"\"" ? string.Empty : "by " + orderString;
}

private static Type GetType<TType>(TType o)
Expand Down
43 changes: 17 additions & 26 deletions Src/FluentAssertions/Collections/GenericDictionaryAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,12 @@ public AndConstraint<TAssertions> NotContainKey(TKey unexpected,
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} not to contain key {0}{reason}, but found <null>.", unexpected);

if (success)
if (success && ContainsKey(Subject, unexpected))
{
if (ContainsKey(Subject, unexpected))
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} {0} not to contain key {1}{reason}, but found it anyhow.", Subject,
unexpected);
}
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} {0} not to contain key {1}{reason}, but found it anyhow.", Subject,
unexpected);
}

return new AndConstraint<TAssertions>((TAssertions)this);
Expand Down Expand Up @@ -569,15 +566,12 @@ public AndConstraint<TAssertions> NotContainValue(TValue unexpected,
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} not to contain value {0}{reason}, but found <null>.", unexpected);

if (success)
if (success && GetValues(Subject).Contains(unexpected))
{
if (GetValues(Subject).Contains(unexpected))
{
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} {0} not to contain value {1}{reason}, but found it anyhow.", Subject,
unexpected);
}
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} {0} not to contain value {1}{reason}, but found it anyhow.", Subject,
unexpected);
}

return new AndConstraint<TAssertions>((TAssertions)this);
Expand Down Expand Up @@ -715,7 +709,7 @@ public AndConstraint<TAssertions> Contain(params KeyValuePair<TKey, TValue>[] ex
Execute.Assertion
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} {0} to contain key {1}{reason}.", Subject,
expectedKeys.First());
expectedKeys[0]);
}
}

Expand Down Expand Up @@ -946,16 +940,13 @@ public AndConstraint<TAssertions> NotContain(TKey key, TValue value,
.FailWith("Expected {context:dictionary} not to contain value {0} at key {1}{reason}, but dictionary is <null>.",
value, key);

if (success)
if (success && TryGetValue(Subject, key, out TValue actual))
{
if (TryGetValue(Subject, key, out TValue actual))
{
Execute.Assertion
.ForCondition(!ObjectExtensions.GetComparer<TValue>()(actual, value))
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} not to contain value {0} at key {1}{reason}, but found it anyhow.",
value, key);
}
Execute.Assertion
.ForCondition(!ObjectExtensions.GetComparer<TValue>()(actual, value))
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:dictionary} not to contain value {0} at key {1}{reason}, but found it anyhow.",
value, key);
}

return new AndConstraint<TAssertions>((TAssertions)this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,9 @@ internal sealed override IOrderedEnumerable<T> GetOrderedEnumerable<TSelector>(
{
Func<T, TSelector> keySelector = propertyExpression.Compile();

IOrderedEnumerable<T> expectation = direction == SortOrder.Ascending
return direction == SortOrder.Ascending
? previousOrderedEnumerable.ThenBy(keySelector, comparer)
: previousOrderedEnumerable.ThenByDescending(keySelector, comparer);

return expectation;
}

return base.GetOrderedEnumerable(propertyExpression, comparer, direction, unordered);
Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Common/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
Expand Down
18 changes: 7 additions & 11 deletions Src/FluentAssertions/Common/Iterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,10 @@ private set

public bool MoveNext()
{
if (!hasCompleted)
if (!hasCompleted && FetchCurrent())
{
if (FetchCurrent())
{
PrefetchNext();
return true;
}
PrefetchNext();
return true;
}

hasCompleted = true;
Expand All @@ -101,11 +98,10 @@ private bool FetchCurrent()

return true;
}
else
{
hasCompleted = true;
return false;
}

hasCompleted = true;

return false;
}

public bool HasReachedMaxItems => Index == maxItems;
Expand Down
12 changes: 4 additions & 8 deletions Src/FluentAssertions/Common/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,8 @@ private static IEnumerable<TMemberInfo> GetMembersFromHierarchy<TMemberInfo>(
{
return GetInterfaceMembers(typeToReflect, getMembers);
}
else
{
return GetClassMembers(typeToReflect, getMembers);
}

return GetClassMembers(typeToReflect, getMembers);
}

private static List<TMemberInfo> GetInterfaceMembers<TMemberInfo>(Type typeToReflect,
Expand Down Expand Up @@ -471,10 +469,8 @@ public static bool IsAssignableToOpenGeneric(this Type type, Type definition)
{
return type.IsImplementationOfOpenGeneric(definition);
}
else
{
return type == definition || type.IsDerivedFromOpenGeneric(definition);
}

return type == definition || type.IsDerivedFromOpenGeneric(definition);
}

private static bool IsImplementationOfOpenGeneric(this Type type, Type definition)
Expand Down
5 changes: 4 additions & 1 deletion Src/FluentAssertions/Data/DataColumnAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,15 @@ public AndConstraint<DataColumnAssertions> BeEquivalentTo(DataColumn expectation
/// <item><description>Unique</description></item>
/// </list>
///
/// <para>
/// Testing of any property can be overridden using the <paramref name="config"/> callback. Exclude specific properties using
/// <see cref="IDataEquivalencyAssertionOptions{T}.Excluding(System.Linq.Expressions.Expression{Func{T, object}})"/>.
///
/// </para>
/// <para>
/// If <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingColumn(DataColumn)"/> or a related function is
/// used and the exclusion matches the subject <see cref="DataColumn"/>, then the equivalency test will never
/// fail.
/// </para>
/// </remarks>
/// <param name="expectation">A <see cref="DataColumn"/> with the expected configuration.</param>
/// <param name="config">
Expand Down
5 changes: 4 additions & 1 deletion Src/FluentAssertions/Data/DataRowAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,19 @@ public AndConstraint<DataRowAssertions<TDataRow>> BeEquivalentTo(DataRow expecta
/// <item><description>RowState</description></item>
/// </list>
///
/// <para>
/// The <see cref="DataRow"/> objects must be of the same type; if two <see cref="DataRow"/> objects
/// are equivalent in all ways, except that one is part of a typed <see cref="DataTable"/> and is of a subclass
/// of <see cref="DataRow"/>, then by default, they will not be considered equivalent.
///
/// </para>
/// <para>
/// This, as well as testing of any property can be overridden using the <paramref name="config"/> callback.
/// By calling <see cref="IDataEquivalencyAssertionOptions{T}.AllowingMismatchedTypes"/>, two <see cref="DataRow"/>
/// objects of differing types can be considered equivalent. Exclude specific properties using
/// <see cref="IDataEquivalencyAssertionOptions{T}.Excluding(System.Linq.Expressions.Expression{Func{T, object}})"/>.
/// Exclude columns of the data table (which also excludes the related field data in <see cref="DataRow"/>
/// objects) using <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingColumn(DataColumn)"/> or a related function.
/// </para>
/// </remarks>
///
/// You can use <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingRelated(System.Linq.Expressions.Expression{Func{DataTable, object}})"/>
Expand Down
11 changes: 8 additions & 3 deletions Src/FluentAssertions/Data/DataSetAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,26 +198,31 @@ public AndConstraint<DataSetAssertions<TDataSet>> BeEquivalentTo(DataSet expecta
/// <item><description>SchemaSerializationMode</description></item>
/// </list>
///
/// <para>
/// The <see cref="DataSet"/> objects must be of the same type; if two <see cref="DataSet"/> objects
/// are equivalent in all ways, except that one is a custom subclass of <see cref="DataSet"/> (e.g. to provide
/// typed accessors for <see cref="DataTable"/> values contained by the <see cref="DataSet"/>), then by default,
/// they will not be considered equivalent.
///
/// </para>
/// <para>
/// This, as well as testing of any property can be overridden using the <paramref name="config"/> callback.
/// By calling <see cref="IDataEquivalencyAssertionOptions{T}.AllowingMismatchedTypes"/>, two <see cref="DataSet"/>
/// objects of differing types can be considered equivalent. This setting applies to all types recursively tested
/// as part of the <see cref="DataSet"/>.
///
/// </para>
/// <para>
/// Exclude specific properties using <see cref="IDataEquivalencyAssertionOptions{T}.Excluding(System.Linq.Expressions.Expression{Func{T, object}})"/>.
/// Exclude specific tables within the data set using <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingTable(string)"/>
/// or a related function. You can also indicate that columns should be excluded within the <see cref="DataTable"/>
/// objects recursively tested as part of the <see cref="DataSet"/> using <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingColumn(DataColumn)"/>
/// or a related function. The <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingColumnInAllTables(string)"/> method
/// can be used to exclude columns across all <see cref="DataTable"/> objects in the <see cref="DataSet"/> that share
/// the same name.
///
/// </para>
/// <para>
/// You can use <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingRelated(System.Linq.Expressions.Expression{Func{DataTable, object}})"/>
/// and related functions to exclude properties on other related System.Data types.
/// </para>
/// </remarks>
/// <param name="expectation">A <see cref="DataColumn"/> with the expected configuration.</param>
/// <param name="config">
Expand Down
9 changes: 6 additions & 3 deletions Src/FluentAssertions/Data/DataTableAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,21 +219,24 @@ public AndConstraint<DataTableAssertions<TDataTable>> BeEquivalentTo(DataTable e
/// <item><description>PrimaryKey</description></item>
/// <item><description>Rows</description></item>
/// </list>
///
/// <para>
/// The <see cref="DataTable"/> objects must be of the same type; if two <see cref="DataTable"/> objects
/// are equivalent in all ways, except that one is a typed <see cref="DataTable"/> that is a subclass
/// of <see cref="DataTable"/>, then by default, they will not be considered equivalent.
///
/// </para>
/// <para>
/// This, as well as testing of any property can be overridden using the <paramref name="config"/> callback.
/// By calling <see cref="IDataEquivalencyAssertionOptions{T}.AllowingMismatchedTypes"/>, two <see cref="DataTable"/>
/// objects of differing types can be considered equivalent. Exclude specific properties using
/// <see cref="IDataEquivalencyAssertionOptions{T}.Excluding(System.Linq.Expressions.Expression{Func{T, object}})"/>.
/// Exclude columns of the data table using <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingColumn(DataColumn)"/>
/// or a related function -- this excludes both the <see cref="DataColumn"/> objects in <see cref="DataTable.Columns"/>
/// and associated field data in <see cref="DataRow"/> objects within the <see cref="DataTable"/>.
///
/// </para>
/// <para>
/// You can use <see cref="IDataEquivalencyAssertionOptions{T}.ExcludingRelated(System.Linq.Expressions.Expression{Func{DataTable, object}})"/>
/// and related functions to exclude properties on other related System.Data types.
/// </para>
/// </remarks>
/// <param name="expectation">A <see cref="DataColumn"/> with the expected configuration.</param>
/// <param name="config">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ public override string ToString()
return Invariant($"{{\"{path}\", {@object}}}");
}

public bool IsComplexType => isComplexType ?? (@object is not null && !@object.GetType().OverridesEquals());
public bool IsComplexType => isComplexType ?? (@object?.GetType().OverridesEquals() == false);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,13 @@ public MappedMemberMatchingRule(string expectationMemberName, string subjectMemb

public IMember Match(IMember expectedMember, object subject, INode parent, IEquivalencyAssertionOptions options)
{
if (parent.Type.IsSameOrInherits(typeof(TExpectation)) && subject is TSubject)
if (parent.Type.IsSameOrInherits(typeof(TExpectation)) && subject is TSubject &&
expectedMember.Name == expectationMemberName)
{
if (expectedMember.Name == expectationMemberName)
{
var member = MemberFactory.Find(subject, subjectMemberName, parent);

if (member is null)
{
throw new ArgumentException(
$"Subject of type {typeof(TSubject)} does not have member {subjectMemberName}");
}

return member;
}
var member = MemberFactory.Find(subject, subjectMemberName, parent);

return member ?? throw new ArgumentException(
$"Subject of type {typeof(TSubject)} does not have member {subjectMemberName}");
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ namespace FluentAssertions.Equivalency.Ordering;
/// </summary>
internal class ByteArrayOrderingRule : IOrderingRule
{
public OrderStrictness Evaluate(IObjectInfo memberInfo)
public OrderStrictness Evaluate(IObjectInfo objectInfo)
{
return memberInfo.CompileTimeType.IsSameOrInherits(typeof(IEnumerable<byte>))
return objectInfo.CompileTimeType.IsSameOrInherits(typeof(IEnumerable<byte>))
? OrderStrictness.Strict
: OrderStrictness.Irrelevant;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@ public OrderStrictness Evaluate(IObjectInfo objectInfo)
{
return Invert ? OrderStrictness.NotStrict : OrderStrictness.Strict;
}
else
{
return OrderStrictness.Irrelevant;
}

return OrderStrictness.Irrelevant;
}

private static bool ContainsIndexingQualifiers(string path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ public OrderStrictness Evaluate(IObjectInfo objectInfo)
{
return Invert ? OrderStrictness.NotStrict : OrderStrictness.Strict;
}
else
{
return OrderStrictness.Irrelevant;
}

return OrderStrictness.Irrelevant;
}

public override string ToString()
Expand Down
2 changes: 1 addition & 1 deletion Src/FluentAssertions/Equivalency/OrderingRuleCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ internal void Clear()
/// </summary>
public bool IsOrderingStrictFor(IObjectInfo objectInfo)
{
List<OrderStrictness> results = rules.Select(r => r.Evaluate(objectInfo)).ToList();
List<OrderStrictness> results = rules.ConvertAll(r => r.Evaluate(objectInfo));
return results.Contains(OrderStrictness.Strict) && !results.Contains(OrderStrictness.NotStrict);
}
}
Loading