# Bank OCR kata in F#: user story 2 by Mark Seemann

Following up on my initial post about the Bank OCR kata, this post walks through the code required to implement user story 2, which is about calculating a checksum.

The code I previously described already contains a function called ParseToDigits which returns a sequence of digits, so it seems reasonable to express the validation function as based on a sequence of digits as input.

### The core unit test #

To ensure that the behavior of the new *IsValid* function would be correct, I wrote this Parameterized Test:

[<Theory>] [<InlineData(1, 2, 3, 4, 5, 6, 7, 8, 9, true)>] [<InlineData(3, 4, 5, 8, 8, 2, 8, 6, 5, true)>] [<InlineData(3, 4, 5, 8, 8, 2, 8, 1, 4, true)>] [<InlineData(7, 1, 5, 8, 8, 2, 8, 6, 4, true)>] [<InlineData(7, 4, 5, 8, 8, 2, 8, 6, 5, false)>] [<InlineData(7, 4, 5, 8, 8, 2, 8, 6, 9, false)>] [<InlineData(7, 4, 5, 8, 8, 2, 8, 6, 8, false)>] [<InlineData(1, 2, 3, 4, 5, 6, 7, 8, 8, false)>] [<InlineData(1, 3, 3, 4, 5, 6, 7, 8, 8, false)>] [<InlineData(1, 3, 3, 4, 5, 6, 7, 8, 0, false)>] let IsValidReturnsCorrectResult d9 d8 d7 d6 d5 d4 d3 d2 d1 expected = seq { yield! [d9; d8; d7; d6; d5; d4; d3; d2; d1] } |> IsValid |> should equal expected

As was the case for the previous tests, this test utilizes xUnit.net's data theories feature to succinctly express a parameterized test, as well as FsUnit for the assertion DSL.

Once again I'd like to point out how the use of pipes enables me to very compactly follow the Arrange Act Assert (AAA) test pattern.

### Implementation #

The IsValid function is very simple:

let IsValid digits = match digits |> Seq.toArray with | [| d9; d8; d7; d6; d5; d4; d3; d2; d1 |] -> (d1 + 2 * d2 + 3 * d3 + 4 * d4 + 5 * d5 + 6 * d6 + 7 * d7 + 8 * d8 + 9 * d9) % 11 = 0 | _ -> false

The input sequence is converted to an array by piping it into the Seq.toArray function. The resulting array is then matched against an expected shape.

If the array contains exactly 9 elements, each element is decomposed into a named variable (d9, d8, etc.) and passed to the correct checksum formula. The formula only returns true if the calculated result is zero; otherwise it returns false.

If the input doesn't match the expected pattern, the return value is false. The following tests prove this:

[<Fact>] let IsValidOfTooShortSequenceReturnsFalse() = seq { yield! [3; 4; 5; 8; 8; 2; 8; 6] } |> IsValid |> should equal false [<Fact>] let IsValidOfTooLongSequenceReturnsFalse() = seq { yield! [3; 4; 5; 8; 8; 2; 8; 6; 5; 7] } |> IsValid |> should equal false

In a future post I will walk you through user stories 3 and 4.

## Comments

Because of F# powerful type inference, that's what the function ends up doing anyway, but with TDD, it's the test that specifies the shape of the API, not the other way around.

However, I could also have written [d9; d8; d7; d6; d5; d4; d3; d2; d1] |> List.toSeq... There's no particular reason why I chose a sequence expression over that...