import XCTest
import PhysarumEngine
@testable import Physarum
final class PresetImportTests: XCTestCase {
func testPresetDocumentRoundTrip() throws {
let preset = PresetCatalog.fallbackPreset
let data = try JSONEncoder().encode(preset)
let decoded = try JSONDecoder().decode(Preset.self, from: data)
XCTAssertEqual(decoded.id, preset.id)
}
func testImportReIdsAndAddsToSlot() {
// Empty factory → all 24 slots free, so the import lands in slot-00.
let s = AppState(slotStore: SlotStore(backend: InMemorySlotBackend(),
factory: PresetSlots.Factory(presets: [], version: 1)))
var incoming = PresetCatalog.fallbackPreset
incoming.id = "some-other-id"; incoming.builtIn = true
let before = s.presets.count
XCTAssertTrue(s.importIntoSlot(incoming))
XCTAssertEqual(s.presets.count, before + 1)
let added = s.presets.last!
XCTAssertEqual(added.id, PresetSlots.slotID(0)) // re-id'd to its slot id (not the incoming id)
XCTAssertFalse(added.builtIn) // forced non-builtin
}
/// Spec W3 (design doc line 289): import error path — a preset JSON missing a
/// required field must throw on decode and must not crash (no force-unwrap).
func testImportMissingRequiredFieldThrows() throws {
// Valid preset JSON minus the required `params` field.
let full = try JSONEncoder().encode(PresetCatalog.fallbackPreset)
var object = try XCTUnwrap(JSONSerialization.jsonObject(with: full) as? [String: Any])
object.removeValue(forKey: "params")
let missing = try JSONSerialization.data(withJSONObject: object)
XCTAssertThrowsError(try JSONDecoder().decode(Preset.self, from: missing)) { error in
guard case DecodingError.keyNotFound(let key, _) = error else {
return XCTFail("expected keyNotFound, got \(error)")
}
XCTAssertEqual(key.stringValue, "params")
}
}
}