rainbow-dragon/Tests/ForgeGradeTests/SerializationTests.swift

74 lines
2.8 KiB
Swift
Raw Permalink Normal View History

import XCTest
import ForgeColor
@testable import ForgeGrade
final class SerializationTests: XCTestCase {
func makeStack() -> GradeStack {
var set = CurveSet.identity
set.master = Curve(points: [.init(x: 0, y: 0.05), .init(x: 1, y: 0.95)])
return GradeStack(nodes: [
GradeNode(kind: .inputTransform(.arriLogC4AWG4)),
GradeNode(kind: .cdl(CDL(
slope: SIMD3(1.1, 0.95, 1.02),
offset: SIMD3(0.01, -0.005, 0),
power: SIMD3(0.98, 1.03, 1.0),
saturation: 1.15))),
GradeNode(kind: .curves(set)),
GradeNode(kind: .saturation(0.9), isEnabled: false),
GradeNode(kind: .lut3d(Lut3D.build(size: 2) { $0 * 0.9 })),
GradeNode(kind: .outputTransform(.rec709Display)),
])
}
// Round trip: encode -> decode -> same stack (ids, kinds, params, enabled flags).
func testRoundTrip() throws {
let stack = makeStack()
let data = try GradeSnapshot.encode(stack)
let back = try GradeSnapshot.decode(data)
XCTAssertEqual(back.nodes.count, stack.nodes.count)
for (a, b) in zip(stack.nodes, back.nodes) {
XCTAssertEqual(a.id, b.id)
XCTAssertEqual(a.isEnabled, b.isEnabled)
}
// Behavioral equality: same eval on sample pixels.
for px in [SIMD3<Float>(0.2, 0.4, 0.6), SIMD3(0.8, 0.1, 0.5)] {
let ea = stack.evaluate(px)
let eb = back.evaluate(px)
XCTAssertEqual(ea.x, eb.x, accuracy: 1e-6)
XCTAssertEqual(ea.y, eb.y, accuracy: 1e-6)
XCTAssertEqual(ea.z, eb.z, accuracy: 1e-6)
}
}
// Deterministic: re-encoding a decoded stack is byte-identical.
func testDeterministicEncoding() throws {
let stack = makeStack()
let data1 = try GradeSnapshot.encode(stack)
let back = try GradeSnapshot.decode(data1)
let data2 = try GradeSnapshot.encode(back)
XCTAssertEqual(data1, data2)
}
// Unknown node kind fails loudly, not silently dropped.
func testUnknownNodeKindFails() {
let json = """
{"nodes":[{"id":"6EC0BD7F-11C0-43DA-975E-2A8AD9EBAE0B","isEnabled":true,"kind":{"type":"warpDrive"}}],"version":1}
"""
XCTAssertThrowsError(try GradeSnapshot.decode(Data(json.utf8)))
}
// Version field present; future-proofing.
func testVersionField() throws {
let data = try GradeSnapshot.encode(GradeStack(nodes: []))
let obj = try JSONSerialization.jsonObject(with: data) as? [String: Any]
XCTAssertEqual(obj?["version"] as? Int, 1)
}
// Wrong version rejected.
func testWrongVersionRejected() {
let json = #"{"nodes":[],"version":99}"#
XCTAssertThrowsError(try GradeSnapshot.decode(Data(json.utf8)))
}
}