cursor-gen-0.0.0.0: test/Cursor/TextSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE RankNTypes #-}
module Cursor.TextSpec
( spec
) where
import Test.Hspec
import Test.QuickCheck
import Test.Validity
import Control.Monad
import Cursor.Text
import Cursor.Text.Gen ()
spec :: Spec
spec = do
eqSpec @TextCursor
genValidSpec @TextCursor
describe "emptyTextCursor" $ it "is valid" $ shouldBeValid emptyTextCursor
describe "makeTextCursor" $
it "produces valid list cursors" $ producesValidsOnValids makeTextCursor
describe "makeTextCursorWithSelection" $
it "produces valid list cursors" $
producesValidsOnValids2 makeTextCursorWithSelection
describe "rebuildTextCursor" $ do
it "produces valid lists" $ producesValidsOnValids rebuildTextCursor
it "is the inverse of makeTextCursor" $
inverseFunctionsIfFirstSucceedsOnValid
makeTextCursor
rebuildTextCursor
it "is the inverse of makeTextCursorWithSelection for any index" $
forAllUnchecked $ \i ->
inverseFunctionsIfFirstSucceedsOnValid
(makeTextCursorWithSelection i)
rebuildTextCursor
describe "textCursorNull" $
it "produces valid bools" $ producesValidsOnValids textCursorNull
describe "textCursorLength" $
it "produces valid ints" $ producesValidsOnValids textCursorLength
describe "textCursorIndex" $
it "produces valid indices" $ producesValidsOnValids textCursorIndex
describe "textCursorSelectPrev" $ do
it "produces valid cursors" $
producesValidsOnValids textCursorSelectPrev
it "is a movement" $ isMovementM textCursorSelectPrev
it "selects the previous position" pending
describe "textCursorSelectNext" $ do
it "produces valid cursors" $
producesValidsOnValids textCursorSelectNext
it "is a movement" $ isMovementM textCursorSelectNext
it "selects the next position" pending
describe "textCursorSelectIndex" $ do
it "produces valid cursors" $
producesValidsOnValids2 textCursorSelectIndex
it "is a movement" $
forAllUnchecked $ \ix -> isMovement (textCursorSelectIndex ix)
it "selects the position at the given index" pending
it
"produces a cursor that has the given selection for valid selections in the cursor" $
forAllValid $ \tc ->
forAll (choose (0, textCursorLength tc)) $ \i ->
textCursorIndex (textCursorSelectIndex i tc) `shouldBe` i
describe "textCursorSelectStart" $ do
it "produces valid cursors" $
producesValidsOnValids textCursorSelectStart
it "is a movement" $ isMovement textCursorSelectStart
it "is idempotent" $ idempotent textCursorSelectStart
it "selects the starting position" pending
describe "textCursorSelectEnd" $ do
it "produces valid cursors" $ producesValidsOnValids textCursorSelectEnd
it "is a movement" $ isMovement textCursorSelectEnd
it "is idempotent" $ idempotent textCursorSelectEnd
it "selects the end position" pending
describe "textCursorPrevChar" $ do
it "produces valid items" $ producesValidsOnValids textCursorPrevChar
it "returns the item before the position" pending
describe "textCursorNextChar" $ do
it "produces valid items" $ producesValidsOnValids textCursorNextChar
it "returns the item after the position" pending
describe "textCursorInsert" $ do
it "produces valids" $
forAllValid $ \d -> producesValidsOnValids (textCursorInsert d)
it "inserts an item before the cursor" $ pending
describe "textCursorAppend" $ do
it "produces valids" $
forAllValid $ \d -> producesValidsOnValids (textCursorAppend d)
it "inserts an item after the cursor" $ pending
describe "textCursorRemove" $ do
it "produces valids" $ validIfSucceedsOnValid textCursorRemove
it "removes an item before the cursor" $ pending
describe "textCursorDelete" $ do
it "produces valids" $ validIfSucceedsOnValid textCursorDelete
it "removes an item before the cursor" $ pending
describe "textCursorSplit" $ do
it "produces valids" $ producesValidsOnValids textCursorSplit
it
"produces two list cursors that rebuild to the rebuilding of the original" $
forAllValid $ \lc ->
let (lc1, lc2) = textCursorSplit lc
in (rebuildTextCursor lc1 <> rebuildTextCursor lc2) `shouldBe`
rebuildTextCursor lc
describe "textCursorCombine" $ do
it "produces valids" $ producesValidsOnValids2 textCursorCombine
it
"produces a list that rebuilds to the rebuilding of the original two cursors" $
forAllValid $ \lc1 ->
forAllValid $ \lc2 ->
let lc = textCursorCombine lc1 lc2
in rebuildTextCursor lc `shouldBe`
(rebuildTextCursor lc1 <> rebuildTextCursor lc2)
isMovementM :: (TextCursor -> Maybe TextCursor) -> Property
isMovementM func =
forAllValid $ \tc ->
case func tc of
Nothing -> pure () -- Fine
Just tc' ->
let t = rebuildTextCursor tc
t' = rebuildTextCursor tc'
in unless (t == t') $
expectationFailure $
unlines
[ "Cursor before:\n" ++ show tc
, "Text before: \n" ++ show t
, "Cursor after: \n" ++ show tc'
, "Text after: \n" ++ show t'
]
isMovement :: (TextCursor -> TextCursor) -> Property
isMovement func =
forAllValid $ \lec ->
rebuildTextCursor lec `shouldBe` rebuildTextCursor (func lec)