Created
September 17, 2024 10:22
-
-
Save rupertlssmith/c140437602e5ef2d6e8864473c7aa0c7 to your computer and use it in GitHub Desktop.
Revisions
-
rupertlssmith created this gist
Sep 17, 2024 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,68 @@ 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,256 @@ 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 ]