packages feed

taffybar-7.2.0: test/unit/System/Taffybar/Information/Workspaces/HyprlandSpec.hs

module System.Taffybar.Information.Workspaces.HyprlandSpec (spec) where

import Data.Text qualified as T
import System.Taffybar.Information.Workspaces.Hyprland
  ( applySpecialWorkspaceWindowTargets,
    sortWorkspaceInfos,
    specialWorkspaceWindowsToMinimized,
  )
import System.Taffybar.Information.Workspaces.Model
import Test.Hspec

mkWindow :: T.Text -> Bool -> WindowInfo
mkWindow title minimized =
  WindowInfo
    { windowIdentity = HyprlandWindowIdentity title,
      windowUpdateRevision = 0,
      windowTitle = title,
      windowClassHints = [],
      windowPosition = Nothing,
      windowUrgent = False,
      windowActive = False,
      windowMinimized = minimized,
      windowPinned = False
    }

mkWorkspace ::
  Maybe Int ->
  T.Text ->
  WorkspaceViewState ->
  Bool ->
  [WindowInfo] ->
  WorkspaceInfo
mkWorkspace idx name state special windows =
  WorkspaceInfo
    { workspaceIdentity =
        WorkspaceIdentity
          { workspaceNumericId = idx,
            workspaceName = name
          },
      workspaceUpdateRevision = 0,
      workspaceState = state,
      workspaceHasUrgentWindow = any windowUrgent windows,
      workspaceIsSpecial = special,
      workspaceWindows = windows
    }

workspaceByName :: T.Text -> [WorkspaceInfo] -> WorkspaceInfo
workspaceByName name workspaces =
  case filter ((== name) . workspaceName . workspaceIdentity) workspaces of
    [workspace] -> workspace
    [] -> error $ "Expected workspace named " <> T.unpack name
    _ -> error $ "Expected one workspace named " <> T.unpack name

spec :: Spec
spec = do
  describe "sortWorkspaceInfos" $
    it "orders normal numeric workspaces before special workspaces" $ do
      let specialMinimized =
            mkWorkspace (Just (-98)) "special:minimized" WorkspaceHidden True []
          specialScratch =
            mkWorkspace (Just (-99)) "special:scratchpad" WorkspaceHidden True []
          normal1 =
            mkWorkspace (Just 1) "1" WorkspaceActive False []
          normal2 =
            mkWorkspace (Just 2) "2" WorkspaceEmpty False []

      sortWorkspaceInfos [specialMinimized, normal2, specialScratch, normal1]
        `shouldBe` [normal1, normal2, specialScratch, specialMinimized]

  describe "applySpecialWorkspaceWindowTargets" $ do
    it "moves non-minimized special workspace windows into special:minimized" $ do
      let scratchWindow = mkWindow "scratch" False
          minimizedWindow = mkWindow "minimized" True
          scratch =
            mkWorkspace
              (Just (-99))
              "special:scratchpad"
              WorkspaceHidden
              True
              [scratchWindow]
          minimized =
            mkWorkspace
              (Just (-98))
              "special:minimized"
              WorkspaceHidden
              True
              [minimizedWindow]
          result =
            applySpecialWorkspaceWindowTargets
              specialWorkspaceWindowsToMinimized
              [scratch, minimized]
          movedScratch = workspaceByName "special:scratchpad" result
          minimizedBucket = workspaceByName "special:minimized" result
          movedWindow =
            case filter ((== HyprlandWindowIdentity "scratch") . windowIdentity) $
              workspaceWindows minimizedBucket of
              [window] -> window
              _ -> error "Expected scratch window in minimized bucket"

      workspaceWindows movedScratch `shouldBe` []
      workspaceState movedScratch `shouldBe` WorkspaceEmpty
      workspaceWindows minimizedBucket `shouldBe` [minimizedWindow, movedWindow]
      windowMinimized movedWindow `shouldBe` True

    it "creates a special:minimized bucket when the target workspace is missing" $ do
      let scratchWindow = mkWindow "scratch" False
          scratch =
            mkWorkspace
              (Just (-99))
              "special:scratchpad"
              WorkspaceHidden
              True
              [scratchWindow]
          result =
            applySpecialWorkspaceWindowTargets
              specialWorkspaceWindowsToMinimized
              [scratch]
          minimizedBucket = workspaceByName "special:minimized" result

      workspaceNumericId (workspaceIdentity minimizedBucket) `shouldBe` Nothing
      workspaceIsSpecial minimizedBucket `shouldBe` True
      workspaceState minimizedBucket `shouldBe` WorkspaceHidden
      map windowIdentity (workspaceWindows minimizedBucket)
        `shouldBe` [HyprlandWindowIdentity "scratch"]