packages feed

cursor-gen-0.0.0.0: test/Cursor/TextFieldSpec.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Cursor.TextFieldSpec
    ( spec
    ) where

import Test.Hspec

import Test.QuickCheck
import Test.Validity

-- import Test.Validity.Optics
import Text.Show.Pretty (ppShow)

import qualified Data.Text as T

import qualified Data.List.NonEmpty as NE

import Control.Monad

import Cursor.TextField
import Cursor.TextField.Gen ()
import Cursor.Types

spec :: Spec
spec = do
    eqSpec @TextFieldCursor
    genValidSpec @TextFieldCursor
    describe "makeTextFieldCursor" $
        it "produces valid cursors" $ producesValidsOnValids makeTextFieldCursor
    describe "makeTextFieldCursorWithSelection" $ do
        it "produces valid cursors" $
            producesValidsOnValids3 makeTextFieldCursorWithSelection
        it
            "is the inverse of rebuildTextFieldCursor when using the current selection" $
            forAllValid $ \tfc -> do
                let (x, y) = textFieldCursorSelection tfc
                    t = rebuildTextFieldCursor tfc
                case makeTextFieldCursorWithSelection x y t of
                    Nothing ->
                        expectationFailure
                            "makeTextFieldCursorWithSelection should not have failed."
                    Just tfc' ->
                        unless (tfc' == tfc) $
                        expectationFailure $
                        unlines
                            [ "expected"
                            , ppShow tfc
                            , "actual"
                            , ppShow tfc'
                            , "The selection of the original (expected) cursor was:"
                            , show (x, y)
                            , "The rebuild text was:"
                            , show t
                            ]
    describe "rebuildTextFieldCursorLines" $ do
        it "produces valid lists" $
            producesValidsOnValids rebuildTextFieldCursorLines
        it "produces texts without newlines" $
            forAllValid $ \tfc -> do
                let ls = NE.toList $ rebuildTextFieldCursorLines tfc
                unless (all (T.all (/= '\n')) ls) $
                    expectationFailure $
                    unlines $
                    "Some of the following lines contain a newline:" :
                    map show ls
    describe "rebuildTextFieldCursor" $ do
        it "produces valid texts" $
            producesValidsOnValids rebuildTextFieldCursor
        it "is the inverse of makeTextFieldCursor for integers" $
            inverseFunctionsOnValid makeTextFieldCursor rebuildTextFieldCursor
        it
            "is the inverse of makeTextFieldCursorWithSelection for integers, for any index" $
            forAllValid $ \x ->
                forAllValid $ \y ->
                    inverseFunctionsIfFirstSucceedsOnValid
                        (makeTextFieldCursorWithSelection x y)
                        rebuildTextFieldCursor
    describe "textFieldCursorSelection" $
        it "produces valid tuples" $
        producesValidsOnValids textFieldCursorSelection
    describe "emptyTextFieldCursor" $
        it "is valid" $ shouldBeValid emptyTextFieldCursor
    describe "nullTextFieldCursor" $
        it "produces valid" $ producesValidsOnValids nullTextFieldCursor
    describe "textFieldCursorSelectPrevLine" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectPrevLine
        it "is a movement" $ isMovementM textFieldCursorSelectPrevLine
        it "selects the previous line" pending
    describe "textFieldCursorSelectNextLine" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectNextLine
        it "is a movement" $ isMovementM textFieldCursorSelectNextLine
        it "selects the next line" pending
    describe "textFieldCursorSelectFirstLine" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectFirstLine
        it "is a movement" $ isMovement textFieldCursorSelectFirstLine
        it "is idempotent" $ idempotentOnValid textFieldCursorSelectFirstLine
        it "selects the first line" pending
    describe "textFieldCursorSelectLastLine" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectLastLine
        it "is a movement" $ isMovement textFieldCursorSelectLastLine
        it "is idempotent" $ idempotentOnValid textFieldCursorSelectLastLine
        it "selects the last line" pending
    describe "textFieldCursorSelectPrevChar" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectPrevChar
        it "selects the previous character on the current line" pending
    describe "textFieldCursorSelectNextChar" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectNextChar
        it "selects the previous character on the current line" pending
    describe "textFieldCursorIndexOnLine" $ do
        it "produces valid indices" $
            producesValidsOnValids textFieldCursorIndexOnLine
        it "returns the index on the current line" pending
    describe "textFieldCursorSelectIndexOnLine" $ do
        it "produces valid cursors for any index" $
            producesValidsOnValids2 textFieldCursorSelectIndexOnLine
        it "selects the given index on the current line" pending
    describe "textFieldCursorInsertChar" $ do
        it "produces valid cursors" $
            forAllValid $ \d ->
                producesValidsOnValids (textFieldCursorInsertChar d)
        it "inserts a character before the cursor on the current line" pending
    describe "textFieldCursorAppendChar" $ do
        it "produces valid cursors" $
            forAllValid $ \d ->
                producesValidsOnValids (textFieldCursorAppendChar d)
        it "inserts a character after the cursor on the currrent line" pending
    describe "textFieldCursorInsertNewline" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorInsertNewline
        it "inserts a new line" pending
    describe "textFieldCursorAppendNewline" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorAppendNewline
    describe "textFieldCursorRemove" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorRemove
        it "removes empty text field cursor" $
            textFieldCursorRemove emptyTextFieldCursor `shouldBe` Just Deleted
        it "removes a character or a line" pending
    describe "textFieldCursorDelete" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorDelete
        it "removes empty text field cursor" $
            textFieldCursorDelete emptyTextFieldCursor `shouldBe` Just Deleted
        it "deletes a character or a line" pending
    describe "textFieldCursorSelectStartOfLine" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectStartOfLine
        it "selects the start of the current line" pending
    describe "textFieldCursorSelectEndOfLine" $ do
        it "produces valid cursors" $
            producesValidsOnValids textFieldCursorSelectEndOfLine
        it "selects the end of the current line" pending

isMovementM :: (TextFieldCursor -> Maybe TextFieldCursor) -> Property
isMovementM func =
    forAllValid $ \tfc ->
        case func tfc of
            Nothing -> pure () -- Fine
            Just tfc' ->
                let tf = rebuildTextFieldCursor tfc
                    tf' = rebuildTextFieldCursor tfc'
                 in unless (tf == tf') $
                    expectationFailure $
                    unlines
                        [ "Cursor before:\n" ++ show tfc
                        , "TextField before:  \n" ++ show tf
                        , "Cursor after: \n" ++ show tfc'
                        , "TextField after:   \n" ++ show tf'
                        ]

isMovement :: (TextFieldCursor -> TextFieldCursor) -> Property
isMovement func =
    forAllValid $ \tfc ->
        rebuildTextFieldCursor tfc `shouldBe` rebuildTextFieldCursor (func tfc)