Skip to content

Commit

Permalink
Be Testable & Added Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyome22 committed Nov 13, 2024
1 parent 2010a8d commit 2898279
Show file tree
Hide file tree
Showing 26 changed files with 543 additions and 178 deletions.
6 changes: 4 additions & 2 deletions ShiftWindow/ShiftWindowApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ struct ShiftWindowApp: App {

var body: some Scene {
MenuBarScene()
.environment(\.appDependency, appDelegate.appDependency)
.environment(\.appDependencies, appDelegate.appDependencies)
.environment(\.appServices, appDelegate.appServices)
SettingsWindowScene()
.environment(\.appDependency, appDelegate.appDependency)
.environment(\.appDependencies, appDelegate.appDependencies)
.environment(\.appServices, appDelegate.appServices)
ShortcutPanelScene(isPresented: $isPresented)
}
}
2 changes: 1 addition & 1 deletion ShiftWindowPackages/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ let package = Package(
name: "DataLayer",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "PanelSceneKit", package: "PanelSceneKit"),
.product(name: "Sparkle", package: "Sparkle"),
.product(name: "SpiceKey", package: "SpiceKey"),
],
Expand All @@ -47,7 +48,6 @@ let package = Package(
dependencies: [
"DataLayer",
.product(name: "Logging", package: "swift-log"),
.product(name: "PanelSceneKit", package: "PanelSceneKit"),
.product(name: "SpiceKey", package: "SpiceKey"),
],
swiftSettings: swiftSettings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ public protocol DependencyClient: Sendable {
static var liveValue: Self { get }
static var testValue: Self { get }
}

public func testDependency<D: DependencyClient>(of type: D.Type, injection: (inout D) -> Void) -> D {
var dependencyClient = type.testValue
injection(&dependencyClient)
return dependencyClient
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
PanelSceneMessengerClient.swift
DataLayer

Created by Takuto Nakamura on 2024/11/14.
Copyright 2022 Takuto Nakamura (Kyome22)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import PanelSceneKit

public struct PanelSceneMessengerClient: DependencyClient {
public var request: @Sendable (PanelAction, String, [AnyHashable : Any]?) -> Void

public static let liveValue = Self(
request: { PanelSceneMessenger.request(panelAction: $0, with: $1, userInfo: $2) }
)

public static let testValue = Self(
request: { _, _, _ in }
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
SpiceKeyClient.swift
DataLayer

Created by Takuto Nakamura on 2024/11/14.
Copyright 2022 Takuto Nakamura (Kyome22)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import SpiceKey

public struct SpiceKeyClient: DependencyClient {
public var register: @Sendable (SpiceKey) -> Void
public var unregister: @Sendable (SpiceKey) -> Void

public static let liveValue = Self(
register: { $0.register() },
unregister: { $0.unregister() }
)

public static let testValue = Self(
register: { _ in },
unregister: { _ in }
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ public struct UserDefaultsRepository: Sendable {
nonmutating set { userDefaultsClient.setBool(newValue, .showShortcutPanel) }
}

public init(_ userDefaultsClient: UserDefaultsClient, reset: Bool) {
public init(_ userDefaultsClient: UserDefaultsClient) {
self.userDefaultsClient = userDefaultsClient

#if DEBUG
if reset {
if ProcessInfo.needsResetUserDefaults {
userDefaultsClient.removePersistentDomain(Bundle.main.bundleIdentifier!)
}
#endif
Expand Down
24 changes: 14 additions & 10 deletions ShiftWindowPackages/Sources/Domain/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,32 @@ import AppKit
import DataLayer

public final class AppDelegate: NSObject, NSApplicationDelegate {
public let appDependency: AppDependency
public let appDependencies = AppDependencies()
public let appServices: AppServices

public override init() {
appDependency = .init(
needsResetUserDefaults: ProcessInfo.needsResetUserDefaults
)
appServices = .init(appDependencies: appDependencies)
super.init()
}

public func applicationDidFinishLaunching(_ notification: Notification) {
Task {
await appDependency.logService.bootstrap()
appDependency.logService.notice(.launchApp)
await appDependency.shortcutService.initializeShortcuts()
await appServices.logService.bootstrap()
appServices.logService.notice(.launchApp)
await appServices.shortcutService.initializeShortcuts()
}
let unmanagedKey = appDependency.hiServicesClient.trustedCheckOptionPrompt()
Task {
for await shiftType in await appServices.shortcutService.shiftTypeStream() {
await appServices.shiftService.shiftWindow(shiftType: shiftType)
}
}
let unmanagedKey = appDependencies.hiServicesClient.trustedCheckOptionPrompt()
let options = [unmanagedKey.takeRetainedValue(): true] as CFDictionary
_ = appDependency.hiServicesClient.isProcessTrusted(options)
_ = appDependencies.hiServicesClient.isProcessTrusted(options)
}

public func applicationWillTerminate(_ notification: Notification) {
let executeClient = appDependency.executeClient
let executeClient = appDependencies.executeClient
Task.detached(priority: .background) {
if try executeClient.checkIconsVisible() {
try executeClient.toggleIconsVisible(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
AppDependency.swift
AppDependencies.swift
Domain

Created by Takuto Nakamura on 2024/11/01.
Expand All @@ -22,18 +22,19 @@ import DataLayer
import Observation
import SwiftUI

public final class AppDependency: Sendable {
public final class AppDependencies: Sendable {
public let cgDirectDisplayClient: CGDirectDisplayClient
public let executeClient: ExecuteClient
public let hiServicesClient: HIServicesClient
public let loggingSystemClient: LoggingSystemClient
public let nsAppClient: NSAppClient
public let nsScreenClient: NSScreenClient
public let nsWorkspaceClient: NSWorkspaceClient
public let checkForUpdatesRepository: CheckForUpdatesRepository
public let userDefaultsRepository: UserDefaultsRepository
public let launchAtLoginRepository: LaunchAtLoginRepository
public let logService: LogService
public let shiftService: ShiftService
public let shortcutService: ShortcutService
public let updateService: UpdateService
public let panelSceneMessengerClient: PanelSceneMessengerClient
public let smAppServiceClient: SMAppServiceClient
public let spiceKeyClient: SpiceKeyClient
public let spuUpdaterClient: SPUUpdaterClient
public let userDefaultsClient: UserDefaultsClient

public nonisolated init(
cgDirectDisplayClient: CGDirectDisplayClient = .liveValue,
Expand All @@ -43,47 +44,47 @@ public final class AppDependency: Sendable {
nsAppClient: NSAppClient = .liveValue,
nsScreenClient: NSScreenClient = .liveValue,
nsWorkspaceClient: NSWorkspaceClient = .liveValue,
panelSceneMessengerClient: PanelSceneMessengerClient = .liveValue,
smAppServiceClient: SMAppServiceClient = .liveValue,
spiceKeyClient: SpiceKeyClient = .liveValue,
spuUpdaterClient: SPUUpdaterClient = .liveValue,
userDefaultsClient: UserDefaultsClient = .liveValue,
needsResetUserDefaults: Bool = false
userDefaultsClient: UserDefaultsClient = .liveValue
) {
self.cgDirectDisplayClient = cgDirectDisplayClient
self.executeClient = executeClient
self.hiServicesClient = hiServicesClient
self.loggingSystemClient = loggingSystemClient
self.nsAppClient = nsAppClient
self.nsScreenClient = nsScreenClient
self.nsWorkspaceClient = nsWorkspaceClient
checkForUpdatesRepository = .init(spuUpdaterClient)
userDefaultsRepository = .init(userDefaultsClient, reset: needsResetUserDefaults)
launchAtLoginRepository = .init(smAppServiceClient)
logService = .init(loggingSystemClient)
shiftService = .init(cgDirectDisplayClient,
hiServicesClient,
nsAppClient,
nsScreenClient,
nsWorkspaceClient)
shortcutService = .init(userDefaultsRepository, shiftService)
updateService = .init(spuUpdaterClient)
self.panelSceneMessengerClient = panelSceneMessengerClient
self.smAppServiceClient = smAppServiceClient
self.spiceKeyClient = spiceKeyClient
self.spuUpdaterClient = spuUpdaterClient
self.userDefaultsClient = userDefaultsClient
}
}

struct AppDependencyKey: EnvironmentKey {
static let defaultValue = AppDependency(
struct AppDependenciesKey: EnvironmentKey {
static let defaultValue = AppDependencies(
cgDirectDisplayClient: .testValue,
executeClient: .testValue,
hiServicesClient: .testValue,
loggingSystemClient: .testValue,
nsAppClient: .testValue,
nsScreenClient: .testValue,
nsWorkspaceClient: .testValue,
panelSceneMessengerClient: .testValue,
smAppServiceClient: .testValue,
spiceKeyClient: .testValue,
spuUpdaterClient: .testValue,
userDefaultsClient: .testValue
)
}

public extension EnvironmentValues {
var appDependency: AppDependency {
get { self[AppDependencyKey.self] }
set { self[AppDependencyKey.self] = newValue }
var appDependencies: AppDependencies {
get { self[AppDependenciesKey.self] }
set { self[AppDependenciesKey.self] = newValue }
}
}
42 changes: 42 additions & 0 deletions ShiftWindowPackages/Sources/Domain/AppServices.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
AppServices.swift
Domain

Created by Takuto Nakamura on 2024/11/14.

*/

import DataLayer
import Observation
import SwiftUI

public final class AppServices: Sendable {
public let logService: LogService
public let shiftService: ShiftService
public let shortcutService: ShortcutService
public let updateService: UpdateService

public nonisolated init(appDependencies: AppDependencies) {
logService = .init(appDependencies.loggingSystemClient)
shiftService = .init(appDependencies.cgDirectDisplayClient,
appDependencies.hiServicesClient,
appDependencies.nsAppClient,
appDependencies.nsScreenClient,
appDependencies.nsWorkspaceClient)
shortcutService = .init(appDependencies.panelSceneMessengerClient,
appDependencies.spiceKeyClient,
appDependencies.userDefaultsClient)
updateService = .init(appDependencies.spuUpdaterClient)
}
}

struct AppServicesKey: EnvironmentKey {
static let defaultValue = AppServices(appDependencies: AppDependenciesKey.defaultValue)
}

public extension EnvironmentValues {
var appServices: AppServices {
get { self[AppServicesKey.self] }
set { self[AppServicesKey.self] = newValue }
}
}
Loading

0 comments on commit 2898279

Please sign in to comment.