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

Avoid to generate duplicated variable name #231

Merged
merged 15 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions Sources/MockoloFramework/Models/ClassModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class ClassModel: Model {
let identifier: String
let declType: DeclType
let entities: [(String, Model)]
let initParamCandidates: [Model]
let initParamCandidates: [VariableModel]
fummicc1 marked this conversation as resolved.
Show resolved Hide resolved
let declaredInits: [MethodModel]
let metadata: AnnotationMetadata?

Expand All @@ -39,7 +39,7 @@ final class ClassModel: Model {
attributes: [String],
offset: Int64,
metadata: AnnotationMetadata?,
initParamCandidates: [Model],
initParamCandidates: [VariableModel],
declaredInits: [MethodModel],
entities: [(String, Model)]) {
self.identifier = identifier
Expand All @@ -55,7 +55,32 @@ final class ClassModel: Model {
self.accessLevel = acl
}

func render(with identifier: String, encloser: String, useTemplateFunc: Bool, useMockObservable: Bool, allowSetCallCount: Bool = false, mockFinal: Bool = false, enableFuncArgsHistory: Bool = false, disableCombineDefaultValues: Bool = false) -> String? {
return applyClassTemplate(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)
func render(
with identifier: String,
encloser: String,
useTemplateFunc: Bool,
useMockObservable: Bool,
allowSetCallCount: Bool = false,
mockFinal: Bool = false,
enableFuncArgsHistory: Bool = false,
disableCombineDefaultValues: Bool = false
) -> String? {
return applyClassTemplate(
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
)
fummicc1 marked this conversation as resolved.
Show resolved Hide resolved
}
}
7 changes: 0 additions & 7 deletions Sources/MockoloFramework/Models/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public protocol Model {
/// Indicates whether mock generation for this model has been processed
var processed: Bool { get }

/// Indicates whether this model can be used as a parameter to an initializer
var canBeInitParam: Bool { get }

/// Indicates whether this model maps to an init method
var isInitializer: Bool { get }

Expand Down Expand Up @@ -106,10 +103,6 @@ extension Model {
return false
}

var canBeInitParam: Bool {
return false
}

var isInitializer: Bool {
return false
}
Expand Down
33 changes: 30 additions & 3 deletions Sources/MockoloFramework/Models/ParamModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,37 @@ final class ParamModel: Model {
var underlyingName: String {
return "_\(name)"
}

var asVarDecl: String? {

/// - Parameters:
/// - eraseType:
/// If other initializers in decl has same name as this param and type is different from each other,
/// please pass `True` to this parameter. Default value is `false`.
///
/// ```
/// protocol A {
/// init(param: String)
/// init(param: any Sequence<Character>)
/// }
/// class B: A {
/// var param: Any! // NOTE: type erasing
/// init () {}
/// required init(param: String) {
/// self.param = param
/// }
/// required init(param: any Sequence<Character>) {
/// self.param = param
/// }
/// }
/// ```
func asInitVarDecl(eraseType: Bool) -> String? {
if self.inInit, self.needVarDecl {
return applyVarTemplate(name: name, type: type)
let type: `Type`
if eraseType {
type = Type(.any)
} else {
type = self.type
}
return applyVarTemplate(type: type)
}
return nil
}
Expand Down
8 changes: 5 additions & 3 deletions Sources/MockoloFramework/Models/ParsedEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ struct ResolvedEntity {
return declaredInits.map { $0.params }.flatMap{$0}
}

var initParamCandidates: [Model] {
return sortedInitVars(in: uniqueModels.map{$0.1})
var initParamCandidates: [VariableModel] {
return sortedInitVars(
in: uniqueModels.compactMap{ $0.1 as? VariableModel }
)
}

/// Returns models that can be used as parameters to an initializer
/// @param models The models of the current entity including unprocessed (ones to generate) and
/// processed (already mocked by a previous run if any) models.
/// @returns A list of init parameter models
private func sortedInitVars(`in` models: [Model]) -> [Model] {
private func sortedInitVars(`in` models: [VariableModel]) -> [VariableModel] {
let processed = models.filter {$0.processed && $0.canBeInitParam}
let unprocessed = models.filter {!$0.processed && $0.canBeInitParam}

Expand Down
1 change: 1 addition & 0 deletions Sources/MockoloFramework/Models/VariableModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ final class VariableModel: Model {
let accessLevel: String
let attributes: [String]?
let encloserType: DeclType
/// Indicates whether this model can be used as a parameter to an initializer
var canBeInitParam: Bool
let processed: Bool
var filePath: String = ""
Expand Down
33 changes: 20 additions & 13 deletions Sources/MockoloFramework/Templates/ClassTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ extension ClassModel {
mockFinal: Bool,
enableFuncArgsHistory: Bool,
disableCombineDefaultValues: Bool,
initParamCandidates: [Model],
initParamCandidates: [VariableModel],
declaredInits: [MethodModel],
entities: [(String, Model)]) -> String {

Expand Down Expand Up @@ -101,14 +101,16 @@ extension ClassModel {
return template
}

private func extraInitsIfNeeded(initParamCandidates: [Model],
declaredInits: [MethodModel],
acl: String,
declType: DeclType,
overrides: [String: String]?) -> String {
private func extraInitsIfNeeded(
initParamCandidates: [VariableModel],
declaredInits: [MethodModel],
acl: String,
declType: DeclType,
overrides: [String: String]?
) -> String {

let declaredInitParamsPerInit = declaredInits.map { $0.params }

var needParamedInit = false
var needBlankInit = false

Expand Down Expand Up @@ -169,13 +171,18 @@ extension ClassModel {
}

let extraInitParamNames = initParamCandidates.map{$0.name}
let extraVarsToDecl = declaredInitParamsPerInit.flatMap{$0}.compactMap { (p: ParamModel) -> String? in
if !extraInitParamNames.contains(p.name) {
return p.asVarDecl
let extraVarsToDecl = Dictionary(
grouping: declaredInitParamsPerInit.flatMap {
$0.filter { !extraInitParamNames.contains($0.name) }
},
by: \.name
)
.compactMap { (name: String, params: [ParamModel]) in
let shouldErase = params.contains { params[0].type.typeName != $0.type.typeName }
return params[0].asInitVarDecl(eraseType: shouldErase)
}
return nil
}
.joined(separator: "\n")
.sorted()
.joined(separator: "\n")

let declaredInitStr = declaredInits.compactMap { (m: MethodModel) -> String? in
if case let .initKind(required, override) = m.kind, !m.processed {
Expand Down
5 changes: 2 additions & 3 deletions Sources/MockoloFramework/Templates/ParamTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ extension ParamModel {
}
return result
}

func applyVarTemplate(name: String,
type: Type) -> String {

func applyVarTemplate(type: `Type`) -> String {
assert(!type.isUnknown)
let vardecl = "\(1.tab)private var \(underlyingName): \(type.underlyingType)"
return vardecl
Expand Down
2 changes: 1 addition & 1 deletion Sources/MockoloFramework/Utils/TypeParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fileprivate var validIdentifierChars: CharacterSet = {
return valid
}()

public final class Type {
public final class `Type` {
let typeName: String
let cast: String?
var cachedDefaultVal: String?
Expand Down
58 changes: 58 additions & 0 deletions Tests/TestInit/FixtureInit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,61 @@ public class ForcastUpdatingMock: ForcastUpdating {
}
"""

let initWithSameParamNameButDifferentType = """
/// \(String.mockAnnotation)
protocol MyProtocol {
init(param: Any)
init(param: String)
init(with param: [Character])
}
"""

let initWithSameParamNameButDifferentTypeMock = """



class MyProtocolMock: MyProtocol {
private var _param: Any!
init() { }
required init(param: Any) {
self._param = param
}
required init(param: String = "") {
self._param = param
}
required init(with param: [Character] = [Character]()) {
self._param = param
}


}
"""

let multipleInitsWithSameParamName = """
/// \(String.mockAnnotation)
protocol MyProtocol {
init(param: String, anotherParam: Int)
init(param: String, anotherParam: String)
}
"""

let multipleInitsWithSameParamNameMock = """



class MyProtocolMock: MyProtocol {
private var _anotherParam: Any!
private var _param: String!
init() { }
required init(param: String = "", anotherParam: Int = 0) {
self._param = param
self._anotherParam = anotherParam
}
required init(param: String = "", anotherParam: String = "") {
self._param = param
self._anotherParam = anotherParam
}


}
"""
14 changes: 14 additions & 0 deletions Tests/TestInit/InitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,18 @@ class InitTests: MockoloTestCase {
verify(srcContent: keywordParams,
dstContent: keywordParamsMock)
}

func testInitiWithSameParamName() {
verify(
srcContent: multipleInitsWithSameParamName,
dstContent: multipleInitsWithSameParamNameMock
)
}

func testInitiWithSameParamNameButDifferentType() {
verify(
srcContent: initWithSameParamNameButDifferentType,
dstContent: initWithSameParamNameButDifferentTypeMock
)
}
}