1
exercism fetch fsharp diamond

DiamondTest.fs

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
module DiamondTest

open Diamond
open System
open FsUnit.Xunit
open Xunit
open FsCheck
open FsCheck.Xunit

let split (x: string) = x.Split([| '\n' |], StringSplitOptions.None)

let trim (x:string) = x.Trim()

let leadingSpaces (x:string) = x.Substring(0, x.IndexOfAny [|'A'..'Z'|])

let trailingSpaces (x:string) = x.Substring(x.LastIndexOfAny [|'A'..'Z'|] + 1)

type Letters =
    static member Chars () =
        Arb.Default.Char()
        |> Arb.filter (fun c -> 'A' <= c && c <= 'Z')

type DiamondPropertyAttribute () =
    inherit PropertyAttribute(Arbitrary = [| typeof<Letters> |])

[<DiamondProperty>]
let ``First row contains 'A'`` (letter:char) =
    let actual = make letter
    let rows = actual |> split
    let firstRowCharacters = rows |> Seq.head |> trim

    firstRowCharacters |> should equal "A"

[<DiamondProperty(Skip = "Remove to run test")>]
let ``All rows must have symmetric contour`` (letter:char) =
    let actual = make letter
    let rows = actual |> split
    let symmetric (row:string) = leadingSpaces row = trailingSpaces row

    rows |> Array.iter (fun x -> symmetric x |> should equal true)

[<DiamondProperty(Skip = "Remove to run test")>]
let ``Top of figure has letters in correct order`` (letter:char) =
    let actual = make letter

    let expected = ['A'..letter]
    let rows = actual |> split
    let firstNonSpaceLetters =
        rows 
        |> Seq.take expected.Length
        |> Seq.map (trim >> Seq.head)
        |> Seq.toList

    expected |> should equal firstNonSpaceLetters

[<DiamondProperty(Skip = "Remove to run test")>]
let ``Figure is symmetric around the horizontal axis`` (letter:char) =
    let actual = make letter

    let rows = actual |> split
    let top = 
        rows
        |> Seq.takeWhile (fun x -> not (x.Contains(string letter)))
        |> List.ofSeq
    
    let bottom = 
        rows 
        |> Array.rev
        |> Seq.takeWhile (fun x -> not (x.Contains(string letter)))
        |> List.ofSeq

    top |> should equal bottom

[<DiamondProperty(Skip = "Remove to run test")>]
let ``Diamond has square shape`` (letter:char) =
    let actual = make letter

    let rows = actual |> split
    let expected = rows.Length
    let correctWidth (x:string) = x.Length = expected

    rows |> Array.iter (fun x -> correctWidth x |> should equal true)

[<DiamondProperty(Skip = "Remove to run test")>]
let ``All rows except top and bottom have two identical letters`` (letter:char) =
    let actual = make letter

    let rows = 
        actual 
        |> split 
        |> Array.filter (fun x -> not (x.Contains("A")))

    let twoIdenticalLetters (row:string) = 
        let twoCharacters = row.Replace(" ", "").Length = 2
        let identicalCharacters = row.Replace(" ", "") |> Seq.distinct |> Seq.length = 1
        twoCharacters && identicalCharacters

    rows |> Array.iter (fun x -> twoIdenticalLetters x |> should equal true)

[<DiamondProperty(Skip = "Remove to run test")>]
let ``Bottom left corner spaces are triangle`` (letter:char) =
    let actual = make letter

    let rows = actual |> split
    
    let cornerSpaces = 
        rows 
        |> Array.rev
        |> Seq.skipWhile (fun x -> not (x.Contains(string letter)))
        |> Seq.map leadingSpaces
        |> Seq.toList

    let spaceCounts = 
        cornerSpaces 
        |> List.map (fun x -> x.Length)

    let expected = 
        Seq.initInfinite id
        |> Seq.take spaceCounts.Length
        |> Seq.toList

    spaceCounts |> should equal expected