136 lines
6.1 KiB
Swift
136 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("{}".utf8).write(to: directory.appendingPathComponent("config.json"))
|
|
expectSameColors(try ColorScheme.load(from: directory), ColorScheme.sunset)
|
|
|
|
try Data(#"{"theme":"sunset"}"#.utf8).write(to: directory.appendingPathComponent("config.json"))
|
|
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(##"{"colors":{"accent":"#aB1234","error":"#123456"}}"##.utf8)
|
|
.write(to: directory.appendingPathComponent("config.json"))
|
|
|
|
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.json"))
|
|
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.json")
|
|
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":{"accent":null}}"#, "colors.accent"),
|
|
(##"{"colors":{"accnet":"#123456"}}"##, "colors.accnet"),
|
|
(#"{"opacity":0.5}"#, "opacity"),
|
|
(#"{"colors":[]}"#, "colors must be an object"),
|
|
(#"{"colors":null}"#, "colors must be an object"),
|
|
(#"{"theme":"unknown"}"#, "theme"),
|
|
(#"{"theme":true}"#, "theme"),
|
|
(#"{"theme":null}"#, "theme"),
|
|
("{", "Invalid JSON"),
|
|
("[]", "JSON object"),
|
|
("null", "JSON object"),
|
|
]
|
|
for (json, reason) in invalid {
|
|
try Data(json.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","colors":{"accent":"#ffffff"}}"##.utf8)
|
|
.write(to: directory.appendingPathComponent("config.json"))
|
|
expectColorSchemeFailure(in: directory, path: theme)
|
|
|
|
let invalid: [(String, String)] = [
|
|
("not JSON", "Invalid JSON"),
|
|
("[]", "JSON object"),
|
|
(#"{"theme":"sunset"}"#, "theme"),
|
|
(##"{"colors":{"accent":"#12345678"}}"##, "colors.accent"),
|
|
(##"{"colors":{"glwo":"#123456"}}"##, "colors.glwo"),
|
|
(#"{"colors":false}"#, "colors must be an object"),
|
|
]
|
|
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)) }
|
|
}
|
|
}
|