monomer-1.0.0.0: test/unit/Monomer/Widgets/Containers/DragDropSpec.hs
{-|
Module : Monomer.Widgets.Containers.DragDropSpec
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 Drag and Drop related widgets.
-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Monomer.Widgets.Containers.DragDropSpec (spec) where
import Control.Lens ((&), (^.), (.~))
import Control.Lens.TH (abbreviatedFields, makeLensesWith)
import Data.Default
import Data.List (delete)
import Data.Sequence (Seq(..))
import Data.Text (Text)
import Test.Hspec
import qualified Data.Sequence as Seq
import qualified Data.Text as T
import Monomer.Core
import Monomer.Core.Combinators
import Monomer.Event
import Monomer.TestUtil
import Monomer.TestEventUtil
import Monomer.Widgets.Composite
import Monomer.Widgets.Containers.Draggable
import Monomer.Widgets.Containers.DropTarget
import Monomer.Widgets.Containers.Grid
import Monomer.Widgets.Containers.Stack
import Monomer.Widgets.Singles.Label
import qualified Monomer.Lens as L
data TestEvt
= DropTo1 Int
| DropTo2 Int
deriving (Eq, Show)
data TestItem = TestItem {
_tiIdx :: Int,
_tiMsg :: Text
} deriving (Eq, Show)
data TestModel = TestModel {
_tmItems1 :: [Int],
_tmItems2 :: [Int]
} deriving (Eq, Show)
makeLensesWith abbreviatedFields ''TestItem
makeLensesWith abbreviatedFields ''TestModel
spec :: Spec
spec = describe "Drag & Drop" $ do
handleEvent
getSizeReq
handleEvent :: Spec
handleEvent = describe "handleEvent" $ do
it "should leave items intact if drag is not completed" $ do
let selStart = Point 20 10
let selEnd = Point 20 100
let steps = evtDrag selStart selEnd
model steps ^. items1 `shouldBe` [1, 2, 3, 4, 5]
model steps ^. items2 `shouldBe` []
it "should update items list if drag was successful" $ do
let selStart = Point 20 10
let selEnd = Point 400 10
let steps = evtDrag selStart selEnd
model steps ^. items1 `shouldBe` [2, 3, 4, 5]
model steps ^. items2 `shouldBe` [1]
it "should both update items list if successive drags were successful" $ do
let selStart = Point 20 10
let selEnd = Point 400 10
let steps = evtDrag selStart selEnd
++ evtDrag selStart selEnd
++ evtDrag selStart selEnd
++ evtDrag selEnd selStart
model steps ^. items1 `shouldBe` [4, 5, 1]
model steps ^. items2 `shouldBe` [2, 3]
where
wenv = mockWenvEvtUnit (TestModel [1..5] [])
handleEvent wenv node model evt = case evt of
DropTo1 idx -> [Model $ model
& items2 .~ delete idx (model ^. items2)
& items1 .~ model ^. items1 ++ [idx]]
DropTo2 idx -> [Model $ model
& items1 .~ delete idx (model ^. items1)
& items2 .~ model ^. items2 ++ [idx]]
buildUI wenv model = hgrid [
dropTarget DropTo1 $ vstack (fmap dragLbl (model ^. items1)),
dropTarget DropTo2 $ vstack (fmap dragLbl (model ^. items2))
]
dragLbl idx = draggable idx (label "Label")
mainNode = composite "main" id buildUI handleEvent
model es = nodeHandleEventModel wenv es mainNode
getSizeReq :: Spec
getSizeReq = describe "getSizeReq" $ do
it "should return same reqW as child node" $ do
dgSizeReqW `shouldBe` lSizeReqW
dtSizeReqW `shouldBe` lSizeReqW
it "should return same reqH as child node" $ do
dgSizeReqH `shouldBe` lSizeReqH
dtSizeReqH `shouldBe` lSizeReqH
where
wenv = mockWenv (TestModel [] [])
item = TestItem 0 ""
lblNode = label "Test label"
(lSizeReqW, lSizeReqH) = nodeGetSizeReq wenv lblNode
(dgSizeReqW, dgSizeReqH) = nodeGetSizeReq wenv (draggable item lblNode)
(dtSizeReqW, dtSizeReqH) = nodeGetSizeReq wenv (dropTarget DropTo2 lblNode)