packages feed

monomer-1.3.0.0: test/unit/Monomer/Widgets/Singles/DialSpec.hs

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

module Monomer.Widgets.Singles.DialSpec (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.Dial

import qualified Monomer.Lens as L

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

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

makeLensesWith abbreviatedFields ''TestModel

spec :: Spec
spec = describe "Dial" $ do
  handleKeyboard
  handleMouseDrag
  handleMouseDragVal
  handleWheel
  handleWheelVal
  handleShiftFocus
  getSizeReq
  testWidgetType

handleKeyboard :: Spec
handleKeyboard = describe "handleKeyboard" $ do
  it "should press arrow up ten times and set the dial value to 20" $ do
    let steps = replicate 10 (evtK keyUp)
    model steps ^. dialVal `shouldBe` 20

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

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

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

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

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

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    dialNode = dial dialVal (-100) 100
    model es = nodeHandleEventModel wenv es dialNode

handleMouseDrag :: Spec
handleMouseDrag = describe "handleMouseDrag" $ do
  it "should not change the value when dragging off bounds" $ do
    let selStart = Point 0 0
    let selEnd = Point 0 100
    let steps = evtDrag selStart selEnd
    model steps ^. dialVal `shouldBe` 0

  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 ^. dialVal `shouldBe` 0

  it "should drag 100 pixels up and set the dial value to 20" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 140
    let steps = evtDrag selStart selEnd
    model steps ^. dialVal `shouldBe` 20

  it "should drag 500 pixels up and set the dial value 100" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-260)
    let steps = evtDrag selStart selEnd
    model steps ^. dialVal `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 ^. dialVal `shouldBe` 100

  where
    wenv = mockWenvEvtUnit (TestModel 0)
      & L.theme .~ darkTheme
    dialNode = dial dialVal (-100) 100
    model es = nodeHandleEventModel wenv es dialNode

handleMouseDragVal :: Spec
handleMouseDragVal = describe "handleMouseDragVal" $ do
  it "should not change the value when dragging off bounds" $ do
    let selStart = Point 0 0
    let selEnd = Point 0 100
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList []

  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 up and set the dial value to 110" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 140
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [DialChanged 110]

  it "should drag 490 pixels up and set the dial value 500" $ do
    let selStart = Point 320 240
    let selEnd = Point 320 (-250)
    let steps = evtDrag selStart selEnd
    evts steps `shouldBe` Seq.fromList [DialChanged 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 [DialChanged 500]

  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 0)
      & L.theme .~ darkTheme
    dialNode = dialV_ 10 DialChanged (-500) 500 [dragRate 1, onFocus GotFocus, onBlur LostFocus]
    evts es = nodeHandleEventEvts wenv es dialNode

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

  where
    wenv = mockWenvEvtUnit (TestModel 200)
      & L.theme .~ darkTheme
    dialNode = dial_ dialVal (-500) 500 [wheelRate 1]
    model es = nodeHandleEventModel wenv es dialNode

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

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

  where
    wenv = mockWenv (TestModel 0)
      & L.theme .~ darkTheme
    dialNode = dialV_ 0 DialChanged (-500) 500 [wheelRate 1]
    evts es = nodeHandleEventEvts wenv es dialNode
    reqs es = nodeHandleEventReqs wenv es dialNode

handleShiftFocus :: Spec
handleShiftFocus = describe "handleShiftFocus" $ do
  it "should set focus when clicked" $ do
    evts [evtPress p] `shouldBe` Seq.fromList [GotFocus $ Seq.fromList [0, 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 25 50
    dialNode = hstack [
        vstack [
          dial_ dialVal (-500) 500 [wheelRate 1],
          dial_ dialVal (-500) 500 [wheelRate 1, onFocus GotFocus]
        ]
      ]
    evts es = nodeHandleEventEvts wenv es dialNode

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

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

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

testWidgetType :: Spec
testWidgetType = describe "testWidgetType" $ do
  it "should set the correct widgetType" $
    node ^. L.info . L.widgetType `shouldBe` "dial-Double"

  where
    node :: WidgetNode TestModel TestEvt
    node = dial dialVal 0 100