Skip to content
Open
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
144 changes: 144 additions & 0 deletions Example/RoboKittenTests/Common/Random.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import Foundation
import UIKit

protocol Random {
static func random() -> Self
}

extension Array: Random {
private static func randomElement() -> Element? {
guard Element.self is Random.Type else {
return nil
}
return (Element.self as? Random.Type)?.random() as? Element
}

static func random() -> [Element] {
return (0...Int(arc4random() % 3))
.map { _ in randomElement() }
.compactMap { $0 }
}
}

extension Optional: Random {
private static func randomElement() -> Wrapped? {
guard Wrapped.self is Random.Type else {
return nil
}
return (Wrapped.self as? Random.Type)?.random() as? Wrapped
}

static func random() -> Wrapped? {
return Int(arc4random() % 2) == 0
? nil
: randomElement()
}
}

extension String: Random {
static func random() -> String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let len = UInt32(letters.length)

var randomString = ""

for _ in 0 ..< 20 {
let rand = arc4random_uniform(len)
var nextChar = letters.character(at: Int(rand))
randomString += NSString(characters: &nextChar, length: 1) as String
}

return randomString
}
}

extension Int: Random {
static func random() -> Int {
return Int(arc4random() % 200)
}
}

extension UInt: Random {
static func random() -> UInt {
return UInt(arc4random() % 200)
}
}

extension Int32: Random {
static func random() -> Int32 {
return Int32(arc4random() % 300)
}
}

extension Int64: Random {
static func random() -> Int64 {
return Int64(arc4random() % 300)
}
}

extension Double: Random {
static func random() -> Double {
return Double(arc4random() % 1000) / 100
}
}

extension Float: Random {
static func random() -> Float {
return Float(arc4random() % 1000) / 100
}
}

extension Bool: Random {
static func random() -> Bool {
return arc4random() % 2 == 1
}
}

extension Data: Random {
static func random() -> Data {
let bytes = [UInt32](repeating: 0, count: 10).map { _ in arc4random() }
return Data(bytes: bytes, count: 10 )
}
}

extension Date: Random {
static func random() -> Date {
return Date(timeIntervalSince1970: Double.random())
}
}

extension UIImage {
static func random() -> UIImage {
let color = UIColor.random()
let rect = CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 1, height: 1))
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()!

context.setFillColor(color.cgColor)
context.fill(rect)

let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

return image!
}
}

extension UIColor {
static func random() -> UIColor {
let literal = CGFloat(arc4random() % 255)
return .init(red: literal, green: literal, blue: literal, alpha: literal)
}
}

extension NSError {
static func random() -> NSError {
return NSError(domain: .random(), code: .random(), userInfo: nil)
}
}

extension URL: Random {
static func random() -> URL {
return URL(string: .random())!
}
}
53 changes: 53 additions & 0 deletions Example/RoboKittenTests/Templates/AutoMockable.stencil
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Foundation
import SwiftyMock
{% if argument.testable %}@testable import {{ argument.testable }}{% endif %}

{% macro parseFunctionType method %}{% if method.parameters.count == 0 %}FunctionVoidCall{% else %}FunctionCall{% endif %}{% endmacro %}

{% macro defineReturn method %}{% if not method.returnTypeName.isVoid %}return {% endif %}{% endmacro %}
{% macro parseArguments method %}{% if method.parameters.count == 1 %}{{ method.parameters.first.typeName }}{% else %}({% for param in method.parameters %}{{ param.name }}: {{ param.typeName|replace:"@escaping ","" }}{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}{% endmacro %}

{% macro parseParameterName parameter %}{{ parameter.typeAttributes }}{% endmacro %}

{% macro parseArgumentsInMethod method %}{% if method.parameters.count > 0 %}, argument: {% if method.parameters.count == 1 %}{{ method.parameters.first.name }}{% else %}({% for param in method.parameters %}{{ param.name }}: {{ param.name }}{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}{% endif %}{% endmacro %}

{% macro parseReturn method %}{% if not method.returnTypeName.isVoid %}{{ method.returnTypeName }}{% else %}(){% endif %}{% endmacro %}

{% macro mockOptionalVariable variable %}
var {{ variable.name }}: {{ variable.typeName }}
{% endmacro %}

{% macro mockNonOptionalArrayOrDictionaryVariable variable %}
var {{ variable.name }}: {{ variable.typeName }} = {% if variable.isArray %}[]{% elif variable.isDictionary %}[:]{% endif %}
{% endmacro %}

{% macro mockNonOptionalVariable variable %}
{% if variable.type.implements.Random or variable.type.implements.AutoRandom %}
var {{ variable.name }} = {{ variable.typeName }}.random()
{% else %}
var {{ variable.name }}: {{ variable.typeName }} {
get { return {% call underlyingMockedVariableName variable %} }
set(value) { {% call underlyingMockedVariableName variable %} = value }
}
var {% call underlyingMockedVariableName variable %}: {{ variable.typeName }}!
{% endif %}
{% endmacro %}

{% macro underlyingMockedVariableName variable %}underlying{{ variable.name|upperFirstLetter }}{% endmacro %}

{% macro parseDefault method %}{% if method.returnTypeName.isVoid %}(){% else %}{% if method.returnTypeName|contains:"Signal" %}.empty{% elif method.returnType.implements.Random or method.returnType.implements.AutoRandom %}{{ method.returnTypeName }}.random(){% else %}Fake{{ method.returnTypeName }}(){%endif%}{% endif %}{% endmacro %}

{% for type in types.protocols where type.based.AutoMock %}
final class Fake{{ type.name }}: {{ type.name }} {
{% for variable in type.allVariables|!definedInExtension %}
{% if variable.isOptional %}{% call mockOptionalVariable variable %}{% elif variable.isArray or variable.isDictionary %}{% call mockNonOptionalArrayOrDictionaryVariable variable %}{% else %}{% call mockNonOptionalVariable variable %}{% endif %}
{% endfor %}
{% for method in type.allMethods|!definedInExtension %}

let {{ method.shortName }}Call = {% call parseFunctionType method %}<{% if method.parameters.count > 0 %}{% call parseArguments method %}, {% endif %}{% call parseReturn method %}>()
func {{ method.name }}{% if method.throws %} throws{% endif %}{% if not method.returnTypeName.isVoid %} -> {{ method.returnTypeName }}{% endif %} {
{% call defineReturn method %}stubCall({{ method.shortName }}Call{% call parseArgumentsInMethod method %}, defaultValue: {% call parseDefault method %})
}
{% endfor %}
}
{% endfor %}
51 changes: 51 additions & 0 deletions Example/RoboKittenTests/Templates/AutoRandom.stencil
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Foundation
{% if argument.testable %}@testable import {{ argument.testable }}{% endif %}

{% macro defineDeclaration var %}{{ var.name }}:{% if var.isClosure and not var.isOptional %} @escaping{% endif %} {{ var.typeName }} = {% call defineRandom var %}{% endmacro %}
{% macro defineRandom var %}{% if var.isClosure %}{}{% else %}.random(){% endif %}{% endmacro %}

{% for type in types.implementing.AutoRandom|!enum %}

extension {{ type.name }}: Random {
static func random() -> {{ type.name }} {
return .restrictedRandom()
}

static func restrictedRandom(
{% for var in type.variables %}
{% if not var.name == "hashValue" %}
{% if forloop.last %}
{% call defineDeclaration var %}
{% else %}
{% call defineDeclaration var %},
{% endif %}
{% endif %}
{% endfor %}
) -> {{ type.name }} {
return {{ type.name }}(
{% for var in type.variables %}
{% if not var.name == "hashValue" %}
{% if forloop.last %}
{{ var.name }}: {{ var.name }}
{% else %}
{{ var.name }}: {{ var.name }},
{% endif %}
{% endif %}
{% endfor %}
)
}
}
{% endfor %}

{% for type in types.implementing.AutoRandom|enum %}
extension {{ type.name }}: Random {
static func random() -> {{ type.name }} {
switch arc4random_uniform({{ type.cases.count }}) {
{% for case in type.cases %}
case {{ forloop.counter0 }}: return .{{ case.name }}{% if case.hasAssociatedValue %}({% for associated in case.associatedValues %}{% if associated.externalName %}{{ associated.externalName }}: {% endif %}.random(){% endfor %}){% endif %}
{% endfor %}
default: return {{ .type.cases.first.name }}
}
}
}
{% endfor %}