packages feed

cursor-gen-0.0.0.0: test/Cursor/Simple/ForestSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cursor.Simple.ForestSpec
    ( spec
    ) where

import Data.Tree

import Control.Monad (unless)

import Test.Hspec

import Test.QuickCheck
import Test.Validity
import Test.Validity.Optics

import Cursor.Forest (ForestCursor(..))
import Cursor.List.NonEmpty
import Cursor.Simple.Forest hiding (ForestCursor)
import qualified Cursor.Simple.Forest as SFC (ForestCursor)
import Cursor.Tree
import Cursor.Types

import Cursor.Simple.Forest.Gen ()

spec :: Spec
spec = do
    eqSpec @(SFC.ForestCursor Int)
    genValidSpec @(SFC.ForestCursor Double)
    shrinkValidSpecWithLimit @(SFC.ForestCursor Double) 100
    describe "makeForestCursor" $
        it "produces valid cursors" $
        producesValidsOnValids (makeForestCursor @Double)
    describe "rebuildForestCursor" $ do
        it "produces valid forests" $
            producesValidsOnValids (rebuildForestCursor @Double)
        it "is the inverse of makeForestCursor for integers" $
            inverseFunctions (makeForestCursor @Int) rebuildForestCursor
    describe "forestCursorLestCursorL" $
        lensSpecOnValid (forestCursorListCursorL @Double @Double)
    describe "forestCursorSelectedTreeL" $
        lensSpecOnValid (forestCursorSelectedTreeL @Double @Double)
    describe "forestCursorSelection" $ do
        it "produces valid ints" $
            producesValidsOnValids (forestCursorSelection @Double @Double)
        it "returns the index of the currently selected element" pending
    describe "forestCursorSelectIndex" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorSelectIndex @Double)
        it "is the identity function when given the current selection" $
            forAllValid $ \fc ->
                forestCursorSelectIndex (forestCursorSelection fc) fc `shouldBe`
                Just (fc :: SFC.ForestCursor Double)
        it "returns selects the element at the given index" pending
    movementsSpec
    collapseSpec
    insertSpec
    swapSpec
    deleteSpec
    shiftingSpec

movementsSpec :: Spec
movementsSpec = do
    describe "forestCursorSelectPrevTreeCursor" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectPrevTreeCursor @Double
        it "is a movement" $ isMovementM forestCursorSelectPrevTreeCursor
        it "selects the previous tree cursor" pending
    describe "forestCursorSelectNextTreeCursor" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectNextTreeCursor @Double
        it "is a movement" $ isMovementM forestCursorSelectNextTreeCursor
        it "selects the next tree" pending
    describe "forestCursorSelectFirstTreeCursor" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectFirstTreeCursor @Double
        it "is a movement" $ isMovement forestCursorSelectFirstTreeCursor
        it "selects the first tree" pending
    describe "forestCursorSelectLastTreeCursor" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectLastTreeCursor @Double
        it "is a movement" $ isMovement forestCursorSelectLastTreeCursor
        it "selects the last tree" pending
    describe "forestCursorSelectPrev" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectPrev @Double
        it "is a movement" $ isMovementM forestCursorSelectPrev
        it "selects the previous node" pending
        -- TODO example with a collapsed tree
        it "Works for this classic example without any collapsing" $
            --   > 1
            --     > 2 <- expected end cursor
            --   > 3 <- start cursor
         do
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [ CNode 1 $
                                          openForest [CNode 2 $ emptyCForest]
                                        ]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 3 :: Int
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext = []
                                  }
                        }
                expected =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove =
                                                  Just
                                                      TreeAbove
                                                          { treeAboveAbove =
                                                                Nothing
                                                          , treeAboveLefts = []
                                                          , treeAboveNode = 1
                                                          , treeAboveRights = []
                                                          }
                                            , treeCurrent = 2
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 3 $ emptyCForest]
                                  }
                        }
            case forestCursorSelectPrev start of
                Nothing ->
                    expectationFailure
                        "forestCursorSelectPrev should not have failed."
                Just actual -> actual `forestShouldBe` expected
    describe "forestCursorSelectNext" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectNext @Double
        it "is a movement" $ isMovementM forestCursorSelectNext
        it "selects the next node" pending
        it "Works for this classic example" $
            --   > 1
            --     > 2 <- start cursor
            --   > 3 <- expected end cursor
         do
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove =
                                                  Just
                                                      TreeAbove
                                                          { treeAboveAbove =
                                                                Nothing
                                                          , treeAboveLefts = []
                                                          , treeAboveNode = 1
                                                          , treeAboveRights = []
                                                          }
                                            , treeCurrent = 2
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 3 $ emptyCForest]
                                  }
                        }
                expected =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [ CNode 1 $
                                          openForest [CNode 2 $ emptyCForest]
                                        ]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 3 :: Int
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext = []
                                  }
                        }
            case forestCursorSelectNext start of
                Nothing ->
                    expectationFailure
                        "forestCursorSelectNext should not have failed."
                Just actual -> actual `forestShouldBe` expected
    describe "forestCursorSelectPrevOnSameLevel" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectPrevOnSameLevel @Double
        it "is a movement" $ isMovementM forestCursorSelectPrevOnSameLevel
        it
            "selects the previous node on the same level as the current node"
            pending
    describe "forestCursorSelectNextOnSameLevel" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectNextOnSameLevel @Double
        it "is a movement" $ isMovementM forestCursorSelectNextOnSameLevel
        it "selects the next node on the same level as the current node" pending
    describe "forestCursorSelectFirst" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectFirst @Double
        it "is a movement" $ isMovement forestCursorSelectFirst
        it "selects the first node in the forest" pending
    describe "forestCursorSelectLast" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectLast @Double
        it "is a movement" $ isMovement forestCursorSelectLast
        it "selects the last node in the forest" pending
    describe "forestCursorSelectBelowAtPos" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 $ forestCursorSelectBelowAtPos @Double
        it "is a movement for any index" $
            forAllValid $ \i -> isMovementM $ forestCursorSelectBelowAtPos i
        it
            "selects the child of the selected node at the given position"
            pending
    describe "forestCursorSelectBelowAtStart" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectBelowAtStart @Double
        it "is a movement" $ isMovementM forestCursorSelectBelowAtStart
        it "selects the first child of the selected node" pending
    describe "forestCursorSelectBelowAtEnd" $ do
        it "produces valid cursors" $
            producesValidsOnValids $ forestCursorSelectBelowAtEnd @Double
        it "is a movement" $ isMovementM forestCursorSelectBelowAtEnd
        it "selects the first child of the selected node" pending

collapseSpec :: Spec
collapseSpec = do
    describe "forestCursorOpenCurrentForest" $
        it "produces valid cursors" $
        producesValidsOnValids $ forestCursorOpenCurrentForest @Double @Double
    describe "forestCursorCloseCurrentForest" $
        it "produces valid cursors" $
        producesValidsOnValids $ forestCursorCloseCurrentForest @Double @Double
    describe "forestCursorToggleCurrentForest" $
        it "produces valid cursors" $
        producesValidsOnValids $ forestCursorToggleCurrentForest @Double @Double

insertSpec :: Spec
insertSpec = do
    describe "forestCursorInsertEntireTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids2
                (forestCursorInsertEntireTree @Double @Double)
        it
            "inserts a tree cursor before the currently selected tree cursor"
            pending
    describe "forestCursorInsertAndSelectTreeCursor" $ do
        it "produces valid cursors" $
            producesValidsOnValids2
                (forestCursorInsertAndSelectTreeCursor @Double)
        it
            "inserts a tree cursor before the currently selected tree cursor and selects it"
            pending
    describe "forestCursorAppendEntireTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids2
                (forestCursorAppendEntireTree @Double @Double)
        it "appends a tree after the currently selected tree cursor" pending
    describe "forestCursorAppendAndSelectTreeCursor" $ do
        it "produces valid cursors" $
            producesValidsOnValids2
                (forestCursorAppendAndSelectTreeCursor @Double)
        it
            "appends a tree cursor after the currently selected tree cursor and selects it"
            pending
    describe "forestCursorInsertTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorInsertTree @Double @Double)
        it "inserts a tree before the currently selected tree" pending
    describe "forestCursorInsertAndSelectTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorInsertAndSelectTree @Double)
        it
            "inserts a tree before the currently selected tree and selects it"
            pending
    describe "forestCursorAppendTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorAppendTree @Double @Double)
        it "appends a tree after the currently selected tree " pending
    describe "forestCursorAppendAndSelectTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorAppendAndSelectTree @Double)
        it
            "appends a tree after the currently selected tree and selects it"
            pending
    describe "forestCursorInsert" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorInsert @Double @Double)
        it "inserts a node before the currently selected node" pending
    describe "forestCursorInsertAndSelect" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorInsertAndSelect @Double)
        it
            "inserts a node before the currently selected node and selects it"
            pending
    describe "forestCursorAppend" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorAppend @Double @Double)
        it "appends a node after the currently selected node" pending
    describe "forestCursorAppendAndSelect" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorAppendAndSelect @Double)
        it
            "appends a node after the currently selected node and selects it"
            pending
    describe "forestCursorAddChildTreeToNodeAtPos" $ do
        it "produces valid cursors" $
            producesValidsOnValids3 $
            forestCursorAddChildTreeToNodeAtPos @Double @Double
        it
            "adds a child tree to a node at the given position in the children of that node"
            pending
    describe "forestCursorAddChildTreeToNodeAtStart" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 $
            forestCursorAddChildTreeToNodeAtStart @Double @Double
        it
            "adds a child tree to a node at the start the children of that node"
            pending
    describe "forestCursorAddChildTreeToNodeAtEnd" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 $
            forestCursorAddChildTreeToNodeAtEnd @Double @Double
        it
            "adds a child tree to a node at the end the children of that node"
            pending
    describe "forestCursorAddChildToNodeAtPos" $ do
        it "produces valid cursors" $
            producesValidsOnValids3 $
            forestCursorAddChildToNodeAtPos @Double @Double
        it
            "adds a child to a node at the given position in the children of that node"
            pending
    describe "forestCursorAddChildToNodeAtStart" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 $
            forestCursorAddChildToNodeAtStart @Double @Double
        it
            "adds a child to a node at the start the children of that node"
            pending
    describe "forestCursorAddChildToNodeAtEnd" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 $
            forestCursorAddChildToNodeAtEnd @Double @Double
        it "adds a child to a node at the end the children of that node" pending
    describe "forestCursorAddRoot" $ do
        it "produces valid cursors" $
            producesValidsOnValids2 (forestCursorAddRoot @Double)
        it "houses the entire forest under the given node" pending

swapSpec :: Spec
swapSpec = do
    describe "forestCursorSwapPrev" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorSwapPrev @Double @Double)
        it "works on the example from the docs" $
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [CNode 'a' $ emptyCForest]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'b'
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext = []
                                  }
                        }
                end =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'b'
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'a' $ emptyCForest]
                                  }
                        }
             in case forestCursorSwapPrev start of
                    Nothing ->
                        expectationFailure
                            "forestCursorSwapPrev should not have failed."
                    Just r -> r `forestShouldBe` end
        it
            "swaps the current node with the previous node on the same level"
            pending
        it "reverts forestCursorSwapNext" $
            inverseFunctionsIfSucceedOnValid
                (forestCursorSwapNext @Double @Double)
                (forestCursorSwapPrev @Double @Double)
    describe "forestCursorSwapNext" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorSwapNext @Double @Double)
        it "works on the example from the docs" $
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'a'
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'b' $ emptyCForest]
                                  }
                        }
                end =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [CNode 'b' $ emptyCForest]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'a'
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext = []
                                  }
                        }
             in case forestCursorSwapNext start of
                    Nothing ->
                        expectationFailure
                            "forestCursorSwapNext should not have failed."
                    Just r -> r `forestShouldBe` end
        it "swaps the current node with the next node on the same level" pending
        it "reverts forestCursorSwapPrev" $
            inverseFunctionsIfSucceedOnValid
                (forestCursorSwapPrev @Double @Double)
                (forestCursorSwapNext @Double @Double)

deleteSpec :: Spec
deleteSpec = do
    describe "forestCursorRemoveElemAndSelectPrev" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorRemoveElemAndSelectPrev @Double)
        it "works for this simple example" $
            forAllValid $ \fs ->
                let simpleDeleteElemStart =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 1 :: Int
                                                , treeBelow =
                                                      closedForest [Node 2 fs]
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                 in case forestCursorRemoveElemAndSelectPrev
                             simpleDeleteElemStart of
                        Nothing -> pure ()
                        Just Deleted ->
                            expectationFailure
                                "forestCursorRemoveElemAndSelectPrev should not have deleted the entire example forest."
                        Just (Updated _) ->
                            expectationFailure
                                "forestCursorRemoveElemAndSelectPrev should not have updated the forest cursor, but failed instead."
        it
            "removes the selected element and selects the previous element"
            pending
    describe "forestCursorDeleteElemAndSelectNext" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorDeleteElemAndSelectNext @Double)
        it "works for this simple example" $
            forAllValid $ \fs ->
                let simpleDeleteElemStart =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 1
                                                , treeBelow =
                                                      closedForest [Node 2 fs]
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                    simpleDeleteElemExpected =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 2 :: Int
                                                , treeBelow = closedForest fs
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                 in case forestCursorDeleteElemAndSelectNext
                             simpleDeleteElemStart of
                        Nothing ->
                            expectationFailure
                                "forestCursorDeleteElemAndSelectNext should not have failed."
                        Just Deleted ->
                            expectationFailure
                                "forestCursorDeleteElemAndSelectNext should not have deleted the entire example forest."
                        Just (Updated f) ->
                            f `shouldBe` simpleDeleteElemExpected
        it "deletes the selected element and selects the next element" pending
    describe "forestCursorRemoveElem" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorRemoveElem @Double)
        it "works for this simple example" $
            forAllValid $ \fs ->
                let simpleDeleteElemStart =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 1
                                                , treeBelow =
                                                      closedForest [Node 2 fs]
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                    simpleDeleteElemExpected =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 2 :: Int
                                                , treeBelow = closedForest fs
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                 in case forestCursorRemoveElem simpleDeleteElemStart of
                        Deleted ->
                            expectationFailure
                                "forestCursorRemoveElem should not have deleted the entire example forest."
                        Updated f -> f `shouldBe` simpleDeleteElemExpected
        it "removes the selected element" pending
    describe "forestCursorDeleteElem" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorDeleteElem @Double)
        it "works for this simple example" $
            forAllValid $ \fs ->
                let simpleDeleteElemStart =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 1
                                                , treeBelow =
                                                      closedForest [Node 2 fs]
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                    simpleDeleteElemExpected =
                        ForestCursor
                            { forestCursorListCursor =
                                  NonEmptyCursor
                                      { nonEmptyCursorPrev = []
                                      , nonEmptyCursorCurrent =
                                            TreeCursor
                                                { treeAbove = Nothing
                                                , treeCurrent = 2 :: Int
                                                , treeBelow = closedForest fs
                                                }
                                      , nonEmptyCursorNext = []
                                      }
                            }
                 in case forestCursorDeleteElem simpleDeleteElemStart of
                        Deleted ->
                            expectationFailure
                                "forestCursorDeleteElem should not have deleted the entire example forest."
                        Updated f -> f `shouldBe` simpleDeleteElemExpected
        it "deletes the selected element" pending
    describe "forestCursorRemoveSubTreeAndSelectPrev" $ do
        it "produces valid cursors" $
            producesValidsOnValids
                (forestCursorRemoveSubTreeAndSelectPrev @Double)
        it "removes the selected subtree and selects the previous tree" pending
    describe "forestCursorDeleteSubTreeAndSelectNext" $ do
        it "produces valid cursors" $
            producesValidsOnValids
                (forestCursorDeleteSubTreeAndSelectNext @Double)
        it "deletes the selected subtree and selects the next tree" pending
    describe "forestCursorRemoveSubTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorRemoveSubTree @Double)
        it "removes the selected subtree" pending
    describe "forestCursorDeleteSubTree" $ do
        it "produces valid cursors" $
            producesValidsOnValids (forestCursorDeleteSubTree @Double)
        it "deletes the selected subtree" pending

shiftingSpec :: Spec
shiftingSpec = do
    describe "forestCursorPromoteElem" $ do
        it "produces valids on valids" $
            producesValidsOnValids $ forestCursorPromoteElem @Double
        it "works on the example from the documentation" $
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove =
                                                  Just
                                                      TreeAbove
                                                          { treeAboveLefts =
                                                                [ CNode 'b' $
                                                                  closedForest
                                                                      [ Node
                                                                            'c'
                                                                            []
                                                                      ]
                                                                ]
                                                          , treeAboveAbove =
                                                                Nothing
                                                          , treeAboveNode = 'a'
                                                          , treeAboveRights =
                                                                [ CNode 'f' $
                                                                  closedForest
                                                                      [ Node
                                                                            'g'
                                                                            []
                                                                      ]
                                                                ]
                                                          }
                                            , treeCurrent = 'd'
                                            , treeBelow =
                                                  closedForest [Node 'e' []]
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'h' $ emptyCForest]
                                  }
                        }
                expected =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [ CNode 'a' $
                                          openForest
                                              [ CNode 'b' $
                                                openForest
                                                    [ CNode 'c' emptyCForest
                                                    , CNode 'e' emptyCForest
                                                    ]
                                              , CNode 'f' $
                                                closedForest [Node 'g' []]
                                              ]
                                        ]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'd'
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'h' emptyCForest]
                                  }
                        }
             in case forestCursorPromoteElem start of
                    Nothing ->
                        expectationFailure
                            "forestCursorPromoteElem should not have failed."
                    Just f -> f `forestShouldBe` expected
        it "promotes the current node to the level of its parent" pending
    describe "forestCursorDemoteElem" $ do
        it "produces valids on valids" $
            producesValidsOnValids $ forestCursorDemoteElem @Double
        it "works on the example from the documentation" $
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [CNode 'a' $ closedForest [Node 'b' []]]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'c'
                                            , treeBelow =
                                                  closedForest [Node 'd' []]
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'e' emptyCForest]
                                  }
                        }
                expected =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove =
                                                  Just
                                                      TreeAbove
                                                          { treeAboveLefts =
                                                                [ CNode 'b' $
                                                                  emptyCForest
                                                                ]
                                                          , treeAboveAbove =
                                                                Nothing
                                                          , treeAboveNode = 'a'
                                                          , treeAboveRights =
                                                                [ CNode 'd' $
                                                                  emptyCForest
                                                                ]
                                                          }
                                            , treeCurrent = 'c'
                                            , treeBelow = emptyCForest
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'e' $ emptyCForest]
                                  }
                        }
             in case forestCursorDemoteElem start of
                    Nothing ->
                        expectationFailure
                            "forestCursorDemoteElem should not have failed."
                    Just f -> f `forestShouldBe` expected
        it "demotes the current node to the level of its children" pending
    describe "forestCursorPromoteSubTree" $ do
        it "produces valids on valids" $
            producesValidsOnValids $ forestCursorPromoteSubTree @Double
        it "works on the example from the documentation" $
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove =
                                                  Just
                                                      TreeAbove
                                                          { treeAboveLefts =
                                                                [ CNode 'b' $
                                                                  closedForest
                                                                      [ Node
                                                                            'c'
                                                                            []
                                                                      ]
                                                                ]
                                                          , treeAboveAbove =
                                                                Nothing
                                                          , treeAboveNode = 'a'
                                                          , treeAboveRights =
                                                                [ CNode 'f' $
                                                                  closedForest
                                                                      [ Node
                                                                            'g'
                                                                            []
                                                                      ]
                                                                ]
                                                          }
                                            , treeCurrent = 'd'
                                            , treeBelow =
                                                  closedForest [Node 'e' []]
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'h' emptyCForest]
                                  }
                        }
                expected =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [ CNode 'a' $
                                          openForest
                                              [ CNode 'b' $
                                                closedForest [Node 'c' []]
                                              , CNode 'f' $
                                                closedForest [Node 'g' []]
                                              ]
                                        ]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'd'
                                            , treeBelow =
                                                  closedForest [Node 'e' []]
                                            }
                                  , nonEmptyCursorNext =
                                        [CNode 'h' emptyCForest]
                                  }
                        }
             in case forestCursorPromoteSubTree start of
                    Nothing ->
                        expectationFailure
                            "forestCursorPromoteSubTree should not have failed."
                    Just f -> f `forestShouldBe` expected
        it "promotes the current subtree to the level of its parent" pending
    describe "forestCursorDemoteSubTree" $ do
        it "produces valids on valids" $
            producesValidsOnValids $ forestCursorDemoteSubTree @Double
        it "works on the example from the documentation" $
            let start =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev =
                                        [CNode 'a' $ closedForest [Node 'b' []]]
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove = Nothing
                                            , treeCurrent = 'c'
                                            , treeBelow =
                                                  closedForest [Node 'd' []]
                                            }
                                  , nonEmptyCursorNext = []
                                  }
                        }
                expected =
                    ForestCursor
                        { forestCursorListCursor =
                              NonEmptyCursor
                                  { nonEmptyCursorPrev = []
                                  , nonEmptyCursorCurrent =
                                        TreeCursor
                                            { treeAbove =
                                                  Just
                                                      TreeAbove
                                                          { treeAboveLefts =
                                                                [ CNode
                                                                      'b'
                                                                      emptyCForest
                                                                ]
                                                          , treeAboveAbove =
                                                                Nothing
                                                          , treeAboveNode = 'a'
                                                          , treeAboveRights = []
                                                          }
                                            , treeCurrent = 'c'
                                            , treeBelow =
                                                  closedForest [Node 'd' []]
                                            }
                                  , nonEmptyCursorNext = []
                                  }
                        }
             in case forestCursorDemoteSubTree start of
                    Nothing ->
                        expectationFailure
                            "forestCursorDemoteSubTree should not have failed."
                    Just f -> f `forestShouldBe` expected
        it "demotes the current subtree to the level of its children" pending
    describe "forestCursorDemoteElemUnder" $ do
        it "produces valids on valids" $
            producesValidsOnValids3 $
            forestCursorDemoteElemUnder @Double @Double
        it "Works on the example from the docs" $
            forAllValid $ \b1 ->
                forAllValid $ \b2 ->
                    let demoteStart =
                            ForestCursor $
                            NonEmptyCursor
                                { nonEmptyCursorPrev = []
                                , nonEmptyCursorCurrent =
                                      TreeCursor
                                          { treeAbove = Nothing
                                          , treeCurrent = 'a'
                                          , treeBelow =
                                                closedForest [Node 'b' []]
                                          }
                                , nonEmptyCursorNext = []
                                }
                        demoteEnd =
                            ForestCursor $
                            NonEmptyCursor
                                { nonEmptyCursorPrev = []
                                , nonEmptyCursorCurrent =
                                      TreeCursor
                                          { treeAbove =
                                                Just
                                                    TreeAbove
                                                        { treeAboveLefts = []
                                                        , treeAboveAbove =
                                                              Nothing
                                                        , treeAboveNode = b1
                                                        , treeAboveRights = []
                                                        }
                                          , treeCurrent = 'a'
                                          , treeBelow = emptyCForest
                                          }
                                , nonEmptyCursorNext =
                                      [CNode b2 $ closedForest [Node 'b' []]]
                                }
                     in forestCursorDemoteElemUnder b1 b2 demoteStart `forestShouldBe`
                        demoteEnd
        it "demotes the current node to the level of its children" pending
    describe "forestCursorDemoteSubTreeUnder" $ do
        it "produces valids on valids" $
            producesValidsOnValids2 $
            forestCursorDemoteSubTreeUnder @Double @Double
        it "Works on the example from the docs" $
            forAllValid $ \v -> do
                let demoteStart =
                        ForestCursor $
                        NonEmptyCursor
                            { nonEmptyCursorPrev = []
                            , nonEmptyCursorCurrent =
                                  TreeCursor
                                      { treeAbove = Nothing
                                      , treeCurrent = 'a'
                                      , treeBelow = closedForest [Node 'b' []]
                                      }
                            , nonEmptyCursorNext = []
                            }
                    demoteEnd =
                        ForestCursor $
                        NonEmptyCursor
                            { nonEmptyCursorPrev = []
                            , nonEmptyCursorCurrent =
                                  TreeCursor
                                      { treeAbove =
                                            Just
                                                TreeAbove
                                                    { treeAboveLefts = []
                                                    , treeAboveAbove = Nothing
                                                    , treeAboveNode = v
                                                    , treeAboveRights = []
                                                    }
                                      , treeCurrent = 'a'
                                      , treeBelow = closedForest [Node 'b' []]
                                      }
                            , nonEmptyCursorNext = []
                            }
                forestCursorDemoteSubTreeUnder v demoteStart `forestShouldBe`
                    demoteEnd
        it
            "demotes the current subtree to the level of its children, by adding a root"
            pending

isMovementM ::
       (forall a. SFC.ForestCursor a -> Maybe (SFC.ForestCursor a)) -> Property
isMovementM func =
    forAllValid @(SFC.ForestCursor Int) $ \lec ->
        case func lec of
            Nothing -> pure () -- Fine
            Just lec' ->
                let ne = rebuildForestCursor lec
                    ne' = rebuildForestCursor lec'
                 in unless (ne == ne') $
                    expectationFailure $
                    unlines
                        [ "Cursor before:\n" ++ show lec
                        , "Forest before:  \n" ++ show ne
                        , "Cursor after: \n" ++ show lec'
                        , "Forest after:   \n" ++ show ne'
                        ]

isMovement :: (forall a. SFC.ForestCursor a -> SFC.ForestCursor a) -> Property
isMovement func =
    forAllValid $ \lec ->
        rebuildForestCursor (lec :: SFC.ForestCursor Int) `shouldBe`
        rebuildForestCursor (func lec)

forestShouldBe ::
       (Show a, Eq a) => SFC.ForestCursor a -> SFC.ForestCursor a -> Expectation
forestShouldBe actual expected =
    unless (actual == expected) $
    expectationFailure $
    unlines
        [ "The following should have been equal."
        , "actual:"
        , drawForestCursor actual
        , "expected:"
        , drawForestCursor expected
        ]