{-| 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