Solving the diamond kata with property-based testing series

  1. How to get started with Property-based Testing in C#
  2. Input generators in property-based tests with FsCheck
  3. First and Last line content
  4. Height equals Width
  5. Outside space symmetry
  6. Symmetry around the vertical axis
  7. Symmetry around the horizontal axis
  8. No padding for input letter row
  9. Letters order

All code samples are available on github


Intro

Last time, we discovered some interesting patterns with the diamond's global shape and found out that it's always quadratic. Today, we'll look at the space distribution around the diamond and try to figure out if there's a property hidden there that we could exploit.

Outside space symmetry

If you take each line individually, it seems there's a pattern where the outside space is equal on each side of that diamond line.

e.g.

For input E:
Line A has four spaces on the left and the right.
Line B has three spaces on the left and the right.
etc., you get the idea

input: E

----A---- 
---B-B--- 
--C---C-- 
-D-----D- 
E-------E 
-D-----D- 
--C---C-- 
---B-B--- 
----A---- 

C# Tests

[Property(Arbitrary = new[] { typeof(LetterGenerator) })]
public Property SpacesPerRowAreSymmetric(char c)
{
    return Diamond.Generate(c).All(row =>
        CountLeadingSpaces(row) == CountTrailingSpaces(row)
    ).ToProperty();
}

private int CountLeadingSpaces(string s)
{
    return s.IndexOf(GetCharInRow(s));
}

private int CountTrailingSpaces(string s)
{
    var i = s.LastIndexOf(GetCharInRow(s));
    return s.Length - i - 1;
}

private static char GetCharInRow(string row)
{
    return row.First(x => x != ' ');
}

Here we used some built-in methods of the .NET library, which makes these tests simple to read and short to write. I also created three helper methods; CountLeadingSpaces, CountTrailingSpaces, and GetCharInRow to make it more readable. It almost reads like a sentence.

  1. Diamond.Generate(c) Generates the diamond
  2. All() validates the inner condition for each line
  3. row => CountLeadingSpaces(row) == CountTrailingSpaces(row) validates that the number of spaces are equal on each side
  4. ToProperty() Transforms a boolean expression to a property

If you are wondering what's [Property(Arbitrary = new[] { typeof(LetterGenerator) })] it's probably because you missed my previous post

Wrapping up

This test is another excellent addition to our tests suite. Symmetry is a fascinating topic, and it's usually behind many properties. Speaking of which, is there any other symmetry that you can spot on the diamond kata? Let's discover it next time. Until then, don't forget to subscribe.


Solving the diamond kata with property-based testing series

  1. How to get started with Property-based Testing in C#
  2. Input generators in property-based tests with FsCheck
  3. First and Last line content
  4. Height equals Width
  5. Outside space symmetry
  6. Symmetry around the vertical axis
  7. Symmetry around the horizontal axis
  8. No padding for input letter row
  9. Letters order

All code samples are available on github