Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support actor object via annotation metadata #221

52 changes: 52 additions & 0 deletions Sources/MockoloFramework/Models/ActorModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
treastrain marked this conversation as resolved.
Show resolved Hide resolved
// ActorModel.swift
// MockoloFramework
//
// Created by treastrain on 2023/03/04.
//

import Foundation

final class ActorModel: Model {
var name: String
var offset: Int64
var type: Type
let attribute: String
let accessLevel: String
let identifier: String
let declType: DeclType
let entities: [(String, Model)]
let initParamCandidates: [Model]
let declaredInits: [MethodModel]
let metadata: AnnotationMetadata?

var modelType: ModelType {
return .actor
}

init(identifier: String,
acl: String,
declType: DeclType,
attributes: [String],
offset: Int64,
metadata: AnnotationMetadata?,
initParamCandidates: [Model],
declaredInits: [MethodModel],
entities: [(String, Model)]) {
self.identifier = identifier
self.name = identifier + "Mock"
self.type = Type(.actor)
self.declType = declType
self.entities = entities
self.declaredInits = declaredInits
self.initParamCandidates = initParamCandidates
self.metadata = metadata
self.offset = offset
self.attribute = Set(attributes.filter {$0.contains(String.available)}).joined(separator: " ")
self.accessLevel = acl
}

func render(with identifier: String, encloser: String, useTemplateFunc: Bool, useMockObservable: Bool, allowSetCallCount: Bool, mockFinal: Bool, enableFuncArgsHistory: Bool, disableCombineDefaultValues: Bool) -> String? {
return applyActorTemplate(name: name, identifier: self.identifier, accessLevel: accessLevel, attribute: attribute, declType: declType, metadata: metadata, useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, disableCombineDefaultValues: disableCombineDefaultValues, initParamCandidates: initParamCandidates, declaredInits: declaredInits, entities: entities)
}
}
2 changes: 1 addition & 1 deletion Sources/MockoloFramework/Models/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation

public enum ModelType {
case variable, method, typeAlias, parameter, macro, `class`
case variable, method, typeAlias, parameter, macro, `class`, `actor`
}

/// Represents a model for an entity such as var, func, class, etc.
Expand Down
40 changes: 30 additions & 10 deletions Sources/MockoloFramework/Models/ParsedEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,29 @@ struct ResolvedEntity {


func model() -> Model {
return ClassModel(identifier: key,
acl: entity.entityNode.accessLevel,
declType: entity.entityNode.declType,
attributes: attributes,
offset: entity.entityNode.offset,
metadata: entity.metadata,
initParamCandidates: initParamCandidates,
declaredInits: declaredInits,
entities: uniqueModels)
let objectType = entity.metadata?.objectType
switch objectType {
case .class, .none:
return ClassModel(identifier: key,
acl: entity.entityNode.accessLevel,
declType: entity.entityNode.declType,
attributes: attributes,
offset: entity.entityNode.offset,
metadata: entity.metadata,
initParamCandidates: initParamCandidates,
declaredInits: declaredInits,
entities: uniqueModels)
case .actor:
return ActorModel(identifier: key,
acl: entity.entityNode.accessLevel,
declType: entity.entityNode.declType,
attributes: attributes,
offset: entity.entityNode.offset,
metadata: entity.metadata,
initParamCandidates: initParamCandidates,
declaredInits: declaredInits,
entities: uniqueModels)
}
}
}

Expand Down Expand Up @@ -117,8 +131,9 @@ public enum CombineType {
}

/// Contains arguments to annotation
/// e.g. @mockable(module: prefix = Foo; typealias: T = Any; U = String; rx: barStream = PublishSubject; history: bazFunc = true; modifiers: someVar = weak; combine: fooPublisher = CurrentValueSubject; otherPublisher = @Published otherProperty, override: name = FooMock)
/// e.g. @mockable(objectType: class; module: prefix = Foo; typealias: T = Any; U = String; rx: barStream = PublishSubject; history: bazFunc = true; modifiers: someVar = weak; combine: fooPublisher = CurrentValueSubject; otherPublisher = @Published otherProperty, override: name = FooMock)
struct AnnotationMetadata {
var objectType: ObjectType?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe the usecase of this option.
Is it not enough when the protocol inherit Actor ?
(It seems that this option is added only to split the implementation 1 and 2 in #216 (comment))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, this is my misunderstanding. I understand 1 and 2 are not dependent of each other.

var nameOverride: String?
var module: String?
var typeAliases: [String: String]?
Expand Down Expand Up @@ -174,6 +189,11 @@ public final class Entity {
}
}

enum ObjectType: String {
case `class` = "class"
case `actor` = "actor"
}

enum Modifier: String {
case none = ""
case weak = "weak"
Expand Down
4 changes: 4 additions & 0 deletions Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,10 @@ extension Trivia {
if argsStr.hasSuffix(")") {
argsStr.removeLast()
}
if let arguments = parseArguments(argsStr, identifier: .objectColon) {
let objectTypeRawValue = arguments.first?.value
ret.objectType = objectTypeRawValue.flatMap(ObjectType.init(rawValue:))
}
if let arguments = parseArguments(argsStr, identifier: .typealiasColon) {
ret.typeAliases = arguments
}
Expand Down
Loading