Skip to content

Commit

Permalink
Add public stub support (#14)
Browse files Browse the repository at this point in the history
* Add public stub support

* Refactor to satisfy SwiftLint
  • Loading branch information
hainayanda authored Apr 21, 2024
1 parent 3d5e833 commit 98ccd25
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 28 deletions.
9 changes: 7 additions & 2 deletions Sources/SwiftEnvironment/Macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ public macro EnvironmentValue() = #externalMacro(
)

@attached(member, names: arbitrary)
public macro Stubbed() = #externalMacro(
public macro Stubbed(_ modifier: Modifier = .internalStub) = #externalMacro(
module: "SwiftEnvironmentMacro", type: "StubGeneratorMacro"
)

@attached(member, names: arbitrary)
public macro Stubbed(_ values: DefaultType...) = #externalMacro(
public macro Stubbed(_ modifier: Modifier = .internalStub, _ values: DefaultType...) = #externalMacro(
module: "SwiftEnvironmentMacro", type: "StubGeneratorMacro"
)

Expand All @@ -40,6 +40,11 @@ public enum StubType {
case openSubclass(AnyClass.Type)
}

public enum Modifier {
case publicStub
case internalStub
}

public struct DefaultType {
public static func value<T>(for: T.Type, _: T) -> DefaultType {
DefaultType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,33 @@
// File.swift
//
//
// Created by Nayanda Haberty on 17/3/24.
// Created by Nayanda Haberty on 21/4/24.
//

import Foundation
import SwiftSyntax

let baseDefaultValues: [String: String] = [
"Int": "0", "Int8": "0", "Int16": "0", "Int32": "0", "Int64": "0",
"UInt": "0", "UInt8": "0", "UInt16": "0", "UInt32": "0", "UInt64": "0",
"Float": "0", "Float16": "0", "Float32": "0", "Float64": "0.0", "Double": "0.0",
"Bool": "false", "Character": "Character(\"\")", "String": "\"\"", "Data": "Data()",
"Date": "Date()", "UUID": "UUID()",
"CGFloat": "0", "CGSize": ".zero", "CGPoint": ".zero", "CGRect": ".zero",
"NSNumber": "0", "NSString": "\"\"", "NSNull": "NSNull()", "NSObject": "NSObject()",
"NSData": "NSData()", "NSDate": "NSDate()", "NSSet": "NSSet()", "NSArray": "NSArray()",
"NSSize": ".zero", "NSPoint": ".zero", "NSRect": ".zero",
"AnyView": "AnyView(EmptyView())"
]

extension AttributeSyntax {
var hasModifiers: Bool {
guard let firstArgument = arguments?.as(LabeledExprListSyntax.self)?
.first?.as(LabeledExprSyntax.self) else { return false }
return firstArgument.trimmedDescription == ".publicStub"
|| firstArgument.trimmedDescription == ".internalStub"
}

var isPublicStub: Bool {
guard let firstArgument = arguments?.as(LabeledExprListSyntax.self)?
.first?.as(LabeledExprSyntax.self) else { return false }
return firstArgument.trimmedDescription == ".publicStub"
}

var defaultValueArguments: [String: String] {
get throws {
let arguments = arguments?.as(LabeledExprListSyntax.self)?
.filter { $0.label == nil }
.compactMap { $0.as(LabeledExprSyntax.self) }
guard let arguments else { return [:] }
guard var arguments else { return [:] }
arguments = hasModifiers ? Array(arguments.suffix(from: 1)) : arguments
return try arguments
.map { try $0.extractDefaultValueArguments() }
.mapToTypeDefaultValueArguments()
Expand All @@ -50,7 +51,7 @@ private extension Sequence where Element == FunctionCallExprSyntax {
try reduce(into: [:]) { partialResult, expression in
let innerArgs = expression.arguments.map { $0 }
guard innerArgs.count == 2,
innerArgs[0].label?.trimmedDescription == "for",
innerArgs[0].label?.trimmedDescription == "for",
innerArgs[1].label == nil,
let memberAccess = innerArgs[0].expression.as(MemberAccessExprSyntax.self),
let type = memberAccess.base?.trimmedDescription else {
Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftEnvironmentMacro/Model/StubInitializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import Foundation

struct StubInitializer {
let isPublicStub: Bool
let name: String
let generateInit: Bool
let argumentPairs: [InitArgumentPairs]

var singletonDeclaration: String {
let singletonClause = "static var stub: \(name) { \(name)("
let modifier = isPublicStub ? "public " : ""
let singletonClause = "\(modifier)static var stub: \(name) { \(name)("
let arguments = argumentPairs.compactMap { $0.asArguments }.joined(separator: ", ")
return "\(singletonClause)\(arguments)) }"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ extension StubGeneratorMacro: MemberMacro {
}
let isClass = declaration.isClass

let isPublicStub = node.isPublicStub

let defaultValues = try node.defaultValueArguments
.reduce(into: baseDefaultValues) { partialResult, pair in
partialResult[pair.key] = pair.value
Expand All @@ -40,7 +42,7 @@ extension StubGeneratorMacro: MemberMacro {
arguments = try arguments.sortToMatch(initArguments: matchedInit)
}

let stubInitializer = StubInitializer(name: name, generateInit: matchedInit == nil && isClass, argumentPairs: arguments)
let stubInitializer = StubInitializer(isPublicStub: isPublicStub, name: name, generateInit: matchedInit == nil && isClass, argumentPairs: arguments)
return [stubInitializer.singletonDeclaration, stubInitializer.initDeclaration]
.compactMap { $0 }
.map { "\(raw: $0)" }
Expand Down
22 changes: 22 additions & 0 deletions Sources/SwiftEnvironmentMacro/Utilities/BaseDefaultValues.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// File.swift
//
//
// Created by Nayanda Haberty on 17/3/24.
//

import Foundation
import SwiftSyntax

let baseDefaultValues: [String: String] = [
"Int": "0", "Int8": "0", "Int16": "0", "Int32": "0", "Int64": "0",
"UInt": "0", "UInt8": "0", "UInt16": "0", "UInt32": "0", "UInt64": "0",
"Float": "0", "Float16": "0", "Float32": "0", "Float64": "0.0", "Double": "0.0",
"Bool": "false", "Character": "Character(\"\")", "String": "\"\"", "Data": "Data()",
"Date": "Date()", "UUID": "UUID()",
"CGFloat": "0", "CGSize": ".zero", "CGPoint": ".zero", "CGRect": ".zero",
"NSNumber": "0", "NSString": "\"\"", "NSNull": "NSNull()", "NSObject": "NSObject()",
"NSData": "NSData()", "NSDate": "NSDate()", "NSSet": "NSSet()", "NSArray": "NSArray()",
"NSSize": ".zero", "NSPoint": ".zero", "NSRect": ".zero",
"AnyView": "AnyView(EmptyView())"
]
16 changes: 8 additions & 8 deletions Tests/SwiftEnvironmentTests/StubFromTypeGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ struct Some {
"""

private let simpleClassWithClosure: String = """
@Stubbed
@Stubbed(.publicStub)
class Some {
let voidClosure: () -> Void
let argVoidClosure: (Int) -> Void
Expand All @@ -131,7 +131,7 @@ class Some {
let argReturnClosure: (Int) -> [Int]
let argsReturnClosure: (Int, Int) -> Int
static var stub: Some {
public static var stub: Some {
Some(voidClosure: {
}, argVoidClosure: { _ in
}, argsVoidClosure: { _, _ in
Expand Down Expand Up @@ -193,7 +193,7 @@ struct Some {
"""

private let simpleClassWithDifferentInit: String = """
@Stubbed
@Stubbed(.publicStub)
class Some {
let int: Int
var double: Double
Expand All @@ -217,7 +217,7 @@ class Some {
self.int = 0
}
static var stub: Some {
public static var stub: Some {
Some(int: 0, double: 0.0)
}
Expand Down Expand Up @@ -260,7 +260,7 @@ class Some {
"""

private let simpleClassWithInit: String = """
@Stubbed
@Stubbed(.publicStub)
class Some {
let int: Int
var double: Double
Expand All @@ -284,7 +284,7 @@ class Some {
self.double = double
}
static var stub: Some {
public static var stub: Some {
Some(int: 0, double: 0.0)
}
}
Expand Down Expand Up @@ -317,7 +317,7 @@ class Some {
"""

private let simpleStruct: String = """
@Stubbed
@Stubbed(.publicStub)
struct Some {
let int: Int
var double: Double
Expand All @@ -331,7 +331,7 @@ struct Some {
var double: Double
let string: String = ""
static var stub: Some {
public static var stub: Some {
Some(int: 0, double: 0.0)
}
}
Expand Down

0 comments on commit 98ccd25

Please sign in to comment.