From 52bd316348605be2cc8fccc6a777b69692f466b3 Mon Sep 17 00:00:00 2001 From: Leif Date: Tue, 5 Nov 2024 16:24:01 -0700 Subject: [PATCH] Add access level for mock, variables and functions --- Sources/MockedMacros/MockedMacro.swift | 79 ++++++++-------- Tests/MockedTests/MockedTests.swift | 122 +++++++++++++++---------- 2 files changed, 118 insertions(+), 83 deletions(-) diff --git a/Sources/MockedMacros/MockedMacro.swift b/Sources/MockedMacros/MockedMacro.swift index 75136b9..a7cdd22 100644 --- a/Sources/MockedMacros/MockedMacro.swift +++ b/Sources/MockedMacros/MockedMacro.swift @@ -46,26 +46,32 @@ public struct MockedMacro: PeerMacro { } } - let mockClassName = "Mocked\(protocolDecl.name.text)" + let initAccessLevel = switch accessLevel { + case "public": "public" + case "open": "open" + case "package": "package" + default: "internal" + } + let mockClassName = "Mocked\(protocolDecl.name.text)" + let members = protocolDecl.memberBlock.members - + // Variables - + let variables: [Variable] = variableBuilder(members: members) - + let variablesDefinitions: String = variableDefinitions(variables: variables, accessLevel: accessLevel) let variablesInitDefinitions: String = variablesInitDefinitions(variables: variables) let variablesInitAssignments: String = variablesInitAssignments(variables: variables) - - + // Functions - + let functions: [Function] = functionBuilder( protocolDecl: protocolDecl, members: members ) - + let functionVariableDefinitions: String = functionVariableDefinitions(functions: functions) let functionVariableInitDefinitions: String = functionVariableInitDefinitions(functions: functions) let functionVariableInitAssignments: String = functionVariableInitAssignments(functions: functions) @@ -85,7 +91,7 @@ public struct MockedMacro: PeerMacro { if let associatedTypeDecl = member.decl.as(AssociatedTypeDeclSyntax.self) { let name = associatedTypeDecl.name.text let constraint = associatedTypeDecl.inheritanceClause?.description.trimmingCharacters(in: .whitespacesAndNewlines) - + if let constraint { associatedTypes.append("\(name)\(constraint)") } else { @@ -93,14 +99,14 @@ public struct MockedMacro: PeerMacro { } } } - + // Construct generic type parameters if there are associated types let genericValues = if associatedTypes.isEmpty { "" } else { "<" + associatedTypes.joined(separator: ", ") + ">" } - + return [ """ /// Mocked version of \(raw: protocolDecl.name.text) @@ -115,7 +121,7 @@ public struct MockedMacro: PeerMacro { // MARK: - \(raw: mockClassName) init - init( + \(raw: initAccessLevel) init( \(raw: variablesInitDefinitions) \(raw: functionVariableInitDefinitions) ) { @@ -131,15 +137,15 @@ public struct MockedMacro: PeerMacro { """ ] } - + // MARK: - Variable helpers - + private static func variableBuilder(members: MemberBlockItemListSyntax) -> [Variable] { members.compactMap { member in guard let variable = member.decl.as(VariableDeclSyntax.self) else { return nil } - + guard let binding = variable.bindings.first else { return nil } @@ -148,10 +154,10 @@ public struct MockedMacro: PeerMacro { else { fatalError("\(String(describing: binding.initializer?.syntaxNodeType))") } - + let name = binding.pattern let type = typeAnnotation.description.trimmingCharacters(in: .whitespacesAndNewlines) - + return Variable( firstName: "\(name)", secondName: nil, @@ -159,7 +165,7 @@ public struct MockedMacro: PeerMacro { ) } } - + private static func variableDefinitions( variables: [Variable], accessLevel: String @@ -176,7 +182,7 @@ public struct MockedMacro: PeerMacro { } .joined(separator: "\n") } - + private static func variablesInitDefinitions( variables: [Variable] ) -> String { @@ -184,7 +190,7 @@ public struct MockedMacro: PeerMacro { .map { "\($0.declaration)," } .joined(separator: "\n") } - + private static func variablesInitAssignments( variables: [Variable] ) -> String { @@ -192,9 +198,9 @@ public struct MockedMacro: PeerMacro { .map { "self.\($0.name) = \($0.name)" } .joined(separator: "\n") } - + // MARK: - Function helpers - + private static func functionBuilder( protocolDecl: ProtocolDeclSyntax, members: MemberBlockItemListSyntax @@ -202,24 +208,24 @@ public struct MockedMacro: PeerMacro { let inheritsSendable = protocolDecl.inheritanceClause?.inheritedTypes.contains { inheritedType in inheritedType.type.description.trimmingCharacters(in: .whitespacesAndNewlines) == "Sendable" } ?? false - + return members.compactMap { member in guard let function = member.decl.as(FunctionDeclSyntax.self) else { return nil } - + let name = function.name.text var parameters: [Variable] = [] let returnType = function.signature.returnClause?.type ?? "Void" - + let isAsync = function.signature.effectSpecifiers?.asyncSpecifier != nil let canThrow = function.signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil - + for parameter in function.signature.parameterClause.parameters { let parameterFirstName = parameter.firstName.text let parameterSecondName = parameter.secondName?.text let parameterType = parameter.type.description.trimmingCharacters(in: .whitespacesAndNewlines) - + parameters.append( Variable( firstName: parameterFirstName, @@ -228,7 +234,7 @@ public struct MockedMacro: PeerMacro { ) ) } - + return Function( name: "\(name)", parameters: parameters, @@ -239,7 +245,7 @@ public struct MockedMacro: PeerMacro { ) } } - + private static func functionVariableDefinitions( functions: [Function] ) -> String { @@ -247,7 +253,7 @@ public struct MockedMacro: PeerMacro { .map { "private let \($0.overrideClosure)" } .joined(separator: "\n") } - + private static func functionVariableInitDefinitions( functions: [Function] ) -> String { @@ -255,7 +261,7 @@ public struct MockedMacro: PeerMacro { .map { "\($0.closure) = nil" } .joined(separator: ",\n") } - + private static func functionVariableInitAssignments( functions: [Function] ) -> String { @@ -263,7 +269,7 @@ public struct MockedMacro: PeerMacro { .map { "self.\($0.overrideName) = \($0.uniqueName)" } .joined(separator: "\n") } - + private static func functionImplementations( functions: [Function], accessLevel: String @@ -277,8 +283,8 @@ public struct MockedMacro: PeerMacro { let parameterUsage: String = function.parameters .map(\.usageName) .joined(separator: ", ") - - + + let effectSignature: String = if function.canThrow && function.isAsync { "async throws " } else if function.canThrow { @@ -288,7 +294,7 @@ public struct MockedMacro: PeerMacro { } else { "" } - + let callSignature: String = if function.canThrow && function.isAsync { "try await " } else if function.canThrow { @@ -307,7 +313,6 @@ public struct MockedMacro: PeerMacro { "internal" } - if parameters.isEmpty { return """ \(accessLevel) func \(function.name)() \(effectSignature)-> \(function.returnType ?? "Void") { @@ -320,7 +325,7 @@ public struct MockedMacro: PeerMacro { """ } else { return """ - func \(function.name)( + \(accessLevel) func \(function.name)( \(parameters) ) \(effectSignature)-> \(function.returnType ?? "Void") { guard let \(function.overrideName) else { diff --git a/Tests/MockedTests/MockedTests.swift b/Tests/MockedTests/MockedTests.swift index 3fb9594..eb33b99 100644 --- a/Tests/MockedTests/MockedTests.swift +++ b/Tests/MockedTests/MockedTests.swift @@ -71,7 +71,7 @@ final class MockedMacroTests: XCTestCase { // MARK: - MockedSomeParameter init - init( + internal init( title: String, description: String, someMethod: (@Sendable () -> Void)? = nil, @@ -96,7 +96,7 @@ final class MockedMacroTests: XCTestCase { // MARK: - MockedSomeParameter Functions - func someMethod() -> Void { + internal func someMethod() -> Void { guard let someMethodOverride else { fatalError("Mocked someMethod: (@Sendable () -> Void)? was not implemented!") } @@ -104,7 +104,7 @@ final class MockedMacroTests: XCTestCase { return someMethodOverride() } - func someMethod( + internal func someMethod( parameter: Int ) -> Void { guard let someMethodOverrideParameter else { @@ -116,7 +116,7 @@ final class MockedMacroTests: XCTestCase { ) } - func someMethod( + internal func someMethod( with parameter: Int ) -> Void { guard let someMethodOverrideWith else { @@ -128,7 +128,7 @@ final class MockedMacroTests: XCTestCase { ) } - func someOtherMethod() throws -> String { + internal func someOtherMethod() throws -> String { guard let someOtherMethodOverrideThrows else { fatalError("Mocked someOtherMethodThrows: (@Sendable () throws -> String)? was not implemented!") } @@ -136,7 +136,7 @@ final class MockedMacroTests: XCTestCase { return try someOtherMethodOverrideThrows() } - func someOtherMethod() async throws -> String { + internal func someOtherMethod() async throws -> String { guard let someOtherMethodOverrideAsyncThrows else { fatalError("Mocked someOtherMethodAsyncThrows: (@Sendable () async throws -> String)? was not implemented!") } @@ -144,7 +144,7 @@ final class MockedMacroTests: XCTestCase { return try await someOtherMethodOverrideAsyncThrows() } - func someAsyncMethod() async -> String { + internal func someAsyncMethod() async -> String { guard let someAsyncMethodOverrideAsync else { fatalError("Mocked someAsyncMethodAsync: (@Sendable () async -> String)? was not implemented!") } @@ -152,7 +152,7 @@ final class MockedMacroTests: XCTestCase { return await someAsyncMethodOverrideAsync() } - func someOptionalMethod() -> String? { + internal func someOptionalMethod() -> String? { guard let someOptionalMethodOverride else { fatalError("Mocked someOptionalMethod: (@Sendable () -> String?)? was not implemented!") } @@ -208,9 +208,9 @@ final class MockedMacroTests: XCTestCase { public struct MockedExampleProtocol: ExampleProtocol { // MARK: - MockedExampleProtocol Variables - var name: String - var count: Int - var isEnabled: Bool + public var name: String + public var count: Int + public var isEnabled: Bool // MARK: - MockedExampleProtocol Function Overrides @@ -222,7 +222,7 @@ final class MockedMacroTests: XCTestCase { // MARK: - MockedExampleProtocol init - init( + public init( name: String, count: Int, isEnabled: Bool, @@ -245,7 +245,7 @@ final class MockedMacroTests: XCTestCase { // MARK: - MockedExampleProtocol Functions - func fetchItem( + public func fetchItem( withID id: Int ) async throws -> ItemType { guard let fetchItemOverrideAsyncThrowsWithid else { @@ -257,7 +257,7 @@ final class MockedMacroTests: XCTestCase { ) } - func saveItem( + public func saveItem( _ item: ItemType ) throws -> Bool { guard let saveItemOverrideThrowsItem else { @@ -269,7 +269,7 @@ final class MockedMacroTests: XCTestCase { ) } - func processAllItems() async -> Void { + public func processAllItems() async -> Void { guard let processAllItemsOverrideAsync else { fatalError("Mocked processAllItemsAsync: (@Sendable () async -> Void)? was not implemented!") } @@ -277,7 +277,7 @@ final class MockedMacroTests: XCTestCase { return await processAllItemsOverrideAsync() } - func reset() -> Void { + public func reset() -> Void { guard let resetOverride else { fatalError("Mocked reset: (@Sendable () -> Void)? was not implemented!") } @@ -285,7 +285,7 @@ final class MockedMacroTests: XCTestCase { return resetOverride() } - func optionalItem() -> ItemType? { + public func optionalItem() -> ItemType? { guard let optionalItemOverride else { fatalError("Mocked optionalItem: (@Sendable () -> ItemType?)? was not implemented!") } @@ -342,7 +342,7 @@ final class MockedMacroTests: XCTestCase { // MARK: - MockedCustomProtocol init - init( + open init( customMethod: (() -> Bool)? = nil ) { @@ -353,7 +353,7 @@ final class MockedMacroTests: XCTestCase { // MARK: - MockedCustomProtocol Functions - func customMethod() -> Bool { + internal func customMethod() -> Bool { guard let customMethodOverride else { fatalError("Mocked customMethod: (() -> Bool)? was not implemented!") } @@ -371,38 +371,48 @@ final class MockedMacroTests: XCTestCase { """ @Mocked(.package) protocol SomeParameter: Sendable { - + var name: String + + func greet() } """, expandedSource: """ protocol SomeParameter: Sendable { - + var name: String + + func greet() } /// Mocked version of SomeParameter package struct MockedSomeParameter: SomeParameter { // MARK: - MockedSomeParameter Variables - + package var name: String // MARK: - MockedSomeParameter Function Overrides - + private let greetOverride: (@Sendable () -> Void)? // MARK: - MockedSomeParameter init - init( - - + package init( + name: String, + greet: (@Sendable () -> Void)? = nil ) { - - + self.name = name + self.greetOverride = greet } // MARK: - MockedSomeParameter Functions + package func greet() -> Void { + guard let greetOverride else { + fatalError("Mocked greet: (@Sendable () -> Void)? was not implemented!") + } + return greetOverride() + } } """, macros: testMacros @@ -414,38 +424,48 @@ final class MockedMacroTests: XCTestCase { """ @Mocked(.private) protocol SomeParameter: Sendable { - + var name: String + + func greet() } """, expandedSource: """ protocol SomeParameter: Sendable { - + var name: String + + func greet() } /// Mocked version of SomeParameter private struct MockedSomeParameter: SomeParameter { // MARK: - MockedSomeParameter Variables - + var name: String // MARK: - MockedSomeParameter Function Overrides - + private let greetOverride: (@Sendable () -> Void)? // MARK: - MockedSomeParameter init - init( - - + internal init( + name: String, + greet: (@Sendable () -> Void)? = nil ) { - - + self.name = name + self.greetOverride = greet } // MARK: - MockedSomeParameter Functions + internal func greet() -> Void { + guard let greetOverride else { + fatalError("Mocked greet: (@Sendable () -> Void)? was not implemented!") + } + return greetOverride() + } } """, macros: testMacros @@ -457,38 +477,48 @@ final class MockedMacroTests: XCTestCase { """ @Mocked(.fileprivate) protocol SomeParameter: Sendable { - + var name: String + + func greet() } """, expandedSource: """ protocol SomeParameter: Sendable { + var name: String + func greet() } - + /// Mocked version of SomeParameter fileprivate struct MockedSomeParameter: SomeParameter { // MARK: - MockedSomeParameter Variables - + var name: String // MARK: - MockedSomeParameter Function Overrides - + private let greetOverride: (@Sendable () -> Void)? // MARK: - MockedSomeParameter init - init( - - + internal init( + name: String, + greet: (@Sendable () -> Void)? = nil ) { - - + self.name = name + self.greetOverride = greet } // MARK: - MockedSomeParameter Functions + internal func greet() -> Void { + guard let greetOverride else { + fatalError("Mocked greet: (@Sendable () -> Void)? was not implemented!") + } + return greetOverride() + } } """, macros: testMacros