packages feed

monomer-1.0.0.0: test/unit/Monomer/Widgets/Util/TextSpec.hs

{-|
Module      : Monomer.Widgets.Util.TextSpec
Copyright   : (c) 2018 Francisco Vallarino
License     : BSD-3-Clause (see the LICENSE file)
Maintainer  : fjvallarino@gmail.com
Stability   : experimental
Portability : non-portable

Unit tests for Text handling.
-}
module Monomer.Widgets.Util.TextSpec (spec) where

import Control.Lens ((^.), ix)
import Data.Default
import Data.Text (Text)
import Test.Hspec

import qualified Data.Sequence as Seq

import Monomer.Core
import Monomer.Core.Combinators
import Monomer.Graphics
import Monomer.Widgets.Util.Text
import Monomer.TestUtil

import qualified Monomer.Lens as L

spec :: Spec
spec = describe "Text" $ do
  fitTextSingle
  fitTextMulti
  fitTextSpace

fitTextSingle :: Spec
fitTextSingle = describe "fitTextToSize single line" $ do
  it "should return the same empty text, trimmed (ellipsis)" $
    elpsTrim "" ^. ix 0 . L.text `shouldBe` ""

  it "should return the same empty text, untrimmed (ellipsis)" $
    elpsKeep "" ^. ix 0 . L.text `shouldBe` ""

  it "should return the same empty text, trimmed (clip)" $
    clipTrim "" ^. ix 0 . L.text `shouldBe` ""

  it "should return the same empty text, untrimmed (clip)" $
    clipKeep "" ^. ix 0 . L.text `shouldBe` ""

  it "should return the same text, trimmed, if it fits (ellipsis)" $
    elpsTrim "Text " ^. ix 0 . L.text `shouldBe` "Text"

  it "should return the same text, untrimmed, if it fits (ellipsis)" $
    elpsKeep "Text " ^. ix 0 . L.text `shouldBe` "Text "

  it "should return the same text, trimmed, if it fits (clip)" $
    clipTrim "Text " ^. ix 0 . L.text `shouldBe` "Text"

  it "should return the same text, untrimmed, if it fits (clip)" $
    clipKeep "Text " ^. ix 0 . L.text `shouldBe` "Text "

  it "should return text with ellipsis, trimmed, if it does not fit" $ do
    elpsTrim "This is longer\nMore" `shouldSatisfy` singleElement
    elpsTrim "This is longer\nMore" ^. ix 0 . L.text `shouldBe` "This is l..."
    elpsTrim "This is a bit longer\nMore" `shouldSatisfy` singleElement
    elpsTrim "This is a bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is a..."

  it "should return text with ellipsis, untrimmed, if it does not fit" $ do
    elpsKeep "This is longer\nMore" `shouldSatisfy` singleElement
    elpsKeep "This is longer\nMore" ^. ix 0 . L.text `shouldBe` "This is l..."
    elpsKeep "This is a bit longer\nMore" `shouldSatisfy` singleElement
    elpsKeep "This is a bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is a..."

  it "should return text clipped, trimmed, if it does not fit" $ do
    clipTrim "This is longer\nMore" `shouldSatisfy` singleElement
    clipTrim "This is longer\nMore" ^. ix 0 . L.text `shouldBe` "This is long"
    clipTrim "This is not a bit longer\nMore" `shouldSatisfy` singleElement
    clipTrim "This is not a bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is not"

  it "should return text clipped, untrimmed, if it does not fit" $ do
    clipKeep "This is longer\nMore" `shouldSatisfy` singleElement
    clipKeep "This is longer\nMore" ^. ix 0 . L.text `shouldBe` "This is long"
    clipKeep "This is not a bit longer\nMore" `shouldSatisfy` singleElement
    clipKeep "This is not a bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is not "

  where
    wenv = mockWenv ()
    fontMgr = wenv ^. L.fontManager
    style = def
    sizeE = Size 120 20
    sizeC = Size 120 10
    elpsTrim text = fitTextToSize fontMgr style Ellipsis SingleLine TrimSpaces Nothing sizeE text
    elpsKeep text = fitTextToSize fontMgr style Ellipsis SingleLine KeepSpaces Nothing sizeE text
    clipTrim text = fitTextToSize fontMgr style ClipText SingleLine TrimSpaces Nothing sizeC text
    clipKeep text = fitTextToSize fontMgr style ClipText SingleLine KeepSpaces Nothing sizeC text
    singleElement sq = Seq.length sq == 1

fitTextMulti :: Spec
fitTextMulti = describe "fitTextToSize multi line" $ do
  it "should return the same text, trimmed, if it fits" $ do
    elpsTrim "Text " `shouldSatisfy` elementCount 1
    elpsTrim "Text " ^. ix 0 . L.text `shouldBe` "Text"

  it "should return the same text, untrimmed, if it fits" $ do
    elpsKeep "Text " `shouldSatisfy` elementCount 1
    elpsKeep "Text " ^. ix 0 . L.text `shouldBe` "Text "

  -- Text.lines does not return an extra line if the last element is \n
  it "should return several empty lines" $ do
    elpsTrim_ sizeTall "Text\n\n\n\n" `shouldSatisfy` elementCount 4
    elpsKeep_ sizeTall "Text\n\n\n\n" `shouldSatisfy` elementCount 4
    clipTrim_ sizeTall "Text\n\n\n\n" `shouldSatisfy` elementCount 4
    clipKeep_ sizeTall "Text\n\n\n\n" `shouldSatisfy` elementCount 4

  it "should return several empty lines and one with text" $ do
    elpsTrim_ sizeTall "Text\n\n\n\nend" `shouldSatisfy` elementCount 5
    elpsKeep_ sizeTall "Text\n\n\n\nend" `shouldSatisfy` elementCount 5
    clipTrim_ sizeTall "Text\n\n\n\nend" `shouldSatisfy` elementCount 5
    clipKeep_ sizeTall "Text\n\n\n\nend" `shouldSatisfy` elementCount 5

  it "should return text with ellipsis, trimmed, if it does not fit" $ do
    elpsTrim "This is    really-long\nMore" `shouldSatisfy` elementCount 2
    elpsTrim "This is    really-long\nMore" ^. ix 0 . L.text `shouldBe` "This is"
    elpsTrim "This is    really-long\nMore" ^. ix 1 . L.text `shouldBe` "reall..."
    elpsTrim "This is    a tad bit longer\nMore" `shouldSatisfy` elementCount 2
    elpsTrim "This is    a tad bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is"
    elpsTrim "This is    a tad bit longer\nMore" ^. ix 1 . L.text `shouldBe` "a tad..."

  it "should return text with ellipsis, untrimmed, if it does not fit" $ do
    elpsKeep "This is    really-long\nMore" `shouldSatisfy` elementCount 2
    elpsKeep "This is    really-long\nMore" ^. ix 0 . L.text `shouldBe` "This is "
    elpsKeep "This is    really-long\nMore" ^. ix 1 . L.text `shouldBe` "   ..."
    elpsKeep "This is    a tad bit longer\nMore" `shouldSatisfy` elementCount 2
    elpsKeep "This is    a tad bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is "
    elpsKeep "This is    a tad bit longer\nMore" ^. ix 1 . L.text `shouldBe` "   a ..."

  it "should return text clipped, trimmed, if it does not fit" $ do
    clipTrim "This is    really-long\nMore" `shouldSatisfy` elementCount 3
    clipTrim "This is    really-long\nMore" ^. ix 0 . L.text `shouldBe` "This is"
    clipTrim "This is    really-long\nMore" ^. ix 1 . L.text `shouldBe` "really-long"
    clipTrim "This is    really-long\nMore" ^. ix 2 . L.text `shouldBe` "More"
    clipTrim "This is    a tad bit longer\nMore" `shouldSatisfy` elementCount 3
    clipTrim "This is    a tad bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is"
    clipTrim "This is    a tad bit longer\nMore" ^. ix 1 . L.text `shouldBe` "a tad"
    clipTrim "This is    a tad bit longer\nMore" ^. ix 2 . L.text `shouldBe` "bit"

  it "should return text clipped, untrimmed, if it does not fit" $ do
    clipKeep "This is    really-long\nMore" `shouldSatisfy` elementCount 3
    clipKeep "This is    really-long\nMore" ^. ix 0 . L.text `shouldBe` "This is "
    clipKeep "This is    really-long\nMore" ^. ix 1 . L.text `shouldBe` "   "
    clipKeep "This is    really-long\nMore" ^. ix 2 . L.text `shouldBe` "really-long"
    clipKeep "This is    a tad bit longer\nMore" `shouldSatisfy` elementCount 3
    clipKeep "This is    a tad bit longer\nMore" ^. ix 0 . L.text `shouldBe` "This is "
    clipKeep "This is    a tad bit longer\nMore" ^. ix 1 . L.text `shouldBe` "   a tad"
    clipKeep "This is    a tad bit longer\nMore" ^. ix 2 . L.text `shouldBe` " bit "

  where
    wenv = mockWenv ()
    fontMgr = wenv ^. L.fontManager
    style = def
    sizeE = Size 80 40
    sizeC = Size 80 50
    sizeTall = Size 80 200
    elpsTrim text = elpsTrim_ sizeE text
    elpsKeep text = elpsKeep_ sizeE text
    clipTrim text = clipTrim_ sizeC text
    clipKeep text = clipKeep_ sizeC text
    elpsTrim_ size text = fitTextToSize fontMgr style Ellipsis MultiLine TrimSpaces Nothing size text
    elpsKeep_ size text = fitTextToSize fontMgr style Ellipsis MultiLine KeepSpaces Nothing size text
    clipTrim_ size text = fitTextToSize fontMgr style ClipText MultiLine TrimSpaces Nothing size text
    clipKeep_ size text = fitTextToSize fontMgr style ClipText MultiLine KeepSpaces Nothing size text
    elementCount count sq = Seq.length sq == count

fitTextSpace :: Spec
fitTextSpace = describe "fitTextToWidth with spacing" $ do
  it "should fit text in (100, 80)" $
    textSize style longText `shouldBe` Size 100 80

  it "should fit text in (96, 120)" $
    textSize styleH longText `shouldBe` Size 96 120

  it "should fit text in (100, 95)" $
    textSize styleV longText `shouldBe` Size 100 95

  it "should fit text in (96, 145)" $
    textSize styleHV longText `shouldBe` Size 96 145

  where
    wenv = mockWenv ()
    fontMgr = wenv ^. L.fontManager
    style = def
    styleH = textSpaceH 2
    styleV = textSpaceV 5
    styleHV = textSpaceH 2 <> textSpaceV 5
    longText = "This is a long piece of text to test space"
    textSize style text = getTextLinesSize (fitTextToWidth fontMgr style 100 TrimSpaces text)