packages feed

taffybar-7.2.0: test/unit/System/Taffybar/Widget/Workspaces/ChannelSpec.hs

module System.Taffybar.Widget.Workspaces.ChannelSpec (spec) where

import Data.Text qualified as T
import Data.Word (Word64)
import System.Taffybar.Information.Workspaces.Model
import System.Taffybar.Widget.Workspaces (sortWindowsByPosition)
import Test.Hspec

mkX11Window :: Word64 -> Bool -> Maybe (Int, Int) -> WindowInfo
mkX11Window wid minimized pos =
  WindowInfo
    { windowIdentity = X11WindowIdentity wid,
      windowUpdateRevision = 0,
      windowTitle = T.pack (show wid),
      windowClassHints = [],
      windowPosition = pos,
      windowUrgent = False,
      windowActive = False,
      windowMinimized = minimized,
      windowPinned = False
    }

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

mkSnapshot :: Word64 -> [WorkspaceInfo] -> WorkspaceSnapshot
mkSnapshot rev workspaces =
  WorkspaceSnapshot
    { snapshotBackend = WorkspaceBackendHyprland,
      snapshotRevision = rev,
      snapshotWindowDataComplete = True,
      snapshotWorkspaces = workspaces
    }

spec :: Spec
spec = do
  describe "sortWindowsByPosition" $ do
    it "orders non-minimized windows first, then by (x, y), then unknown positions" $ do
      let a = mkX11Window 1 False (Just (10, 0))
          b = mkX11Window 2 False (Just (0, 100))
          c = mkX11Window 3 True (Just (0, 0))
          d = mkX11Window 4 False Nothing
      sortWindowsByPosition [a, b, c, d] `shouldBe` [b, a, d, c]

  describe "diffWorkspaceSnapshots" $ do
    it "returns no events for identical snapshots" $ do
      let w1 = mkX11Window 1 False (Just (0, 0))
          ws1 = mkWorkspace 1 "1" WorkspaceActive [w1]
          snap = mkSnapshot 7 [ws1]
      diffWorkspaceSnapshots snap snap `shouldBe` []

    it "emits order/add/change/window events for meaningful updates" $ do
      let oldW1 = mkX11Window 1 False (Just (0, 0))
          newW1 = oldW1 {windowTitle = "updated"}
          newW2 = mkX11Window 2 False (Just (50, 50))
          oldWs1 = mkWorkspace 1 "1" WorkspaceActive [oldW1]
          newWs1 = mkWorkspace 1 "1" WorkspaceHidden [newW1, newW2]
          newWs2 = mkWorkspace 2 "2" WorkspaceVisible []
          oldSnap = mkSnapshot 10 [oldWs1]
          newSnap = mkSnapshot 11 [newWs2, newWs1]
          expectedEvents =
            [ WorkspaceOrderChanged [workspaceIdentity newWs2, workspaceIdentity newWs1],
              WorkspaceAdded newWs2,
              WorkspaceChanged newWs1,
              WorkspaceWindowsChanged
                (workspaceIdentity newWs1)
                [WindowAdded newW2, WindowChanged newW1]
            ]
      diffWorkspaceSnapshots oldSnap newSnap `shouldBe` expectedEvents

    it "bumps update revisions for targeted window refreshes" $ do
      let w1 = mkX11Window 1 False (Just (0, 0))
          w2 = mkX11Window 2 False (Just (50, 50))
          ws1 = mkWorkspace 1 "1" WorkspaceActive [w1, w2]
          snap = mkSnapshot 10 [ws1]
          refreshed = bumpWorkspaceRefreshTarget (RefreshWindow $ X11WindowIdentity 2) snap
          refreshedRevisions =
            concatMap
              (map windowUpdateRevision . workspaceWindows)
              (snapshotWorkspaces refreshed)
      refreshedRevisions `shouldBe` [0, 1]

    it "preserves update revisions across backend snapshots" $ do
      let oldW1 = (mkX11Window 1 False (Just (0, 0))) {windowUpdateRevision = 3}
          oldWs1 = (mkWorkspace 1 "1" WorkspaceActive [oldW1]) {workspaceUpdateRevision = 4}
          previous = mkSnapshot 10 [oldWs1]
          newW1 = (mkX11Window 1 False (Just (5, 5))) {windowUpdateRevision = 0}
          newWs1 = (mkWorkspace 1 "1" WorkspaceHidden [newW1]) {workspaceUpdateRevision = 0}
          next = preserveWorkspaceUpdateRevisions previous $ mkSnapshot 11 [newWs1]
          preservedWorkspaces = snapshotWorkspaces next
          preservedWindows = concatMap workspaceWindows preservedWorkspaces
      map workspaceUpdateRevision preservedWorkspaces `shouldBe` [4]
      map windowUpdateRevision preservedWindows `shouldBe` [3]