import CoreGraphics import Foundation import XCTest @testable import CallsKit /// 2026-10-05: a tile's placeholder centred in the whole tile, the stage /// filling the window under the filmstrip, a camera cropped with headroom, /// and the screen's backdrop. final class TileLayoutTests: XCTestCase { // MARK: Placeholder func testCentredInTheWholeTileWhenThereIsRoom() { // A stage 600 tall, a 34 pt label block: centred, not above the label. let top = PlaceholderPlacement.top(tile: 600, content: 80, reserve: 34) XCTAssertEqual(top, 260) XCTAssertEqual(top + 40, 300, "its middle is the tile's middle") } func testRisesOnlyAsFarAsTheLabelNeedsOnAShortTile() { // The mini window at its smallest, 200 × 112.5, label block 44: a // 34 pt symbol centred would end at 73.25, past the label's top less // the gap (112.5 - 48 = 64.5), so it rises by 8.75 and no more. let top = PlaceholderPlacement.top(tile: 112.5, content: 34, reserve: 44) XCTAssertEqual(top + 34, 112.5 - 44 - PlaceholderPlacement.gap, accuracy: 0.001) XCTAssertLessThan(top, (112.5 - 34) / 2) XCTAssertEqual((112.5 - 34) / 2 - top, 8.75, accuracy: 0.001) } func testNeverAboveTheTop() { XCTAssertEqual(PlaceholderPlacement.top(tile: 60, content: 50, reserve: 40), 0) } func testNoLabelIsPlainCentring() { XCTAssertEqual(PlaceholderPlacement.top(tile: 100, content: 20, reserve: 0), 40) XCTAssertEqual(PlaceholderPlacement.room(tile: 100, reserve: 0), 100) } func testRoomIsWhatChoosesTheWords() { // At 200 wide the words and symbol (about 66 pt) do not fit above a // 44 pt label in 112.5: the symbol stands alone. XCTAssertLessThan(PlaceholderPlacement.room(tile: 112.5, reserve: 44), 66) // At 320 (180 tall) they do. XCTAssertGreaterThan(PlaceholderPlacement.room(tile: 180, reserve: 44), 66) } func testEveryMiniSizeKeepsTheSymbolClearOfTheLabelAndCentredWhereItCan() { for width in [200.0, 320, 480] { let tile = width * 9 / 16 let reserve: CGFloat = 44 let content: CGFloat = PlaceholderPlacement.room(tile: tile, reserve: reserve) >= 66 ? 66 : 34 let top = PlaceholderPlacement.top(tile: tile, content: content, reserve: reserve) XCTAssertLessThanOrEqual(top + content, tile - reserve - PlaceholderPlacement.gap + 0.001, "\(width)") let centred = (tile - content) / 2 if centred + content <= tile - reserve - PlaceholderPlacement.gap { XCTAssertEqual(top, centred, accuracy: 0.001, "\(width): centred when it clears") } } } // MARK: The stage func testStageLabelRidesAboveTheFilmstrip() { // Controls showing: the filmstrip rises 72 for the bar; band 102. XCTAssertEqual(StageLabel.lift(bar: 72, band: 102), 174) // Hidden: just the band. XCTAssertEqual(StageLabel.lift(bar: 0, band: 102), 102) // A call of two: no filmstrip, the bar alone. XCTAssertEqual(StageLabel.lift(bar: 72, band: 0), 72) } func testACameraFillsWithMoreCropFromTheBottom() { // 16:9 into a 4:3 window: fills, crops sides evenly. let wide = VideoFrame.place(video: CGSize(width: 1280, height: 720), in: CGSize(width: 800, height: 600), fit: false) XCTAssertEqual(wide.height, 600, accuracy: 0.001) XCTAssertEqual(wide.minX, -(wide.width - 800) / 2, accuracy: 0.001) XCTAssertEqual(wide.minY, 0, accuracy: 0.001) // 16:9 into a tall window: crops top and bottom, 35% from the top. let tall = VideoFrame.place(video: CGSize(width: 1280, height: 720), in: CGSize(width: 1600, height: 600), fit: false) let overflow = tall.height - 600 XCTAssertGreaterThan(overflow, 0) XCTAssertEqual(-tall.minY, overflow * VideoFrame.headroom, accuracy: 0.001) XCTAssertEqual(tall.maxY - 600, overflow * (1 - VideoFrame.headroom), accuracy: 0.001) } func testAScreenIsFittedWholeAndCentred() { let r = VideoFrame.place(video: CGSize(width: 1920, height: 1200), in: CGSize(width: 1000, height: 1000), fit: true) XCTAssertEqual(r.width, 1000, accuracy: 0.001) XCTAssertEqual(r.minY, (1000 - r.height) / 2, accuracy: 0.001) XCTAssertGreaterThanOrEqual(r.minY, 0) } // MARK: The screen's backdrop func testBackdropPictureIsTheFramesColoursBlurred() throws { // A 64 × 36 I420 frame: left half pure red, right half pure blue. let (w, h) = (BackdropSampler.width, BackdropSampler.height) var y = [UInt8](repeating: 0, count: w * h) var u = [UInt8](repeating: 0, count: (w / 2) * (h / 2)) var v = [UInt8](repeating: 0, count: (w / 2) * (h / 2)) for row in 0..