Files
Gas-Tank-AR-App/GasTankARTests/TankModelSelectionTests.swift
2026-11-07 18:38:35 +01:00

98 lines
3.8 KiB
Swift

//
// TankModelSelectionTests.swift
// GasTankARTests
//
// Created by Dennis Nemec on 14.09.26.
//
import Testing
import Foundation
import RealityKit
@testable import GasTankAR
/// Prüft, dass für eine Tank-Auswahl im AR-Modus die richtige Datei geladen wird:
/// Der Katalog aus dem echten App-Bundle (`Tanks.json`) muss vollständig sein,
/// jede referenzierte Datei muss existieren und die AR-Factory muss das echte
/// Modell (statt des Ersatzkörpers) erzeugen.
struct TankModelSelectionTests {
/// Katalog, geladen aus dem realen App-Bundle (dem Test-Host).
private static func bundleCatalog() -> TankCatalog {
let bundle = Bundle(for: TankEntityFactory.self)
return TankCatalog(loader: BundleTankCatalogLoader(bundle: bundle))
}
// MARK: - Katalog aus dem Bundle
@Test func bundleCatalogContainsAllNineVariants() {
let catalog = Self.bundleCatalog()
#expect(catalog.definitions.count == 9)
// 3 Größen, jeweils oberirdisch weiß/grün + unterirdisch oliv.
#expect(catalog.sizes(for: .aboveGround).count == 3)
#expect(catalog.sizes(for: .belowGround).count == 3)
}
@Test func everyModelFileExistsInBundle() {
let bundle = Bundle(for: TankEntityFactory.self)
let catalog = Self.bundleCatalog()
for def in catalog.definitions {
let url = bundle.url(forResource: def.modelResourceName, withExtension: def.modelFileExtension)
#expect(url != nil, "Modell-Datei fehlt im Bundle: \(def.modelPath)")
}
}
@Test func everyVariantHasItsMeasuredDomeCenter() {
let expected: [String: Float] = [
"DG-2700_wh.usdz": -0.426,
"DG-2700_mi.usdz": -0.426,
"DG-2700_ol.usdz": -0.498,
"DG-4850_wh.usdz": -1.317,
"DG-4850_mi.usdz": -1.317,
"DG-4850_ol.usdz": -1.395,
"DG-6400_wh.usdz": -1.939,
"DG-6400_mi.usdz": -1.939,
"DG-6400_ol.usdz": -2.018,
]
let definitions = Self.bundleCatalog().definitions
#expect(definitions.count == expected.count)
for definition in definitions {
let measured = expected[definition.modelPath]
#expect(measured != nil, "Kein Domschachtmaß für \(definition.modelPath)")
if let measured {
#expect(abs(definition.domeCenterX - measured) < 0.001)
}
}
}
// MARK: - Auswahl → richtige Datei
@Test func aboveGroundColorsMapToExpectedFiles() {
let catalog = Self.bundleCatalog()
let white = catalog.resolvedDefinition(for: Tank(size: .t1_2, color: .white, placement: .aboveGround))
let green = catalog.resolvedDefinition(for: Tank(size: .t1_2, color: .green, placement: .aboveGround))
#expect(white?.modelPath == "DG-2700_wh.usdz")
#expect(green?.modelPath == "DG-2700_mi.usdz")
}
@Test func belowGroundMapsToUndergroundFile() {
let catalog = Self.bundleCatalog()
let def = catalog.resolvedDefinition(for: Tank(size: .t2_9, color: .olive, placement: .belowGround))
#expect(def?.modelPath == "DG-6400_ol.usdz")
}
// MARK: - AR-Factory lädt das echte Modell (kein Ersatzkörper)
@MainActor
@Test func factoryLoadsRealModelNotFallbackCube() {
// Repräsentative oberirdische Konfiguration: der Tank ist deutlich länger
// als der 0,3 m große Ersatzwürfel, der nur bei fehlendem Modell entsteht.
let tank = Tank(size: .t2_9, color: .white, placement: .aboveGround)
let factory = TankEntityFactory(catalog: Self.bundleCatalog())
let container = factory.makeContainer(for: tank)
let bounds = container.visualBounds(relativeTo: nil)
#expect(bounds.extents.x > 0.5, "Es wurde vermutlich der Ersatzwürfel geladen statt des echten Modells.")
}
}