Place to hold stencil templates to be used in Sourcery.
Creates special initializer fixture
to simplify testing when mocking objects.
// Input ⬅️
enum MyEnum {
case firstCase
case secondCase
}
struct MyModel: AutoFixture {
let anInt: Int
let anUInt: UInt
let aFloat: Float
let aDouble: Double
let aBool: Bool
let aString: String
let aCharacter: Character
let anArray: Array
let anArray2: [Int]
let aDictionary: Dictionary
let aDictionary2: [String: String]
let aSet: Set
let aDate: Date
let aData: Data
let anURL: URL
let aSomething: Something
let anEnum: MyEnum
}
// Output ➡️
extension MyModel {
static func fixture(
anInt: Int = 0,
anUInt: UInt = 0,
aFloat: Float = 0,
aDouble: Double = 0,
aBool: Bool = false,
aString: String = "aString",
aCharacter: Character = "",
anArray: Array = .fixture(),
anArray2: [Int] = .init(),
aDictionary: Dictionary = .fixture(),
aDictionary2: [String: String] = .init(),
aSet: Set = .fixture(),
aDate: Date = .distantFuture,
aData: Data = .init(),
anURL: URL = .init(),
aSomething: Something = .fixture(),
anEnum: MyEnum = .firstCase
) -> Self {
return .init(
anInt: anInt,
anUInt: anUInt,
aFloat: aFloat,
aDouble: aDouble,
aBool: aBool,
aString: aString,
aCharacter: aCharacter,
anArray: anArray,
anArray2: anArray2,
aDictionary: aDictionary,
aDictionary2: aDictionary2,
aSet: aSet,
aDate: aDate,
aData: aData,
anURL: anURL,
aSomething: aSomething,
anEnum: anEnum
)
}
}
#endif
Creates a Failing
based on a dependency protocol.
NOTE: it assumes that all models returned have a fixture
method previously defined.
enum MyEnum {
case firstCase
case secondCase
}
protocol SomeServiceProtocol {
func getSomething(_ id: String) async throws -> Something
func getEnum() async throws -> MyEnum
func getDate() async throws -> Date
func getData() async throws -> Data
func getURL() async throws -> URL
func getArray() async throws -> [String]
func getDictionary() async throws -> [String: String]
func postSomething() async throws
}
import XCTestDynamicOverlay
// MARK: - SomeServiceProtocolFailing
public struct SomeServiceFailing: SomeServiceProtocol {
public init() {}
public func getSomething(_ id: String) async throws -> Something {
XCTFail("\(#function) is not implemented.")
return .fixture()
}
public func getEnum() async throws -> MyEnum {
XCTFail("\(#function) is not implemented.")
return .firstCase
}
public func getDate() async throws -> Date {
XCTFail("\(#function) is not implemented.")
return .init()
}
public func getData() async throws -> Data {
XCTFail("\(#function) is not implemented.")
return .init()
}
public func getURL() async throws -> URL {
XCTFail("\(#function) is not implemented.")
return .init()
}
public func getArray() async throws -> [String] {
XCTFail("\(#function) is not implemented.")
return .init()
}
public func getDictionary() async throws -> [String: String] {
XCTFail("\(#function) is not implemented.")
return .init()
}
public func postSomething() async throws {
XCTFail("\(#function) is not implemented.")
}
}
#endif
Generates Spy
s based on a dependency protocol, mostly applicable for datasources like services and repositories.
NOTE: it assumes that all models returned have a fixture
method previously defined.
Based on Protocol Mock
template from Łukasz Kuczborski
enum MyEnum {
case firstCase
case secondCase
}
protocol SomethingRepositoryInterface {
init(input: String)
func fetchSomething(_ id: String) async throws -> Something
func getEnum() async throws -> MyEnum
func getDate() async throws -> Date
func getData() async throws -> Data
func fetchURL() async throws -> URL
func fetchArray() async throws -> [String]
func fetchDictionary() async throws -> [String: String]
func saveSomething(stringParam: String, intParam: Int, somethingParam: Something) async throws
func saveSomethingNoThrow(_ data: Data) async
}
// MARK: - SomethingRepositoryInterfaceSpy
internal final class SomethingRepositorySpy: SomethingRepositoryInterface {
internal init() {}
// MARK: - init
internal var initInputReceivedInput: String?
internal var initInputReceivedInvocations: [String] = []
internal var initInputClosure: ((String) -> Void)?
required init(input: String) {
initInputReceivedInput = input
initInputReceivedInvocations.append(input)
initInputClosure?(input)
}
// MARK: - fetchSomething
internal var fetchSomethingCallsCount = 0
internal var fetchSomethingCalled: Bool {
fetchSomethingCallsCount > 0
}
internal var fetchSomethingReceivedId: String?
internal var fetchSomethingReceivedInvocations: [String] = []
internal func fetchSomething(_ id: String) async throws -> Something {
fetchSomethingCallsCount += 1
fetchSomethingReceivedId = id
fetchSomethingReceivedInvocations.append(id)
return .fixture()
}
// MARK: - getEnum
internal var getEnumCallsCount = 0
internal var getEnumCalled: Bool {
getEnumCallsCount > 0
}
internal func getEnum() async throws -> MyEnum {
getEnumCallsCount += 1
return .firstCase
}
// MARK: - getDate
internal var getDateCallsCount = 0
internal var getDateCalled: Bool {
getDateCallsCount > 0
}
internal func getDate() async throws -> Date {
getDateCallsCount += 1
return .init()
}
// MARK: - getData
internal var getDataCallsCount = 0
internal var getDataCalled: Bool {
getDataCallsCount > 0
}
internal func getData() async throws -> Data {
getDataCallsCount += 1
return .init()
}
// MARK: - fetchURL
internal var fetchURLCallsCount = 0
internal var fetchURLCalled: Bool {
fetchURLCallsCount > 0
}
internal func fetchURL() async throws -> URL {
fetchURLCallsCount += 1
return .init(string:"www.test.com").unsafelyUnwrapped
}
// MARK: - fetchArray
internal var fetchArrayCallsCount = 0
internal var fetchArrayCalled: Bool {
fetchArrayCallsCount > 0
}
internal func fetchArray() async throws -> [String] {
fetchArrayCallsCount += 1
return .init()
}
// MARK: - fetchDictionary
internal var fetchDictionaryCallsCount = 0
internal var fetchDictionaryCalled: Bool {
fetchDictionaryCallsCount > 0
}
internal func fetchDictionary() async throws -> [String: String] {
fetchDictionaryCallsCount += 1
return .init()
}
// MARK: - saveSomething
internal var saveSomethingStringParamIntParamSomethingParamCallsCount = 0
internal var saveSomethingStringParamIntParamSomethingParamCalled: Bool {
saveSomethingStringParamIntParamSomethingParamCallsCount > 0
}
internal var saveSomethingStringParamIntParamSomethingParamReceivedArguments: (stringParam: String, intParam: Int, somethingParam: Something)?
internal var saveSomethingStringParamIntParamSomethingParamReceivedInvocations: [(stringParam: String, intParam: Int, somethingParam: Something)] = []
internal func saveSomething(stringParam: String, intParam: Int, somethingParam: Something) async throws {
saveSomethingStringParamIntParamSomethingParamCallsCount += 1
saveSomethingStringParamIntParamSomethingParamReceivedArguments = (stringParam: stringParam, intParam: intParam, somethingParam: somethingParam)
saveSomethingStringParamIntParamSomethingParamReceivedInvocations.append((stringParam: stringParam, intParam: intParam, somethingParam: somethingParam))
}
// MARK: - saveSomethingNoThrow
internal var saveSomethingNoThrowCallsCount = 0
internal var saveSomethingNoThrowCalled: Bool {
saveSomethingNoThrowCallsCount > 0
}
internal var saveSomethingNoThrowReceivedData: Data?
internal var saveSomethingNoThrowReceivedInvocations: [Data] = []
internal func saveSomethingNoThrow(_ data: Data) async {
saveSomethingNoThrowCallsCount += 1
saveSomethingNoThrowReceivedData = data
saveSomethingNoThrowReceivedInvocations.append(data)
}
}
Generates Test Doubles
that serve as Spy
and Stub
based on a dependency protocol, mostly applicable for datasources like services and repositories.
NOTE: it assumes that all models returned have a fixture
method previously defined.
*Based on Protocol Mock
template from `Łukasz Kuczborski``
enum SomeEnum {
case firstCase
case secondCase
}
protocol SomethingRepositoryInterface {
init(input: String)
func fetchSomethingWithID(_ id: String) async throws -> Something
func fetchArrayOfSomething() async throws -> [Something]
func fetchArrayOfSomeEnum() async throws -> [SomeEnum]
func postSomething(stringParam: String, intParam: Int, somethingParam: Something) async throws
}
// MARK: - SomethingRepositoryInterfaceSpyingStub
internal final class SomethingRepositorySpyingStub: SomethingRepositoryInterface {
internal init() {}
// MARK: - init
internal var initInputReceivedInput: String?
internal var initInputReceivedInvocations: [String] = []
internal var initInputClosure: ((String) -> Void)?
required init(input: String) {
initInputReceivedInput = input
initInputReceivedInvocations.append(input)
initInputClosure?(input)
}
// MARK: - fetchSomething
internal var fetchSomethingResultToBeReturned: Result<Something, Error> = .success(.fixture())
internal var fetchSomethingCallsCount = 0
internal var fetchSomethingCalled: Bool {
fetchSomethingCallsCount > 0
}
internal var fetchSomethingReceivedId: String?
internal var fetchSomethingReceivedInvocations: [String] = []
internal func fetchSomething(_ id: String) async throws -> Something {
fetchSomethingCallsCount += 1
fetchSomethingReceivedId = id
fetchSomethingReceivedInvocations.append(id)
return try fetchSomethingResultToBeReturned.get()
}
// MARK: - getEnum
internal var getEnumResultToBeReturned: Result<MyEnum, Error> = .success(.firstCase)
internal var getEnumCallsCount = 0
internal var getEnumCalled: Bool {
getEnumCallsCount > 0
}
internal func getEnum() async throws -> MyEnum {
getEnumCallsCount += 1
return try getEnumResultToBeReturned.get()
}
// MARK: - getDate
internal var getDateResultToBeReturned: Result<Date, Error> = .success(.init())
internal var getDateCallsCount = 0
internal var getDateCalled: Bool {
getDateCallsCount > 0
}
internal func getDate() async throws -> Date {
getDateCallsCount += 1
return try getDateResultToBeReturned.get()
}
// MARK: - getData
internal var getDataResultToBeReturned: Result<Data, Error> = .success(.init())
internal var getDataCallsCount = 0
internal var getDataCalled: Bool {
getDataCallsCount > 0
}
internal func getData() async throws -> Data {
getDataCallsCount += 1
return try getDataResultToBeReturned.get()
}
// MARK: - fetchURL
internal var fetchURLResultToBeReturned: Result<URL, Error> = .success(.init(string:"www.test.com").unsafelyUnwrapped)
internal var fetchURLCallsCount = 0
internal var fetchURLCalled: Bool {
fetchURLCallsCount > 0
}
internal func fetchURL() async throws -> URL {
fetchURLCallsCount += 1
return try fetchURLResultToBeReturned.get()
}
// MARK: - fetchArray
internal var fetchArrayResultToBeReturned: Result<[String], Error> = .success(.init())
internal var fetchArrayCallsCount = 0
internal var fetchArrayCalled: Bool {
fetchArrayCallsCount > 0
}
internal func fetchArray() async throws -> [String] {
fetchArrayCallsCount += 1
return try fetchArrayResultToBeReturned.get()
}
// MARK: - fetchDictionary
internal var fetchDictionaryResultToBeReturned: Result<[String: String], Error> = .success(.init())
internal var fetchDictionaryCallsCount = 0
internal var fetchDictionaryCalled: Bool {
fetchDictionaryCallsCount > 0
}
internal func fetchDictionary() async throws -> [String: String] {
fetchDictionaryCallsCount += 1
return try fetchDictionaryResultToBeReturned.get()
}
// MARK: - saveSomething
internal var saveSomethingResultToBeReturned: Result<Void, Error> = .success(())
internal var saveSomethingStringParamIntParamSomethingParamCallsCount = 0
internal var saveSomethingStringParamIntParamSomethingParamCalled: Bool {
saveSomethingStringParamIntParamSomethingParamCallsCount > 0
}
internal var saveSomethingStringParamIntParamSomethingParamReceivedArguments: (stringParam: String, intParam: Int, somethingParam: Something)?
internal var saveSomethingStringParamIntParamSomethingParamReceivedInvocations: [(stringParam: String, intParam: Int, somethingParam: Something)] = []
internal func saveSomething(stringParam: String, intParam: Int, somethingParam: Something) async throws {
saveSomethingStringParamIntParamSomethingParamCallsCount += 1
saveSomethingStringParamIntParamSomethingParamReceivedArguments = (stringParam: stringParam, intParam: intParam, somethingParam: somethingParam)
saveSomethingStringParamIntParamSomethingParamReceivedInvocations.append((stringParam: stringParam, intParam: intParam, somethingParam: somethingParam))
return try saveSomethingResultToBeReturned.get()
}
// MARK: - saveSomethingNoThrow
internal var saveSomethingNoThrowResultToBeReturned: Result<Void, Error> = .success(())
internal var saveSomethingNoThrowCallsCount = 0
internal var saveSomethingNoThrowCalled: Bool {
saveSomethingNoThrowCallsCount > 0
}
internal var saveSomethingNoThrowReceivedData: Data?
internal var saveSomethingNoThrowReceivedInvocations: [Data] = []
internal func saveSomethingNoThrow(_ data: Data) async {
saveSomethingNoThrowCallsCount += 1
saveSomethingNoThrowReceivedData = data
saveSomethingNoThrowReceivedInvocations.append(data)
}
}
Creates a Stub
based on a dependency protocol, mostly applicable for datasources like services and repositories.
NOTE: it assumes that all models returned have a fixture
method previously defined.
enum MyEnum {
case firstCase
case secondCase
}
protocol SomethingRepositoryInterface {
init(input: String)
init(something: String) throws
func fetchSomething(_ id: String) async throws -> Something
func getEnum() async throws -> MyEnum
func getDate() async throws -> Date
func getData() async throws -> Data
func fetchURL() async throws -> URL
func fetchArray() async throws -> [String]
func fetchDictionary() async throws -> [String: String]
func saveSomething(stringParam: String, intParam: Int, somethingParam: Something) async throws
func saveSomethingNoThrow(_ data: Data) async
}
// MARK: - SomethingRepositoryInterfaceStub
internal final class SomethingRepositoryStub: SomethingRepositoryInterface {
internal init() {}
// MARK: - init
internal var initResultToBeReturned: Result<Void, Error> = .success(())
internal func init(something: String) {
try initResultToBeReturned.get()
}
// MARK: - fetchSomething
internal var fetchSomethingResultToBeReturned: Result<Something, Error> = .success(.fixture())
internal func fetchSomething(_ id: String) async throws -> Something {
try fetchSomethingResultToBeReturned.get()
}
// MARK: - getEnum
internal var getEnumResultToBeReturned: Result<MyEnum, Error> = .success(.firstCase)
internal func getEnum() async throws -> MyEnum {
try getEnumResultToBeReturned.get()
}
// MARK: - getDate
internal var getDateResultToBeReturned: Result<Date, Error> = .success(.init())
internal func getDate() async throws -> Date {
try getDateResultToBeReturned.get()
}
// MARK: - getData
internal var getDataResultToBeReturned: Result<Data, Error> = .success(.init())
internal func getData() async throws -> Data {
try getDataResultToBeReturned.get()
}
// MARK: - fetchURL
internal var fetchURLResultToBeReturned: Result<URL, Error> = .success(.init(string:"www.test.com").unsafelyUnwrapped)
internal func fetchURL() async throws -> URL {
try fetchURLResultToBeReturned.get()
}
// MARK: - fetchArray
internal var fetchArrayResultToBeReturned: Result<[String], Error> = .success(.init())
internal func fetchArray() async throws -> [String] {
try fetchArrayResultToBeReturned.get()
}
// MARK: - fetchDictionary
internal var fetchDictionaryResultToBeReturned: Result<[String: String], Error> = .success(.init())
internal func fetchDictionary() async throws -> [String: String] {
try fetchDictionaryResultToBeReturned.get()
}
// MARK: - saveSomething
internal var saveSomethingResultToBeReturned: Result<Void, Error> = .success(())
internal func saveSomething(stringParam: String, intParam: Int, somethingParam: Something) async throws {
try saveSomethingResultToBeReturned.get()
}
// MARK: - saveSomethingNoThrow
internal func saveSomethingNoThrow(_ data: Data) async {}
}
Creates the initializer for class that have a DTO in order to map from DTO to Domain entity.
// Input ⬅️
struct MyObjectDTO: Decodable {
let id: String
let position: Int
let status: RoundStatusDTO
let groups: [RoundGroupDTO]
}
struct MyObject: Equatable, Identifiable, AutoMappableFromDTO {
let id: String
let position: Int
let status: RoundStatus
let groups: [RoundGroup]
}
// Output ➡️
extension MyObject {
init(dto: MyObjectDTO) {
self.id = dto.id
self.position = dto.position
self.status = .init(dto: dto.status)
self.groups = .init(dto: dto.groups)
}
}
Creates a TCA Scaffold from a specification struct, based on the Reducer protocol versions of the library.
NOTE: Based on @tgrapperon’s work from the Composable Feature
template.
- The selected struct is only used as a specification for the TCAFeature and should be deleted after generation
- All specification structs should contain
// sourcery: describesTCAFeature
annotation - In case the specification contains other TCAFeatures as properties (i.e. Composition), // it should containt // sourcery: containsComposition` annotation
// Input ⬅️
// sourcery: describesTCAFeature
struct SimpleFeature: Equatable {
var name: String = ""
var description: String? = nil
var numberOfItems: Int = 0
}
// Output ➡️
import ComposableArchitecture
import Dependencies
import SwiftUI
// MARK: - State
extension SimpleFeature {
internal struct State: Equatable {
internal var name: String
internal var description: String?
internal var numberOfItems: Int
internal init(
name: String = "",
description: String? = nil,
numberOfItems: Int = 0
) {
self.name = name
self.description = description
self.numberOfItems = numberOfItems
}
}
}
// MARK: - Actions
extension SimpleFeature {
internal enum Action: Equatable {
case placeholder
}
}
// MARK: - Reducer
internal struct SimpleFeature: Reducer {
// MARK: - Dependencies
@Dependency(\.fireAndForget) var fireAndForget
// MARK: - Reducer
internal func reduce(
into state: inout State,
action: Action
) -> ComposableArchitecture.Effect<Action> {
switch action {
case .placeholder:
return .none
}
}
}
// MARK: - Scene
extension SimpleFeature {
internal struct Scene: View {
let store: StoreOf<SimpleFeature>
internal init(store: StoreOf<SimpleFeature>) {
self.store = store
}
internal var body: some View {
ZStack {
Text("SimpleFeatureScene")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
// MARK: Preview
struct SimpleFeatureScene_Previews: PreviewProvider {
static var previews: some View {
SimpleFeature.Scene(
store: .init(
initialState: SimpleFeature.State(),
reducer: { EmptyReducer() }
)
)
}
}
struct Child1: Reducer {
struct State: Equatable {}
enum Action: Equatable {}
func reduce(into state: inout State, action: Action) -> Effect<Action> { .none }
}
struct Child2: Reducer {
struct State: Equatable {}
enum Action: Equatable {}
func reduce(into state: inout State, action: Action) -> Effect<Action> { .none }
}
// sourcery: describesTCAFeature
// sourcery: containsComposition
struct ComposedFeature: Equatable {
var name: String = ""
var description: String? = nil
var numberOfItems: Int = 0
var child: Child1.State = .init()
var optionalChild: Child2.State? = nil
}
// Output ➡️
import ComposableArchitecture
import Dependencies
import SwiftUI
// MARK: - State
extension ComposedFeature {
internal struct State: Equatable {
internal var name: String
internal var description: String?
internal var numberOfItems: Int
internal var child: Child1.State
internal var optionalChild: Child2.State?
internal init(
name: String = "",
description: String? = nil,
numberOfItems: Int = 0,
child: Child1.State = .init(),
optionalChild: Child2.State? = nil
) {
self.name = name
self.description = description
self.numberOfItems = numberOfItems
self.child = child
self.optionalChild = optionalChild
}
}
}
// MARK: - Actions
extension ComposedFeature {
internal enum Action: Equatable {
case placeholder
case child(Child1.Action)
case optionalChild(Child2.Action)
}
}
// MARK: - Reducer
internal struct ComposedFeature: Reducer {
// MARK: - Dependencies
@Dependency(\.fireAndForget) var fireAndForget
// MARK: - Composition
var body: some ReducerOf<ComposedFeature> {
Reduce(reduceCore(into:action:))
.ifLet(
\.optionalChild,
action: /Action.optionalChild,
then: { Child2() }
)
Scope(
state: \.child,
action: /Action.child,
child: Child1.State() }
)
}
// MARK: - Core Reducer
internal func reduceCore(
into state: inout State,
action: Action
) -> ComposableArchitecture.Effect<Action> {
switch action {
case .placeholder:
return .none
case let .child(childAction):
return reduceChild1.State(
into: &state,
action: childAction
)
case let .optionalChild(optionalChildAction):
return reduceChild2.State?(
into: &state,
action: optionalChildAction
)
}
}
// MARK: - Child Reducer
internal func reduceChild1(
into state: inout State,
action: Child1Action
) -> ComposableArchitecture.Effect<Action> {
switch action {
default: return .none // TODO: remove default` case
}
}
// MARK: - OptionalChild Reducer
internal func reduceChild2(
into state: inout State,
action: Child2Action
) -> ComposableArchitecture.Effect<Action> {
switch action {
default: return .none // TODO: remove default` case
}
}
}
// MARK: - Scene
extension ComposedFeature {
internal struct Scene: View {
let store: StoreOf<ComposedFeature>
internal init(store: StoreOf<ComposedFeature>) {
self.store = store
}
internal var body: some View {
ZStack {
Text("ComposedFeatureScene")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
// MARK: Preview
struct ComposedFeatureScene_Previews: PreviewProvider {
static var previews: some View {
ComposedFeature.Scene(
store: .init(
initialState: ComposedFeature.State(),
reducer: { EmptyReducer() }
)
)
}
}
Generates code that automates the registration of dependencies using the swift-dependencies library. It identifies protocols and structs marked with the swiftDepAutoregister
annotation, automatically registering them for dependency injection.
All specification structs or protocols that you intend on registering should contain // sourcery: swiftDepAutoregister
annotation
// sourcery: swiftDepAutoregister
protocol SomeDependencyProtocol {
func doSomething() async throws -> String
}
// sourcery: swiftDepAutoregister
struct SomeDependencyStruct {
let doSomething: () async throws -> String
}
struct DoNotRegister {
func doSomething() async throws -> String
}
// MARK: - Dependency Injection
import Dependencies
import XCTestDynamicOverlay
internal enum SomeDependencyDependencyKey: TestDependencyKey {
static var testValue: SomeDependencyProtocol {
#if DEBUG
return SomeDependencyFailing()
#else
fatalError("`testValue` should not be acessed on non DEBUG builds.")
#endif
}
}
internal extension DependencyValues {
var someDependency: SomeDependencyProtocol {
get { self[SomeDependencyDependencyKey.self] }
set { self[SomeDependencyDependencyKey.self] = newValue }
}
}
// MARK: - Dependency Injection
import Dependencies
extension SomeDependencyStruct: TestDependencyKey {
internal static var testValue: SomeDependencyStruct {
return .init(
doSomething: unimplemented()
)
}
}
internal extension DependencyValues {
var : SomeDependencyStruct {
get { self[SomeDependencyStruct.self] }
set { self[SomeDependencyStruct.self] = newValue }
}
}