Zum Inhalt

apple/PhysarumApp/Tests/RandomizeTests.swift

import XCTest
@testable import Physarum
import PhysarumEngine

final class RandomizeTests: XCTestCase {
    func testEveryScalarStrategySamplesWithinDescriptorRange() {
        var g = SeededGenerator(seed: 42)
        for d in ParamRegistry.all {
            let strat = RandomizeProfiles.strategy(for: d.id)
            for _ in 0..<200 {
                let v = strat.sample(using: &g)
                XCTAssertGreaterThanOrEqual(v, d.range.lowerBound - 1e-9, "\(d.idKey) below range")
                XCTAssertLessThanOrEqual(v, d.range.upperBound + 1e-9, "\(d.idKey) above range")
            }
        }
    }

    func testMostlyZeroEmitsZeroAndNonZero() {
        var g = SeededGenerator(seed: 7)
        let strat = RandomStrategy.mostlyZero(zeroProb: 0.7, 0.1...0.6)
        var zeros = 0, nonzeros = 0
        for _ in 0..<500 { strat.sample(using: &g) == 0 ? (zeros += 1) : (nonzeros += 1) }
        XCTAssertGreaterThan(zeros, 0)
        XCTAssertGreaterThan(nonzeros, 0)
    }

    func testRandomizeRespectsLocks() {
        let state = AppState()
        let d = ParamRegistry.all.first { $0.id == .moveSpeed(0) }!
        state.toggleLock(.moveSpeed(0))
        let locked = d.get(state.edited)
        var g = SeededGenerator(seed: 99)
        state.randomize(using: &g)
        XCTAssertEqual(d.get(state.edited), locked, accuracy: 1e-4, "locked param must not change")
    }

    func testRandomizeKeepsAllScalarsInRange() {
        let state = AppState()
        var g = SeededGenerator(seed: 3)
        state.randomize(using: &g)
        for d in ParamRegistry.all {
            let v = d.get(state.edited)
            XCTAssertGreaterThanOrEqual(v, d.range.lowerBound - 0.5, "\(d.idKey)")
            XCTAssertLessThanOrEqual(v, d.range.upperBound + 0.5, "\(d.idKey)")
        }
    }

    func testRandomizePushesOneUndoSnapshot() {
        let state = AppState()
        let before = state.undoStack.count
        var g = SeededGenerator(seed: 5)
        state.randomize(using: &g)
        XCTAssertEqual(state.undoStack.count, before + 1)
        // undo returns to the pre-randomize state
        let preMove = ParamRegistry.all.first { $0.id == .moveSpeed(0) }!.get(state.baseline)
        state.undoEdit()
        XCTAssertEqual(ParamRegistry.all.first { $0.id == .moveSpeed(0) }!.get(state.edited),
                       preMove, accuracy: 1e-4)
    }

    func testRandomizeIsDeterministicForSameSeed() {
        let a = AppState(); var g1 = SeededGenerator(seed: 1234); a.randomize(using: &g1)
        let b = AppState(); var g2 = SeededGenerator(seed: 1234); b.randomize(using: &g2)
        XCTAssertTrue(paramsEqual(a.edited, b.edited), "same seed → same result")
    }
}