Skip to content

Commit

Permalink
Fix type extraction code
Browse files Browse the repository at this point in the history
  • Loading branch information
fummicc1 committed Jul 6, 2024
1 parent bbb6de0 commit c5c877f
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 97 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PackageDescription
let package = Package(
name: "Mockolo",
platforms: [
.macOS(.v13),
.macOS(.v12),
],
products: [
.executable(name: "mockolo", targets: ["Mockolo"]),
Expand Down
23 changes: 1 addition & 22 deletions Sources/MockoloFramework/Utils/StringExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,32 +110,11 @@ extension String {

var hasThrowsOrRethrows: Bool {
return components(separatedBy: .whitespaces).contains { component in
let hasTypedThrow = hasPrefix(String.throws.withLeftParen)
let hasTypedThrow = hasPrefix(String.throws.withLeftParen) && hasSuffix(")")
return component == .throws || hasTypedThrow || component == .rethrows
}
}

/// Extract Error type in typed-throw.
///
/// - Note: Because any keyword can appear, it was hard to split by whitespace.
///
/// - ex
/// ```
/// throws(any LocalizedError)
/// ↓ should extract
/// any LocalizedError
/// ```
var typedThrowTypeName: String {
let pattern = #"throws\((?<thrownType>.+)\)"#
guard let regex = try? Regex(pattern, as: (Substring, thrownType: Substring).self) else {
return ""
}
guard let match = firstMatch(of: regex) else {
return ""
}
return String(match.output.thrownType)
}

var hasAsync: Bool {
return components(separatedBy: .whitespaces).contains { component in
return component == .async
Expand Down
23 changes: 21 additions & 2 deletions Sources/MockoloFramework/Utils/TypeParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,25 @@ public final class `Type` {
return mutableArg
}

/// Parse throws clause from suffix and return typed-throw's type.
///
/// - Returns: if typed-throw is used, returns its concrete type, unless returns nil.
static func extractTypedThrow(
suffix: String
) -> String? {
return suffix
.components(separatedBy: .whitespaces)
.compactMap { clause in
guard let prefixRange = clause.range(of: "\(String.throws)(") else {
return nil
}
let endIndex = clause.dropLast().endIndex
return String(
clause[prefixRange.upperBound..<endIndex]
)
}
.first
}

static func toClosureType(with params: [Type], typeParams: [String], suffix: String, returnType: Type, encloser: String) -> Type {

Expand Down Expand Up @@ -559,9 +578,9 @@ public final class `Type` {
}

let hasThrowsOrRethrows = suffix.hasThrowsOrRethrows
let typedThrowTypeName = suffix.typedThrowTypeName
let typedThrowTypeName = extractTypedThrow(suffix: suffix)

let thrownSuffix: String = if typedThrowTypeName.isNotEmpty {
let thrownSuffix: String = if let typedThrowTypeName {
"\(String.throws)(\(typedThrowTypeName))"
} else {
String.throws
Expand Down
86 changes: 22 additions & 64 deletions Tests/TestFuncs/TestFuncThrow/FixtureFuncThrow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import Foundation
protocol FuncThrow {
func f1(arg: Int) throws -> String
func f2(arg: Int) throws
func f3(arg: Int) throws(SomeError)
func f4(arg: Int) throws(SomeError) -> String
func g1(arg: (Int) throws -> ())
throws -> String
func g2(arg: (Int) throws -> ()) throws
Expand Down Expand Up @@ -47,6 +49,26 @@ class FuncThrowMock: FuncThrow {
}
private(set) var f3CallCount = 0
var f3Handler: ((Int) throws(SomeError) -> ())?
func f3(arg: Int) throws(SomeError) {
f3CallCount += 1
if let f3Handler = f3Handler {
try f3Handler(arg)
}
}
private(set) var f4CallCount = 0
var f4Handler: ((Int) throws(SomeError) -> (String))?
func f4(arg: Int) throws(SomeError) -> String {
f4CallCount += 1
if let f4Handler = f4Handler {
return try f4Handler(arg)
}
return ""
}
private(set) var g1CallCount = 0
var g1Handler: (((Int) throws -> ()) throws -> (String))?
func g1(arg: (Int) throws -> ()) throws -> String {
Expand Down Expand Up @@ -99,68 +121,4 @@ class FuncThrowMock: FuncThrow {
}
"""

let funcTypedThrow = """
import Foundation
/// \(String.mockAnnotation)
protocol FuncTypedThrow {
func f1(arg: Int) throws(any LocalizedError) -> String
func f2(arg: Int) throws(any LocalizedError)
func f3(arg: Int) throws(SomeError) -> String
func f4(arg: Int) throws(SomeError)
}
"""
let funcTypedThrowMock = """
import Foundation
class FuncTypedThrowMock: FuncTypedThrow {
init() { }
private(set) var f1CallCount = 0
var f1Handler: ((Int) throws(any LocalizedError) -> (String))?
func f1(arg: Int) throws(any LocalizedError) -> String {
f1CallCount += 1
if let f1Handler = f1Handler {
return try f1Handler(arg)
}
return ""
}
private(set) var f2CallCount = 0
var f2Handler: ((Int) throws(any LocalizedError) -> ())?
func f2(arg: Int) throws(any LocalizedError) {
f2CallCount += 1
if let f2Handler = f2Handler {
try f2Handler(arg)
}
}
private(set) var f3CallCount = 0
var f3Handler: ((Int) throws(SomeError) -> (String))?
func f3(arg: Int) throws(SomeError) -> String {
f3CallCount += 1
if let f3Handler = f3Handler {
return try f3Handler(arg)
}
return ""
}
private(set) var f4CallCount = 0
var f4Handler: ((Int) throws(SomeError) -> ())?
func f4(arg: Int) throws(SomeError) {
f4CallCount += 1
if let f4Handler = f4Handler {
try f4Handler(arg)
}
}
}
"""
7 changes: 0 additions & 7 deletions Tests/TestFuncs/TestFuncThrow/FuncThrowTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,4 @@ class FuncThrowTests: MockoloTestCase {
verify(srcContent: funcThrow,
dstContent: funcThrowMock)
}

func testTypedThrows() {
verify(
srcContent: funcTypedThrow,
dstContent: funcTypedThrowMock
)
}
}
22 changes: 21 additions & 1 deletion Tests/TestInit/FixtureInit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,14 +330,34 @@ class MyProtocolMock: MyProtocol {
let throwableInit = """
/// \(String.mockAnnotation)
protocol MyProtocol {
init(param: String) throws(SomeError)
init(param: String) throws
}
"""

let throwableInitMock = """
class MyProtocolMock: MyProtocol {
private var _param: String!
init() { }
required init(param: String = "") throws {
self._param = param
}
}
"""

let typedThrowableInit = """
/// \(String.mockAnnotation)
protocol MyProtocol {
init(param: String) throws(SomeError)
}
"""

let typedThrowableInitMock = """
class MyProtocolMock: MyProtocol {
private var _param: String!
init() { }
Expand Down
7 changes: 7 additions & 0 deletions Tests/TestInit/InitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,11 @@ class InitTests: MockoloTestCase {
dstContent: throwableInitMock
)
}

func testTypedThrowableInit() {
verify(
srcContent: typedThrowableInit,
dstContent: typedThrowableInitMock
)
}
}

0 comments on commit c5c877f

Please sign in to comment.