diff --git a/Cuckoo.xcodeproj/project.pbxproj b/Cuckoo.xcodeproj/project.pbxproj index 6d84ccb..9554e6b 100644 --- a/Cuckoo.xcodeproj/project.pbxproj +++ b/Cuckoo.xcodeproj/project.pbxproj @@ -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 = ""; }; 58C54B2B810BC9284205CB16 /* ExcludedStubTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExcludedStubTest.swift; sourceTree = ""; }; 58C54D12B64AF3169FC8A1A3 /* ExcludedTestClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExcludedTestClass.swift; sourceTree = ""; }; + 680894BE21ABFDCB00C8D2EF /* GenericClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericClassTest.swift; sourceTree = ""; }; 6861B30B21A31DA2002EC2DA /* GenericClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericClass.swift; sourceTree = ""; }; 6861B32B21A32279002EC2DA /* GenericProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericProtocol.swift; sourceTree = ""; }; + 6896352D21AC5A4700B25D47 /* GenericProtocolTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericProtocolTest.swift; sourceTree = ""; }; /* 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 */, diff --git a/Tests/GenericClassTest.swift b/Tests/GenericClassTest.swift new file mode 100644 index 0000000..d57c74d --- /dev/null +++ b/Tests/GenericClassTest.swift @@ -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 +} + +class GenericClassTest: XCTestCase { + private var mock: MockGenericClass! + private var original: GenericClass! + + 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.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()) + } +} diff --git a/Tests/GenericProtocolTest.swift b/Tests/GenericProtocolTest.swift new file mode 100644 index 0000000..124087e --- /dev/null +++ b/Tests/GenericProtocolTest.swift @@ -0,0 +1,180 @@ +// +// GenericProtocolTest.swift +// Cuckoo +// +// Created by Matyáš Kříž on 26/11/2018. +// + +import XCTest +import Cuckoo + +private class GenericProtocolConformerClass: 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: 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(value: V) -> MockGenericProtocol { + 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 + } +} diff --git a/Tests/Source/GenericClass.swift b/Tests/Source/GenericClass.swift index be0c7c9..253d71f 100644 --- a/Tests/Source/GenericClass.swift +++ b/Tests/Source/GenericClass.swift @@ -8,10 +8,14 @@ import Foundation class GenericClass { + 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 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() {} } diff --git a/Tests/Source/GenericProtocol.swift b/Tests/Source/GenericProtocol.swift index e897066..f0d1b93 100644 --- a/Tests/Source/GenericProtocol.swift +++ b/Tests/Source/GenericProtocol.swift @@ -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() }