Skip to content

Commit

Permalink
Improve unit tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
eminencegrs committed Feb 4, 2024
1 parent 618cb92 commit fafb30d
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/FPinFSharp.Exercises/Chapter_02/Exercises.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
namespace FPinFSharp.Exercises.Chapter_02

open System;

module Exercises =

// 2.1 Declare a function f: int -> bool such that f(n) = true
// exactly when n is divisible by 2 or divisible by 3 but not divisible by 5.
// Write down the expected values of f(24), f(27), f(29) and f(30) and compare with the result.
let f (x: int) : bool =
(x % 2 = 0 || x % 3 = 0) && x % 5 <> 0

// 2.2 Declare a function: string * int -> string, where: pow(s,n) = s · s · ... · s
// We use '·' to denote string concatenation. (The F# representation is '+'.).
let rec concatenateStringV1 (s: string, n: int) : string =
if n <= 0
then ""
else s + concatenateStringV1(s, n - 1)

let rec concatenateStringV2 (s: string, n: int) : string =
match n with
| _ when n <= 0 -> ""
| _ -> s + concatenateStringV2(s, n - 1)

// 2.3 Declare a function isIthChar: string * int * char -> bool
// where the value of isIthChar(str, i, ch) is true if and only
// if ch is the i’th character in the string str (numbering starting at zero).
let isIthCharV1 (str: string, i: int, ch: char) : bool =
if i < 0 then ArgumentOutOfRangeException() |> raise
str.IndexOf(ch) = i

let isIthCharV2 (str: string, i: int, ch: char) : bool =
if i < 0 then ArgumentOutOfRangeException() |> raise
let positions =
let rec inner (part: string, from: int, x: char) =
match from with
| _ when from >= str.Length -> []
| _ ->
if x = part.[from]
then from :: inner(part, from + 1, ch)
else inner(part, from + 1, ch)
inner(str, 0, ch)
List.contains i positions

// 2.4 Declare a function occFromIth: string * int * char -> int
// where occFromIth(str, i, ch) = the number of occurrences of character 'ch' in positions 'j'
// in the string 'str' with j ≥ i.
// Hint: the value should be 0 for i ≥ size str.
let rec occFromIth (str: string, from: int, ch: char) : int =
if from < 0 then ArgumentOutOfRangeException() |> raise
match from with
| _ when from >= str.Length -> 0
| _ ->
let current = str[from]
let sum = occFromIth(str, from + 1, ch)
if current = ch
then sum + 1
else sum

// 2.5 Declare the F# function occInString: string * char -> int
// where occInString(str, ch) = the number of occurrences of character ch in the string str.
let rec occInString (str: string, ch: char) : int =
let mutable sum = 0;
match str.Length with
| 0 -> sum
| _ ->
if ch = str.[0] then
sum <- sum + 1
sum + occInString(str.Substring(1), ch)
1 change: 1 addition & 0 deletions src/FPinFSharp.Exercises/FPinFSharp.Exercises.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<Compile Include="Chapter_02\Section_02_10.fs" />
<Compile Include="Chapter_02\Section_02_11.fs" />
<Compile Include="Chapter_02\Section_02_12.fs" />
<Compile Include="Chapter_02\Exercises.fs" />
<Content Include="Chapter_03\Description.md" />
</ItemGroup>

Expand Down
76 changes: 76 additions & 0 deletions tests/FPinFSharp.Exercises.UnitTests/Chapter_02/Exercises_Tests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
namespace FPinFSharp.Exercises.UnitTests.Chapter_02

open FPinFSharp.Exercises.Chapter_02.Exercises
open Shouldly
open Xunit

module Exercises_Tests =

// 2.1
[<Theory>]
[<InlineData(6, true)>]
[<InlineData(24, true)>]
[<InlineData(27, true)>]
[<InlineData(29, false)>]
[<InlineData(30, false)>]
let ``GIVEN x WHEN f THEN result as expected`` (x: int) (expectedResult: bool) =
let actualResult = f x
actualResult.ShouldBe(expectedResult)

// 2.2
[<Theory>]
[<InlineData("A", 3, "AAA")>]
[<InlineData("1 ", 5, "1 1 1 1 1 ")>]
[<InlineData(" x", 7, " x x x x x x x")>]
let ``GIVEN s and n WHEN concatenateStringV1 THEN result as expected`` (s: string) (n: int) (expectedResult: string) =
let actualResult = concatenateStringV1(s, n)
actualResult.ShouldBe(expectedResult)

[<Theory>]
[<InlineData("A", 3, "AAA")>]
[<InlineData("1 ", 5, "1 1 1 1 1 ")>]
[<InlineData(" x", 7, " x x x x x x x")>]
let ``GIVEN s and n WHEN concatenateStringV2 THEN result as expected`` (s: string) (n: int) (expectedResult: string) =
let actualResult = concatenateStringV2(s, n)
actualResult.ShouldBe(expectedResult)

[<Theory>]
[<InlineData("This is my string", 13, 'r', true)>]
[<InlineData("This is my string", 1, 'T', false)>]
[<InlineData("This is my string", 4, ' ', true)>]
[<InlineData("This is my string", 7, ' ', false)>]
[<InlineData("This is my string", 3, 's', true)>]
[<InlineData("This is my string", 6, 's', false)>]
let ``GIVEN str, i and ch WHEN isIthCharV1 THEN result as expected``
(str: string) (i: int) (ch: char) (expectedResult: bool) =
let actualResult = isIthCharV1(str, i, ch)
actualResult.ShouldBe(expectedResult)

[<Theory>]
[<InlineData("This is my string", 13, 'r', true)>]
[<InlineData("This is my string", 1, 'T', false)>]
[<InlineData("This is my string", 4, ' ', true)>]
[<InlineData("This is my string", 7, ' ', true)>]
[<InlineData("This is my string", 3, 's', true)>]
[<InlineData("This is my string", 6, 's', true)>]
let ``GIVEN str, i and ch WHEN isIthCharV2 THEN result as expected``
(str: string) (i: int) (ch: char) (expectedResult: bool) =
let actualResult = isIthCharV2(str, i, ch)
actualResult.ShouldBe(expectedResult)

[<Theory>]
[<InlineData("This is my string", 0, 'i', 3)>]
let ``GIVEN str, i and ch WHEN occFromIth THEN result as expected``
(str: string) (from: int) (ch: char) (expectedResult: int) =
let actualResult = occFromIth(str, from, ch)
actualResult.ShouldBe(expectedResult)

[<Theory>]
[<InlineData("This is my first string", 't', 2)>]
[<InlineData("This is my second string", 's', 4)>]
[<InlineData("This is my third string", 'r', 2)>]
[<InlineData("This is my fourth string", 'x', 0)>]
let ``GIVEN string and char WHEN occInString THEN result as expected``
(str: string) (ch: char) (expectedResult: int) =
let actualResult = occInString(str, ch)
actualResult.ShouldBe(expectedResult)

Check warning on line 76 in tests/FPinFSharp.Exercises.UnitTests/Chapter_02/Exercises_Tests.fs

View workflow job for this annotation

GitHub Actions / build

Main module of program is empty: nothing will happen when it is run

Check warning on line 76 in tests/FPinFSharp.Exercises.UnitTests/Chapter_02/Exercises_Tests.fs

View workflow job for this annotation

GitHub Actions / build

Main module of program is empty: nothing will happen when it is run
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<Compile Include="Chapter_02\Section_02_10_Tests.fs" />
<Compile Include="Chapter_02\Section_02_11_Tests.fs" />
<Compile Include="Chapter_02\Section_02_12_Tests.fs" />
<Compile Include="Chapter_02\Exercises_Tests.fs" />
<Folder Include="Chapter_03\" />
</ItemGroup>

Expand Down

0 comments on commit fafb30d

Please sign in to comment.