Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve formatting of multidimensional arrays (#991) #1044

Conversation

DmitriyMaksimov
Copy link
Contributor

  • Implemented formatting of multidimensional arrays (MultidimensionalArrayFormatter)
  • Added unit test for the formatter
  • Supported formatting of multidimensional arrays with bounds
  • Supported formatting of n-ary dimensional arrays

@DmitriyMaksimov
Copy link
Contributor Author

Test When_no_exception_should_be_thrown_after_wait_time_but_it_was_it_should_throw failed - think the test is "blinking" it has failed on my PC few times as well. Don't see why my changes could affect the test.

Copy link
Member

@dennisdoomen dennisdoomen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the work you've done. IMHO, it needs a bit of cleaning. I hope you're willing to spend a bit more time on this.


var indecies = Enumerable.Range(0, arr.Rank).Select(dimention => arr.GetLowerBound(dimention)).ToArray();

bool IsFirstIteration(int index, int dimention)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use local functions. This method is already extremely long and quite difficult to follow.

{
var arr = (Array)value;

if (arr.Length <= 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this ever be negative?

}

/// <inheritdoc />
public string Format(object value, FormattingContext context, FormatChild formatChild)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance you can break it down into smaller methods so that the algorithm is more clearer?

result.Should().Match("{{{'1-5-7', '1-5-8', '1-5-9', '1-5-10'}, {'1-6-7', '1-6-8', '1-6-9', '1-6-10'}, {'1-7-7', '1-7-8', '1-7-9', '1-7-10'}}, {{'2-5-7', '2-5-8', '2-5-9', '2-5-10'}, {'2-6-7', '2-6-8', '2-6-9', '2-6-10'}, {'2-7-7', '2-7-8', '2-7-9', '2-7-10'}}}".Replace("'", "\""));
}

public static IEnumerable<object[]> MultiDimentionalArrayData =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put this directly below the test method that needs it.

@@ -748,6 +748,65 @@ public void When_formatting_a_completion_source_it_should_include_the_underlying
result.Should().Match("*TaskCompletionSource*Task*System.Int32*Status=WaitingForActivation*");
}

[Theory]
[MemberData(nameof(MultiDimentionalArrayData))]
public void When_formatting_a_multi_dimentional_array_it_should_show_structure(object value, string expected)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please move these into a dedicated specs class? Most of what's here is pretty old and still needs to be split.

* Unit tests moved into a dedicated specs class
* MemberData moved directly below the test method that needs it
* Use private methods instead of local functions
@DmitriyMaksimov
Copy link
Contributor Author

@dennisdoomen Thanks for your code review!
I made requested changes except "Any chance you can break it down into smaller methods so that the algorithm is more clearer?" - it's a tricky one. Actually it's a while loop which emulates n-ary loop - have no idea how to split it. Saying that, I moved local functions out, so now the method is 58 lines and half of them are empty lines/brackets, so not as bad as used to be.
Please let me know if you spot another issue(s).

Copy link
Member

@jnyrup jnyrup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implemented algorithm and tests looks good to me.
I especially liked that you cover the case, where the array does not start at index 0.

I've given some comments which I think could help making the intent of the algorithm more clear.


var sb = new StringBuilder();

var indecies = Enumerable.Range(0, arr.Rank).Select(dimention => arr.GetLowerBound(dimention)).ToArray();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about dimensionIndices?


var sb = new StringBuilder();

var indecies = Enumerable.Range(0, arr.Rank).Select(dimention => arr.GetLowerBound(dimention)).ToArray();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dimention ->dimension

return sb.ToString();
}

private bool IsFirstIteration(Array arr, int index, int dimention)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dimention ->dimension

return index == arr.Rank - 1;
}

private bool IsLastIteration(Array arr, int index, int dimention)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dimention ->dimension

return index == arr.GetLowerBound(dimention);
}

private bool IsMostInnerLoop(Array arr, int index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsMostInnerLoop -> IsInnerMostLoop

return index >= arr.GetUpperBound(dimention);
}

private bool IsNotLastIteration(Array arr, int index, int dimention)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙃 I would leave out that function and just use !IsLastIteration directly.

// Emulate n-ary loop
while (currentLoopIndex >= 0)
{
var loopValue = indecies[currentLoopIndex];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would currentDimensionIndex be a more describing name for loopValue?

sb.Append(formatChild(string.Join("-", indecies), enumerator.Current));
if (IsNotLastIteration(arr, loopValue, currentLoopIndex))
sb.Append(", ");
++indecies[currentLoopIndex]; // Increment loop variable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put comments right above the statement.

if (currentLoopIndex < 0)
break;

// update loopValue and loopMaxValue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loopMaxValue does not exist.
From CSharpGuidelines

Try to focus comments on the why and what of a code block and not the how. Avoid explaining the statements in words, but instead help the reader understand why you chose a certain solution or algorithm and what you are trying to achieve. If applicable, also mention that you chose an alternative solution because you ran into a problem with the obvious solution. ...


var sb = new StringBuilder();

var indecies = Enumerable.Range(0, arr.Rank).Select(dimention => arr.GetLowerBound(dimention)).ToArray();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* Renamed variables
* Removed redundant comments
* Use explicit type instead of `var`
@DmitriyMaksimov
Copy link
Contributor Author

@jnyrup Thanks for your comments!
I made requested changes - they are improved code readability significantly.
Please review when you have a chance.

@jnyrup jnyrup merged commit 0ed6bbd into fluentassertions:master May 15, 2019
@jnyrup
Copy link
Member

jnyrup commented May 15, 2019

@DmitriyMaksimov Thanks for the contribution - Fluent Assertions just got one tad better.
Look out for your name in the next release.

@DmitriyMaksimov
Copy link
Contributor Author

Happy to contribute 😄
It's my first, but hope not last contribution into FluentAssertions.
Thank you very much for guiding me along the process!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants