Introduce TankDefinition/TankCatalog loaded from Tanks.json, bundle the Drachengas USDZ tank models, add tank selection and preview views, and update the AR experience, editor and project views to use the catalog. Includes tests for catalog loading and model selection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.9 KiB
Swift
75 lines
2.9 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)")
|
|
}
|
|
}
|
|
|
|
// 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.")
|
|
}
|
|
}
|