Skip to content

Commit

Permalink
Merge branch 'uber/es-refactor'
Browse files Browse the repository at this point in the history
-Remove private init flag
-Add more input options to commandline
-Allow a custom func to be called in all mocked functions
-Add a template func to be used with --use-template-func flag
-Allow filtering by types to mock (protocols, classes, all)
-Cache default value for types for speedup
-Refactor util scan functions with concurrency
-Support propertywrapper for RxSwift observable variables
-Rename mock underlying variables
-Fix optional generic type param handling
-Fix inout param handling
  • Loading branch information
Ellie Shin committed Apr 1, 2020
1 parent 9b38dba commit d1f5f71
Show file tree
Hide file tree
Showing 69 changed files with 1,805 additions and 1,701 deletions.
42 changes: 30 additions & 12 deletions Sources/Mockolo/Executor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,22 @@ class Executor {
// MARK: - Private
private var loggingLevel: OptionArgument<Int>!
private var outputFilePath: OptionArgument<String>!
private var mockFileList: OptionArgument<String>!
private var mockFilePaths: OptionArgument<[String]>!
private var sourceDirs: OptionArgument<[String]>!
private var sourceFiles: OptionArgument<[String]>!
private var sourceFileList: OptionArgument<String>!
private var depFileList: OptionArgument<String>!
private var exclusionSuffixes: OptionArgument<[String]>!
private var header: OptionArgument<String>!
private var macro: OptionArgument<String>!
private var testableImports: OptionArgument<[String]>!
private var customImports: OptionArgument<[String]>!
private var annotation: OptionArgument<String>!
private var useTemplateFunc: OptionArgument<Bool>!
private var mockAll: OptionArgument<Bool>!
private var concurrencyLimit: OptionArgument<Int>!
private var useSourceKit: OptionArgument<Bool>!

/// Initializer.
///
/// - parameter name: The name used to check if this command should
Expand Down Expand Up @@ -70,15 +73,14 @@ class Executor {
kind: [String].self,
usage: "Paths to the directories containing source files to generate mocks for. If the --filelist or --sourcefiles values exist, they will be ignored. ",
completion: .filename)
depFileList = parser.add(option: "--depfilelist",
shortName: "-deplist",
mockFileList = parser.add(option: "--mock-filelist",
kind: String.self,
usage: "Path to a file containing a list of dependent files (separated by a new line) from modules this target depends on. ",
usage: "Path to a file containing a list of dependent files (separated by a new line) of modules this target depends on.",
completion: .filename)
mockFilePaths = parser.add(option: "--mockfiles",
shortName: "-mocks",
kind: [String].self,
usage: "List of mock files (separated by a comma or a space) from modules this target depends on. If the --depfilelist value exists, this will be ignored.",
usage: "List of mock files (separated by a comma or a space) from modules this target depends on. If the --mock-filelist value exists, this will be ignored.",
completion: .filename)
outputFilePath = parser.add(option: "--destination",
shortName: "-d",
Expand All @@ -102,9 +104,19 @@ class Executor {
shortName: "-i",
kind: [String].self,
usage: "If set, @testable import statments will be added for each module name in this list.")
customImports = parser.add(option: "--custom-imports",
shortName: "-c",
kind: [String].self,
usage: "If set, custom module imports will be added to the final import statement list.")
header = parser.add(option: "--header",
kind: String.self,
usage: "A custom header documentation to be added to the beginning of a generated mock file.")
useTemplateFunc = parser.add(option: "--use-template-func",
kind: Bool.self,
usage: "If set, a common template function will be called from all functions in mock classes (default is set to false).")
mockAll = parser.add(option: "--mock-all",
kind: Bool.self,
usage: "If set, it will mock all types (protocols and classes) with a mock annotation (default is set to false and only mocks protocols with a mock annotation).")
concurrencyLimit = parser.add(option: "--concurrency-limit",
shortName: "-j",
kind: Int.self,
Expand All @@ -129,7 +141,6 @@ class Executor {
///
/// - parameter arguments: The command line arguments to execute the command with.
func execute(with arguments: ArgumentParser.Result) {

guard let outputArg = arguments.get(outputFilePath) else { fatalError("Missing destination file path") }
let outputFilePath = fullPath(outputArg)

Expand All @@ -148,22 +159,26 @@ class Executor {
}

var mockFilePaths: [String]?
// If dep file list exists, mock filepaths value will be overriden (see the usage in setupArguments above)
if let depList = arguments.get(self.depFileList) {
let text = try? String(contentsOfFile: depList, encoding: String.Encoding.utf8)
// First see if a list of mock files are stored in a file
if let mockList = arguments.get(self.mockFileList) {
let text = try? String(contentsOfFile: mockList, encoding: String.Encoding.utf8)
mockFilePaths = text?.components(separatedBy: "\n").filter{!$0.isEmpty}.map(fullPath)
} else {
mockFilePaths = arguments.get(self.mockFilePaths)?.map(fullPath)
// If not, see if a list of mock files are directly passed in
mockFilePaths = arguments.get(self.mockFilePaths)?.map(fullPath)
}

let concurrencyLimit = arguments.get(self.concurrencyLimit)
let exclusionSuffixes = arguments.get(self.exclusionSuffixes) ?? []
let annotation = arguments.get(self.annotation) ?? String.mockAnnotation
let header = arguments.get(self.header)
let loggingLevel = arguments.get(self.loggingLevel) ?? 0
let macro = arguments.get(self.macro)
let testableImports = arguments.get(self.testableImports)
let customImports = arguments.get(self.customImports)
let shouldUseSourceKit = arguments.get(useSourceKit) ?? false
let shouldUseTemplateFunc = arguments.get(useTemplateFunc) ?? false
let shouldMockAll = arguments.get(mockAll) ?? false

do {
try generate(sourceDirs: srcDirs,
Expand All @@ -174,7 +189,10 @@ class Executor {
annotation: annotation,
header: header,
macro: macro,
declType: shouldMockAll ? .all : .protocolType,
useTemplateFunc: shouldUseTemplateFunc,
testableImports: testableImports,
customImports: customImports,
to: outputFilePath,
loggingLevel: loggingLevel,
concurrencyLimit: concurrencyLimit,
Expand Down
8 changes: 4 additions & 4 deletions Sources/MockoloFramework/Models/ClassModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class ClassModel: Model {
var offset: Int64
var type: Type
let attribute: String
let accessControlLevelDescription: String
let accessLevel: String
let identifier: String
let declType: DeclType
let entities: [(String, Model)]
Expand Down Expand Up @@ -52,10 +52,10 @@ final class ClassModel: Model {
self.metadata = metadata
self.offset = offset
self.attribute = Set(attributes.filter {$0.contains(String.available)}).joined(separator: " ")
self.accessControlLevelDescription = acl.isEmpty ? "" : acl + " "
self.accessLevel = acl
}

func render(with identifier: String, typeKeys: [String: String]? = nil) -> String? {
return applyClassTemplate(name: name, identifier: self.identifier, typeKeys: typeKeys, accessControlLevelDescription: accessControlLevelDescription, attribute: attribute, declType: declType, metadata: metadata, initParamCandidates: initParamCandidates, declaredInits: declaredInits, entities: entities)
func render(with identifier: String, encloser: String, useTemplateFunc: Bool) -> String? {
return applyClassTemplate(name: name, identifier: self.identifier, accessLevel: accessLevel, attribute: attribute, declType: declType, metadata: metadata, useTemplateFunc: useTemplateFunc, initParamCandidates: initParamCandidates, declaredInits: declaredInits, entities: entities)
}
}
8 changes: 3 additions & 5 deletions Sources/MockoloFramework/Models/ClosureModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ final class ClosureModel: Model {
var type: Type
var offset: Int64 = .max
let funcReturnType: Type
let staticKind: String
let genericTypeNames: [String]
let paramNames: [String]
let paramTypes: [Type]
Expand All @@ -31,9 +30,9 @@ final class ClosureModel: Model {
return .class
}

init(name: String, genericTypeParams: [ParamModel], paramNames: [String], paramTypes: [Type], suffix: String, returnType: Type, staticKind: String) {

init(name: String, genericTypeParams: [ParamModel], paramNames: [String], paramTypes: [Type], suffix: String, returnType: Type) {
self.name = name + .handlerSuffix
self.staticKind = staticKind
self.suffix = suffix
let genericTypeNameList = genericTypeParams.map(path: \.name)
self.genericTypeNames = genericTypeNameList
Expand All @@ -43,10 +42,9 @@ final class ClosureModel: Model {
self.type = Type.toClosureType(with: paramTypes, typeParams: genericTypeNameList, suffix: suffix, returnType: returnType)
}

func render(with identifier: String, typeKeys: [String: String]?) -> String? {
func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false) -> String? {
return applyClosureTemplate(name: identifier + .handlerSuffix,
type: type,
typeKeys: typeKeys,
genericTypeNames: genericTypeNames,
paramVals: paramNames,
paramTypes: paramTypes,
Expand Down
4 changes: 2 additions & 2 deletions Sources/MockoloFramework/Models/IfMacroModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ final class IfMacroModel: Model {
self.type = Type(name)
}

func render(with identifier: String, typeKeys: [String: String]? = nil) -> String? {
return applyMacroTemplate(name: name, typeKeys: typeKeys, entities: entities)
func render(with identifier: String, encloser: String, useTemplateFunc: Bool) -> String? {
return applyMacroTemplate(name: name, useTemplateFunc: useTemplateFunc, entities: entities)
}
}
25 changes: 12 additions & 13 deletions Sources/MockoloFramework/Models/MethodModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ final class MethodModel: Model {
var type: Type
var offset: Int64
let length: Int64
let accessControlLevelDescription: String
let accessLevel: String
var attributes: [String]? = nil
let genericTypeParams: [ParamModel]
let params: [ParamModel]
let processed: Bool
var modelDescription: String? = nil
let isStatic: Bool
var isStatic: Bool
let shouldOverride: Bool
let suffix: String
let kind: MethodKind
var modelType: ModelType {
return .method
}

var staticKind: String {
private var staticKind: String {
return isStatic ? .static : ""
}

Expand Down Expand Up @@ -94,8 +94,7 @@ final class MethodModel: Model {
paramNames: paramNames,
paramTypes: paramTypes,
suffix: suffix,
returnType: type,
staticKind: staticKind)
returnType: type)

return ret
}()
Expand Down Expand Up @@ -126,7 +125,7 @@ final class MethodModel: Model {
self.genericTypeParams = genericTypeParams
self.processed = processed
self.modelDescription = modelDescription
self.accessControlLevelDescription = acl
self.accessLevel = acl
}

init(_ ast: Structure, encloserType: DeclType, filepath: String, data: Data, processed: Bool) {
Expand Down Expand Up @@ -184,7 +183,7 @@ final class MethodModel: Model {
self.suffix = ""
}

self.accessControlLevelDescription = ast.accessControlLevelDescription
self.accessLevel = ast.accessLevel
self.attributes = ast.hasAvailableAttribute ? ast.extractAttributes(data, filterOn: SwiftDeclarationAttributeKind.available.rawValue) : []
}

Expand All @@ -201,7 +200,7 @@ final class MethodModel: Model {
return name(by: level - 1) + postfix
}

func render(with identifier: String, typeKeys: [String: String]? = nil) -> String? {
func render(with identifier: String, encloser: String, useTemplateFunc: Bool) -> String? {
if processed {
var prefix = shouldOverride ? "\(String.override) " : ""

Expand All @@ -211,7 +210,7 @@ final class MethodModel: Model {
}
}

if let ret = modelDescription?.trimmingCharacters(in: .whitespacesAndNewlines) ?? self.data?.toString(offset: offset, length: length) {
if let ret = modelDescription?.trimmingCharacters(in: .newlines) ?? self.data?.toString(offset: offset, length: length) {
return prefix + ret
}
return nil
Expand All @@ -220,15 +219,15 @@ final class MethodModel: Model {
let result = applyMethodTemplate(name: name,
identifier: identifier,
kind: kind,
useTemplateFunc: useTemplateFunc,
isStatic: isStatic,
isOverride: shouldOverride,
genericTypeParams: genericTypeParams,
params: params,
returnType: type,
staticKind: staticKind,
accessControlLevelDescription: accessControlLevelDescription,
accessLevel: accessLevel,
suffix: suffix,
handler: handler,
typeKeys: typeKeys)
handler: handler)
return result
}
}
22 changes: 21 additions & 1 deletion Sources/MockoloFramework/Models/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public protocol Model {
/// Fully qualified identifier
var fullName: String { get }

var underlyingName: String { get }

/// Type of this model
var modelType: ModelType { get }

Expand All @@ -40,19 +42,22 @@ public protocol Model {
/// Indicates whether this model maps to an init method
var isInitializer: Bool { get }

var isStatic: Bool { get }

/// Decl(e.g. class/struct/protocol/enum) or return type (e.g. var/func)
var type: Type { get set }

/// Offset where this type is declared
var offset: Int64 { get set }

/// Applies a corresponding template to this model to output mocks
func render(with identifier: String, typeKeys: [String: String]?) -> String?
func render(with identifier: String, encloser: String, useTemplateFunc: Bool) -> String?

/// Used to differentiate multiple entities with the same name
/// @param level The verbosity level
/// @returns a unique name given the verbosity (default is name)
func name(by level: Int) -> String


func isEqual(_ other: Model) -> Bool

Expand Down Expand Up @@ -81,6 +86,20 @@ extension Model {
return name
}

var underlyingName: String {
if isStatic {
return "_\(name)"
}
if !(type.isRxObservable || type.defaultVal() != nil) {
return "_\(name)"
}
return name.safeName
}

var isStatic: Bool {
return false
}

var processed: Bool {
return false
}
Expand All @@ -93,3 +112,4 @@ extension Model {
return false
}
}

14 changes: 13 additions & 1 deletion Sources/MockoloFramework/Models/ParamModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ final class ParamModel: Model {
let isGeneric: Bool
let inInit: Bool
let needVarDecl: Bool

var isStatic: Bool {
return false
}

var modelType: ModelType {
return .parameter
Expand All @@ -34,6 +38,14 @@ final class ParamModel: Model {
var fullName: String {
return label + "_" + name
}

func underlyingName(with defaultTypeValue: String?) -> String {
if let _ = defaultTypeValue, !type.isRxObservable {
return "_\(name)"
}
return name
}


init(label: String = "", name: String, typeName: String, isGeneric: Bool = false, inInit: Bool = false, needVarDecl: Bool, offset: Int64, length: Int64) {
self.name = name.trimmingCharacters(in: .whitespaces)
Expand Down Expand Up @@ -69,7 +81,7 @@ final class ParamModel: Model {
return nil
}

func render(with identifier: String, typeKeys: [String: String]? = nil) -> String? {
func render(with identifier: String, encloser: String, useTemplateFunc: Bool = false) -> String? {
return applyParamTemplate(name: name, label: label, type: type, inInit: inInit)
}
}
6 changes: 3 additions & 3 deletions Sources/MockoloFramework/Models/ParsedEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct ResolvedEntity {

func model() -> Model {
return ClassModel(identifier: key,
acl: entity.entityNode.acl,
acl: entity.entityNode.accessLevel,
declType: entity.entityNode.declType,
attributes: attributes,
offset: entity.entityNode.offset,
Expand All @@ -80,7 +80,7 @@ struct ResolvedEntityContainer {

protocol EntityNode {
var name: String { get }
var acl: String { get }
var accessLevel: String { get }
var attributesDescription: String { get }
var declType: DeclType { get }
var inheritedTypes: [String] { get }
Expand Down Expand Up @@ -122,7 +122,7 @@ public final class Entity {
}

static func node(with entityNode: EntityNode,
filepath: String = "",
filepath: String,
data: Data? = nil,
isPrivate: Bool,
isFinal: Bool,
Expand Down
Loading

0 comments on commit d1f5f71

Please sign in to comment.