Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Sep 11, 2024
1 parent f12cc79 commit e98a190
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 17 deletions.
10 changes: 4 additions & 6 deletions [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ let package = Package(
name: "DependenciesMacros",
targets: ["DependenciesMacros"]
),
// NB: A Swift bug prevents the test trait from being useful at the moment.
// https://github.com/swiftlang/swift/issues/76409
// .library(
// name: "DependenciesTestSupport",
// targets: ["DependenciesTestSupport"]
// ),
.library(
name: "DependenciesTestSupport",
targets: ["DependenciesTestSupport"]
),
],
dependencies: [
.package(url: "https://github.com/pointfreeco/combine-schedulers", from: "1.0.2"),
Expand Down
4 changes: 2 additions & 2 deletions Sources/Dependencies/DependencyValues/MainQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/// For example, you could introduce controllable timing to an observable object model that
/// counts the number of seconds it's onscreen:
///
/// ```
/// ```swift
/// @Observable
/// final class TimerModel {
/// var elapsed = 0
Expand All @@ -31,7 +31,7 @@
///
/// And you could test this model by overriding its main queue with a test scheduler:
///
/// ```
/// ```swift
/// @Test
/// func feature() {
/// let mainQueue = DispatchQueue.test
Expand Down
40 changes: 37 additions & 3 deletions Sources/Dependencies/Traits/PreviewTrait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,52 @@

@available(iOS 18, macOS 15, tvOS 18, watchOS 11, visionOS 2, *)
extension PreviewTrait where T == Preview.ViewTraits {
/// A trait that overrides a preview's dependency.
///
/// Useful for overriding a dependency in a preview without incurring the nesting and
/// indentation of ``withDependencies(_:operation:)-4uz6m``.
///
/// ```swift
/// #Preview(
/// .dependency(\.continuousClock, .immediate)
/// ) {
/// TimerView()
/// }
/// ```
///
/// - Parameters:
/// - keyPath: A key path to a dependency value.
/// - value: A dependency value to override for the lifetime of the preview.
public static func dependency<Value: Sendable>(
_ keyPath: WritableKeyPath<DependencyValues, Value> & Sendable,
_ value: Value
) -> PreviewTrait {
.dependencies { $0[keyPath: keyPath] = value }
}


/// A trait that overrides a preview's dependencies.
///
/// Useful for overriding several dependencies in a preview without incurring the nesting and
/// indentation of ``withDependencies(_:operation:)-4uz6m``.
///
/// ```swift
/// #Preview(
/// .dependencies {
/// $0.continuousClock = .immediate
/// $0.date.now = Date(timeIntervalSinceReferenceDate: 0)
/// }
/// ) {
/// TimerView()
/// }
/// ```
///
/// - Parameter updateValuesForPreview: A closure for updating the current dependency values for
/// the lifetime of the preview.
public static func dependencies(
_ operation: @Sendable (inout DependencyValues) -> Void
_ updateValuesForPreview: @Sendable (inout DependencyValues) -> Void
) -> PreviewTrait {
previewValues.withValue {
operation(&$0)
updateValuesForPreview(&$0)
}
return PreviewTrait()
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/Dependencies/Traits/TestTrait.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
public struct _DependenciesTrait: Sendable {
package let operation: @Sendable (inout DependencyValues) -> Void
package let updateValues: @Sendable (inout DependencyValues) -> Void

package init(_ operation: @escaping @Sendable (inout DependencyValues) -> Void) {
self.operation = operation
package init(_ updateValues: @escaping @Sendable (inout DependencyValues) -> Void) {
self.updateValues = updateValues
}

package static let all = LockIsolated<[AnyHashable: DependencyValues]>([:])
Expand Down
44 changes: 41 additions & 3 deletions Sources/DependenciesTestSupport/TestTrait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,63 @@
import Testing

extension Trait where Self == _DependenciesTrait {
/// A trait that overrides a test's or suite's dependency.
///
/// Useful for overriding a dependency in a test without incurring the nesting and
/// indentation of ``withDependencies(_:operation:)-4uz6m``.
///
/// ```swift
/// @Test(
/// .dependency(\.continuousClock, .immediate)
/// )
/// func feature() {
/// // ...
/// }
/// ```
///
/// > Important: Due to [a Swift bug](https://github.com/swiftlang/swift/issues/76409), it is
/// > not possible to specify a closure directly inside a `@Suite` or `@Test` macro:
/// >
/// > ```swift
/// > @Suite(
/// > .dependency(\.apiClient.fetchUser, { _ in .mock }) // 🛑
/// > )
/// > struct FeatureTests { /* ... */ }
/// > ```
/// >
/// > To work around: extract the closure so that it is created outside the macro:
/// >
/// > private let fetchUser: @Sendable (Int) async throws -> User = { _ in .mock }
/// > @Suite(
/// > .dependency(\.apiClient.fetchUser, fetchUser)
/// > )
/// > struct FeatureTests { /* ... */ }
///
/// - Parameters:
/// - keyPath: A key path to a dependency value.
/// - value: A dependency value to override for the test.
public static func dependency<Value: Sendable>(
_ keyPath: WritableKeyPath<DependencyValues, Value> & Sendable,
_ value: Value
) -> Self {
Self { $0[keyPath: keyPath] = value }
}

/// A trait that overrides a test's or suite's dependencies.
public static func dependencies(
_ operation: @escaping @Sendable (inout DependencyValues) -> Void
_ updateValues: @escaping @Sendable (inout DependencyValues) -> Void
) -> Self {
Self(operation)
Self(updateValues)
}
}

extension _DependenciesTrait: SuiteTrait, TestTrait {
public var isRecursive: Bool { true }

public func prepare(for test: Test) async throws {
Self.all.withValue { self.operation(&$0[test.id, default: DependencyValues(context: .test)]) }
Self.all.withValue {
self.updateValues(&$0[test.id, default: DependencyValues(context: .test)])
}
}
}
#endif

0 comments on commit e98a190

Please sign in to comment.