Files
iccery-v2-mac/Tests/ICCeryCoreTests/GamutMeshParserTests.swift
gronodandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 150d094632 test(m9): convert pure core test suites from Swift Testing to XCTest
Slice 2 (Phase 1a) of the M9 Monterey retarget. Converts all pure Core
suites (argv builders, CGATS/CUPS/profcheck/gamut-mesh parsers, colour
math, file/artefact helpers, classifiers) to XCTestCase, and adds the
shared assertAsyncThrows helper for the async-throws sites that Slice 3
will convert.

Deferred to Slice 3 (kept on Swift Testing in mixed files):
ProcessManagerTests, ArgyllRunner*Tests, ProcessRunSupportTests,
store/UI suites, and the runner suites embedded in TargenTests /
PrinttargTests / ProcessManagerTests.

Also qualifies six bare `throw .case` expressions in CGATSParser with
CGATSParseError — they only compiled under typed throws, which Slice 1
demoted to untyped `throws`; without this the ICCeryCore target fails to
build and no test gate can run.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-11 20:43:42 +01:00

162 lines
4.5 KiB
Swift

import Foundation
import XCTest
@testable import ICCeryCore
/// ``GamutMeshParser`` acceptance + edge-case tests.
final class GamutMeshParserTests: XCTestCase {
/// Returns the bundled real `sRGB.gam` in `Resources/Argyll/reference_gamuts`.
private var bundledSRGBGamURL: URL {
let bundle = Bundle.main
let resource = bundle.resourceURL ?? bundle.bundleURL
return resource.appendingPathComponent("Argyll/reference_gamuts/sRGB.gam")
}
func testParsesBundledSRGB() throws {
let mesh = try GamutMeshParser.parse(url: bundledSRGBGamURL)
XCTAssertEqual(mesh.vertices.count, 448, "sRGB.gam has 448 vertices")
XCTAssertEqual(mesh.faces.count, 892, "sRGB.gam has 892 faces")
}
func testDiscardsVertexNo() throws {
let text = """
GAMUT
NUMBER_OF_FIELDS 4
BEGIN_DATA_FORMAT
VERTEX_NO LAB_L LAB_A LAB_B
END_DATA_FORMAT
NUMBER_OF_SETS 4
BEGIN_DATA
100 10.0 20.0 30.0
50 20.0 30.0 40.0
2 30.0 40.0 50.0
7 40.0 50.0 60.0
END_DATA
NUMBER_OF_FIELDS 3
BEGIN_DATA_FORMAT
VERTEX_0 VERTEX_1 VERTEX_2
END_DATA_FORMAT
NUMBER_OF_SETS 2
BEGIN_DATA
0 1 2
1 2 3
END_DATA
"""
let mesh = try GamutMeshParser.parse(text: text)
XCTAssertEqual(mesh.vertices.count, 4)
XCTAssertEqual(mesh.faces.count, 2)
XCTAssertEqual(mesh.vertices[0].lab, LabColor(l: 10, a: 20, b: 30))
XCTAssertEqual(mesh.vertices[3].lab, LabColor(l: 40, a: 50, b: 60))
}
func testIgnoresComments() throws {
let text = """
# Header comment
NUMBER_OF_FIELDS 4
BEGIN_DATA_FORMAT
VERTEX_NO LAB_L LAB_A LAB_B
END_DATA_FORMAT
NUMBER_OF_SETS 2
BEGIN_DATA
0 10.0 20.0 30.0
# inline comment
1 20.0 30.0 40.0
END_DATA
# another comment
NUMBER_OF_FIELDS 3
BEGIN_DATA_FORMAT
VERTEX_0 VERTEX_1 VERTEX_2
END_DATA_FORMAT
NUMBER_OF_SETS 1
BEGIN_DATA
0 1 0
END_DATA
"""
let mesh = try GamutMeshParser.parse(text: text)
XCTAssertEqual(mesh.vertices.count, 2)
XCTAssertEqual(mesh.faces.count, 1)
}
func testRemapsCoordinates() throws {
let text = """
NUMBER_OF_FIELDS 4
BEGIN_DATA_FORMAT
VERTEX_NO LAB_L LAB_A LAB_B
END_DATA_FORMAT
NUMBER_OF_SETS 1
BEGIN_DATA
0 50.0 -20.0 80.0
END_DATA
"""
let mesh = try GamutMeshParser.parse(text: text)
XCTAssertEqual(mesh.vertices.first?.position, SIMD3<Float>(-20, 50, 80))
}
func testComputesVertexColor() throws {
let text = """
NUMBER_OF_FIELDS 4
BEGIN_DATA_FORMAT
VERTEX_NO LAB_L LAB_A LAB_B
END_DATA_FORMAT
NUMBER_OF_SETS 1
BEGIN_DATA
0 100.0 0.0 0.0
END_DATA
"""
let mesh = try GamutMeshParser.parse(text: text)
let white = try XCTUnwrap(mesh.vertices.first).rgb
XCTAssertTrue(white.r > 0.95)
XCTAssertTrue(white.g > 0.95)
XCTAssertTrue(white.b > 0.95)
}
func testDropsOutOfBoundsFaces() throws {
let text = """
NUMBER_OF_FIELDS 4
BEGIN_DATA_FORMAT
VERTEX_NO LAB_L LAB_A LAB_B
END_DATA_FORMAT
NUMBER_OF_SETS 2
BEGIN_DATA
0 10.0 0.0 0.0
1 20.0 0.0 0.0
END_DATA
NUMBER_OF_FIELDS 3
BEGIN_DATA_FORMAT
VERTEX_0 VERTEX_1 VERTEX_2
END_DATA_FORMAT
NUMBER_OF_SETS 2
BEGIN_DATA
0 1 0
0 1 99
END_DATA
"""
let mesh = try GamutMeshParser.parse(text: text)
XCTAssertEqual(mesh.faces.count, 1)
}
func testThrowsOnEmptyFile() {
XCTAssertThrowsError(try GamutMeshParser.parse(text: "")) { error in
guard case GamutMeshParseError.noDataBlock = error else {
return XCTFail("Expected GamutMeshParseError.noDataBlock, got \(error)")
}
}
}
func testThrowsWhenMissing() {
let url = URL(fileURLWithPath: "/nonexistent/path/to/mesh.gam")
XCTAssertThrowsError(try GamutMeshParser.parse(url: url)) { error in
guard case GamutMeshParseError.missingFile = error else {
return XCTFail("Expected GamutMeshParseError.missingFile, got \(error)")
}
}
}
}