From 1ba28c5272b8d6c58561167c5df21e32cbf4d9cd Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 03:40:32 +0900
Subject: [PATCH 01/12] Add `String.actor`
---
Sources/MockoloFramework/Utils/StringExtensions.swift | 1 +
1 file changed, 1 insertion(+)
diff --git a/Sources/MockoloFramework/Utils/StringExtensions.swift b/Sources/MockoloFramework/Utils/StringExtensions.swift
index 9fee0222..1726ac5c 100644
--- a/Sources/MockoloFramework/Utils/StringExtensions.swift
+++ b/Sources/MockoloFramework/Utils/StringExtensions.swift
@@ -38,6 +38,7 @@ extension String {
static let `static` = "static"
static let importSpace = "import "
static public let `class` = "class"
+ static public let `actor` = "actor"
static public let `final` = "final"
static let override = "override"
static let privateSet = "private(set)"
From 3f261980ab47c12cba7f5c44ef0aaf98ed30af98 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 03:43:24 +0900
Subject: [PATCH 02/12] Add `ModelType.actor`
---
Sources/MockoloFramework/Models/Model.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Sources/MockoloFramework/Models/Model.swift b/Sources/MockoloFramework/Models/Model.swift
index 2743c8e0..ef22faff 100644
--- a/Sources/MockoloFramework/Models/Model.swift
+++ b/Sources/MockoloFramework/Models/Model.swift
@@ -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.
From c5463878ad577daad274d15937565d5a2cf55291 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 03:43:44 +0900
Subject: [PATCH 03/12] Create ActorTemplate.swift
---
.../Templates/ActorTemplate.swift | 286 ++++++++++++++++++
1 file changed, 286 insertions(+)
create mode 100644 Sources/MockoloFramework/Templates/ActorTemplate.swift
diff --git a/Sources/MockoloFramework/Templates/ActorTemplate.swift b/Sources/MockoloFramework/Templates/ActorTemplate.swift
new file mode 100644
index 00000000..9788666f
--- /dev/null
+++ b/Sources/MockoloFramework/Templates/ActorTemplate.swift
@@ -0,0 +1,286 @@
+//
+// ActorTemplate.swift
+// MockoloFramework
+//
+// Created by treastrain on 2023/03/04.
+//
+
+import Foundation
+
+extension ActorModel {
+ func applyActorTemplate(name: String,
+ identifier: String,
+ accessLevel: String,
+ attribute: String,
+ declType: DeclType,
+ metadata: AnnotationMetadata?,
+ useTemplateFunc: Bool,
+ useMockObservable: Bool,
+ allowSetCallCount: Bool,
+ mockFinal: Bool,
+ enableFuncArgsHistory: Bool,
+ disableCombineDefaultValues: Bool,
+ initParamCandidates: [Model],
+ declaredInits: [MethodModel],
+ entities: [(String, Model)]) -> String {
+
+ processCombineAliases(entities: entities)
+
+ let acl = accessLevel.isEmpty ? "" : accessLevel + " "
+ let typealiases = typealiasWhitelist(in: entities)
+ let renderedEntities = entities
+ .compactMap { (uniqueId: String, model: Model) -> (String, Int64)? in
+ if model.modelType == .typeAlias, let _ = typealiases?[model.name] {
+ // this case will be handlded by typealiasWhitelist look up later
+ return nil
+ }
+ if model.modelType == .variable, model.name == String.hasBlankInit {
+ return nil
+ }
+ if model.modelType == .method, model.isInitializer, !model.processed {
+ return nil
+ }
+ if let ret = model.render(with: uniqueId, encloser: name, useTemplateFunc: useTemplateFunc, useMockObservable: useMockObservable, allowSetCallCount: allowSetCallCount, mockFinal: mockFinal, enableFuncArgsHistory: enableFuncArgsHistory, disableCombineDefaultValues: disableCombineDefaultValues) {
+ return (ret, model.offset)
+ }
+ return nil
+ }
+ .sorted { (left: (String, Int64), right: (String, Int64)) -> Bool in
+ if left.1 == right.1 {
+ return left.0 < right.0
+ }
+ return left.1 < right.1
+ }
+ .map {$0.0}
+ .joined(separator: "\n")
+
+ var typealiasTemplate = ""
+ let addAcl = declType == .protocolType ? acl : ""
+ if let typealiasWhitelist = typealiases {
+ typealiasTemplate = typealiasWhitelist.map { (arg: (key: String, value: [String])) -> String in
+ let joinedType = arg.value.sorted().joined(separator: " & ")
+ return "\(1.tab)\(addAcl)\(String.typealias) \(arg.key) = \(joinedType)"
+ }.joined(separator: "\n")
+ }
+
+ var moduleDot = ""
+ if let moduleName = metadata?.module, !moduleName.isEmpty {
+ moduleDot = moduleName + "."
+ }
+
+ let extraInits = extraInitsIfNeeded(initParamCandidates: initParamCandidates, declaredInits: declaredInits, acl: acl, declType: declType, overrides: metadata?.varTypes)
+
+ var body = ""
+ if !typealiasTemplate.isEmpty {
+ body += "\(typealiasTemplate)\n"
+ }
+ if !extraInits.isEmpty {
+ body += "\(extraInits)\n"
+ }
+ if !renderedEntities.isEmpty {
+ body += "\(renderedEntities)"
+ }
+
+ let finalStr = mockFinal ? "\(String.final) " : ""
+ let template = """
+ \(attribute)
+ \(acl)\(finalStr)actor \(name): \(moduleDot)\(identifier) {
+ \(body)
+ }
+ """
+
+ return template
+ }
+
+ private func extraInitsIfNeeded(initParamCandidates: [Model],
+ declaredInits: [MethodModel],
+ acl: String,
+ declType: DeclType,
+ overrides: [String: String]?) -> String {
+
+ let declaredInitParamsPerInit = declaredInits.map { $0.params }
+
+ var needParamedInit = false
+ var needBlankInit = false
+
+ if declaredInits.isEmpty, initParamCandidates.isEmpty {
+ needBlankInit = true
+ needParamedInit = false
+ } else {
+ if declType == .protocolType {
+ needParamedInit = !initParamCandidates.isEmpty
+ needBlankInit = true
+
+ let buffer = initParamCandidates.sorted(path: \.fullName, fallback: \.name)
+ for paramList in declaredInitParamsPerInit {
+ if paramList.isEmpty {
+ needBlankInit = false
+ } else {
+ let list = paramList.sorted(path: \.fullName, fallback: \.name)
+ if list.count > 0, list.count == buffer.count {
+ let dups = zip(list, buffer).filter {$0.0.fullName == $0.1.fullName}
+ if !dups.isEmpty {
+ needParamedInit = false
+ }
+ }
+ }
+ }
+ }
+ }
+
+ var initTemplate = ""
+ if needParamedInit {
+ var paramsAssign = ""
+ let params = initParamCandidates
+ .map { (element: Model) -> String in
+ if let val = element.type.defaultVal(with: overrides, overrideKey: element.name, isInitParam: true) {
+ return "\(element.name): \(element.type.typeName) = \(val)"
+ }
+ var prefix = ""
+ if element.type.hasClosure {
+ if !element.type.isOptional {
+ prefix = String.escaping + " "
+ }
+ }
+ return "\(element.name): \(prefix)\(element.type.typeName)"
+ }
+ .joined(separator: ", ")
+
+
+ paramsAssign = initParamCandidates.map { p in
+ return "\(2.tab)self.\(p.underlyingName) = \(p.name.safeName)"
+
+ }.joined(separator: "\n")
+
+ initTemplate = """
+ \(1.tab)\(acl)init(\(params)) {
+ \(paramsAssign)
+ \(1.tab)}
+ """
+ }
+
+ let extraInitParamNames = initParamCandidates.map{$0.name}
+ let extraVarsToDecl = declaredInitParamsPerInit.flatMap{$0}.compactMap { (p: ParamModel) -> String? in
+ if !extraInitParamNames.contains(p.name) {
+ return p.asVarDecl
+ }
+ return nil
+ }
+ .joined(separator: "\n")
+
+ let declaredInitStr = declaredInits.compactMap { (m: MethodModel) -> String? in
+ if case let .initKind(required, override) = m.kind, !m.processed {
+ let modifier = required ? "\(String.required) " : (override ? "\(String.override) " : "")
+ let mAcl = m.accessLevel.isEmpty ? "" : "\(m.accessLevel) "
+ let genericTypeDeclsStr = m.genericTypeParams.compactMap {$0.render(with: "", encloser: "")}.joined(separator: ", ")
+ let genericTypesStr = genericTypeDeclsStr.isEmpty ? "" : "<\(genericTypeDeclsStr)>"
+ let paramDeclsStr = m.params.compactMap{$0.render(with: "", encloser: "")}.joined(separator: ", ")
+
+ if override {
+ let paramsList = m.params.map { param in
+ return "\(param.name): \(param.name.safeName)"
+ }.joined(separator: ", ")
+
+ return """
+ \(1.tab)\(modifier)\(mAcl)init\(genericTypesStr)(\(paramDeclsStr)) {
+ \(2.tab)super.init(\(paramsList))
+ \(1.tab)}
+ """
+ } else {
+ let paramsAssign = m.params.map { param in
+ let underVars = initParamCandidates.compactMap { return $0.name.safeName == param.name.safeName ? $0.underlyingName : nil}
+ if let underVar = underVars.first {
+ return "\(2.tab)self.\(underVar) = \(param.name.safeName)"
+ } else {
+ return "\(2.tab)self.\(param.underlyingName) = \(param.name.safeName)"
+ }
+ }.joined(separator: "\n")
+
+ return """
+ \(1.tab)\(modifier)\(mAcl)init\(genericTypesStr)(\(paramDeclsStr)) {
+ \(paramsAssign)
+ \(1.tab)}
+ """
+ }
+ }
+ return nil
+ }.sorted().joined(separator: "\n")
+
+ var template = ""
+
+ if !extraVarsToDecl.isEmpty {
+ template += "\(1.tab)\(extraVarsToDecl)\n"
+ }
+
+ if needBlankInit {
+ // In case of protocol mocking, we want to provide a blank init (if not present already) for convenience,
+ // where instance vars do not have to be set in init since they all have get/set (see VariableTemplate).
+ let blankInit = "\(acl)init() { }"
+ template += "\(1.tab)\(blankInit)\n"
+ }
+
+ if !initTemplate.isEmpty {
+ template += "\(initTemplate)\n"
+ }
+
+ if !declaredInitStr.isEmpty {
+ template += "\(declaredInitStr)\n"
+ }
+
+ return template
+ }
+
+
+ /// Returns a map of typealiases with conflicting types to be whitelisted
+ /// @param models Potentially contains typealias models
+ /// @returns A map of typealiases with multiple possible types
+ func typealiasWhitelist(`in` models: [(String, Model)]) -> [String: [String]]? {
+ let typealiasModels = models.filter{$0.1.modelType == .typeAlias}
+ var aliasMap = [String: [String]]()
+ typealiasModels.forEach { (arg: (key: String, value: Model)) in
+
+ let alias = arg.value
+ if aliasMap[alias.name] == nil {
+ aliasMap[alias.name] = [alias.type.typeName]
+ } else {
+ if let val = aliasMap[alias.name], !val.contains(alias.type.typeName) {
+ aliasMap[alias.name]?.append(alias.type.typeName)
+ }
+ }
+ }
+ let aliasDupes = aliasMap.filter {$0.value.count > 1}
+ return aliasDupes.isEmpty ? nil : aliasDupes
+ }
+
+ // Finds all combine properties that are attempting to use a property wrapper alias
+ // and locates the matching property within the actor, if one exists.
+ //
+ private func processCombineAliases(entities: [(String, Model)]) {
+ var variableModels = [VariableModel]()
+ var nameToVariableModels = [String: VariableModel]()
+
+ for entity in entities {
+ guard let variableModel = entity.1 as? VariableModel else {
+ continue
+ }
+ variableModels.append(variableModel)
+ nameToVariableModels[variableModel.name] = variableModel
+ }
+
+ for variableModel in variableModels {
+ guard case .property(let wrapper, let name) = variableModel.combineType else {
+ continue
+ }
+
+ // If a variable member in this entity already exists, link the two together.
+ // Otherwise, the user's setup is incorrect and we will fallback to using a PassthroughSubject.
+ //
+ if let matchingAliasModel = nameToVariableModels[name] {
+ variableModel.wrapperAliasModel = matchingAliasModel
+ matchingAliasModel.propertyWrapper = wrapper
+ } else {
+ variableModel.combineType = .passthroughSubject
+ }
+ }
+ }
+}
From 8a1dcc9ca81c799eccd37e8dbbf51c8159a20ab2 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 03:43:52 +0900
Subject: [PATCH 04/12] Create ActorModel.swift
---
.../MockoloFramework/Models/ActorModel.swift | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 Sources/MockoloFramework/Models/ActorModel.swift
diff --git a/Sources/MockoloFramework/Models/ActorModel.swift b/Sources/MockoloFramework/Models/ActorModel.swift
new file mode 100644
index 00000000..b4c30445
--- /dev/null
+++ b/Sources/MockoloFramework/Models/ActorModel.swift
@@ -0,0 +1,52 @@
+//
+// 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)
+ }
+}
From 61ff44f550e448a1a076e96c287b365c79a1f3c9 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 06:19:50 +0900
Subject: [PATCH 05/12] Add `String.objectColon`
---
Sources/MockoloFramework/Utils/StringExtensions.swift | 1 +
1 file changed, 1 insertion(+)
diff --git a/Sources/MockoloFramework/Utils/StringExtensions.swift b/Sources/MockoloFramework/Utils/StringExtensions.swift
index 1726ac5c..f90f3905 100644
--- a/Sources/MockoloFramework/Utils/StringExtensions.swift
+++ b/Sources/MockoloFramework/Utils/StringExtensions.swift
@@ -76,6 +76,7 @@ extension String {
static let `required` = "required"
static let `convenience` = "convenience"
static let closureArrow = "->"
+ static let objectColon = "object:"
static let moduleColon = "module:"
static let typealiasColon = "typealias:"
static let combineColon = "combine:"
From 9907a753c361dfb470213263ab88a2a71d320075 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 06:21:15 +0900
Subject: [PATCH 06/12] Add `AnnotationMetadata.objectType`
---
Sources/MockoloFramework/Models/ParsedEntity.swift | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/Sources/MockoloFramework/Models/ParsedEntity.swift b/Sources/MockoloFramework/Models/ParsedEntity.swift
index 6f5e525a..8737dce7 100644
--- a/Sources/MockoloFramework/Models/ParsedEntity.swift
+++ b/Sources/MockoloFramework/Models/ParsedEntity.swift
@@ -117,8 +117,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?
var nameOverride: String?
var module: String?
var typeAliases: [String: String]?
@@ -174,6 +175,11 @@ public final class Entity {
}
}
+enum ObjectType: String {
+ case `class` = "class"
+ case `actor` = "actor"
+}
+
enum Modifier: String {
case none = ""
case weak = "weak"
From dd5ea02d8cf78c90c63f04bc895af993b0299426 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 06:22:10 +0900
Subject: [PATCH 07/12] Update `Trivia.metadata(with:in:)` for parsing
`AnnotationMetadata.objectType`
---
Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift
index 1ceff1db..ac5b5ff6 100644
--- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift
+++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift
@@ -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
}
From 7861ba0b383c18cc3fc5165f70026c05e65bfad4 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Sat, 4 Mar 2023 06:23:49 +0900
Subject: [PATCH 08/12] `ResolvedEntity.model()` returns either `ClassModel` or
`ActorModel`
---
.../Models/ParsedEntity.swift | 32 +++++++++++++------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/Sources/MockoloFramework/Models/ParsedEntity.swift b/Sources/MockoloFramework/Models/ParsedEntity.swift
index 8737dce7..9e099572 100644
--- a/Sources/MockoloFramework/Models/ParsedEntity.swift
+++ b/Sources/MockoloFramework/Models/ParsedEntity.swift
@@ -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)
+ }
}
}
From f9f4ddc1aaf6e16fb990477d4d2813d37ed756fc Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Tue, 7 Mar 2023 02:15:17 +0900
Subject: [PATCH 09/12] Create FixtureObjectTypes.swift
---
.../TestObjectTypes/FixtureObjectTypes.swift | 76 +++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 Tests/TestObjectTypes/FixtureObjectTypes.swift
diff --git a/Tests/TestObjectTypes/FixtureObjectTypes.swift b/Tests/TestObjectTypes/FixtureObjectTypes.swift
new file mode 100644
index 00000000..b0a0aec3
--- /dev/null
+++ b/Tests/TestObjectTypes/FixtureObjectTypes.swift
@@ -0,0 +1,76 @@
+import MockoloFramework
+
+let argumentsObjectTypesWithNoAnnotation =
+"""
+/// \(String.mockAnnotation)
+protocol Foo {
+ func foo(arg: String) async -> Result
+ var bar: Int { get }
+}
+"""
+
+let argumentsObjectTypesWithClassAnnotation =
+"""
+/// \(String.mockAnnotation)(object: class)
+protocol Foo {
+ func foo(arg: String) async -> Result
+ var bar: Int { get }
+}
+"""
+
+let argumentsObjectTypesWithClassAnnotationMock =
+"""
+class FooMock: Foo {
+ init() { }
+ init(bar: Int = 0) {
+ self.bar = bar
+ }
+
+
+ private(set) var fooCallCount = 0
+ var fooHandler: ((String) async -> (Result))?
+ func foo(arg: String) async -> Result {
+ fooCallCount += 1
+ if let fooHandler = fooHandler {
+ return await fooHandler(arg)
+ }
+ fatalError("fooHandler returns can't have a default value thus its handler must be set")
+ }
+
+ private(set) var barSetCallCount = 0
+ var bar: Int = 0 { didSet { barSetCallCount += 1 } }
+}
+"""
+
+let argumentsObjectTypesWithActorAnnotation =
+"""
+/// \(String.mockAnnotation)(object: actor)
+protocol Foo: Actor {
+ func foo(arg: String) async -> Result
+ var bar: Int { get }
+}
+"""
+
+let argumentsObjectTypesWithActorAnnotationMock =
+"""
+actor FooMock: Foo {
+ init() { }
+ init(bar: Int = 0) {
+ self.bar = bar
+ }
+
+
+ private(set) var fooCallCount = 0
+ var fooHandler: ((String) async -> (Result))?
+ func foo(arg: String) async -> Result {
+ fooCallCount += 1
+ if let fooHandler = fooHandler {
+ return await fooHandler(arg)
+ }
+ fatalError("fooHandler returns can't have a default value thus its handler must be set")
+ }
+
+ private(set) var barSetCallCount = 0
+ var bar: Int = 0 { didSet { barSetCallCount += 1 } }
+}
+"""
From 104e47fa56d4cbc477ada1b2b8694b07b3be1697 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Tue, 7 Mar 2023 02:15:22 +0900
Subject: [PATCH 10/12] Create ObjectTypesTests.swift
---
Tests/TestObjectTypes/ObjectTypesTests.swift | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Tests/TestObjectTypes/ObjectTypesTests.swift
diff --git a/Tests/TestObjectTypes/ObjectTypesTests.swift b/Tests/TestObjectTypes/ObjectTypesTests.swift
new file mode 100644
index 00000000..18840f55
--- /dev/null
+++ b/Tests/TestObjectTypes/ObjectTypesTests.swift
@@ -0,0 +1,19 @@
+import Foundation
+
+final class ObjectTypesTests: MockoloTestCase {
+
+ func testObjectTypesWithNoProperty() {
+ verify(srcContent: argumentsObjectTypesWithNoAnnotation,
+ dstContent: argumentsObjectTypesWithClassAnnotationMock)
+ }
+
+ func testObjectTypesWithClassProperty() {
+ verify(srcContent: argumentsObjectTypesWithClassAnnotation,
+ dstContent: argumentsObjectTypesWithClassAnnotationMock)
+ }
+
+ func testObjectTypesWithActorProperty() {
+ verify(srcContent: argumentsObjectTypesWithActorAnnotation,
+ dstContent: argumentsObjectTypesWithActorAnnotationMock)
+ }
+}
From 9d74f74c2dfdb84a10ddc71f5afe1dee9df54a54 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Mon, 13 Mar 2023 18:37:33 +0900
Subject: [PATCH 11/12] Update by the review
https://github.com/uber/mockolo/pull/221/files/104e47fa56d4cbc477ada1b2b8694b07b3be1697#r1133613190
---
.../MockoloFramework/Models/ActorModel.swift | 38 ++++++++++++++++---
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/Sources/MockoloFramework/Models/ActorModel.swift b/Sources/MockoloFramework/Models/ActorModel.swift
index b4c30445..66dbc049 100644
--- a/Sources/MockoloFramework/Models/ActorModel.swift
+++ b/Sources/MockoloFramework/Models/ActorModel.swift
@@ -1,9 +1,35 @@
-//
-// ActorModel.swift
-// MockoloFramework
-//
-// Created by treastrain on 2023/03/04.
-//
+///
+/// Copyright (c) 2023 Uber Technologies
+///
+/// Permission is hereby granted, free of charge, to any person obtaining a copy
+/// of this software and associated documentation files (the "Software"), to deal
+/// in the Software without restriction, including without limitation the rights
+/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+/// copies of the Software, and to permit persons to whom the Software is
+/// furnished to do so, subject to the following conditions:
+///
+/// The above copyright notice and this permission notice shall be included in
+/// all copies or substantial portions of the Software.
+///
+/// Notwithstanding the foregoing, you may not use, copy, modify, merge, publish,
+/// distribute, sublicense, create a derivative work, and/or sell copies of the
+/// Software in any work that is designed, intended, or marketed for pedagogical or
+/// instructional purposes related to programming, coding, application development,
+/// or information technology. Permission for such use, copying, modification,
+/// merger, publication, distribution, sublicensing, creation of derivative works,
+/// or sale is expressly withheld.
+///
+/// This project and source code may use libraries or frameworks that are
+/// released under various Open-Source licenses. Use of those libraries and
+/// frameworks are governed by their own individual licenses.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+/// THE SOFTWARE.
import Foundation
From fe81ea5c08f54a8d70f2c77f07b42c693401d854 Mon Sep 17 00:00:00 2001
From: treastrain / Tanaka Ryoga
Date: Tue, 11 Apr 2023 00:21:09 +0900
Subject: [PATCH 12/12] Update Tests/TestObjectTypes/ObjectTypesTests.swift
---
Tests/TestObjectTypes/ObjectTypesTests.swift | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Tests/TestObjectTypes/ObjectTypesTests.swift b/Tests/TestObjectTypes/ObjectTypesTests.swift
index 18840f55..9cdb1828 100644
--- a/Tests/TestObjectTypes/ObjectTypesTests.swift
+++ b/Tests/TestObjectTypes/ObjectTypesTests.swift
@@ -1,5 +1,6 @@
import Foundation
+#if compiler(>=5.5.2) && canImport(_Concurrency)
final class ObjectTypesTests: MockoloTestCase {
func testObjectTypesWithNoProperty() {
@@ -17,3 +18,4 @@ final class ObjectTypesTests: MockoloTestCase {
dstContent: argumentsObjectTypesWithActorAnnotationMock)
}
}
+#endif