// // ClientEnvironmentKeyTests.swift // // Copyright 2026 Brendan Szymanski // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // SPDX-License-Identifier: GPL-3.0-or-later // import Foundation import LuminateCore @_spi(Portico) import Portico import Testing @testable import LuminateUI /// A ``JellyfinService`` that exists only to be told apart from the default. private final class StubJellyfinService: JellyfinService { var isAuthenticated: Bool { true } func publicServerInfo() async throws -> JellyfinServerInfo { JellyfinServerInfo() } func serverInfo() async throws -> JellyfinServerInfo { JellyfinServerInfo() } func publicUsers() async throws -> [JellyfinUser] { [] } func currentUser() async throws -> JellyfinUser { JellyfinUser() } func authenticate(username: String, password: String) async throws -> JellyfinAuthentication { JellyfinAuthentication(accessToken: "stub") } func quickConnectEnabled() async throws -> Bool { false } func initiateQuickConnect() async throws -> JellyfinQuickConnectState { JellyfinQuickConnectState() } func quickConnectState(secret: String) async throws -> JellyfinQuickConnectState { JellyfinQuickConnectState() } func authenticateWithQuickConnect(secret: String) async throws -> JellyfinAuthentication { JellyfinAuthentication(accessToken: "stub") } func updateUserPassword( userID: String?, currentPassword: String?, currentPIN: String?, newPassword: String?, resetPassword: Bool? ) async throws {} func libraries(_ options: JellyfinListOptions) async throws -> [JellyfinLibrary] { [] } func items(_ query: JellyfinMediaQuery) async throws -> JellyfinMediaPage { JellyfinMediaPage() } func item(id: String, userID: String?) async throws -> JellyfinMediaItem { JellyfinMediaItem() } func resumeItems(_ options: JellyfinListOptions) async throws -> JellyfinMediaPage { JellyfinMediaPage() } func nextUp(seriesID: String?, options: JellyfinListOptions) async throws -> JellyfinMediaPage { JellyfinMediaPage() } func latestMedia(_ options: JellyfinListOptions) async throws -> [JellyfinMediaItem] { [] } func seasons(seriesID: String, options: JellyfinListOptions) async throws -> JellyfinMediaPage { JellyfinMediaPage() } func episodes(seriesID: String, options: JellyfinListOptions) async throws -> JellyfinMediaPage { JellyfinMediaPage() } func searchHints(term: String, options: JellyfinListOptions) async throws -> [JellyfinSearchHint] { [] } func image( itemID: String, type: JellyfinImageType, index: Int32?, request: JellyfinImageRequest ) async throws -> Data { Data() } func markPlayed(itemID: String, userID: String?, datePlayed: Date?) async throws -> JellyfinUserData { JellyfinUserData() } func markUnplayed(itemID: String, userID: String?) async throws -> JellyfinUserData { JellyfinUserData() } func markFavorite(itemID: String, userID: String?) async throws -> JellyfinUserData { JellyfinUserData() } func unmarkFavorite(itemID: String, userID: String?) async throws -> JellyfinUserData { JellyfinUserData() } } /// Guards the `\\.client` environment slot itself. /// /// No widgets are constructed, so these run on a headless machine without `Gtk.initCheck()`. @MainActor @Suite struct ClientEnvironmentKeyTests { @Test("An unresolved slot falls back to the unconfigured service") func defaultIsUnconfigured() { #expect(EnvironmentValues().client is UnconfiguredJellyfinService) } @Test("The key path routes through the environment subscript") func keyPathResolvesToABox() { #expect(EnvironmentValues()._box(for: \.client) != nil) } @Test("An injected service replaces the default") func injectionOverridesDefault() { var values = EnvironmentValues() values.client = StubJellyfinService() #expect(values.client is StubJellyfinService) } }