import XCTest
@testable import Physarum
final class SimFormatTests: XCTestCase {
func testSquareViewGivesSquareField() {
XCTAssertEqual(fieldSize(viewWidth: 800, viewHeight: 800), FieldSize(width: 720, height: 720))
}
func testPortraitViewIsTallField() {
// 402x874 ≈ 1:2.17 → short edge 720, long edge ~1564 (under the 1600 cap)
let f = fieldSize(viewWidth: 402, viewHeight: 874)
XCTAssertEqual(f.width, 720)
XCTAssertTrue(f.height > 1400 && f.height <= 1600, "got \(f.height)")
XCTAssertTrue(f.height > f.width)
}
func testLandscapeViewIsWideField() {
let f = fieldSize(viewWidth: 874, viewHeight: 402)
XCTAssertEqual(f.height, 720)
XCTAssertTrue(f.width > f.height)
}
func testLongEdgeIsCapped() {
// extreme aspect → long edge clamped to maxLong (1600)
let f = fieldSize(viewWidth: 200, viewHeight: 4000)
XCTAssertEqual(f.width, 720)
XCTAssertEqual(f.height, 1600)
}
func testDegenerateViewFallsBackToSquare() {
XCTAssertEqual(fieldSize(viewWidth: 0, viewHeight: 0), FieldSize(width: 720, height: 720))
}
func testDensityScalesWithArea() {
// baseline area → unchanged
XCTAssertEqual(densityScaledAgentCount(10_000, fieldWidth: 512, fieldHeight: 512), 10_000)
// 2× area → ~2× count
XCTAssertEqual(densityScaledAgentCount(10_000, fieldWidth: 512, fieldHeight: 1024), 20_000)
}
func testDensityRespectsTierMaxAndFloor() {
XCTAssertEqual(densityScaledAgentCount(400_000, fieldWidth: 1024, fieldHeight: 1024), 500_000) // capped
XCTAssertGreaterThanOrEqual(densityScaledAgentCount(50, fieldWidth: 512, fieldHeight: 512), 100) // floor
}
func testTargetFieldSizeAutoUsesViewAspect() {
XCTAssertEqual(targetFieldSize(viewWidth: 800, viewHeight: 800, format: .auto),
fieldSize(viewWidth: 800, viewHeight: 800))
}
func testTargetFieldSizeFixedIgnoresView() {
XCTAssertEqual(targetFieldSize(viewWidth: 800, viewHeight: 800, format: .square),
FieldSize(width: 720, height: 720))
let p = targetFieldSize(viewWidth: 800, viewHeight: 800, format: .portrait)
XCTAssertTrue(p.height > p.width)
let l = targetFieldSize(viewWidth: 800, viewHeight: 800, format: .landscape)
XCTAssertTrue(l.width > l.height)
}
func testSimFormatRawRoundTrip() {
for f in SimFormat.allCases {
XCTAssertEqual(SimFormat(rawValue: f.rawValue), f)
}
}
// MARK: - FieldTier (live-path device tiers; capture stays untiered)
func testPhoneTierStaysNearPresetTuningBaseline() {
XCTAssertEqual(FieldTier.phone.base, 512)
XCTAssertEqual(FieldTier.phone.maxLong, 1280)
XCTAssertEqual(FieldTier.phone.agentCap, 250_000)
}
func testDesktopTierKeepsPreTierValues() {
XCTAssertEqual(FieldTier.desktop.base, 720)
XCTAssertEqual(FieldTier.desktop.maxLong, 1600)
XCTAssertEqual(FieldTier.desktop.agentCap, 500_000)
}
func testCurrentTierOnMacIsDesktop() {
#if os(macOS)
XCTAssertEqual(FieldTier.current, .desktop)
#endif
}
func testTabletTierIsConservative() {
XCTAssertEqual(FieldTier.tablet.base, 512)
XCTAssertEqual(FieldTier.tablet.maxLong, 1280)
XCTAssertEqual(FieldTier.tablet.agentCap, 250_000)
// Distinct identity from the phone tier despite identical workload values today,
// so the seam is real and `== .phone` checks never accidentally match iPad.
XCTAssertNotEqual(FieldTier.tablet, FieldTier.phone)
}
func testFieldTierMapsIdiomToTier() {
XCTAssertEqual(fieldTier(for: .phone), .phone)
XCTAssertEqual(fieldTier(for: .pad), .tablet)
XCTAssertEqual(fieldTier(for: .mac), .desktop)
}
func testTargetFieldSizeHonorsTier() {
// iPhone portrait aspect (~1:2.17) on the phone tier: short edge 512, long ≈ 1113.
let f = targetFieldSize(viewWidth: 402, viewHeight: 874, format: .auto, tier: .phone)
XCTAssertEqual(f.width, 512)
XCTAssertTrue(f.height > 1000 && f.height <= FieldTier.phone.maxLong, "got \(f.height)")
// Fixed formats honor the tier base too.
XCTAssertEqual(targetFieldSize(viewWidth: 800, viewHeight: 800, format: .square, tier: .phone),
FieldSize(width: 512, height: 512))
// Desktop tier reproduces the untiered defaults exactly.
XCTAssertEqual(targetFieldSize(viewWidth: 402, viewHeight: 874, format: .auto, tier: .desktop),
targetFieldSize(viewWidth: 402, viewHeight: 874, format: .auto))
}
func testDensityScaledAgentCountHonorsTierCap() {
XCTAssertEqual(densityScaledAgentCount(400_000, fieldWidth: 1024, fieldHeight: 1024, tier: .phone),
250_000)
XCTAssertEqual(densityScaledAgentCount(400_000, fieldWidth: 1024, fieldHeight: 1024, tier: .desktop),
500_000)
// Below the cap the tier changes nothing — density scaling is identical.
XCTAssertEqual(densityScaledAgentCount(10_000, fieldWidth: 512, fieldHeight: 1024, tier: .phone),
20_000)
}
}