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

136 lines
5.3 KiB
Swift

//
// TankCatalogTests.swift
// GasTankARTests
//
// Created by Dennis Nemec on 14.09.26.
//
import Testing
import Foundation
@testable import GasTankAR
/// Prüft das Laden/Decodieren des Tank-Katalogs aus JSON sowie die abgeleiteten
/// Abfragen (verfügbare Größen/Farben, Auflösung & Normalisierung der Auswahl).
struct TankCatalogTests {
// Kleiner, in sich konsistenter Beispielkatalog für Query-Tests.
private static let sampleJSON = """
{
"sizeDisplayNames": { "t1_2": "1,2 t", "t2_9": "2,9 t" },
"colorDisplayNames": { "white": "Weiß", "green": "Hellgrün", "olive": "Olivgrün" },
"tanks": [
{ "size": "t1_2", "color": "white", "placement": "aboveGround", "modelPath": "DG-2700_wh.usdz", "domeCenterX": -0.426 },
{ "size": "t1_2", "color": "green", "placement": "aboveGround", "modelPath": "DG-2700_mi.usdz", "domeCenterX": -0.426 },
{ "size": "t1_2", "color": "olive", "placement": "belowGround", "modelPath": "DG-2700_ol.usdz", "domeCenterX": -0.498 },
{ "size": "t2_9", "color": "white", "placement": "aboveGround", "modelPath": "DG-6400_wh.usdz", "domeCenterX": -1.939 },
{ "size": "t2_9", "color": "olive", "placement": "belowGround", "modelPath": "DG-6400_ol.usdz", "domeCenterX": -2.018 }
]
}
"""
private static func sampleCatalog() throws -> TankCatalog {
let loader = DataTankCatalogLoader(data: Data(sampleJSON.utf8))
return TankCatalog(file: try loader.load())
}
// MARK: - Decoding
@Test func decodesAllFieldsFromJSON() throws {
let catalog = try Self.sampleCatalog()
let def = try #require(catalog.definitions.first)
#expect(def.size == .t1_2)
#expect(def.color == .white)
#expect(def.placement == .aboveGround)
#expect(def.modelPath == "DG-2700_wh.usdz")
#expect(def.domeCenterX == -0.426)
#expect(def.modelResourceName == "DG-2700_wh")
#expect(def.modelFileExtension == "usdz")
}
@Test func decodesDisplayNameMappings() throws {
let catalog = try Self.sampleCatalog()
#expect(catalog.sizeDisplayNames["t1_2"] == "1,2 t")
#expect(catalog.colorDisplayNames["olive"] == "Olivgrün")
}
@Test func displayNameFallsBackToRawValueWhenMissing() {
// Katalog ohne Mappings → Anzeigename ist der rawValue.
let catalog = TankCatalog(definitions: [])
#expect(catalog.displayName(for: TankSize.t2_1) == "t2_1")
#expect(catalog.displayName(for: TankColor.green) == "green")
}
@Test func missingResourceThrows() {
let loader = BundleTankCatalogLoader(
bundle: .main,
resourceName: "Datei-die-nicht-existiert",
resourceExtension: "json"
)
#expect(throws: TankCatalogLoaderError.self) {
_ = try loader.load()
}
}
@Test func emptyCatalogWhenLoaderFails() {
let loader = BundleTankCatalogLoader(resourceName: "gibt-es-nicht")
let catalog = TankCatalog(loader: loader)
#expect(catalog.definitions.isEmpty)
}
// MARK: - Abgeleitete Abfragen
@Test func availableColorsDependOnPlacement() throws {
let catalog = try Self.sampleCatalog()
#expect(catalog.colors(for: .t1_2, placement: .aboveGround) == [.white, .green])
#expect(catalog.colors(for: .t1_2, placement: .belowGround) == [.olive])
}
@Test func availableSizesPerPlacement() throws {
let catalog = try Self.sampleCatalog()
#expect(catalog.sizes(for: .aboveGround) == [.t1_2, .t2_9])
#expect(catalog.sizes(for: .belowGround) == [.t1_2, .t2_9])
}
@Test func placementsPreserveOrder() throws {
let catalog = try Self.sampleCatalog()
#expect(catalog.placements == [.aboveGround, .belowGround])
}
@Test func displayNamesResolveFromCatalog() throws {
let catalog = try Self.sampleCatalog()
#expect(catalog.displayName(for: TankSize.t2_9) == "2,9 t")
#expect(catalog.displayName(for: TankColor.olive) == "Olivgrün")
}
// MARK: - Auflösung & Normalisierung
@Test func definitionMatchesExactSelection() throws {
let catalog = try Self.sampleCatalog()
let tank = Tank(size: .t2_9, color: .olive, placement: .belowGround)
#expect(catalog.definition(for: tank)?.modelPath == "DG-6400_ol.usdz")
}
@Test func normalizesInconsistentColorForPlacement() throws {
let catalog = try Self.sampleCatalog()
// Weiß gibt es unterirdisch nicht → sollte auf Olivgrün korrigiert werden.
let tank = Tank(size: .t2_9, color: .white, placement: .belowGround)
let normalized = catalog.normalized(tank)
#expect(normalized.color == .olive)
#expect(catalog.definition(for: normalized) != nil)
}
@Test func resolvedDefinitionHealsLegacySelection() throws {
let catalog = try Self.sampleCatalog()
// Altdaten: unterirdisch + weiß → muss trotzdem das Olivgrün-Modell liefern.
let legacy = Tank(size: .t2_9, color: .white, placement: .belowGround)
#expect(catalog.resolvedDefinition(for: legacy)?.modelPath == "DG-6400_ol.usdz")
}
@Test func validSelectionStaysUnchanged() throws {
let catalog = try Self.sampleCatalog()
let tank = Tank(size: .t1_2, color: .green, placement: .aboveGround)
#expect(catalog.normalized(tank) == tank)
}
}