I'm trying to build a macro for mocking properties and I stumbled upon the following issue:
I have this protocol and I attached my macro to it
@MyMock
protocol SomeProtocolHere {
var thisIsMyProperty: Bool { get }
}
Behind the scenes, I want the macro to create me a mock class for that protocol
class SomeProtocolHereMock: SomeProtocolHere {
var thisIsMyPropertyMocked: Bool!
var thisIsMyProperty: Bool { thisIsMyPropertyMocked }
}
The issue that I'm having is that I only get generated the declaration of the property, without the accessor block. Why doesn't it generate the accessor block?
final class SomeProtocolHereMock: SomeProtocolHere {
var somethingToReturnReturnValue: Bool!
var somethingToReturn: Bool
}
This is the code that I'm using to generate properties
static func makeVariableMock(from variableDecl: VariableDeclSyntax) -> MemberBlockItemListSyntax {
let returnValueVariableName = "\(variableDecl.name)ReturnValue"
let mockedUnwrappedProperty = VariableDeclSyntax(
modifiers:
DeclModifierListSyntax {
if variableDecl.isPublic {
DeclModifierSyntax(name: .keyword(.public))
}
},
bindingSpecifier: .keyword(.var),
bindings:
PatternBindingListSyntax {
PatternBindingSyntax(
pattern:
IdentifierPatternSyntax(identifier: .identifier(returnValueVariableName)),
typeAnnotation:
TypeAnnotationSyntax(type:
ImplicitlyUnwrappedOptionalTypeSyntax(
wrappedType: IdentifierTypeSyntax(
name: TokenSyntax.identifier(variableDecl.type)))
)
)
}
)
let originalVariable = VariableDeclSyntax(
modifiers:
DeclModifierListSyntax {
if variableDecl.isPublic {
DeclModifierSyntax(name: .keyword(.public))
}
},
bindingSpecifier: .keyword(.var),
bindings:
PatternBindingListSyntax {
PatternBindingSyntax(
pattern:
IdentifierPatternSyntax(identifier: .identifier(variableDecl.name)),
typeAnnotation:
TypeAnnotationSyntax(type: IdentifierTypeSyntax(name: TokenSyntax.identifier(variableDecl.type))),
accessorBlock: AccessorBlockSyntax(
CodeBlockItemListSyntax {
CodeBlockItemSyntax(
item: .expr(ExprSyntax(fromProtocol: DeclReferenceExprSyntax(baseName: TokenSyntax.identifier(returnValueVariableName))))
)
}
))
}
)
return MemberBlockItemListSyntax {
MemberBlockItemSyntax(decl: mockedUnwrappedProperty)
MemberBlockItemSyntax(decl: originalVariable)
}
}
After digging a bit more I found the issue. The
accessorBlock
parameter was nil. In order to fix it, I had to use theinit(accessors:)
initializer rather thaninit?(_ node:)