Skip to content

Commit

Permalink
Support forced unwrapped type as function return type
Browse files Browse the repository at this point in the history
  • Loading branch information
Matejkob committed Jun 25, 2024
1 parent 3209fc1 commit f4aee27
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 6 deletions.
1 change: 1 addition & 0 deletions Examples/Sources/ViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ protocol ServiceProtocol {
func insert(name: (any Codable)?, surname: (any Codable)?)
func append(name: (any Codable) -> (any Codable)?)
func get() async throws -> any Codable
func read() -> String!
}

final class ViewModel {
Expand Down
38 changes: 32 additions & 6 deletions Sources/SpyableMacro/Factories/ClosureFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,37 @@ struct ClosureFactory {
variablePrefix: String,
functionSignature: FunctionSignatureSyntax
) throws -> VariableDeclSyntax {
let returnClause: ReturnClauseSyntax
if let functionReturnClause = functionSignature.returnClause {
/*
func f() -> String!
*/
if let implicitlyUnwrappedType = functionReturnClause.type.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
var functionReturnClause = functionReturnClause
/*
`() -> String!` is not a valid code
so we have to convert it to `() -> String?
*/
functionReturnClause.type = TypeSyntax(OptionalTypeSyntax(wrappedType: implicitlyUnwrappedType.wrappedType))
returnClause = functionReturnClause
/*
func f() -> Any
func f() -> Any?
*/
} else {
returnClause = functionReturnClause
}
/*
func f()
*/
} else {
returnClause = ReturnClauseSyntax(
type: IdentifierTypeSyntax(
name: .identifier("Void")
)
)
}

let elements = TupleTypeElementListSyntax {
TupleTypeElementSyntax(
type: FunctionTypeSyntax(
Expand All @@ -44,12 +75,7 @@ struct ClosureFactory {
asyncSpecifier: functionSignature.effectSpecifiers?.asyncSpecifier,
throwsSpecifier: functionSignature.effectSpecifiers?.throwsSpecifier
),
returnClause: functionSignature.returnClause
?? ReturnClauseSyntax(
type: IdentifierTypeSyntax(
name: .identifier("Void")
)
)
returnClause: returnClause
)
)
}
Expand Down
16 changes: 16 additions & 0 deletions Tests/SpyableMacroTests/Factories/UT_ClosureFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ final class UT_ClosureFactory: XCTestCase {
)
}

func testVariableDeclarationOptionalTypeReturnValue() throws {
try assertProtocolFunction(
withFunctionDeclaration: "func _ignore_() -> Data?",
prefixForVariable: "_prefix_",
expectingVariableDeclaration: "var _prefix_Closure: (() -> Data? )?"
)
}

func testVariableDeclarationForcedUnwrappedOptionalTypeReturnValue() throws {
try assertProtocolFunction(
withFunctionDeclaration: "func _ignore_() -> Data!",
prefixForVariable: "_prefix_",
expectingVariableDeclaration: "var _prefix_Closure: (() -> Data?)?"
)
}

func testVariableDeclarationEverything() throws {
try assertProtocolFunction(
withFunctionDeclaration: """
Expand Down
8 changes: 8 additions & 0 deletions Tests/SpyableMacroTests/Factories/UT_ReturnValueFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ final class UT_ReturnValueFactory: XCTestCase {
)
}

func testVariableDeclarationForcedUnwrappedType() throws {
try assert(
functionReturnType: "String!",
prefixForVariable: "_prefix_",
expectingVariableDeclaration: "var _prefix_ReturnValue: String!"
)
}

func testVariableDeclarationExistentialType() throws {
try assert(
functionReturnType: "any Codable",
Expand Down
28 changes: 28 additions & 0 deletions Tests/SpyableMacroTests/Factories/UT_SpyFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,34 @@ final class UT_SpyFactory: XCTestCase {
)
}

func testDeclarationReturnsForcedUnwrappedType() throws {
try assertProtocol(
withDeclaration: """
protocol ServiceProtocol {
func foo() -> String!
}
""",
expectingClassDeclaration: """
class ServiceProtocolSpy: ServiceProtocol {
var fooCallsCount = 0
var fooCalled: Bool {
return fooCallsCount > 0
}
var fooReturnValue: String!
var fooClosure: (() -> String?)?
func foo() -> String! {
fooCallsCount += 1
if fooClosure != nil {
return fooClosure!()
} else {
return fooReturnValue
}
}
}
"""
)
}

func testDeclarationVariable() throws {
try assertProtocol(
withDeclaration: """
Expand Down

0 comments on commit f4aee27

Please sign in to comment.