packages feed

monomer-1.2.0.0: test/unit/Monomer/Widgets/Singles/SliderSpec.hs

{-|
Module      : Monomer.Widgets.Singles.SliderSpec
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 Slider widget.
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}

module Monomer.Widgets.Singles.SliderSpec (spec) where

import Control.Lens ((&), (^.), (.~))
import Control.Lens.TH (abbreviatedFields, makeLensesWith)
import Data.Default
import Data.Sequence (Seq(..))
import Data.Text (Text)
import Test.Hspec

import qualified Data.Sequence as Seq

import Monomer.Core
import Monomer.Core.Combinators
import Monomer.Core.Themes.SampleThemes
import Monomer.Event
import Monomer.TestUtil
import Monomer.TestEventUtil
import Monomer.Widgets.Containers.Stack
import Monomer.Widgets.Singles.Slider

import qualified Monomer.Lens as L

data TestEvt
  = SliderChanged Double
  | GotFocus Path
  | LostFocus Path
  deriving (Eq, Show)

newtype TestModel = TestModel {
  _tmSliderVal :: Double
} deriving (Eq, Show)

makeLensesWith abbreviatedFields ''TestModel

spec :: Spec
spec = describe "Slider" $ do
  handleKeyboardH
  handleKeyboardV
  handleMouseDragH
  handleMouseDragV
  handleMouseDragThumb
  handleMouseDragValH
  handleMouseDragValV
  handleWheelH
  handleWheelValV
  handleShiftFocus
  getSizeReqH
  getSizeReqV
  getSizeReqThumb

handleKeyboardH :: Spec
handleKeyboardH = describe "handleKeyboardH" $ do
  it "should not change the value when using vertical arrows" $ do
    let steps = [evtK keyUp, evtK keyDown, evtK keyDown]
    model steps ^. sliderVal `shouldBe` 0

  it "should press arrow right ten times and set the slider value to 20" $ do
    let steps = replicate 10 (evtK keyRight)
    model steps ^. sliderVal `shouldBe` 20

  it "should press arrow right + shift ten times and set the slider value to 2" $ do
    let steps = replicate 10 (evtKS keyRight)
    model steps ^. sliderVal `shouldBe` 2

  it "should press arrow right + ctrl four times and set the slider value to 80" $ do
    let steps = replicate 4 (evtKG keyRight)
    model steps ^. sliderVal `shouldBe` 80

  it "should press arrow left ten times and set the slider value to -20" $ do
    let steps = replicate 10 (evtK keyLeft)
    model steps ^. sliderVal `shouldBe` (-20)

  it "should press arrow left + shift five times and set the slider value to 1" $ do
    let steps = replicate 5 (evtKS keyLeft)
    model steps ^. sliderVal `shouldBe` -1

  it "should press arrow right + ctrl one time and set the slider value to -20" $ do
    let steps = [evtKG keyLeft]
    model steps ^. sliderVal `shouldBe` (-20)

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    sliderNode = hslider sliderVal (-100) 100
    model es = nodeHandleEventModel wenv es sliderNode

handleKeyboardV :: Spec
handleKeyboardV = describe "handleKeyboardV" $ do
  it "should not change the value when using horizontal arrows" $ do
    let steps = [evtK keyLeft, evtK keyRight, evtK keyRight]
    model steps ^. sliderVal `shouldBe` 0

  it "should press arrow up ten times and set the slider value to 20" $ do
    let steps = replicate 10 (evtK keyUp)
    model steps ^. sliderVal `shouldBe` 20

  it "should press arrow up + shift ten times and set the slider value to 2" $ do
    let steps = replicate 10 (evtKS keyUp)
    model steps ^. sliderVal `shouldBe` 2

  it "should press arrow up + ctrl four times and set the slider value to 80" $ do
    let steps = replicate 4 (evtKG keyUp)
    model steps ^. sliderVal `shouldBe` 80

  it "should press arrow down ten times and set the slider value to -20" $ do
    let steps = replicate 10 (evtK keyDown)
    model steps ^. sliderVal `shouldBe` (-20)

  it "should press arrow down + shift five times and set the slider value to 1" $ do
    let steps = replicate 5 (evtKS keyDown)
    model steps ^. sliderVal `shouldBe` -1

  it "should press arrow up + ctrl one time and set the slider value to -20" $ do
    let steps = [evtKG keyDown]
    model steps ^. sliderVal `shouldBe` (-20)

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    sliderNode = vslider sliderVal (-100) 100
    model es = nodeHandleEventModel wenv es sliderNode

handleMouseDragH :: Spec
handleMouseDragH = describe "handleMouseDragH" $ do
  it "should not change the value when dragging vertically" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 120
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 0

  it "should drag 160 pixels right and set the slider value to 50" $ do
    let selStart = Point 320 240
    let selEnd = Point 480 240
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 50

  it "should drag 320 pixels right and set the slider value 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 640 240
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 100

  it "should drag 1000 pixels right, but stay on 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 1320 240
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 100

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    sliderNode = hslider sliderVal (-100) 100
    model es = nodeHandleEventModel wenv es sliderNode

handleMouseDragV :: Spec
handleMouseDragV = describe "handleMouseDragV" $ do
  it "should not change the value when dragging horizontally" $ do
    let selStart = Point 320 240
    let selEnd = Point 500 240
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 0

  it "should drag 100 pixels up and set the slider value to 50" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 120
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 50

  it "should drag 500 pixels up and set the slider value 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-260)
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 100

  it "should drag 1000 pixels up, but stay on 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-760)
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 100

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    sliderNode = vslider sliderVal (-100) 100
    model es = nodeHandleEventModel wenv es sliderNode

handleMouseDragThumb :: Spec
handleMouseDragThumb = describe "handleMouseDragThumb" $ do
  it "should not change the value when dragging horizontally" $ do
    let selStart = Point 320 240
    let selEnd = Point 500 240
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 0

  it "should drag 100 pixels up and set the slider value to 50" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 120
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 50

  it "should drag 500 pixels up and set the slider value 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-260)
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 100

  it "should drag 1000 pixels up, but stay on 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-760)
    let steps = evtDrag selStart selEnd
    model steps ^. sliderVal `shouldBe` 100

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    sliderNode = vslider_ sliderVal (-100) 100 [thumbVisible]
    model es = nodeHandleEventModel wenv es sliderNode

handleMouseDragValH :: Spec
handleMouseDragValH = describe "handleMouseDragValH" $ do
  it "should not change the value when dragging vertically" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 0
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList []

  it "should drag 160 pixels left and set the slider value to -250" $ do
    let selStart = Point 320 240
    let selEnd = Point 160 240
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [SliderChanged (-250.0)]

  it "should drag right to 640 and set the slider value 500" $ do
    let selStart = Point 320 240
    let selEnd = Point 640 240
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [SliderChanged 500]

  it "should drag 1000 pixels right, but stay on 500" $ do
    let selStart = Point 320 240
    let selEnd = Point 1000 240
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [SliderChanged 500]

  it "should click 160 pixels left and set the slider to -250" $ do
    let point = Point 160 240
    let steps = [evtRelease point]
    evts steps `shouldBe` Seq.fromList [SliderChanged (-250)]

  it "should generate an event when focus is received" $
    evts [evtFocus] `shouldBe` Seq.singleton (GotFocus emptyPath)

  it "should generate an event when focus is lost" $
    evts [evtBlur] `shouldBe` Seq.singleton (LostFocus emptyPath)

  where
    wenv = mockWenv (TestModel 500)
      & L.theme .~ darkTheme
    sliderNode = hsliderV_ 0 SliderChanged (-500) 500 [dragRate 1, onFocus GotFocus, onBlur LostFocus]
    evts es = nodeHandleEventEvts wenv es sliderNode

handleMouseDragValV :: Spec
handleMouseDragValV = describe "handleMouseDragValV" $ do
  it "should not change the value when dragging horizontally" $ do
    let selStart = Point 320 240
    let selEnd = Point 500 240
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList []

  it "should drag 100 pixels down and set the slider value to -250" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 360
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [SliderChanged (-250.0)]

  it "should drag up to zero and set the slider value 500" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 0
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [SliderChanged 500]

  it "should drag 1000 pixels up, but stay on 500" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-760)
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [SliderChanged 500]

  it "should click 120 pixels down and set the slider to -250" $ do
    let point = Point 320 360
    let steps = [evtRelease point]
    evts steps `shouldBe` Seq.fromList [SliderChanged (-250)]

  it "should generate an event when focus is received" $
    evts [evtFocus] `shouldBe` Seq.singleton (GotFocus emptyPath)

  it "should generate an event when focus is lost" $
    evts [evtBlur] `shouldBe` Seq.singleton (LostFocus emptyPath)

  where
    wenv = mockWenv (TestModel 500)
      & L.theme .~ darkTheme
    sliderNode = vsliderV_ 0 SliderChanged (-500) 500 [dragRate 1, onFocus GotFocus, onBlur LostFocus]
    evts es = nodeHandleEventEvts wenv es sliderNode

handleWheelH :: Spec
handleWheelH = describe "handleWheelH" $ do
  it "should update the model when using the wheel" $ do
    let p = Point 100 10
    let steps = [WheelScroll p (Point 0 100) WheelNormal]
    model steps ^. sliderVal `shouldBe` 300

  it "should generate IgnoreParentEvents when using the wheel" $ do
    let p = Point 100 10
    let steps = [WheelScroll p (Point 0 (-64)) WheelNormal]
    reqs steps `shouldSatisfy` (IgnoreParentEvents `elem`)

  where
    wenv = mockWenvEvtUnit (TestModel 200)
      & L.theme .~ darkTheme
    sliderNode = hslider_ sliderVal (-500) 500 [wheelRate 1]
    model es = nodeHandleEventModel wenv es sliderNode
    reqs es = nodeHandleEventReqs wenv es sliderNode

handleWheelValV :: Spec
handleWheelValV = describe "handleWheelValV" $ do
  it "should update the model when using the wheel" $ do
    let p = Point 100 10
    let steps = [WheelScroll p (Point 0 (-200)) WheelNormal]
    evts steps `shouldBe` Seq.singleton (SliderChanged (-200))

  where
    wenv = mockWenv (TestModel 0)
      & L.theme .~ darkTheme
    sliderNode = vsliderV_ 0 SliderChanged (-500) 500 [wheelRate 1]
    evts es = nodeHandleEventEvts wenv es sliderNode

handleShiftFocus :: Spec
handleShiftFocus = describe "handleShiftFocus" $ do
  it "should set focus when clicked" $ do
    evts [evtPress p] `shouldBe` Seq.fromList [GotFocus $ Seq.fromList [0, 0]]

  it "should not set focus when clicked with shift pressed" $ do
    evts [evtKS keyA, evtPress p] `shouldBe` Seq.empty

  where
    wenv = mockWenv (TestModel 0)
      & L.theme .~ darkTheme
    p = Point 100 30
    sliderNode = vstack [
        hslider_ sliderVal (-500) 500 [wheelRate 1] `styleBasic` [height 20],
        hslider_ sliderVal (-500) 500 [wheelRate 1, onFocus GotFocus] `styleBasic` [height 20]
      ]
    evts es = nodeHandleEventEvts wenv es sliderNode

getSizeReqH :: Spec
getSizeReqH = describe "getSizeReqH" $ do
  it "should return width = Expand 1000 1" $
    sizeReqW `shouldBe` expandSize 1000 1

  it "should return height = Fixed 10" $
    sizeReqH `shouldBe` fixedSize 10

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    (sizeReqW, sizeReqH) = nodeGetSizeReq wenv (hslider sliderVal 0 100)

getSizeReqV :: Spec
getSizeReqV = describe "getSizeReqV" $ do
  it "should return width = Fixed 10" $
    sizeReqW `shouldBe` fixedSize 10

  it "should return height = Expand 1000 1" $
    sizeReqH `shouldBe` expandSize 1000 1

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    (sizeReqW, sizeReqH) = nodeGetSizeReq wenv (vslider sliderVal 0 100)

getSizeReqThumb :: Spec
getSizeReqThumb = describe "getSizeReqThumb" $ do
  it "should return width = Fixed 10" $
    sizeReqW `shouldBe` fixedSize 10

  it "should return height = Expand 1000 1" $
    sizeReqH `shouldBe` expandSize 1000 1

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    (sizeReqW, sizeReqH) = nodeGetSizeReq wenv (vslider_ sliderVal 0 100 [thumbVisible])