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
59 changes: 59 additions & 0 deletions Source/aweXpect.Reflection/Formatting/FormattableMember.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace aweXpect.Reflection.Formatting;

/// <summary>
/// Wraps a constructor, event, field, method or property, so that the formatters of this package format it.
/// </summary>
/// <remarks>
/// The formatter is registered for this type instead of the reflection types, which this package does not own, so
/// that formatting them outside of this package does not depend on whether a test used this package before.
/// </remarks>
internal sealed class FormattableMember
{
private static readonly IValueFormatter[] Formatters =
[
new ConstructorFormatter(), new EventFormatter(), new FieldFormatter(), new MethodFormatter(),
new PropertyFormatter(),
];

private readonly MemberInfo _member;

private FormattableMember(MemberInfo member)
{
_member = member;
}

/// <summary>
/// Wraps the <paramref name="value" /> if it is a constructor, event, field, method or property, otherwise
/// returns it unchanged.
/// </summary>
public static object? From(object? value)
=> value is ConstructorInfo or EventInfo or FieldInfo or MethodInfo or PropertyInfo
? new FormattableMember((MemberInfo)value)
: value;

/// <summary>
/// Wraps each of the <paramref name="values" /> with <see cref="From(object?)" />.
/// </summary>
/// <remarks>
/// A collection is copied, so that a truncated message still names the number of remaining items; any other
/// sequence stays lazy.
/// </remarks>
public static IEnumerable<object?> FromAll<T>(IEnumerable<T> values)
{
IEnumerable<object?> wrapped = values.Select(value => From(value));
return values is ICollection or ICollection<T> or IReadOnlyCollection<T> ? wrapped.ToArray() : wrapped;
}

internal sealed class MemberFormatter : IValueFormatter
{
public bool TryFormat(StringBuilder stringBuilder, object value, FormattingOptions? options)
=> value is FormattableMember formattableMember &&
Formatters.Any(formatter => formatter.TryFormat(stringBuilder, formattableMember._member, options));
}
}
14 changes: 4 additions & 10 deletions Source/aweXpect.Reflection/Formatting/FormatterRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,17 @@ namespace aweXpect.Reflection.Formatting;
internal static class FormatterRegistration
{
/// <summary>
/// Registers the reflection value formatters when the assembly is loaded.
/// Registers the formatter for the <see cref="FormattableMember" /> when the assembly is loaded.
/// </summary>
/// <remarks>
/// A module initializer keeps the registration reachable without reflection, so it survives trimming and
/// Native AOT - which is why CA2255 (discouraging module initializers in libraries) is suppressed here.
/// The registrations intentionally last for the lifetime of the process, hence the
/// <see cref="System.IDisposable" /> handles returned by <see cref="ValueFormatter.Register" /> are discarded.
/// The registration intentionally lasts for the lifetime of the process, hence the
/// <see cref="System.IDisposable" /> handle returned by <see cref="ValueFormatter.Register" /> is discarded.
/// </remarks>
#pragma warning disable CA2255
[ModuleInitializer]
internal static void Initialize()
{
ValueFormatter.Register(new ConstructorFormatter());
ValueFormatter.Register(new EventFormatter());
ValueFormatter.Register(new FieldFormatter());
ValueFormatter.Register(new MethodFormatter());
ValueFormatter.Register(new PropertyFormatter());
}
=> ValueFormatter.Register(new FormattableMember.MemberFormatter());
#pragma warning restore CA2255
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Core.EvaluationContext;
using aweXpect.Reflection.Formatting;

namespace aweXpect.Reflection.Helpers;

Expand Down Expand Up @@ -261,7 +262,7 @@ public override void AppendContexts(ResultContextCollector contexts)
/// state that is captured when this method is called.
/// </remarks>
protected virtual Func<string?> FormatItems(T[] items)
=> () => Formatter.Format(items, FormattingOptions.MultipleLines);
=> () => Formatter.Format(FormattableMember.FromAll(items), FormattingOptions.MultipleLines);

/// <inheritdoc cref="ConstraintResult.TryGetStoredValue{TValue}(out TValue)" />
public override bool TryGetStoredValue<TValue>(out TValue? value) where TValue : default
Expand Down
6 changes: 4 additions & 2 deletions Source/aweXpect.Reflection/Helpers/MemberViolationRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Reflection;
using System.Text;
using aweXpect.Core;
using aweXpect.Reflection.Formatting;

namespace aweXpect.Reflection.Helpers;

Expand All @@ -25,7 +26,8 @@ public static void AddMembersContext(this ResultContextCollector contexts, strin
if (members.Length > 0)
{
contexts.Add(new ResultContext.SyncCallback(title,
() => Formatter.Format(members, FormattingOptions.MultipleLines), int.MaxValue));
() => Formatter.Format(FormattableMember.FromAll(members), FormattingOptions.MultipleLines),
int.MaxValue));
}
}

Expand All @@ -52,7 +54,7 @@ public static string FormatTypesWithViolatingMembers(

if (type is not null && violations.TryGetValue(type, out MemberInfo[]? members))
{
stringBuilder.Append(memberHeader).Append(Formatter.Format(members));
stringBuilder.Append(memberHeader).Append(Formatter.Format(FormattableMember.FromAll(members)));
}

if (index < types.Count - 1)
Expand Down
11 changes: 6 additions & 5 deletions Source/aweXpect.Reflection/In.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Reflection;
using aweXpect.Customization;
using aweXpect.Reflection.Collections;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;

// ReSharper disable PossibleMultipleEnumeration
Expand Down Expand Up @@ -90,29 +91,29 @@ public static Filtered.Types Types(params IEnumerable<Type> types)
/// Defines expectations on the given <paramref name="constructors" />.
/// </summary>
public static Filtered.Constructors Constructors(params IEnumerable<ConstructorInfo> constructors)
=> new(constructors, $"in the constructors {Formatter.Format(constructors)}");
=> new(constructors, $"in the constructors {Formatter.Format(FormattableMember.FromAll(constructors))}");

/// <summary>
/// Defines expectations on the given <paramref name="events" />.
/// </summary>
public static Filtered.Events Events(params IEnumerable<EventInfo> events)
=> new(events, $"in the events {Formatter.Format(events)}");
=> new(events, $"in the events {Formatter.Format(FormattableMember.FromAll(events))}");

/// <summary>
/// Defines expectations on the given <paramref name="fields" />.
/// </summary>
public static Filtered.Fields Fields(params IEnumerable<FieldInfo> fields)
=> new(fields, $"in the fields {Formatter.Format(fields)}");
=> new(fields, $"in the fields {Formatter.Format(FormattableMember.FromAll(fields))}");

/// <summary>
/// Defines expectations on the given <paramref name="methods" />.
/// </summary>
public static Filtered.Methods Methods(params IEnumerable<MethodInfo> methods)
=> new(methods, $"in the methods {Formatter.Format(methods)}");
=> new(methods, $"in the methods {Formatter.Format(FormattableMember.FromAll(methods))}");

/// <summary>
/// Defines expectations on the given <paramref name="properties" />.
/// </summary>
public static Filtered.Properties Properties(params IEnumerable<PropertyInfo> properties)
=> new(properties, $"in the properties {Formatter.Format(properties)}");
=> new(properties, $"in the properties {Formatter.Format(FormattableMember.FromAll(properties))}");
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatConstructor.Has.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Reflection.Options;
using aweXpect.Reflection.Results;
Expand Down Expand Up @@ -70,7 +71,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" did not in ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -79,7 +80,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" did in ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatConstructor.IsStatic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

Expand Down Expand Up @@ -46,7 +47,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-static ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -55,7 +56,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was static ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatEvent.Has.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Reflection.Options;
using aweXpect.Reflection.Results;
Expand Down Expand Up @@ -78,7 +79,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" did not in ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -87,7 +88,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" did in ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatEvent.IsAbstract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

Expand Down Expand Up @@ -46,7 +47,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-abstract ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -55,7 +56,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was abstract ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatEvent.IsNullable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

Expand Down Expand Up @@ -55,7 +56,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-nullable ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -64,7 +65,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was nullable ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatEvent.IsSealed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

Expand Down Expand Up @@ -46,7 +47,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-sealed ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -55,7 +56,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was sealed ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatEvent.IsStatic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

Expand Down Expand Up @@ -46,7 +47,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-static ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -55,7 +56,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was static ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
5 changes: 3 additions & 2 deletions Source/aweXpect.Reflection/ThatEvent.IsVirtual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Formatting;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

Expand Down Expand Up @@ -46,7 +47,7 @@ protected override void AppendNormalExpectation(StringBuilder stringBuilder, str
protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-virtual ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Expand All @@ -55,7 +56,7 @@ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, st
protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was virtual ");
Formatter.Format(stringBuilder, Actual);
Formatter.Format(stringBuilder, FormattableMember.From(Actual));
}
}
}
Loading
Loading