Add some basic tests for generic class and generic protocol mocks.

This commit is contained in:
Matyáš Kříž 2018-11-26 19:11:01 +01:00
parent a7a779c9e2
commit 335a2175c1
5 changed files with 388 additions and 8 deletions

View File

@ -141,10 +141,14 @@
58C54612D0DB47A284F29AD5 /* ExcludedStubTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C54B2B810BC9284205CB16 /* ExcludedStubTest.swift */; };
58C54C0D4A65BCDC47704C0B /* ExcludedTestClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C54D12B64AF3169FC8A1A3 /* ExcludedTestClass.swift */; };
58C54E2CB6689135915CFC3E /* ExcludedStubTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C54B2B810BC9284205CB16 /* ExcludedStubTest.swift */; };
680894BF21ABFDCB00C8D2EF /* GenericClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 680894BE21ABFDCB00C8D2EF /* GenericClassTest.swift */; };
680894C021ABFDCB00C8D2EF /* GenericClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 680894BE21ABFDCB00C8D2EF /* GenericClassTest.swift */; };
6861B32921A31DAC002EC2DA /* GenericClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6861B30B21A31DA2002EC2DA /* GenericClass.swift */; };
6861B32A21A31DAD002EC2DA /* GenericClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6861B30B21A31DA2002EC2DA /* GenericClass.swift */; };
6861B32C21A32279002EC2DA /* GenericProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6861B32B21A32279002EC2DA /* GenericProtocol.swift */; };
6861B32D21A32279002EC2DA /* GenericProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6861B32B21A32279002EC2DA /* GenericProtocol.swift */; };
6896352E21AC5A4700B25D47 /* GenericProtocolTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6896352D21AC5A4700B25D47 /* GenericProtocolTest.swift */; };
6896352F21AC5A4700B25D47 /* GenericProtocolTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6896352D21AC5A4700B25D47 /* GenericProtocolTest.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -349,8 +353,10 @@
18E2A3971FBB43E60058FEC5 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = "<group>"; };
58C54B2B810BC9284205CB16 /* ExcludedStubTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExcludedStubTest.swift; sourceTree = "<group>"; };
58C54D12B64AF3169FC8A1A3 /* ExcludedTestClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExcludedTestClass.swift; sourceTree = "<group>"; };
680894BE21ABFDCB00C8D2EF /* GenericClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericClassTest.swift; sourceTree = "<group>"; };
6861B30B21A31DA2002EC2DA /* GenericClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericClass.swift; sourceTree = "<group>"; };
6861B32B21A32279002EC2DA /* GenericProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericProtocol.swift; sourceTree = "<group>"; };
6896352D21AC5A4700B25D47 /* GenericProtocolTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericProtocolTest.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -520,6 +526,7 @@
isa = PBXGroup;
children = (
18E2A2601FBB1C330058FEC5 /* ClassTest.swift */,
680894BE21ABFDCB00C8D2EF /* GenericClassTest.swift */,
18E2A2611FBB1C330058FEC5 /* CuckooFunctionsTest.swift */,
18E2A2621FBB1C330058FEC5 /* DefaultValueRegistryTest.swift */,
18E2A2631FBB1C330058FEC5 /* FailTest.swift */,
@ -527,6 +534,7 @@
18E2A2661FBB1C330058FEC5 /* Info.plist */,
18E2A2671FBB1C330058FEC5 /* Matching */,
18E2A26D1FBB1C330058FEC5 /* ProtocolTest.swift */,
6896352D21AC5A4700B25D47 /* GenericProtocolTest.swift */,
18E2A26E1FBB1C330058FEC5 /* Source */,
18E2A2771FBB1C330058FEC5 /* Stubbing */,
18E2A27D1FBB1C330058FEC5 /* StubTest.swift */,
@ -1068,6 +1076,7 @@
18E2A2EF1FBB22CB0058FEC5 /* StubNoReturnThrowingFunctionTest.swift in Sources */,
18E2A2E31FBB22C40058FEC5 /* TestedSubProtocol.swift in Sources */,
18E2A2DE1FBB22C40058FEC5 /* ClassWithOptionals.swift in Sources */,
6896352F21AC5A4700B25D47 /* GenericProtocolTest.swift in Sources */,
18E2A2D41FBB22BC0058FEC5 /* ProtocolTest.swift in Sources */,
18E2A2ED1FBB22CB0058FEC5 /* StubFunctionTest.swift in Sources */,
18E2A2C51FBB22B60058FEC5 /* ClassTest.swift in Sources */,
@ -1084,6 +1093,7 @@
18E2A2C71FBB22B60058FEC5 /* DefaultValueRegistryTest.swift in Sources */,
18E2A2E01FBB22C40058FEC5 /* TestedClass.swift in Sources */,
18E2A2F51FBB22ED0058FEC5 /* ArgumentCaptorTest.swift in Sources */,
680894C021ABFDCB00C8D2EF /* GenericClassTest.swift in Sources */,
58C540B5C5EF0037F77C90B5 /* ExcludedTestClass.swift in Sources */,
58C54612D0DB47A284F29AD5 /* ExcludedStubTest.swift in Sources */,
6861B32D21A32279002EC2DA /* GenericProtocol.swift in Sources */,
@ -1107,6 +1117,7 @@
18E2A2E81FBB22CA0058FEC5 /* StubNoReturnThrowingFunctionTest.swift in Sources */,
18E2A2DB1FBB22C30058FEC5 /* TestedSubProtocol.swift in Sources */,
18E2A2D61FBB22C30058FEC5 /* ClassWithOptionals.swift in Sources */,
6896352E21AC5A4700B25D47 /* GenericProtocolTest.swift in Sources */,
18E2A2CE1FBB22BC0058FEC5 /* ProtocolTest.swift in Sources */,
18E2A2E61FBB22CA0058FEC5 /* StubFunctionTest.swift in Sources */,
18E2A2C11FBB22B50058FEC5 /* ClassTest.swift in Sources */,
@ -1123,6 +1134,7 @@
18E2A2C31FBB22B50058FEC5 /* DefaultValueRegistryTest.swift in Sources */,
18E2A2D81FBB22C30058FEC5 /* TestedClass.swift in Sources */,
18E2A2F31FBB22EC0058FEC5 /* ArgumentCaptorTest.swift in Sources */,
680894BF21ABFDCB00C8D2EF /* GenericClassTest.swift in Sources */,
58C54C0D4A65BCDC47704C0B /* ExcludedTestClass.swift in Sources */,
58C54E2CB6689135915CFC3E /* ExcludedStubTest.swift in Sources */,
6861B32C21A32279002EC2DA /* GenericProtocol.swift in Sources */,

View File

@ -0,0 +1,178 @@
//
// GenericClassTest.swift
// Cuckoo
//
// Created by Matyáš Kříž on 26/11/2018.
//
import XCTest
import Cuckoo
extension GenericClass: Mocked {
typealias MockType = MockGenericClass<T, U, V>
}
class GenericClassTest: XCTestCase {
private var mock: MockGenericClass<Int, String, Bool>!
private var original: GenericClass<Int, String, Bool>!
override func setUp() {
super.setUp()
mock = MockGenericClass(theT: 10, theU: "Hello, generics!", theV: false)
original = GenericClass(theT: 42, theU: "Hello world!", theV: false)
}
func testReadWritePropertyWithMockCreator() {
let mock = createMock(for: GenericClass<Int, String, Bool>.self) { builder, stub in
when(stub.readWritePropertyU.get).thenReturn("a")
return MockGenericClass(theT: 0, theU: "", theV: true)
}
XCTAssertEqual(mock.readWritePropertyU, "a")
_ = verify(mock).readWritePropertyU.get
}
func testReadWriteProperty() {
stub(mock) { mock in
when(mock.readWritePropertyV.get).thenReturn(true)
}
XCTAssertEqual(mock.readWritePropertyV, true)
_ = verify(mock).readWritePropertyV.get
}
func testConstantProperty() {
mock.enableDefaultImplementation(original)
XCTAssertEqual(mock.constant, 10.0)
}
func testModification() {
mock.enableDefaultImplementation(original)
let numbers = [127, 0, 0, 1]
for number in numbers {
original.readWritePropertyT = number
XCTAssertEqual(mock.readWritePropertyT, number)
}
verify(mock, times(numbers.count)).readWritePropertyT.get
}
func testReadWriteProperties() {
var calledT = false
var calledU = false
var calledV = false
stub(mock) { mock in
when(mock.readWritePropertyT.get).thenReturn(1)
when(mock.readWritePropertyT.set(anyInt())).then { _ in calledT = true }
when(mock.readWritePropertyU.get).thenReturn("Hello, mocker!")
when(mock.readWritePropertyU.set(anyString())).then { _ in calledU = true }
when(mock.readWritePropertyV.get).thenReturn(false)
when(mock.readWritePropertyV.set(any(Bool.self))).then { _ in calledV = true }
}
mock.readWritePropertyT = 0
XCTAssertEqual(mock.readWritePropertyT, 1)
XCTAssertTrue(calledT)
_ = verify(mock).readWritePropertyT.get
verify(mock).readWritePropertyT.set(0)
mock.readWritePropertyU = "NO MOCKING FOR YOU"
XCTAssertEqual(mock.readWritePropertyU, "Hello, mocker!")
XCTAssertTrue(calledU)
_ = verify(mock).readWritePropertyU.get
verify(mock).readWritePropertyU.set("NO MOCKING FOR YOU")
mock.readWritePropertyV = true
XCTAssertEqual(mock.readWritePropertyV, false)
XCTAssertTrue(calledV)
_ = verify(mock).readWritePropertyV.get
verify(mock).readWritePropertyV.set(true)
}
func testOptionalProperty() {
var called = false
stub(mock) { mock in
when(mock.optionalProperty.get).thenReturn(nil)
when(mock.optionalProperty.set(anyString())).then { _ in called = true }
}
mock.optionalProperty = "tukabel"
XCTAssertNil(mock.optionalProperty)
XCTAssertTrue(called)
_ = verify(mock).optionalProperty.get
verify(mock).optionalProperty.set(equal(to: "tukabel"))
}
func testNoReturn() {
var called = false
stub(mock) { mock in
when(mock.noReturn()).then { _ in called = true }
}
mock.noReturn()
XCTAssertTrue(called)
verify(mock).noReturn()
}
func testUnequal() {
stub(mock) { mock in
when(mock.unequal(one: false, two: false)).thenReturn(false)
when(mock.unequal(one: false, two: true)).thenReturn(true)
when(mock.unequal(one: true, two: false)).thenReturn(true)
when(mock.unequal(one: true, two: true)).thenReturn(false)
}
XCTAssertFalse(mock.unequal(one: false, two: false))
XCTAssertTrue(mock.unequal(one: false, two: true))
XCTAssertTrue(mock.unequal(one: true, two: false))
XCTAssertFalse(mock.unequal(one: true, two: true))
}
func testGetThird() {
stub(mock) { mock in
when(mock.getThird(foo: anyInt(), bar: "gimme true", baz: any(Bool.self))).thenReturn(false)
when(mock.getThird(foo: anyInt(), bar: "gimme false", baz: any(Bool.self))).thenReturn(true)
}
XCTAssertFalse(mock.getThird(foo: 10, bar: "gimme true", baz: true))
verify(mock).getThird(foo: 10, bar: "gimme true", baz: true)
XCTAssertTrue(mock.getThird(foo: 1099, bar: "gimme false", baz: false))
verify(mock).getThird(foo: 1099, bar: "gimme false", baz: false)
}
func testPrint() {
stub(mock) { mock in
when(mock.print(theT: anyInt())).thenDoNothing()
}
mock.print(theT: 555)
verify(mock).print(theT: 555)
}
func testEncode() {
mock.enableDefaultImplementation(original)
stub(mock) { mock in
when(mock.encode(theU: anyString())).thenCallRealImplementation()
}
let encoder = JSONEncoder()
let world = "Hello, world!"
XCTAssertEqual(mock.encode(theU: world), try! encoder.encode(["root": world]))
verify(mock).encode(theU: world)
}
func testWithClosure() {
stub(mock) { mock in
when(mock.withClosure(anyClosure())).then { $0(666) }
}
XCTAssertEqual(mock.withClosure { number in number * 2 + 5 }, 1337)
verify(mock).withClosure(anyClosure())
}
}

View File

@ -0,0 +1,180 @@
//
// GenericProtocolTest.swift
// Cuckoo
//
// Created by Matyáš Kříž on 26/11/2018.
//
import XCTest
import Cuckoo
private class GenericProtocolConformerClass<C: AnyObject, V>: GenericProtocol {
let readOnlyPropertyC: C
var readWritePropertyV: V
let constant: Int = 0
var optionalProperty: V?
required init(theC: C, theV: V) {
readOnlyPropertyC = theC
readWritePropertyV = theV
}
func callSomeC(theC: C) -> Int {
return 1
}
func callSomeV(theV: V) -> Int {
switch theV {
case let int as Int:
return int
case let string as String:
return Int(string) ?? 8008135
default:
return 0
}
}
func compute(classy: C, value: V) -> C {
guard let testyClassy = classy as? TestedClass else { return classy }
switch value {
case let int as Int:
testyClassy.readWriteProperty = int
case _ as String:
testyClassy.optionalProperty = nil
default:
break
}
return testyClassy as! C
}
func noReturn() {}
}
private class GenericProtocolConformerStruct<C: AnyObject, V>: GenericProtocol {
let readOnlyPropertyC: C
var readWritePropertyV: V
let constant: Int = 0
var optionalProperty: V?
required init(theC: C, theV: V) {
readOnlyPropertyC = theC
readWritePropertyV = theV
}
func callSomeC(theC: C) -> Int {
return 1
}
func callSomeV(theV: V) -> Int {
return 0
}
func compute(classy: C, value: V) -> C {
return classy
}
func noReturn() {}
}
class GenericProtocolTest: XCTestCase {
private func createMock<V>(value: V) -> MockGenericProtocol<MockTestedClass, V> {
let classy = MockTestedClass()
return MockGenericProtocol(theC: classy, theV: value)
}
func testReadOnlyProperty() {
let mock = createMock(value: 10)
stub(mock) { mock in
when(mock.readOnlyPropertyC.get).thenReturn(MockTestedClass())
}
_ = verify(mock).readOnlyPropertyC.get
}
func testReadWriteProperty() {
let mock = createMock(value: 10)
stub(mock) { mock in
when(mock.readWritePropertyV.get).then { 11 }
when(mock.readWritePropertyV.set(anyInt())).thenDoNothing()
}
mock.readWritePropertyV = 42
XCTAssertEqual(mock.readWritePropertyV, 11)
_ = verify(mock).readWritePropertyV.get
verify(mock).readWritePropertyV.set(42)
}
func testOptionalProperty() {
let mock = createMock(value: false)
var called = false
stub(mock) { mock in
when(mock.optionalProperty.get).thenReturn(true)
when(mock.optionalProperty.set(any(Bool?.self))).then { _ in called = true }
}
mock.optionalProperty = false
XCTAssertTrue(mock.optionalProperty == true)
XCTAssertTrue(called)
_ = verify(mock).optionalProperty.get
verify(mock).optionalProperty.set(equal(to: false))
}
func testNoReturn() {
let mock = createMock(value: "Hello. Sniffing through tests? If you're having trouble with Cuckoo, shoot us a message!")
var called = false
stub(mock) { mock in
when(mock.noReturn()).then { _ in called = true }
}
mock.noReturn()
XCTAssertTrue(called)
verify(mock).noReturn()
}
func testModification() {
let mock = createMock(value: ["EXTERMINATE!": "EXTERMINATE!!", "EXTERMINATE!!!": "EXTERMINATE!!!!"])
let original = GenericProtocolConformerClass(theC: MockTestedClass(), theV: ["Sir, may I help you?": "Nope, just lookin' 👀"])
mock.enableDefaultImplementation(original)
original.readWritePropertyV["Are you sure?"] = "Yeah, I'm just waiting for my wife."
XCTAssertEqual(mock.readWritePropertyV, ["Sir, may I help you?": "Nope, just lookin' 👀", "Are you sure?": "Yeah, I'm just waiting for my wife."])
original.readWritePropertyV["Alright, have a nice weekend!"] = "Thanks, you too."
XCTAssertEqual(mock.readWritePropertyV, ["Sir, may I help you?": "Nope, just lookin' 👀",
"Are you sure?": "Yeah, I'm just waiting for my wife.",
"Alright, have a nice weekend!": "Thanks, you too."])
verify(mock, times(2)).readWritePropertyV.get
}
func testStructModification() {
let mock = createMock(value: ["EXTERMINATE!": "EXTERMINATE!!", "EXTERMINATE!!!": "EXTERMINATE!!!!"])
var original = GenericProtocolConformerStruct(theC: MockTestedClass(), theV: ["Sir, may I help you?": "Nope, just lookin' 👀"])
mock.enableDefaultImplementation(mutating: &original)
original.readWritePropertyV["Are you sure?"] = "Yeah, I'm just waiting for my wife."
XCTAssertEqual(mock.readWritePropertyV, ["Sir, may I help you?": "Nope, just lookin' 👀", "Are you sure?": "Yeah, I'm just waiting for my wife."])
original.readWritePropertyV["Alright, have a nice weekend!"] = "Thanks, you too."
XCTAssertEqual(mock.readWritePropertyV, ["Sir, may I help you?": "Nope, just lookin' 👀",
"Are you sure?": "Yeah, I'm just waiting for my wife.",
"Alright, have a nice weekend!": "Thanks, you too."])
verify(mock, times(2)).readWritePropertyV.get
}
func testStructNonModification() {
let mock = createMock(value: ["EXTERMINATE!": "EXTERMINATE!!", "EXTERMINATE!!!": "EXTERMINATE!!!!"])
let original = GenericProtocolConformerStruct(theC: MockTestedClass(), theV: ["Sir, may I help you?": "Nope, just lookin' 👀"])
mock.enableDefaultImplementation(original)
original.readWritePropertyV["Are you sure?"] = "Yeah, I'm just waiting for my wife."
XCTAssertEqual(mock.readWritePropertyV, ["Sir, may I help you?": "Nope, just lookin' 👀", "Are you sure?": "Yeah, I'm just waiting for my wife."])
original.readWritePropertyV["Alright, have a nice weekend!"] = "Thanks, you too."
XCTAssertEqual(mock.readWritePropertyV, ["Sir, may I help you?": "Nope, just lookin' 👀"])
verify(mock, times(2)).readWritePropertyV.get
}
}

View File

@ -8,10 +8,14 @@
import Foundation
class GenericClass<T: CustomStringConvertible, U: Codable & CustomStringConvertible, V: Hashable & Equatable> {
let constant = 10.0
var readWritePropertyT: T
var readWritePropertyU: U
var readWritePropertyV: V
var optionalProperty: U?
init(theT: T, theU: U, theV: V) {
readWritePropertyT = theT
readWritePropertyU = theU
@ -32,10 +36,12 @@ class GenericClass<T: CustomStringConvertible, U: Codable & CustomStringConverti
func encode(theU: U) -> Data {
let encoder = JSONEncoder()
return try! encoder.encode(theU)
return try! encoder.encode(["root": theU])
}
func withClosure(_ closure: (T) -> Int) -> Int {
return closure(readWritePropertyT)
}
func noReturn() {}
}

View File

@ -8,15 +8,19 @@
import Foundation
protocol GenericProtocol {
associatedtype C: TestedClass
associatedtype P: TestedProtocol
associatedtype C: AnyObject
associatedtype V
var readWritePropertyT: C { get }
var readWritePropertyU: P { get set }
var readOnlyPropertyC: C { get }
var readWritePropertyV: V { get set }
init(theC: C, theP: P)
var constant: Int { get }
var optionalProperty: V? { get set }
init(theC: C, theV: V)
func callSomeC(theC: C) -> Int
func callSomeP(theP: P) -> Int
func compute(classy: C, proto: P) -> C
func callSomeV(theV: V) -> Int
func compute(classy: C, value: V) -> C
func noReturn()
}