Skip to content

Commit

Permalink
Enumerable opening brace may be on a new line if children are large
Browse files Browse the repository at this point in the history
  • Loading branch information
benagain committed Apr 8, 2023
1 parent 85a15e4 commit 0d74c41
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 31 deletions.
33 changes: 11 additions & 22 deletions Src/FluentAssertions/Formatting/EnumerableValueFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,14 @@ public virtual bool CanHandle(object value)

public void Format(object value, FormattedObjectGraph formattedGraph, FormattingContext context, FormatChild formatChild)
{
int startCount = formattedGraph.LineCount;
IEnumerable<object> collection = ((IEnumerable)value).Cast<object>();

using var iterator = new Iterator<object>(collection, MaxItems);

var iteratorGraph = formattedGraph.StartPossibleMultilineFragment();

while (iterator.MoveNext())
{
if (iterator.IsFirst)
{
formattedGraph.AddFragment("{");
}

if (!iterator.HasReachedMaxItems)
{
formatChild(iterator.Index.ToString(CultureInfo.InvariantCulture), iterator.Current, formattedGraph);
Expand All @@ -49,34 +45,27 @@ public void Format(object value, FormattedObjectGraph formattedGraph, Formatting
{
using IDisposable _ = formattedGraph.WithIndentation();
string moreItemsMessage = value is ICollection c ? $"{c.Count - MaxItems} more…" : "…more…";
AddLineOrFragment(formattedGraph, startCount, moreItemsMessage);
iteratorGraph.AddLineOrFragment(moreItemsMessage);
}

if (iterator.IsFirst)
{
iteratorGraph.AddFragmentAtStart("{");
}

if (iterator.IsLast)
{
AddLineOrFragment(formattedGraph, startCount, "}");
iteratorGraph.AddLineOrFragment("}");
}
else
{
formattedGraph.AddFragment(", ");
iteratorGraph.AddFragmentAtEndOfLine(", ");
}
}

if (iterator.IsEmpty)
{
formattedGraph.AddFragment("{empty}");
}
}

private static void AddLineOrFragment(FormattedObjectGraph formattedGraph, int startCount, string fragment)
{
if (formattedGraph.LineCount > (startCount + 1))
{
formattedGraph.AddLine(fragment);
}
else
{
formattedGraph.AddFragment(fragment);
iteratorGraph.AddFragment("{empty}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;

namespace FluentAssertions.Formatting;

/// <summary>
/// Implementation of the contained PossibleMultilineFragment.
/// </summary>
public partial class FormattedObjectGraph
{
/// <summary>
/// Write fragments that may be on a single line or span multiple lines,
/// and this is not known until later parts of the fragment are written.
/// </summary>
internal record PossibleMultilineFragment
{
private readonly FormattedObjectGraph formattedGraph;
private readonly int startingLineBuilderIndex;
private readonly int startingLineCount;

public PossibleMultilineFragment(FormattedObjectGraph formattedGraph)
{
this.formattedGraph = formattedGraph;
startingLineBuilderIndex = formattedGraph.lineBuilder.Length;
startingLineCount = formattedGraph.lines.Count;
}

/// <summary>
/// Write the fragment at the position the graph was in when this instance was created.
///
/// <para>
/// If more lines have been added since this instance was created then write the
/// fragment on a new line, otherwise write it on the same line.
/// </para>
/// </summary>
internal void AddFragmentAtStart(string fragment)
{
if (FormatOnSingleLine)
{
formattedGraph.lineBuilder.Insert(startingLineBuilderIndex, fragment);
}
else
{
formattedGraph.lines.Insert(startingLineCount, Environment.NewLine + fragment);
InsertAtStartOfLine(startingLineCount + 1, MakeWhitespace(1));
}
}

private bool FormatOnSingleLine => formattedGraph.lines.Count == startingLineCount;

private void InsertAtStartOfLine(int lineIndex, string insertion)
{
formattedGraph.lines[lineIndex] = formattedGraph.lines[lineIndex].Insert(0, insertion);
}

/// <summary>
/// If more lines have been added since this instance was created then write the
/// fragment on a new line, otherwise write it on the same line.
/// </summary>
internal void AddLineOrFragment(string fragment)
{
if (FormatOnSingleLine)
{
formattedGraph.AddFragment(fragment);
}
else
{
formattedGraph.AddFragmentOnNewLine(fragment);
}
}

/// <summary>
/// Write the fragment. If more lines have been added since this instance was
/// created then also flush the line and indent the next line.
/// </summary>
internal void AddFragmentAtEndOfLine(string fragment)
{
if (FormatOnSingleLine)
{
formattedGraph.AddFragment(fragment);
}
else
{
formattedGraph.AddFragment(fragment);
formattedGraph.FlushCurrentLine();
formattedGraph.lineBuilderWhitespace += MakeWhitespace(1);
}
}

internal void AddFragment(string fragment) => formattedGraph.AddFragment(fragment);
}
}
14 changes: 11 additions & 3 deletions Src/FluentAssertions/Formatting/FormattedObjectGraph.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using FluentAssertions.Execution;

Expand All @@ -15,7 +16,7 @@ namespace FluentAssertions.Formatting;
/// to the maximum number of lines provided through its constructor. It will throw
/// a <see cref="MaxLinesExceededException"/> if the number of lines exceeds the maximum.
/// </remarks>
public class FormattedObjectGraph
public partial class FormattedObjectGraph
{
private readonly int maxLines;
private readonly List<string> lines = new();
Expand Down Expand Up @@ -139,5 +140,12 @@ public override string ToString()
return string.Join(Environment.NewLine, lines.Concat(new[] { lineBuilder.ToString() }));
}

private string Whitespace => new(' ', indentation * SpacesPerIndentation);
internal PossibleMultilineFragment StartPossibleMultilineFragment()
{
return new PossibleMultilineFragment(this);
}

private string Whitespace => MakeWhitespace(indentation);

private static string MakeWhitespace(int indent) => new(' ', indent * SpacesPerIndentation);
}
12 changes: 6 additions & 6 deletions Tests/FluentAssertions.Specs/Formatting/FormatterSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ public void When_the_object_is_a_generic_type_without_custom_string_representati
act.Should().Throw<XunitException>()
.And.Message.Should().Match(
"""
Expected stuff to be equal to {
Expected stuff to be equal to
{
FluentAssertions.Specs.Formatting.FormatterSpecs+Stuff`1[[System.Int32*]]
{
Children = {1, 2, 3, 4},
Expand All @@ -226,8 +227,8 @@ public void When_the_object_is_a_generic_type_without_custom_string_representati
Description = "WRONG_DESCRIPTION",
StuffId = 2
}
}
, but {
}, but
{
FluentAssertions.Specs.Formatting.FormatterSpecs+Stuff`1[[System.Int32*]]
{
Children = {1, 2, 3, 4},
Expand All @@ -240,8 +241,7 @@ public void When_the_object_is_a_generic_type_without_custom_string_representati
Description = "Stuff_2",
StuffId = 2
}
}
differs at index 1.
} differs at index 1.
""");
}

Expand Down Expand Up @@ -1139,7 +1139,7 @@ public void When_defining_a_custom_enumerable_value_formatter_it_should_respect_
// Act
string str = Formatter.ToString(values);

str.Should().Match(
str.Should().Match(Environment.NewLine +
"{*FluentAssertions*FormatterSpecs+CustomClass" + Environment.NewLine +
" {" + Environment.NewLine +
" IntProperty = 1, " + Environment.NewLine +
Expand Down

0 comments on commit 0d74c41

Please sign in to comment.