Files
conjure/Tests/ConjureKitTests/ColorSchemeTests.swift
T

144 lines
6.1 KiB
Swift

import AppKit
import Testing
@testable import Conjure
@Test @MainActor
func missingColorConfigurationUsesSunsetWithoutReadingGeneratedTheme() throws {
let directory = try colorConfigurationDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
try Data("not JSON".utf8).write(to: directory.appendingPathComponent("theme.json"))
let loaded = try ColorScheme.load(from: directory)
expectSameColors(loaded, ColorScheme.sunset)
try Data("# Comments-only configuration\n".utf8).write(to: directory.appendingPathComponent("config.toml"))
expectSameColors(try ColorScheme.load(from: directory), ColorScheme.sunset)
try Data("theme = 'sunset'\n".utf8).write(to: directory.appendingPathComponent("config.toml"))
expectSameColors(try ColorScheme.load(from: directory), ColorScheme.sunset)
}
@Test @MainActor
func partialManualColorsOverrideSunsetWithoutChangingOtherFields() throws {
let directory = try colorConfigurationDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
try Data("""
# Personal color overrides
[colors]
accent = '#aB1234' # Keep the hash inside the quoted color
error = "#123456"
""".utf8).write(to: directory.appendingPathComponent("config.toml"))
var expected = ColorScheme.sunset
expected.accent = NSColor(srgbRed: 171.0 / 255, green: 18.0 / 255, blue: 52.0 / 255, alpha: 1)
expected.error = NSColor(srgbRed: 18.0 / 255, green: 52.0 / 255, blue: 86.0 / 255, alpha: 1)
expectSameColors(try ColorScheme.load(from: directory), expected)
}
@Test @MainActor
func tintColorsLayerBetweenDefaultsAndManualOverrides() throws {
let directory = try colorConfigurationDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
try Data("""
theme = "tint"
[colors]
accent = "#ffffff"
text = "#000000"
""".utf8).write(to: directory.appendingPathComponent("config.toml"))
try Data(##"{"colors":{"accent":"#ff0000","background":"#123456","glow":"#00ff00"}}"##.utf8)
.write(to: directory.appendingPathComponent("theme.json"))
var expected = ColorScheme.sunset
expected.accent = NSColor(srgbRed: 1, green: 1, blue: 1, alpha: 1)
expected.text = NSColor(srgbRed: 0, green: 0, blue: 0, alpha: 1)
expected.background = NSColor(srgbRed: 18.0 / 255, green: 52.0 / 255, blue: 86.0 / 255, alpha: 1)
expected.glow = NSColor(srgbRed: 0, green: 1, blue: 0, alpha: 1)
expectSameColors(try ColorScheme.load(from: directory), expected)
}
@Test @MainActor
func malformedColorConfigurationReportsItsPathAndReason() throws {
let directory = try colorConfigurationDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
let config = directory.appendingPathComponent("config.toml")
let invalid: [(String, String?)] = [
("colors.accent = '#12345678'", "colors.accent"),
("colors.accent = '#fff'", "colors.accent"),
("colors.accent = '#12gg56'", "colors.accent"),
("colors.accent = '#123456'", "colors.accent"),
("colors.accent = '123456'", "colors.accent"),
("colors.accent = ' #123456'", "colors.accent"),
("colors.accent = 42", "colors.accent"),
("colors.accnet = '#123456'", "colors.accnet"),
("opacity = 0.5", "opacity"),
("variant = 'light'", "variant"),
("colors = []", "colors"),
("colors = false", "colors"),
("theme = 'unknown'", "theme"),
("theme = true", "theme"),
("[colors", nil),
("colors.accent = '#123456'\ncolors.accent = '#abcdef'", nil),
("[colors]\n[colors]", nil),
("theme = 'sunset'\ntheme = 'tint'", nil),
]
for (toml, reason) in invalid {
try Data(toml.utf8).write(to: config)
expectColorSchemeFailure(in: directory, path: config, reason: reason)
}
}
@Test @MainActor
func selectedTintRequiresAnExistingValidGeneratedTheme() throws {
let directory = try colorConfigurationDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
let theme = directory.appendingPathComponent("theme.json")
try Data("theme = 'tint'\ncolors.accent = '#ffffff'\n".utf8)
.write(to: directory.appendingPathComponent("config.toml"))
expectColorSchemeFailure(in: directory, path: theme)
let invalid: [(String, String?)] = [
("not JSON", nil),
("[]", nil),
(#"{"theme":"sunset"}"#, "theme"),
(##"{"colors":{"accent":"#12345678"}}"##, "colors.accent"),
(##"{"colors":{"glwo":"#123456"}}"##, "colors.glwo"),
(#"{"colors":false}"#, "colors"),
]
for (json, reason) in invalid {
try Data(json.utf8).write(to: theme)
expectColorSchemeFailure(in: directory, path: theme, reason: reason)
}
try Data(#"{"colors":{}}"#.utf8).write(to: theme)
var expected = ColorScheme.sunset
expected.accent = NSColor(srgbRed: 1, green: 1, blue: 1, alpha: 1)
expectSameColors(try ColorScheme.load(from: directory), expected)
}
private func colorConfigurationDirectory() throws -> URL {
let directory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
return directory
}
@MainActor private func expectSameColors(_ actual: ColorScheme, _ expected: ColorScheme) {
#expect(actual.background == expected.background)
#expect(actual.text == expected.text)
#expect(actual.secondaryText == expected.secondaryText)
#expect(actual.accent == expected.accent)
#expect(actual.glow == expected.glow)
#expect(actual.keyBackground == expected.keyBackground)
#expect(actual.error == expected.error)
}
@MainActor private func expectColorSchemeFailure(in directory: URL, path: URL, reason: String? = nil) {
do {
_ = try ColorScheme.load(from: directory)
Issue.record("Expected invalid color configuration to throw: \(path.path)")
} catch {
#expect(error is any LocalizedError)
#expect(error.localizedDescription.contains(path.path))
if let reason { #expect(error.localizedDescription.contains(reason)) }
}
}