Created
September 17, 2024 10:22
-
-
Save rupertlssmith/c140437602e5ef2d6e8864473c7aa0c7 to your computer and use it in GitHub Desktop.
Modal groups and tests for them in Elm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ModalGroup exposing (..) | |
{-| A ModalGroup is a collection of items, zero or one of which can be active at a time. | |
It is intended for modelling the behaviour of modal dialog boxes, where at most one dialog box can | |
be open at a time. | |
-} | |
import Dict exposing (Dict) | |
type ModalGroup k comparable a | |
= Group | |
{ active : Maybe k | |
, group : Dict comparable a | |
, keyFn : k -> comparable | |
} | |
{-| Empty grouping. | |
Map the key type of the group with a function, so that non-comparable keys can be used. | |
-} | |
empty : (k -> comparableKey) -> ModalGroup k comparableKey a | |
empty keyFn = | |
Group { active = Nothing, group = Dict.empty, keyFn = keyFn } | |
{-| Clears any active item. | |
-} | |
reset : ModalGroup k comparableKey a -> ModalGroup k comparableKey a | |
reset (Group record) = | |
Group { record | active = Nothing } | |
{-| Adds a new item to the group by its key. | |
-} | |
add : k -> a -> ModalGroup k comparableKey a -> ModalGroup k comparableKey a | |
add key value (Group record) = | |
let | |
compKey = | |
record.keyFn key | |
newGroup = | |
Dict.insert compKey value record.group | |
in | |
Group { record | group = newGroup } | |
{-| Sets the active item in the group. If no matching item can be found any active item will be cleared. | |
-} | |
active : k -> ModalGroup k comparableKey a -> ( ModalGroup k comparableKey a, Maybe a ) | |
active key (Group record) = | |
let | |
compKey = | |
record.keyFn key | |
maybeValue = | |
Dict.get compKey record.group | |
newActive = | |
maybeValue | |
|> Maybe.map (always key) | |
newRecord = | |
Group { record | active = newActive } | |
in | |
( newRecord, maybeValue ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ModalGroupTest exposing (..) | |
import Dict exposing (Dict) | |
import ModalGroup exposing (..) | |
import Expect | |
import Test exposing (..) | |
{-| Test that an empty ModalGroup has no active item and no items in the group. | |
-} | |
test_emptyModalGroup : Test | |
test_emptyModalGroup = | |
test "Empty ModalGroup has no active item and no items" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
in | |
case modalGroup of | |
Group record -> | |
Expect.all | |
[ \_ -> Expect.equal record.active Nothing | |
, \_ -> Expect.equal (Dict.size record.group) 0 | |
] | |
() | |
{-| Test that adding an item to the ModalGroup increases the group size. | |
-} | |
test_addItemToModalGroup : Test | |
test_addItemToModalGroup = | |
test "Add an item to ModalGroup" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
in | |
case modalGroup of | |
Group record -> | |
Expect.equal (Dict.size record.group) 1 | |
{-| Test that adding multiple items to the ModalGroup works correctly. | |
-} | |
test_addMultipleItemsToModalGroup : Test | |
test_addMultipleItemsToModalGroup = | |
test "Add multiple items to ModalGroup" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> add 2 "Item 2" | |
in | |
case modalGroup of | |
Group record -> | |
Expect.equal (Dict.size record.group) 2 | |
{-| Test activating an existing item updates the active item and returns the correct item. | |
-} | |
test_activateExistingItem : Test | |
test_activateExistingItem = | |
test "Activate an existing item" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> add 2 "Item 2" | |
( updatedGroup, maybeItem ) = | |
active 1 modalGroup | |
in | |
case updatedGroup of | |
Group record -> | |
Expect.all | |
[ \_ -> Expect.equal record.active (Just 1) | |
, \_ -> Expect.equal maybeItem (Just "Item 1") | |
] | |
() | |
{-| Test that activating a non-existing item resets the active item to Nothing. | |
-} | |
test_activateNonExistingItem : Test | |
test_activateNonExistingItem = | |
test "Activate a non-existing item resets active" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> add 2 "Item 2" | |
( updatedGroup, maybeItem ) = | |
active 3 modalGroup | |
in | |
case updatedGroup of | |
Group record -> | |
Expect.all | |
[ \_ -> Expect.equal record.active Nothing | |
, \_ -> Expect.equal maybeItem Nothing | |
] | |
() | |
{-| Test that resetting the ModalGroup clears any active item. | |
-} | |
test_resetClearsActiveItem : Test | |
test_resetClearsActiveItem = | |
test "Reset clears active item" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> (\mg -> Tuple.first (active 1 mg)) | |
|> reset | |
in | |
case modalGroup of | |
Group record -> | |
Expect.equal record.active Nothing | |
{-| Test that activating another item changes the active item. | |
-} | |
test_activateAnotherItem : Test | |
test_activateAnotherItem = | |
test "Active item changes when activating another item" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> add 2 "Item 2" | |
|> (\mg -> Tuple.first (active 1 mg)) | |
( updatedGroup, maybeItem ) = | |
active 2 modalGroup | |
in | |
case updatedGroup of | |
Group record -> | |
Expect.all | |
[ \_ -> Expect.equal record.active (Just 2) | |
, \_ -> Expect.equal maybeItem (Just "Item 2") | |
] | |
() | |
type CustomKey | |
= One | |
| Two | |
| Three | |
customKeyFn : CustomKey -> Int | |
customKeyFn ck = | |
case ck of | |
One -> | |
1 | |
Two -> | |
2 | |
Three -> | |
3 | |
{-| Test adding items with a custom key function using a custom type. | |
-} | |
test_addItemWithCustomKeyFunction : Test | |
test_addItemWithCustomKeyFunction = | |
test "Adding items with a custom key function using CustomKey type" <| | |
\_ -> | |
let | |
modalGroup = | |
empty customKeyFn | |
|> add One "Item One" | |
|> add Three "Item Three" | |
( updatedGroup, maybeItem ) = | |
active Three modalGroup | |
in | |
case updatedGroup of | |
Group record -> | |
Expect.all | |
[ \_ -> Expect.equal record.active (Just Three) | |
, \_ -> Expect.equal maybeItem (Just "Item Three") | |
, \_ -> Expect.equal (Dict.size record.group) 2 | |
] | |
() | |
{-| Test that items can be activated after resetting. | |
-} | |
test_activateAfterReset : Test | |
test_activateAfterReset = | |
test "Activating an item after reset" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> (\mg -> Tuple.first (active 1 mg)) | |
|> reset | |
( updatedGroup, maybeItem ) = | |
active 1 modalGroup | |
in | |
case updatedGroup of | |
Group record -> | |
Expect.all | |
[ \_ -> Expect.equal record.active (Just 1) | |
, \_ -> Expect.equal maybeItem (Just "Item 1") | |
] | |
() | |
{-| Test that adding an item with a duplicate key overwrites the existing item. | |
-} | |
test_addDuplicateKeyOverwritesItem : Test | |
test_addDuplicateKeyOverwritesItem = | |
test "Add duplicate keys overwrites the item" <| | |
\_ -> | |
let | |
modalGroup = | |
empty identity | |
|> add 1 "Item 1" | |
|> add 1 "Item 1 Updated" | |
maybeItem = | |
case modalGroup of | |
Group record -> | |
Dict.get 1 record.group | |
in | |
Expect.equal maybeItem (Just "Item 1 Updated") | |
{-| Collect all tests into a test suite. | |
-} | |
tests : Test | |
tests = | |
describe "ModalGroup Tests" | |
[ test_emptyModalGroup | |
, test_addItemToModalGroup | |
, test_addMultipleItemsToModalGroup | |
, test_activateExistingItem | |
, test_activateNonExistingItem | |
, test_resetClearsActiveItem | |
, test_activateAnotherItem | |
, test_addItemWithCustomKeyFunction | |
, test_activateAfterReset | |
, test_addDuplicateKeyOverwritesItem | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment