1
exercism fetch csharp diamond

DiamondTest.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using Xunit;
using FsCheck.Xunit;
using FsCheck;
using System;
using System.Linq;

public class DiamondTest
{
    public static readonly char[] AllLetters = GetLetterRange('A', 'Z');
    private static string[] Rows(string x) => x.Split(new[] { '\n' }, StringSplitOptions.None);

    private static string LeadingSpaces(string x) => x.Substring(0, x.IndexOfAny(AllLetters));
    private static string TrailingSpaces(string x) => x.Substring(x.LastIndexOfAny(AllLetters) + 1);
    private static char[] GetLetterRange(char min, char max) => Enumerable.Range(min, max - min + 1).Select(i => (char)i).ToArray();

    [DiamondProperty]
    public void Diamond_is_not_empty(char letter)
    {
        var actual = Diamond.Make(letter);

        Assert.NotEmpty(actual);
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void First_row_contains_a(char letter)
    {
        var actual = Diamond.Make(letter);
        var rows = Rows(actual);
        var firstRowCharacters = rows.First().Trim();

        Assert.Equal("A", firstRowCharacters);
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void All_rows_must_have_symmetric_contour(char letter)
    {
        var actual = Diamond.Make(letter);
        var rows = Rows(actual);

        Assert.All(rows, row =>
        {
            Assert.Equal(LeadingSpaces(row), TrailingSpaces(row));
        });
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void Top_of_figure_has_letters_in_correct_order(char letter)
    {
        var actual = Diamond.Make(letter);
        var rows = Rows(actual);

        var expected = GetLetterRange('A', letter);
        var firstNonSpaceLetters = rows.Take(expected.Length).Select(row => row.Trim()[0]);

        Assert.Equal(firstNonSpaceLetters, expected);
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void Figure_is_symmetric_around_the_horizontal_axis(char letter)
    {
        var actual = Diamond.Make(letter);

        var rows = Rows(actual);
        var top = rows.TakeWhile(row => !row.Contains(letter));
        var bottom = rows.Reverse().TakeWhile(row => !row.Contains(letter));

        Assert.Equal(bottom, top);
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void Diamond_has_square_shape(char letter)
    {
        var actual = Diamond.Make(letter);

        var rows = Rows(actual);
        var expected = rows.Length;

        Assert.All(rows, row =>
        {
            Assert.Equal(expected, row.Length);
        });
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void All_rows_except_top_and_bottom_have_two_identical_letters(char letter)
    {
        var actual = Diamond.Make(letter);

        var rows = Rows(actual).Where(row => !row.Contains('A'));

        Assert.All(rows, row =>
        {
            var twoCharacters = row.Replace(" ", "").Length == 2;
            var identicalCharacters = row.Replace(" ", "").Distinct().Count() == 1;
            Assert.True(twoCharacters && identicalCharacters, "Does not have two identical letters");
        });
    }

    [DiamondProperty(Skip = "Remove to run test")]
    public void Bottom_left_corner_spaces_are_triangle(char letter)
    {
        var actual = Diamond.Make(letter);

        var rows = Rows(actual);

        var cornerSpaces = rows.Reverse().SkipWhile(row => !row.Contains(letter)).Select(LeadingSpaces);
        var spaceCounts = cornerSpaces.Select(row => row.Length).ToList();
        var expected = Enumerable.Range(0, spaceCounts.Count).Select(i => i).ToList();

        Assert.Equal(expected, spaceCounts);
    }
}

public class DiamondPropertyAttribute : PropertyAttribute
{
    public DiamondPropertyAttribute()
    {
        Arbitrary = new[] { typeof(LettersOnlyStringArbitrary) };
    }
}

public static class LettersOnlyStringArbitrary
{
    public static Arbitrary<char> Chars()
    {
        return Arb.Default.Char().Filter(x => x >= 'A' && x <= 'Z');
    }
}