Skip to content

Commit

Permalink
Merge pull request #89 from maxwellE/testable_imports
Browse files Browse the repository at this point in the history
Adds ability to add @testable import statements
  • Loading branch information
ellie authored Feb 25, 2020
2 parents 64c1825 + 2e476d5 commit 11c8b0c
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ OPTIONS:
--annotation, -a A custom annotation string used to indicate if a type should be mocked (default = @mockable).
--header, -h A custom header documentation to be added to the beginning of a generated mock file.
--macro, -m If set, #if [macro] / #endif will be added to the generated mock file content to guard compilation.
--testable-imports, -i If set, @testable import statments will be added for each module name in this list.
--concurrency-limit, -j Maximum number of threads to execute concurrently (default = number of cores on the running machine).
--logging-level, -v The logging level to use. Default is set to 0 (info only). Set 1 for verbose, 2 for warning, and 3 for error.
--use-sourcekit If this argument is added, it will use SourceKit for parsing. By default it uses SwiftSyntax.
Expand Down
7 changes: 7 additions & 0 deletions Sources/Mockolo/Executor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Executor {
private var exclusionSuffixes: OptionArgument<[String]>!
private var header: OptionArgument<String>!
private var macro: OptionArgument<String>!
private var testableImports: OptionArgument<[String]>!
private var annotation: OptionArgument<String>!
private var concurrencyLimit: OptionArgument<Int>!
private var useSourceKit: OptionArgument<Bool>!
Expand Down Expand Up @@ -97,6 +98,10 @@ class Executor {
shortName: "-m",
kind: String.self,
usage: "If set, #if [macro] / #endif will be added to the generated mock file content to guard compilation.")
testableImports = parser.add(option: "--testable-imports",
shortName: "-i",
kind: [String].self,
usage: "If set, @testable import statments will be added for each module name in this list.")
header = parser.add(option: "--header",
shortName: "-h",
kind: String.self,
Expand Down Expand Up @@ -158,6 +163,7 @@ class Executor {
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 shouldUseSourceKit = arguments.get(useSourceKit) ?? false

do {
Expand All @@ -169,6 +175,7 @@ class Executor {
annotation: annotation,
header: header,
macro: macro,
testableImports: testableImports,
to: outputFilePath,
loggingLevel: loggingLevel,
concurrencyLimit: concurrencyLimit,
Expand Down
2 changes: 2 additions & 0 deletions Sources/MockoloFramework/Operations/Generator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public func generate(sourceDirs: [String]?,
annotation: String,
header: String?,
macro: String?,
testableImports: [String]?,
to outputFilePath: String,
loggingLevel: Int,
concurrencyLimit: Int?,
Expand Down Expand Up @@ -160,6 +161,7 @@ public func generate(sourceDirs: [String]?,
pathToContentMap: pathToContentMap,
header: header,
macro: macro,
testableImports: testableImports,
to: outputFilePath)
signpost_end(name: "Write results")
let t5 = CFAbsoluteTimeGetCurrent()
Expand Down
25 changes: 22 additions & 3 deletions Sources/MockoloFramework/Operations/OutputWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func write(candidates: [(String, Int64)],
pathToContentMap: [(String, Data, Int64)],
header: String?,
macro: String?,
testableImports: [String]?,
to outputFilePath: String) -> String {

var importLines = [String]()
Expand All @@ -36,9 +37,27 @@ func write(candidates: [(String, Int64)],
importLines.append(contentsOf: v)
break
}

let importsSet = Set(importLines.map{$0.trimmingCharacters(in: .whitespaces)})
let importLineStr = importsSet.sorted().joined(separator: "\n")

var importLineStr = ""

if let testableImports = testableImports {
var imports = importLines.compactMap { (importLine) -> String? in
return importLine.moduleName
}
imports.append(contentsOf: testableImports)
importLineStr = Set(imports)
.sorted()
.map { testableModuleName -> String in
guard testableImports.contains(testableModuleName) else {
return testableModuleName.asImport
}
return testableModuleName.asTestableImport
}
.joined(separator: "\n")
} else {
let importsSet = Set(importLines.map{$0.trimmingCharacters(in: .whitespaces)})
importLineStr = importsSet.sorted().joined(separator: "\n")
}

let entities = candidates
.sorted { (left: (String, Int64), right: (String, Int64)) -> Bool in
Expand Down
1 change: 0 additions & 1 deletion Sources/MockoloFramework/Utils/InheritanceResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,3 @@ func findImportLines(data: Data, offset: Int64?) -> [String] {

return []
}

12 changes: 12 additions & 0 deletions Sources/MockoloFramework/Utils/StringExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,16 @@ extension StringProtocol {
return ret.components(separatedBy: separatorsForDisplay)
}

var asTestableImport: String {
return "@testable \(self.asImport)"
}

var asImport: String {
return "import \(self)"
}

var moduleName: String? {
guard self.hasPrefix(String.import) else { return nil }
return self.dropFirst(String.import.count).trimmingCharacters(in: CharacterSet.whitespaces)
}
}
7 changes: 4 additions & 3 deletions Tests/MockoloTestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ class MockoloTestCase: XCTestCase {
}
}

func verify(srcContent: String, mockContent: String? = nil, dstContent: String, header: String = "", concurrencyLimit: Int? = 1, parser: ParserType = .random) {
func verify(srcContent: String, mockContent: String? = nil, dstContent: String, header: String = "", testableImports: [String]? = [], concurrencyLimit: Int? = 1, parser: ParserType = .random) {
var mockList: [String]?
if let mock = mockContent {
if mockList == nil {
mockList = [String]()
}
mockList?.append(mock)
}
verify(srcContents: [srcContent], mockContents: mockList, dstContent: dstContent, header: header, concurrencyLimit: concurrencyLimit, parser: parser)
verify(srcContents: [srcContent], mockContents: mockList, dstContent: dstContent, header: header, testableImports: testableImports, concurrencyLimit: concurrencyLimit, parser: parser)
}

func verify(srcContents: [String], mockContents: [String]?, dstContent: String, header: String, concurrencyLimit: Int?, parser: ParserType) {
func verify(srcContents: [String], mockContents: [String]?, dstContent: String, header: String, testableImports: [String]?, concurrencyLimit: Int?, parser: ParserType) {
var index = 0
srcFilePathsCount = srcContents.count
mockFilePathsCount = mockContents?.count ?? 0
Expand Down Expand Up @@ -124,6 +124,7 @@ class MockoloTestCase: XCTestCase {
annotation: String.mockAnnotation,
header: header,
macro: "MOCK",
testableImports: testableImports,
to: dstFilePath,
loggingLevel: 3,
concurrencyLimit: concurrencyLimit,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import MockoloFramework

let testableImports = """
\(String.headerDoc)
import Foundation
/// \(String.mockAnnotation)
protocol SimpleVar {
var name: Int { get set }
}
"""

let testableImportsMock =
"""
import Foundation
@testable import SomeImport1
@testable import SomeImport2
class SimpleVarMock: SimpleVar {
private var _doneInit = false
init() { _doneInit = true }
init(name: Int = 0) {
self.name = name
_doneInit = true
}
var nameSetCallCount = 0
var underlyingName: Int = 0
var name: Int {
get { return underlyingName }
set {
underlyingName = newValue
if _doneInit { nameSetCallCount += 1 }
}
}
}
"""

let testableImportsWithOverlap = """
\(String.headerDoc)
import Foundation
import SomeImport1
/// \(String.mockAnnotation)
protocol SimpleVar {
var name: Int { get set }
}
"""

let testableImportsWithOverlapMock =
"""
import Foundation
@testable import SomeImport1
class SimpleVarMock: SimpleVar {
private var _doneInit = false
init() { _doneInit = true }
init(name: Int = 0) {
self.name = name
_doneInit = true
}
var nameSetCallCount = 0
var underlyingName: Int = 0
var name: Int {
get { return underlyingName }
set {
underlyingName = newValue
if _doneInit { nameSetCallCount += 1 }
}
}
}
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Foundation

class TestableImportStatementsTests: MockoloTestCase {

func testTesableImportStatements() {
verify(srcContent: testableImports,
dstContent: testableImportsMock,
testableImports: ["SomeImport1", "SomeImport2"])
}

func testTesableImportStatementsWithOverlap() {
verify(srcContent: testableImportsWithOverlap,
dstContent: testableImportsWithOverlapMock,
testableImports: ["SomeImport1"])
}
}

0 comments on commit 11c8b0c

Please sign in to comment.