133 lines
5.2 KiB
Swift
133 lines
5.2 KiB
Swift
// SPDX-FileCopyrightText: 2026 Kaede Akino
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import Foundation
|
|
import Testing
|
|
|
|
@testable import Termind
|
|
|
|
@Suite
|
|
@MainActor
|
|
struct PersistentWorkspaceDeckLayoutTests {
|
|
@Test
|
|
func verticalWorkspaceDropUsesRowMidpointsForFirstMiddleAndLastInsertion() {
|
|
let frames = [
|
|
CGRect(x: 0, y: 20, width: 200, height: 30),
|
|
CGRect(x: 0, y: 50, width: 200, height: 30),
|
|
CGRect(x: 0, y: 80, width: 200, height: 30),
|
|
]
|
|
|
|
#expect(WorkspaceSidebarDropGeometry.insertionIndex(rowFrames: frames, pointerY: 20) == 0)
|
|
#expect(WorkspaceSidebarDropGeometry.insertionIndex(rowFrames: frames, pointerY: 51) == 1)
|
|
#expect(WorkspaceSidebarDropGeometry.insertionIndex(rowFrames: frames, pointerY: 96) == 3)
|
|
}
|
|
|
|
@Test
|
|
func workspaceDropKeepsMoveIndexAndVisibleInsertionLineIndependent() {
|
|
let frames = [
|
|
CGRect(x: 0, y: 20, width: 200, height: 30),
|
|
CGRect(x: 0, y: 50, width: 200, height: 30),
|
|
CGRect(x: 0, y: 80, width: 200, height: 30),
|
|
]
|
|
|
|
let sourceUpperHalf = WorkspaceSidebarDropGeometry.target(
|
|
rowFrames: frames, draggedRowIndex: 1, pointerY: 55
|
|
)
|
|
#expect(sourceUpperHalf.insertionIndex == 1)
|
|
#expect(sourceUpperHalf.visibleBoundaryIndex == 1)
|
|
|
|
let sourceLowerHalf = WorkspaceSidebarDropGeometry.target(
|
|
rowFrames: frames, draggedRowIndex: 1, pointerY: 75
|
|
)
|
|
#expect(sourceLowerHalf.insertionIndex == 1)
|
|
#expect(sourceLowerHalf.visibleBoundaryIndex == 2)
|
|
|
|
let afterLastRow = WorkspaceSidebarDropGeometry.target(
|
|
rowFrames: frames, draggedRowIndex: 0, pointerY: 96
|
|
)
|
|
#expect(afterLastRow.insertionIndex == 2)
|
|
#expect(afterLastRow.visibleBoundaryIndex == 3)
|
|
}
|
|
|
|
@Test
|
|
func workspaceDropClampsPointsOutsideTheWorkspaceSectionToItsEdges() {
|
|
let frames = [
|
|
CGRect(x: 0, y: 100, width: 200, height: 30),
|
|
CGRect(x: 0, y: 130, width: 200, height: 30),
|
|
]
|
|
|
|
let above = WorkspaceSidebarDropGeometry.target(
|
|
rowFrames: frames, draggedRowIndex: nil, pointerY: -1_000
|
|
)
|
|
#expect(above.insertionIndex == 0)
|
|
#expect(above.visibleBoundaryIndex == 0)
|
|
|
|
let below = WorkspaceSidebarDropGeometry.target(
|
|
rowFrames: frames, draggedRowIndex: nil, pointerY: 1_000
|
|
)
|
|
#expect(below.insertionIndex == 2)
|
|
#expect(below.visibleBoundaryIndex == 2)
|
|
}
|
|
|
|
@Test
|
|
func activeWorkspaceTracksContainerWhileHiddenTabKeepsItsLastSize() {
|
|
var state = PersistentWorkspaceDeckSizingState()
|
|
let workspace = UUID()
|
|
let initial = CGSize(width: 900, height: 600)
|
|
let narrower = CGSize(width: 620, height: 600)
|
|
|
|
#expect(state.size(for: workspace, isActive: true, containerSize: initial) == initial)
|
|
#expect(state.size(for: workspace, isActive: false, containerSize: narrower) == initial)
|
|
#expect(state.cachedSize(for: workspace) == initial)
|
|
}
|
|
|
|
@Test
|
|
func neverVisibleWorkspaceCapturesItsFirstUsableParkingSize() {
|
|
var state = PersistentWorkspaceDeckSizingState()
|
|
let workspace = UUID()
|
|
let first = CGSize(width: 780, height: 520)
|
|
let later = CGSize(width: 540, height: 520)
|
|
|
|
#expect(state.size(for: workspace, isActive: false, containerSize: .zero) == .zero)
|
|
#expect(state.cachedSize(for: workspace) == nil)
|
|
#expect(state.size(for: workspace, isActive: false, containerSize: first) == first)
|
|
#expect(state.size(for: workspace, isActive: false, containerSize: later) == first)
|
|
}
|
|
|
|
@Test
|
|
func switchingWorkspacesParksTheOldTabAtItsFinalActiveSize() {
|
|
var state = PersistentWorkspaceDeckSizingState()
|
|
let first = UUID()
|
|
let second = UUID()
|
|
let original = CGSize(width: 800, height: 500)
|
|
let final = CGSize(width: 960, height: 500)
|
|
|
|
_ = state.size(for: first, isActive: true, containerSize: original)
|
|
_ = state.size(for: second, isActive: false, containerSize: original)
|
|
_ = state.size(for: first, isActive: true, containerSize: final)
|
|
|
|
#expect(state.size(for: first, isActive: false, containerSize: final) == final)
|
|
#expect(state.size(for: second, isActive: true, containerSize: final) == final)
|
|
}
|
|
|
|
@Test
|
|
func cacheUsesIdentityAcrossReorderingAndPrunesClosedWorkspaces() {
|
|
var state = PersistentWorkspaceDeckSizingState()
|
|
let first = UUID()
|
|
let second = UUID()
|
|
let firstSize = CGSize(width: 700, height: 480)
|
|
let secondSize = CGSize(width: 920, height: 640)
|
|
|
|
_ = state.size(for: first, isActive: true, containerSize: firstSize)
|
|
_ = state.size(for: second, isActive: true, containerSize: secondSize)
|
|
|
|
// Reading in reverse order does not exchange the cached proposals.
|
|
#expect(state.size(for: second, isActive: false, containerSize: firstSize) == secondSize)
|
|
#expect(state.size(for: first, isActive: false, containerSize: secondSize) == firstSize)
|
|
|
|
state.prune(keeping: [second])
|
|
#expect(state.cachedSize(for: first) == nil)
|
|
#expect(state.cachedSize(for: second) == secondSize)
|
|
}
|
|
}
|