module Data.Text.ParagraphLayout.Internal.ZipperSpec (spec) where import Control.Monad (forM_) import Data.Text (Text, empty, pack) import qualified Data.Text as Text import Test.Hspec import qualified Data.Text.ParagraphLayout.Internal.Zipper as Zipper sampleText :: Text sampleText = Text.dropEnd 6 $ Text.drop 4 $ pack "xxx Příliš žluťoučký kůň úpěl ďábelské ódy. yyyyy" sampleLength :: Int sampleLength = 39 midPositions :: [Int] midPositions = [1, 2, 5, 8, 38] preMidPositions :: [Int] preMidPositions = map pred midPositions spec :: Spec spec = do describe "start on empty text" $ do let z = Zipper.start empty it "is at start" $ Zipper.atStart z `shouldBe` True it "is at end" $ Zipper.atEnd z `shouldBe` True it "has nothing preceding it" $ Zipper.preceding z `shouldBe` empty it "has nothing following it" $ Zipper.following z `shouldBe` empty it "has no next character" $ Zipper.next z `shouldBe` Nothing it "recombines into empty text" $ Zipper.recombine z `shouldBe` empty it "unchanged by step" $ Zipper.step z `shouldBe` z it "unchanged by advance" $ Zipper.advanceBy 999 z `shouldBe` z describe "start" $ do let z = Zipper.start sampleText it "is at start" $ Zipper.atStart z `shouldBe` True it "is not at end" $ Zipper.atEnd z `shouldBe` False it "has nothing preceding it" $ Zipper.preceding z `shouldBe` empty it "has everything following it" $ Zipper.following z `shouldBe` sampleText it "has next character 'P'" $ Zipper.next z `shouldBe` Just 'P' it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText describe "split at zero" $ do let z = Zipper.splitAt 0 sampleText it "is at start" $ Zipper.atStart z `shouldBe` True it "is not at end" $ Zipper.atEnd z `shouldBe` False it "has nothing preceding it" $ Zipper.preceding z `shouldBe` empty it "has everything following it" $ Zipper.following z `shouldBe` sampleText it "has next character 'P'" $ Zipper.next z `shouldBe` Just 'P' it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText describe "split at negative value" $ do let z = Zipper.splitAt (-3) sampleText it "is at start" $ Zipper.atStart z `shouldBe` True it "is not at end" $ Zipper.atEnd z `shouldBe` False it "has nothing preceding it" $ Zipper.preceding z `shouldBe` empty it "has everything following it" $ Zipper.following z `shouldBe` sampleText it "has next character 'P'" $ Zipper.next z `shouldBe` Just 'P' it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText midPositions `forM_` \ n -> describe ("split at " ++ (show n)) $ do let z = Zipper.splitAt n sampleText it "is not at start" $ Zipper.atStart z `shouldBe` False it "is not at end" $ Zipper.atEnd z `shouldBe` False it ("preceding text has length " ++ show n) $ Text.length (Zipper.preceding z) `shouldBe` n it ("following text has length " ++ show (sampleLength - n)) $ Text.length (Zipper.following z) `shouldBe` (sampleLength - n) it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText preMidPositions `forM_` \ n -> describe ("split at " ++ (show n) ++ " and step") $ do let z = Zipper.step $ Zipper.splitAt n sampleText it "is not at start" $ Zipper.atStart z `shouldBe` False it "is not at end" $ Zipper.atEnd z `shouldBe` False it ("preceding text has length " ++ show (n + 1)) $ Text.length (Zipper.preceding z) `shouldBe` (n + 1) it ("following text has length " ++ show (sampleLength - n - 1)) $ Text.length (Zipper.following z) `shouldBe` (sampleLength - n - 1) it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText describe "start and advance by 3" $ do let z = Zipper.advanceBy 3 $ Zipper.start sampleText it "should be the same as splitting at 3" $ z `shouldBe` Zipper.splitAt 3 sampleText it "has next character 'l'" $ Zipper.next z `shouldBe` Just 'l' it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText describe "split at 4 and advance by 3" $ do let z = Zipper.advanceBy 3 $ Zipper.splitAt 4 sampleText it "should be the same as splitting at 7" $ z `shouldBe` Zipper.splitAt 7 sampleText it "has next character z-caron" $ Zipper.next z `shouldBe` Just 'ž' it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText describe "split past text bounds" $ do let z = Zipper.splitAt 999 sampleText it "is not at start" $ Zipper.atStart z `shouldBe` False it "is at end" $ Zipper.atEnd z `shouldBe` True it "has everything preceding it" $ Zipper.preceding z `shouldBe` sampleText it "has nothing following it" $ Zipper.following z `shouldBe` empty it "has no next character" $ Zipper.next z `shouldBe` Nothing it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText describe "split at 3 and advance past text bounds" $ do let z = Zipper.advanceBy sampleLength $ Zipper.splitAt 3 sampleText it "is not at start" $ Zipper.atStart z `shouldBe` False it "is at end" $ Zipper.atEnd z `shouldBe` True it "has everything preceding it" $ Zipper.preceding z `shouldBe` sampleText it "has nothing following it" $ Zipper.following z `shouldBe` empty it "has no next character" $ Zipper.next z `shouldBe` Nothing it "recombines into original text" $ Zipper.recombine z `shouldBe` sampleText