Compare commits

...

1 Commits

Author SHA1 Message Date
Matyáš Kříž dcf7358b19 WIP: Initial SwiftSyntax support. 2023-05-04 23:33:11 +02:00
214 changed files with 2581 additions and 2761 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
Generator/lib_InternalSwiftSyntaxParser.xcframework.zip filter=lfs diff=lfs merge=lfs -text

4
.gitignore vendored
View File

@ -33,12 +33,11 @@ Generator/*.app
cuckoo_generator
.fastlane
Generator/CuckooGenerator.xcodeproj
Cuckoo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Cuckoo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
Cuckoo.xcworkspace
Cuckoo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Tuist/Dependencies/graph.json
Tuist/Dependencies/Carthage
@ -48,3 +47,4 @@ Tuist/Dependencies/Cocoapods
Generator/Generator.xcodeproj
Generator/GeneratedMocks.swift
Generator/lib_InternalSwiftSyntaxParser.xcframework

View File

@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/nvzqz/FileKit.git",
"state" : {
"branch" : "develop",
"revision" : "6937ec38b0c383b0505caeea6603e62086bf5431"
"revision" : "9006d2888025fbe893c3c396327b2fe45a8c177b",
"version" : "6.1.0"
}
},
{
@ -54,15 +54,6 @@
"version" : "4.1.0"
}
},
{
"identity" : "sourcekitten",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "79ca340f609adee48defa966e6a3dd0e0acbeb08",
"version" : "0.21.3"
}
},
{
"identity" : "spectre",
"kind" : "remoteSourceControl",
@ -77,26 +68,53 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/kylef/Stencil.git",
"state" : {
"revision" : "ccd9402682f4c07dac9561befd207c8156e80e20",
"version" : "0.14.2"
"revision" : "4f222ac85d673f35df29962fc4c36ccfdaf9da5b",
"version" : "0.15.1"
}
},
{
"identity" : "swxmlhash",
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/drmohundro/SWXMLHash.git",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "f43166a8e18fdd0857f29e303b1bb79a5428bca0",
"version" : "4.9.0"
"revision" : "9f39744e025c7d377987f30b03770805dcb0bcd1",
"version" : "1.1.4"
}
},
{
"identity" : "yams",
"identity" : "swift-format",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"location" : "https://github.com/apple/swift-format.git",
"state" : {
"revision" : "b08dba4bcea978bf1ad37703a384097d3efce5af",
"version" : "1.0.2"
"revision" : "5f184220d032a019a63df457cdea4b9c8241e911",
"version" : "0.50700.1"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "72d3da66b085c2299dd287c2be3b92b5ebd226de",
"version" : "0.50700.1"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "836bc4557b74fe6d2660218d56e3ce96aff76574",
"version" : "1.1.1"
}
},
{
"identity" : "swift-tools-support-core",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-tools-support-core.git",
"state" : {
"revision" : "4f07be3dc201f6e2ee85b6942d0c220a16926811",
"version" : "0.2.7"
}
}
],

View File

@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.homepage = "https://github.com/Brightify/Cuckoo"
s.license = 'MIT'
s.author = { "Tadeas Kriz" => "tadeas@brightify.org", "Filip Dolnik" => "filip@brightify.org", "Adriaan (Arjan) Duijzer" => "arjan@nxtstep.nl" }
s.author = { "Matyas Kriz" => "m@tyas.cz", "Tadeas Kriz" => "tadeas@brightify.org", "Filip Dolnik" => "filip@brightify.org", "Adriaan (Arjan) Duijzer" => "arjan@nxtstep.nl" }
s.source = {
:git => "https://github.com/Brightify/Cuckoo.git",
:tag => s.version.to_s

View File

@ -33,6 +33,7 @@
09C45035E8B83C11AF029E91 /* Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE4758812545462B94DAB7A4 /* Stub.swift */; };
0A3DB4FDAAF378953FE620F2 /* CallMatcherFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC319F6F55C00CFD3D0AF96 /* CallMatcherFunctions.swift */; };
0A63C1802D5BBDCCFB91DE3A /* StubFunctionThenCallRealImplementationTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5319F82EEAE3868CE8F23172 /* StubFunctionThenCallRealImplementationTrait.swift */; };
0BEB6AA4984EF02EA3A6AA00 /* NestedSubclassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C4A20137742161D649D3E3B /* NestedSubclassTest.swift */; };
0BFE2DDD3E06D51F9B297E07 /* ToBeStubbedReadOnlyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375E2C8E10768E1A9A04C362 /* ToBeStubbedReadOnlyProperty.swift */; };
0C2B108704AEB93556C4B0CE /* StubNoReturnFunctionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7635A46FDE48804E6E21EC0 /* StubNoReturnFunctionTest.swift */; };
0D789EF876584F271908B424 /* StubNoReturnFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700931036CB43C60AEFB7FEB /* StubNoReturnFunction.swift */; };
@ -49,6 +50,7 @@
116D8FBB03787C2D7F7C99CC /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8F1FB05574F9DB1A4CE7AB3 /* TestError.swift */; };
11700496E1D2DF02E9CD49BE /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B81133817083F2B8122BE188 /* XCTest.framework */; };
11B3B5F6FFF87351410F8B43 /* ToBeStubbedReadOnlyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375E2C8E10768E1A9A04C362 /* ToBeStubbedReadOnlyProperty.swift */; };
11B3F573CEAEDBC88BDC8AFF /* NestedSubclassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C4A20137742161D649D3E3B /* NestedSubclassTest.swift */; };
1261E976B71C9A806A73DA9D /* CreateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44692276AAFF9261EDD5D75 /* CreateMock.swift */; };
138FB34F332E9076D2C30FDC /* NSObjectProtocolInheritanceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FBE411D64C1D2B056E42C52 /* NSObjectProtocolInheritanceTest.swift */; };
13A6FF70A68C12E237C85B4C /* StubFunctionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CBF18CC12259A96D05F579B /* StubFunctionTest.swift */; };
@ -64,6 +66,7 @@
18A8AA3E4C7365AB6658D626 /* Dictionary+matchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6975D97C79395805A3BB3B04 /* Dictionary+matchers.swift */; };
18A918338118AE7B7FDDDD8E /* TestedSubProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3E7F562DC17ECF3B32CBB3 /* TestedSubProtocol.swift */; };
1B0F180FCABE289F64EF37B6 /* DefaultValueRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190FB7FABF7486D2963F4B44 /* DefaultValueRegistry.swift */; };
1B35986E55804D8DFE6FC061 /* Pods_Cuckoo_OCMock_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F87AB6F574DC47448E8F3863 /* Pods_Cuckoo_OCMock_tvOS.framework */; };
1B425DF3B416C5E4FA04532C /* ArgumentCaptorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76DE925DA03AAA0FD9734CFE /* ArgumentCaptorTest.swift */; };
1B57B5A8CEAD3FFB218A379B /* Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE4758812545462B94DAB7A4 /* Stub.swift */; };
1B6BDFF7EF9B2385D50910C3 /* MultiNestedClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002B2852C62F702127A3D24E /* MultiNestedClassTest.swift */; };
@ -89,6 +92,7 @@
25611F1843D374BB1840D16B /* NestedStructExtensionClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0512EFCB8EDE906B3E54057B /* NestedStructExtensionClassTest.swift */; };
25B3658FB7569F94794BC8E7 /* StubNoReturnFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700931036CB43C60AEFB7FEB /* StubNoReturnFunction.swift */; };
25D818649F9686990D6E25AF /* StubTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40FB9A410020B1B90952823C /* StubTest.swift */; };
2647BA750CED383CE3439905 /* Pods_Cuckoo_OCMock_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D77AB55B3A73709BDA8437F0 /* Pods_Cuckoo_OCMock_iOS.framework */; };
2711CAFD8EEBC32B4991A237 /* StubNoReturnFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700931036CB43C60AEFB7FEB /* StubNoReturnFunction.swift */; };
2728634862DD41A1F558CE7F /* ExcludedStubTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F2852ABE97CC059DD98D13 /* ExcludedStubTest.swift */; };
27645AF0AE6BE0B714E4A7A8 /* StubFunctionThenThrowTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 201DFAD306F0F1B18CE9EFBE /* StubFunctionThenThrowTrait.swift */; };
@ -107,7 +111,6 @@
2E54AB548933FF3D2F7E1384 /* DefaultValueRegistryTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E80D1401CB6046B1AEDBE204 /* DefaultValueRegistryTest.swift */; };
2FA8B5B7D3DBD836A3FE9694 /* ObjectiveArgumentClosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D63F5E63DF9302E70BF764 /* ObjectiveArgumentClosure.swift */; };
2FB87BFE2FFBCF459D35DF5E /* MockManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91992FE8D38A6900C005B0A4 /* MockManager.swift */; };
3083E891A8AA06D2D571B18C /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DD3286025BB166116AD2BAE /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework */; };
3172B5B4F28F82A9393194EE /* StubCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA3EB970DE7CF1D83AC121F /* StubCall.swift */; };
31968C424EAAE213191924C0 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 648E1DCC3FA05944AC970663 /* XCTest.framework */; };
31EC7665C1236E34B1B21642 /* OCMockObject+CuckooMockObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EE3E19406E96533EBBBD138 /* OCMockObject+CuckooMockObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -119,6 +122,7 @@
355E1D135C0ABDEE2521647D /* ToBeStubbedReadOnlyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375E2C8E10768E1A9A04C362 /* ToBeStubbedReadOnlyProperty.swift */; };
35A2CEA0553DFBABD2391BBB /* NestedExtensionClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F42B443F090072DFF751FD /* NestedExtensionClassTest.swift */; };
35AB01E0F9979120DD4E385A /* CallMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C854CC76B478ED72B6D3A65 /* CallMatcher.swift */; };
35DB3CFDF76FAFC186CCF5E5 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 194F548C24DA8152FAEAE7E9 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework */; };
35E0698113191B077A7C0B24 /* CuckooFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 938B3F655E8E20AB6D341A0D /* CuckooFunctions.swift */; };
35FFC4C64E3C99174A7E7E91 /* ThreadLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB65661C2188A3E830EEBF72 /* ThreadLocal.swift */; };
360F056E5B1803C9CFE68DA3 /* StubAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C647EAE09B6AB55FF6C0CE /* StubAction.swift */; };
@ -164,7 +168,6 @@
49397518100C50FB12E4D57E /* ParameterMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A843913B61AB11A80097F51 /* ParameterMatcher.swift */; };
4979C7CD6F921D3627A7DB83 /* NestedStructTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 245F73FBA37EA0E055BA4EA2 /* NestedStructTest.swift */; };
4A0037995B682F70C67C1839 /* StubFunctionThenCallRealImplementationTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5319F82EEAE3868CE8F23172 /* StubFunctionThenCallRealImplementationTrait.swift */; };
4A62B192708AD7476317E384 /* Pods_Cuckoo_OCMock_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CCFC4929BB6578E62C06913A /* Pods_Cuckoo_OCMock_tvOS.framework */; };
4A6C033747BA78251DE47F48 /* ParameterMatcherFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6CA2236A30B54754F335DC3 /* ParameterMatcherFunctions.swift */; };
4A91D2B262ED9EC2EAC65D85 /* ExcludedTestClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB36E482FF288D775B744A02 /* ExcludedTestClass.swift */; };
4B94FF7B55E04D0177ED4770 /* ThreadLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB65661C2188A3E830EEBF72 /* ThreadLocal.swift */; };
@ -241,7 +244,6 @@
718886B6E9C79E094F9A472B /* ParameterMatcherFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6CA2236A30B54754F335DC3 /* ParameterMatcherFunctions.swift */; };
71C2BCE31CA3B6FCD55224AA /* Dictionary+matchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6975D97C79395805A3BB3B04 /* Dictionary+matchers.swift */; };
71E5A49D8F6F49CFDECEA3D5 /* StubbingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A9BEFC601EF66DF42D5022 /* StubbingProxy.swift */; };
7357129D17477272975CBCBC /* NestedSubclassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E654F50A34B51CD16E76A2 /* NestedSubclassTests.swift */; };
73B01B742C366190692DC3F2 /* VerifyReadOnlyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A08AF20C937EF4EB98795B /* VerifyReadOnlyProperty.swift */; };
73C243460EAE2D834DA55E94 /* ObjectiveCatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 654DD2C28B20B62C30F20699 /* ObjectiveCatcher.m */; };
73ECEBE34D54DE64870F9020 /* StubThrowingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808091A975F4E8BDDF0C80D9 /* StubThrowingFunction.swift */; };
@ -276,6 +278,7 @@
827A670BF9391A7C01822AF1 /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8F1FB05574F9DB1A4CE7AB3 /* TestError.swift */; };
83A5A8205205BF4D44F93CD0 /* ArgumentCaptorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76DE925DA03AAA0FD9734CFE /* ArgumentCaptorTest.swift */; };
8443421090DA81C2C68570A1 /* Cuckoo_OCMock_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD83449ACABE73EE786CA3E3 /* Cuckoo_OCMock_macOS.framework */; };
84A7C123934DF31E3CB48DF1 /* Pods_Cuckoo_OCMock_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EAF21976FCFA3343C232939 /* Pods_Cuckoo_OCMock_macOS.framework */; };
84CF3EB0CA4FDF5F01BB6847 /* OCMockObject+Workaround.h in Headers */ = {isa = PBXBuildFile; fileRef = 95B3E26DA5700FCAF7286B16 /* OCMockObject+Workaround.h */; settings = {ATTRIBUTES = (Public, ); }; };
84E115FC5DA7BC43B2751E6E /* GenericProtocolTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 905EC88A402004B01C6FE73E /* GenericProtocolTest.swift */; };
85804B9F05012E7EA4659860 /* UnavailablePlatformClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6665FD7C16558B821564AADB /* UnavailablePlatformClass.swift */; };
@ -300,7 +303,6 @@
8C61162C8AFDB8D153798DBC /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 648E1DCC3FA05944AC970663 /* XCTest.framework */; };
8CB6ABE1F6EB68B5F081CD2A /* NestedClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3646D56C8005FB7E1B11B67 /* NestedClassTest.swift */; };
8D80FA22DC7306DD02A3E6E0 /* StubNoReturnThrowingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D920573D13B938FEACFF82C6 /* StubNoReturnThrowingFunction.swift */; };
8EABFB3D5035C5628E0B0A1B /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A8232B39A1033045A35B60A /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework */; };
8EC6901E5D2329815A954132 /* BaseStubFunctionTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B55AC80C790F69750B2F80 /* BaseStubFunctionTrait.swift */; };
8F64666ABEA12593621A1E5B /* StubFunctionThenTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C749F49256DDA51A9C96C9 /* StubFunctionThenTrait.swift */; };
8FCE701ABF6436EA73A75767 /* CallMatcherFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC319F6F55C00CFD3D0AF96 /* CallMatcherFunctions.swift */; };
@ -323,6 +325,7 @@
97F6BD5C658631C6B86F13E8 /* ArgumentCaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94FEF459CF7A13B3FC66D390 /* ArgumentCaptor.swift */; };
9820ACF2D223E8C1DE7CB9CE /* StubNoReturnThrowingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D920573D13B938FEACFF82C6 /* StubNoReturnThrowingFunction.swift */; };
98833B16634285BFDA764222 /* MultiNestedInExtensionFromClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB894FF725838C4DE9FFDC9A /* MultiNestedInExtensionFromClass.swift */; };
992E1CFD5221BEB55CD337FF /* NestedSubclassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C4A20137742161D649D3E3B /* NestedSubclassTest.swift */; };
993AC06E43973AF2E8DB5A1B /* ObjectiveArgumentClosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6D63F5E63DF9302E70BF764 /* ObjectiveArgumentClosure.swift */; };
996F90892116045116104676 /* Cuckoo_OCMock_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DD5D3471880E656BEA0A210 /* Cuckoo_OCMock_iOS.framework */; platformFilter = ios; };
9A973F6AD57DD908C9D75B9B /* __DoNotUse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511DD0B1EA1EAF535C598A8C /* __DoNotUse.swift */; };
@ -376,6 +379,7 @@
B4CABEBF620374BC06D2823B /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55014A1A85497F2153371D7 /* TestUtils.swift */; };
B4D4670EAA09DA5A79BB11AB /* MockManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91992FE8D38A6900C005B0A4 /* MockManager.swift */; };
B4FFDFFB75D194453AE2D175 /* StubCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA3EB970DE7CF1D83AC121F /* StubCall.swift */; };
B576F1274DC3407E43F86C8A /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F21B45333B1857F3854D779 /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework */; };
B626F2DA221BF968E127B54A /* VerifyReadOnlyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A08AF20C937EF4EB98795B /* VerifyReadOnlyProperty.swift */; };
B648456E51B3FF8CB037B3B5 /* Matchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C633EBD6E6E6568FE9B40567 /* Matchable.swift */; };
B6C4CC5A967C0CC567A9F454 /* MockManager+preconfigured.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83C4A633699E5B88D9A9C1B /* MockManager+preconfigured.swift */; };
@ -390,7 +394,6 @@
BA5FFE5076C1E8B3CD590D77 /* GenericMethodClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E584CAC626A3E38BC45E773 /* GenericMethodClass.swift */; };
BA6739666F5DDC4ADA564E2C /* GenericClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01C5ABA73DC1B0CCE088669 /* GenericClass.swift */; };
BAA6262023C7BBD7F945FA91 /* ObjectiveVerify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 107C9243167200396831A18F /* ObjectiveVerify.swift */; };
BB289937FFF493E53DBF7FE8 /* NestedSubclassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E654F50A34B51CD16E76A2 /* NestedSubclassTests.swift */; };
BB2E89CC430EFA7009FFFD47 /* StubFunctionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CBF18CC12259A96D05F579B /* StubFunctionTest.swift */; };
BBA5EEAD87D96D3B15C78757 /* CollisionClasses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CDB969240E4E2B12FF93284 /* CollisionClasses.swift */; };
BBAC0B12C70D9B414A0E93E1 /* VerifyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753FC6D19235B2C8F2DBAA7B /* VerifyProperty.swift */; };
@ -418,7 +421,6 @@
C918EF1A82AE3300CFD0178C /* Cuckoo-BridgingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = A78767AF78A5705F914CB5F1 /* Cuckoo-BridgingHeader.h */; settings = {ATTRIBUTES = (Public, ); }; };
C98DD2231948D6D9486E3C1C /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55014A1A85497F2153371D7 /* TestUtils.swift */; };
CA88A2D7512A9EE0D64D6879 /* StubbingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A9BEFC601EF66DF42D5022 /* StubbingProxy.swift */; };
CB4F2E994373AF88A32748D3 /* Pods_Cuckoo_OCMock_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02E7D093817E7CE04A04C2AF /* Pods_Cuckoo_OCMock_macOS.framework */; };
CB95B245036865240B20E448 /* MultiLayeredNestedTestedSubclassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F0DF66BC063943C91FB2C3 /* MultiLayeredNestedTestedSubclassTest.swift */; };
CBB7017EE143A38098AD7287 /* GenericMethodClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B965102D09D6B0E94CDA8EA /* GenericMethodClassTest.swift */; };
CC2BA5A130CB61216E489D99 /* VerifyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753FC6D19235B2C8F2DBAA7B /* VerifyProperty.swift */; };
@ -479,16 +481,13 @@
EA58B9A4A3DDB81EBB31BC26 /* OCMockObject+CuckooMockObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D732D63C18B4DE267CB365CF /* OCMockObject+CuckooMockObject.m */; };
EAFA72896871E0A2629AC784 /* ClassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6873C8013002AFEA7565BDAC /* ClassTest.swift */; };
EB12D8BACB131BD4DF064AF0 /* ObjectiveMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70C4FAE3318E21F0A87531A /* ObjectiveMatchers.swift */; };
EB37DBF5C5EEB81AE40E203F /* Pods_Cuckoo_OCMock_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAC201DCB53797CB6435DB1 /* Pods_Cuckoo_OCMock_iOS.framework */; };
EB3BC2A3CB2C8FA24CA01B18 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09B97C65DA87366B8605109 /* Utils.swift */; };
ECED2B81290B73C2EC6D70A5 /* NestedInNestedStruct.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90E9A4C6A1716C6D219D26E /* NestedInNestedStruct.swift */; };
ECFFBD0F7DB6DD452B542425 /* NestedPrivateExtensionClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFED3C29F5CA48398AF0C5B /* NestedPrivateExtensionClass.swift */; };
ED2DFFFD32E3D5EC061C89DA /* ClassWithUnavailablePlatformMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FB937EA0F029B222D748FED /* ClassWithUnavailablePlatformMembers.swift */; };
ED34902303F797CACE7C47FC /* StubFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82D83797450CB57EC3E0A693 /* StubFunction.swift */; };
ED9646245798F318CAD33E12 /* NestedSubclassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E654F50A34B51CD16E76A2 /* NestedSubclassTests.swift */; };
EDD2EDC801189CF637948AA4 /* DefaultValueRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190FB7FABF7486D2963F4B44 /* DefaultValueRegistry.swift */; };
EEF3DC22DC7212C654EF328D /* __DoNotUse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511DD0B1EA1EAF535C598A8C /* __DoNotUse.swift */; };
EFB24DDC33700188444EA5F0 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E045C7BF96B0FF85FAE2988 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework */; };
EFB5C46F8B4DFE1801EA6114 /* StubThrowingFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808091A975F4E8BDDF0C80D9 /* StubThrowingFunction.swift */; };
F01B6FF9BCFEED923AFCE5FC /* CallMatcherTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F445E0EFD2FD1FBC888DB72 /* CallMatcherTest.swift */; };
F09C7E5B6AD4AEB0166F871F /* ClassWithOptionals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A299482E4D2B7B774373A1 /* ClassWithOptionals.swift */; };
@ -514,6 +513,7 @@
F7F9CC2F71A29EFD3670D387 /* NSObjectProtocolInheritanceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FBE411D64C1D2B056E42C52 /* NSObjectProtocolInheritanceTest.swift */; };
F8540250669374FFC11720A2 /* StubbingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A9BEFC601EF66DF42D5022 /* StubbingProxy.swift */; };
F86949BD502D4EBFC978FC24 /* NestedInExtensionFromClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9699C3284544FE817C78E474 /* NestedInExtensionFromClass.swift */; };
F93AE8CCD2CF4BD1FFAAAC70 /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 598FA7C4C26C7322B25F1358 /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework */; };
F98A5E661D992AB274733FAF /* MockManager+preconfigured.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83C4A633699E5B88D9A9C1B /* MockManager+preconfigured.swift */; };
FA4E1EA6ED897418E81B360F /* StubFunctionThenThrowingTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = F398C1D87D71EE8DED0C6EA3 /* StubFunctionThenThrowingTrait.swift */; };
FA7B45FA1AD8F9CA07CC8506 /* NSObject+TrustMe.m in Sources */ = {isa = PBXBuildFile; fileRef = E0656C5164A529DCCADBA8F1 /* NSObject+TrustMe.m */; };
@ -696,7 +696,7 @@
/* Begin PBXFileReference section */
002B2852C62F702127A3D24E /* MultiNestedClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiNestedClassTest.swift; sourceTree = "<group>"; };
01496A793103612242EE7A04 /* VerificationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationTest.swift; sourceTree = "<group>"; };
02E7D093817E7CE04A04C2AF /* Pods_Cuckoo_OCMock_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
02EAAA14360EE993DF2A2AA3 /* Pods-Cuckoo_OCMock-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS/Pods-Cuckoo_OCMock-iOS.debug.xcconfig"; sourceTree = "<group>"; };
03A9BEFC601EF66DF42D5022 /* StubbingProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubbingProxy.swift; sourceTree = "<group>"; };
03AF60404FD2D5FD3198825E /* StubRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubRecorder.swift; sourceTree = "<group>"; };
03B55AC80C790F69750B2F80 /* BaseStubFunctionTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseStubFunctionTrait.swift; sourceTree = "<group>"; };
@ -706,12 +706,14 @@
09F0DF66BC063943C91FB2C3 /* MultiLayeredNestedTestedSubclassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiLayeredNestedTestedSubclassTest.swift; sourceTree = "<group>"; };
0A933D33D55AE257FE9B1097 /* ObjectiveStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectiveStub.swift; sourceTree = "<group>"; };
0BEF42DC82FC0EF50E83E6CA /* CuckooFunctionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CuckooFunctionsTest.swift; sourceTree = "<group>"; };
0FCC7E0CFC29DFD7C97EB8FC /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig"; sourceTree = "<group>"; };
107C9243167200396831A18F /* ObjectiveVerify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectiveVerify.swift; sourceTree = "<group>"; };
119D4E6C9798F70CEBDBB1F2 /* TestedClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestedClass.swift; sourceTree = "<group>"; };
18D8112F0A64A41ED070EA9F /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
190FB7FABF7486D2963F4B44 /* DefaultValueRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultValueRegistry.swift; sourceTree = "<group>"; };
194F548C24DA8152FAEAE7E9 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1A843913B61AB11A80097F51 /* ParameterMatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMatcher.swift; sourceTree = "<group>"; };
1B965102D09D6B0E94CDA8EA /* GenericMethodClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericMethodClassTest.swift; sourceTree = "<group>"; };
1DCDA7E7A2DA0E7AD149208B /* Pods-Cuckoo_OCMock-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS/Pods-Cuckoo_OCMock-macOS.debug.xcconfig"; sourceTree = "<group>"; };
1E13C3DFFA9A3676F92404B7 /* Cuckoo_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Cuckoo_macOS.framework; path = Cuckoo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
201DFAD306F0F1B18CE9EFBE /* StubFunctionThenThrowTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionThenThrowTrait.swift; sourceTree = "<group>"; };
245F73FBA37EA0E055BA4EA2 /* NestedStructTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedStructTest.swift; sourceTree = "<group>"; };
@ -721,14 +723,14 @@
29F42B443F090072DFF751FD /* NestedExtensionClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedExtensionClassTest.swift; sourceTree = "<group>"; };
2C68FC814ACBD3D5E1C7ED1B /* StubFunctionThenDoNothingTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionThenDoNothingTrait.swift; sourceTree = "<group>"; };
2F445E0EFD2FD1FBC888DB72 /* CallMatcherTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMatcherTest.swift; sourceTree = "<group>"; };
2FC3CF194933ED399D9483E2 /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig"; sourceTree = "<group>"; };
30EE51B1225328733D4F5DBA /* Cuckoo_OCMock-macOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo_OCMock-macOS-Info.plist"; sourceTree = "<group>"; };
3191519C8ED4DD5B3D439A93 /* StubFunctionThenReturnTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionThenReturnTrait.swift; sourceTree = "<group>"; };
323D9BB2B0A99E0408471845 /* Pods-Cuckoo_OCMock-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS/Pods-Cuckoo_OCMock-iOS.debug.xcconfig"; sourceTree = "<group>"; };
32A299482E4D2B7B774373A1 /* ClassWithOptionals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassWithOptionals.swift; sourceTree = "<group>"; };
33EBD5D113A20F38FCE13BDC /* Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mock.swift; sourceTree = "<group>"; };
355C36C0536DBF7EDA3C2B96 /* ObjcProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjcProtocol.swift; sourceTree = "<group>"; };
375E2C8E10768E1A9A04C362 /* ToBeStubbedReadOnlyProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToBeStubbedReadOnlyProperty.swift; sourceTree = "<group>"; };
3A8232B39A1033045A35B60A /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B4C9565EA304E2CF62B1D4F /* Pods-Cuckoo_OCMock-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS/Pods-Cuckoo_OCMock-macOS.release.xcconfig"; sourceTree = "<group>"; };
3C3E2B1C12FF95C6DCA418D5 /* ObjectiveCatcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjectiveCatcher.h; sourceTree = "<group>"; };
3CD1EF95EED208CF56D123F8 /* Cuckoo_OCMock_tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Cuckoo_OCMock_tvOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3D1D814F035D5D39FC84D26C /* Array+matchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+matchers.swift"; sourceTree = "<group>"; };
@ -741,9 +743,9 @@
511DD0B1EA1EAF535C598A8C /* __DoNotUse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = __DoNotUse.swift; sourceTree = "<group>"; };
5319F82EEAE3868CE8F23172 /* StubFunctionThenCallRealImplementationTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionThenCallRealImplementationTrait.swift; sourceTree = "<group>"; };
55DE1954C1D6E94F2911830A /* ClassForStubTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassForStubTesting.swift; sourceTree = "<group>"; };
55E654F50A34B51CD16E76A2 /* NestedSubclassTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedSubclassTests.swift; sourceTree = "<group>"; };
5673B933A24CA65D15B3FD3A /* CallMatcherFunctionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMatcherFunctionsTest.swift; sourceTree = "<group>"; };
58E1385A0AB0BD61D0DFD5C1 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
5776F80847FB1775D23C8064 /* Pods-Cuckoo_OCMock-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS/Pods-Cuckoo_OCMock-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
598FA7C4C26C7322B25F1358 /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5A67E79E73B4710B3C846F96 /* StubNoReturnThrowingFunctionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubNoReturnThrowingFunctionTest.swift; sourceTree = "<group>"; };
5BA3EB970DE7CF1D83AC121F /* StubCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubCall.swift; sourceTree = "<group>"; };
5CC319F6F55C00CFD3D0AF96 /* CallMatcherFunctions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMatcherFunctions.swift; sourceTree = "<group>"; };
@ -751,15 +753,14 @@
648E1DCC3FA05944AC970663 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
64F2852ABE97CC059DD98D13 /* ExcludedStubTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExcludedStubTest.swift; sourceTree = "<group>"; };
654DD2C28B20B62C30F20699 /* ObjectiveCatcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ObjectiveCatcher.m; sourceTree = "<group>"; };
65F7304C5992843A0A5D3863 /* Pods-Cuckoo_OCMock-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS/Pods-Cuckoo_OCMock-macOS.release.xcconfig"; sourceTree = "<group>"; };
6665FD7C16558B821564AADB /* UnavailablePlatformClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnavailablePlatformClass.swift; sourceTree = "<group>"; };
6873C8013002AFEA7565BDAC /* ClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassTest.swift; sourceTree = "<group>"; };
6975D97C79395805A3BB3B04 /* Dictionary+matchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+matchers.swift"; sourceTree = "<group>"; };
6978339A31BEDF22A4115E81 /* ProtocolTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolTest.swift; sourceTree = "<group>"; };
6C0DC4D2D6B0E6C61B27E90E /* Stubber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stubber.swift; sourceTree = "<group>"; };
6DBE7A13FEE1B8C7EE8DA363 /* Cuckoo-macOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo-macOS-Info.plist"; sourceTree = "<group>"; };
6E045C7BF96B0FF85FAE2988 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6E4033B8F0022DDDDA758351 /* Pods-Cuckoo_OCMock-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS/Pods-Cuckoo_OCMock-tvOS.release.xcconfig"; sourceTree = "<group>"; };
6EAF21976FCFA3343C232939 /* Pods_Cuckoo_OCMock_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6F21B45333B1857F3854D779 /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
700931036CB43C60AEFB7FEB /* StubNoReturnFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubNoReturnFunction.swift; sourceTree = "<group>"; };
7054833FFF0D253B1E2379FA /* MultiNestedInNestedClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiNestedInNestedClass.swift; sourceTree = "<group>"; };
70AE18F5D3419D1025D081CA /* ParameterMatcherTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMatcherTest.swift; sourceTree = "<group>"; };
@ -771,18 +772,19 @@
7BA242F7A830953CD5E4AC4A /* StringProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StringProxy.m; sourceTree = "<group>"; };
7CBF18CC12259A96D05F579B /* StubFunctionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionTest.swift; sourceTree = "<group>"; };
7F29DC9C5F5CCE01FEAE648D /* MultiNestedExtensionClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiNestedExtensionClassTest.swift; sourceTree = "<group>"; };
7FE031A1E54FBEBABC465F88 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
808091A975F4E8BDDF0C80D9 /* StubThrowingFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubThrowingFunction.swift; sourceTree = "<group>"; };
82D83797450CB57EC3E0A693 /* StubFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunction.swift; sourceTree = "<group>"; };
83908D3F58736F1C6DA7B2CA /* GenericClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericClassTest.swift; sourceTree = "<group>"; };
866CED1C72D1F35C10251CCC /* NSObjectProtocolInheritanceTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSObjectProtocolInheritanceTesting.swift; sourceTree = "<group>"; };
86D638696C1458550D4524F1 /* Cuckoo_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Cuckoo_tvOS.framework; path = Cuckoo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8B40CC43D7A77DFD4702178A /* MultiNestedPrivateExtensionClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiNestedPrivateExtensionClass.swift; sourceTree = "<group>"; };
8C4A20137742161D649D3E3B /* NestedSubclassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedSubclassTest.swift; sourceTree = "<group>"; };
8C854CC76B478ED72B6D3A65 /* CallMatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMatcher.swift; sourceTree = "<group>"; };
8CDB969240E4E2B12FF93284 /* CollisionClasses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollisionClasses.swift; sourceTree = "<group>"; };
8FAA0AEFE10E214A84C0E8EA /* Cuckoo_OCMock-iOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo_OCMock-iOS-Info.plist"; sourceTree = "<group>"; };
8FBE411D64C1D2B056E42C52 /* NSObjectProtocolInheritanceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSObjectProtocolInheritanceTest.swift; sourceTree = "<group>"; };
905EC88A402004B01C6FE73E /* GenericProtocolTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericProtocolTest.swift; sourceTree = "<group>"; };
90AE2C9146A1126EC1109B2B /* Pods-Cuckoo_OCMock-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS/Pods-Cuckoo_OCMock-tvOS.debug.xcconfig"; sourceTree = "<group>"; };
90CA6A2E0084041FD2CA4DD9 /* Cuckoo_tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Cuckoo_tvOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
91992FE8D38A6900C005B0A4 /* MockManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockManager.swift; sourceTree = "<group>"; };
919EA0D2C416F1E4F22DAC20 /* NestedInPrivateNestedClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedInPrivateNestedClass.swift; sourceTree = "<group>"; };
@ -793,8 +795,8 @@
9699C3284544FE817C78E474 /* NestedInExtensionFromClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedInExtensionFromClass.swift; sourceTree = "<group>"; };
96C749F49256DDA51A9C96C9 /* StubFunctionThenTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionThenTrait.swift; sourceTree = "<group>"; };
989EFADEC10AB6D627A5FAE6 /* NSValueConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSValueConvertible.swift; sourceTree = "<group>"; };
99D050972B5669B5B58E9DE7 /* Pods-Cuckoo_OCMock-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS/Pods-Cuckoo_OCMock-tvOS.release.xcconfig"; sourceTree = "<group>"; };
9C0889A597AF4CCA8841B471 /* MockBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBuilder.swift; sourceTree = "<group>"; };
9DD3286025BB166116AD2BAE /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9DD5D3471880E656BEA0A210 /* Cuckoo_OCMock_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Cuckoo_OCMock_iOS.framework; path = Cuckoo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9DE5DC1B6EC0BF686019517B /* UnavailablePlatformProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnavailablePlatformProtocol.swift; sourceTree = "<group>"; };
9E584CAC626A3E38BC45E773 /* GenericMethodClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericMethodClass.swift; sourceTree = "<group>"; };
@ -802,12 +804,13 @@
A21CD7B8ADE5ABE0295581D4 /* VerificationProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationProxy.swift; sourceTree = "<group>"; };
A398D6337F320A5F78FA4A5A /* GenericProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericProtocol.swift; sourceTree = "<group>"; };
A78767AF78A5705F914CB5F1 /* Cuckoo-BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Cuckoo-BridgingHeader.h"; sourceTree = "<group>"; };
A83242F5AF363867836B8970 /* Pods-Cuckoo_OCMock-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS/Pods-Cuckoo_OCMock-iOS.release.xcconfig"; sourceTree = "<group>"; };
AC30579DC4B1D5D5CC959724 /* Cuckoo-iOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo-iOS-Info.plist"; sourceTree = "<group>"; };
AD3E7F562DC17ECF3B32CBB3 /* TestedSubProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestedSubProtocol.swift; sourceTree = "<group>"; };
AE4758812545462B94DAB7A4 /* Stub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stub.swift; sourceTree = "<group>"; };
B30A194A634E5972418D171E /* Mocked.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mocked.swift; sourceTree = "<group>"; };
B6098DE536CCBA16747765FD /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig"; sourceTree = "<group>"; };
B6B86DCAC6958FF36DF3639C /* ParameterMatcherFunctionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMatcherFunctionsTest.swift; sourceTree = "<group>"; };
B712732E2656B55EDE652691 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig"; sourceTree = "<group>"; };
B81133817083F2B8122BE188 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
B9813FA38F8AB71BEE454CF4 /* Cuckoo-iOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo-iOSTests-Info.plist"; sourceTree = "<group>"; };
BA8CA90EAB7BD8AB7F5840D0 /* Cuckoo_OCMock-macOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo_OCMock-macOSTests-Info.plist"; sourceTree = "<group>"; };
@ -820,27 +823,27 @@
C55014A1A85497F2153371D7 /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
C61C355CDFD7F0A7C0F32A25 /* NSInvocation+OCMockWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+OCMockWrapper.m"; sourceTree = "<group>"; };
C633EBD6E6E6568FE9B40567 /* Matchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Matchable.swift; sourceTree = "<group>"; };
C6A3C8DF4AD4DE7807F60B62 /* Pods-Cuckoo_OCMock-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS/Pods-Cuckoo_OCMock-macOS.debug.xcconfig"; sourceTree = "<group>"; };
C6D63F5E63DF9302E70BF764 /* ObjectiveArgumentClosure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectiveArgumentClosure.swift; sourceTree = "<group>"; };
C8D7931D2C7E8A64861A1863 /* OCMockObject+Workaround.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OCMockObject+Workaround.m"; sourceTree = "<group>"; };
C8EEC51ACDE645FA676CB016 /* Cuckoo-macOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo-macOSTests-Info.plist"; sourceTree = "<group>"; };
C90E9A4C6A1716C6D219D26E /* NestedInNestedStruct.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedInNestedStruct.swift; sourceTree = "<group>"; };
C9525C20EA498D59BFCE3F7B /* ObjectiveAssertThrows.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectiveAssertThrows.swift; sourceTree = "<group>"; };
CB65661C2188A3E830EEBF72 /* ThreadLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadLocal.swift; sourceTree = "<group>"; };
CCFC4929BB6578E62C06913A /* Pods_Cuckoo_OCMock_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CEBE505B4B98BE6289678CD1 /* MatchableTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchableTest.swift; sourceTree = "<group>"; };
D09B97C65DA87366B8605109 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
D4108DD343B556BAA2BC0501 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig"; sourceTree = "<group>"; };
D3399F3F2FE04AE3E357B548 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig"; sourceTree = "<group>"; };
D44692276AAFF9261EDD5D75 /* CreateMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateMock.swift; sourceTree = "<group>"; };
D535CF4BAE6BA1CA7220CDB7 /* Set+matchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Set+matchers.swift"; sourceTree = "<group>"; };
D732D63C18B4DE267CB365CF /* OCMockObject+CuckooMockObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OCMockObject+CuckooMockObject.m"; sourceTree = "<group>"; };
D7635A46FDE48804E6E21EC0 /* StubNoReturnFunctionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubNoReturnFunctionTest.swift; sourceTree = "<group>"; };
D77AB55B3A73709BDA8437F0 /* Pods_Cuckoo_OCMock_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D7A08AF20C937EF4EB98795B /* VerifyReadOnlyProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyReadOnlyProperty.swift; sourceTree = "<group>"; };
D920573D13B938FEACFF82C6 /* StubNoReturnThrowingFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubNoReturnThrowingFunction.swift; sourceTree = "<group>"; };
DA0F20F08A3C63CB00D2E7E4 /* TestedSubclass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestedSubclass.swift; sourceTree = "<group>"; };
DAFDD79179243CBB217358C7 /* TestedProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestedProtocol.swift; sourceTree = "<group>"; };
DD83449ACABE73EE786CA3E3 /* Cuckoo_OCMock_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Cuckoo_OCMock_macOS.framework; path = Cuckoo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E0656C5164A529DCCADBA8F1 /* NSObject+TrustMe.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+TrustMe.m"; sourceTree = "<group>"; };
E13C3B0AD475F81DE8BBB18D /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig"; sourceTree = "<group>"; };
E216B22B63CECBFA5F681510 /* Cuckoo-tvOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo-tvOSTests-Info.plist"; sourceTree = "<group>"; };
E3646D56C8005FB7E1B11B67 /* NestedClassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedClassTest.swift; sourceTree = "<group>"; };
E4A99A2173E7F7743145B11B /* GeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneratedMocks.swift; sourceTree = "<group>"; };
@ -852,17 +855,14 @@
ECFED3C29F5CA48398AF0C5B /* NestedPrivateExtensionClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedPrivateExtensionClass.swift; sourceTree = "<group>"; };
EE5F4691EE101415724C1D73 /* Cuckoo_OCMock-iOSTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo_OCMock-iOSTests-Info.plist"; sourceTree = "<group>"; };
F01C5ABA73DC1B0CCE088669 /* GenericClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericClass.swift; sourceTree = "<group>"; };
F2B26467F81DC89FAA7E0C15 /* Pods-Cuckoo_OCMock-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS/Pods-Cuckoo_OCMock-iOS.release.xcconfig"; sourceTree = "<group>"; };
F398C1D87D71EE8DED0C6EA3 /* StubFunctionThenThrowingTrait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubFunctionThenThrowingTrait.swift; sourceTree = "<group>"; };
F3C87227E4CAE60FD9202D6F /* NSInvocation+OCMockWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+OCMockWrapper.h"; sourceTree = "<group>"; };
F6CA2236A30B54754F335DC3 /* ParameterMatcherFunctions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterMatcherFunctions.swift; sourceTree = "<group>"; };
F70C4FAE3318E21F0A87531A /* ObjectiveMatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectiveMatchers.swift; sourceTree = "<group>"; };
F81B5143E65D60134B59CFA4 /* Cuckoo_OCMock-tvOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Cuckoo_OCMock-tvOS-Info.plist"; sourceTree = "<group>"; };
F9735ACE5BF868774A356231 /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig"; sourceTree = "<group>"; };
F87AB6F574DC47448E8F3863 /* Pods_Cuckoo_OCMock_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F981A41C0D53F5AF59BD7202 /* Cuckoo_OCMock_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Cuckoo_OCMock_tvOS.framework; path = Cuckoo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FAAC201DCB53797CB6435DB1 /* Pods_Cuckoo_OCMock_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cuckoo_OCMock_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FB36E482FF288D775B744A02 /* ExcludedTestClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExcludedTestClass.swift; sourceTree = "<group>"; };
FD600CEE1B82473FC8F31F06 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig"; path = "Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig"; sourceTree = "<group>"; };
FE705433C346CA3DF4E2AB96 /* ToBeStubbedProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToBeStubbedProperty.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -896,7 +896,7 @@
buildActionMask = 2147483647;
files = (
8C61162C8AFDB8D153798DBC /* XCTest.framework in Frameworks */,
CB4F2E994373AF88A32748D3 /* Pods_Cuckoo_OCMock_macOS.framework in Frameworks */,
84A7C123934DF31E3CB48DF1 /* Pods_Cuckoo_OCMock_macOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -905,7 +905,7 @@
buildActionMask = 2147483647;
files = (
11700496E1D2DF02E9CD49BE /* XCTest.framework in Frameworks */,
EB37DBF5C5EEB81AE40E203F /* Pods_Cuckoo_OCMock_iOS.framework in Frameworks */,
2647BA750CED383CE3439905 /* Pods_Cuckoo_OCMock_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -914,7 +914,7 @@
buildActionMask = 2147483647;
files = (
3CFAA76E52C3382D06DDDB7A /* Cuckoo_OCMock_tvOS.framework in Frameworks */,
8EABFB3D5035C5628E0B0A1B /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework in Frameworks */,
F93AE8CCD2CF4BD1FFAAAC70 /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -923,7 +923,7 @@
buildActionMask = 2147483647;
files = (
8443421090DA81C2C68570A1 /* Cuckoo_OCMock_macOS.framework in Frameworks */,
3083E891A8AA06D2D571B18C /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework in Frameworks */,
B576F1274DC3407E43F86C8A /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -948,7 +948,7 @@
buildActionMask = 2147483647;
files = (
996F90892116045116104676 /* Cuckoo_OCMock_iOS.framework in Frameworks */,
EFB24DDC33700188444EA5F0 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework in Frameworks */,
35DB3CFDF76FAFC186CCF5E5 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -957,7 +957,7 @@
buildActionMask = 2147483647;
files = (
48C1BD8F4E0BA4C6CA1D76D3 /* XCTest.framework in Frameworks */,
4A62B192708AD7476317E384 /* Pods_Cuckoo_OCMock_tvOS.framework in Frameworks */,
1B35986E55804D8DFE6FC061 /* Pods_Cuckoo_OCMock_tvOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1015,7 +1015,7 @@
B9E2517ABB4C90F2E8FA4696 /* Project */,
FEEC9B8DBF0FA8678CE815E0 /* Frameworks */,
512C697A5D123B937FE97812 /* Products */,
49C7C79888FCE0DEB1110FBF /* Pods */,
312C3FBE428B8E2EAEB1851F /* Pods */,
);
sourceTree = "<group>";
};
@ -1044,6 +1044,25 @@
path = OCMock;
sourceTree = "<group>";
};
312C3FBE428B8E2EAEB1851F /* Pods */ = {
isa = PBXGroup;
children = (
02EAAA14360EE993DF2A2AA3 /* Pods-Cuckoo_OCMock-iOS.debug.xcconfig */,
A83242F5AF363867836B8970 /* Pods-Cuckoo_OCMock-iOS.release.xcconfig */,
E13C3B0AD475F81DE8BBB18D /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig */,
2FC3CF194933ED399D9483E2 /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig */,
1DCDA7E7A2DA0E7AD149208B /* Pods-Cuckoo_OCMock-macOS.debug.xcconfig */,
3B4C9565EA304E2CF62B1D4F /* Pods-Cuckoo_OCMock-macOS.release.xcconfig */,
D3399F3F2FE04AE3E357B548 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig */,
B712732E2656B55EDE652691 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig */,
5776F80847FB1775D23C8064 /* Pods-Cuckoo_OCMock-tvOS.debug.xcconfig */,
99D050972B5669B5B58E9DE7 /* Pods-Cuckoo_OCMock-tvOS.release.xcconfig */,
18D8112F0A64A41ED070EA9F /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig */,
7FE031A1E54FBEBABC465F88 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
422FE57E963E63B12F0FE722 /* Source */ = {
isa = PBXGroup;
children = (
@ -1081,25 +1100,6 @@
path = Verification;
sourceTree = "<group>";
};
49C7C79888FCE0DEB1110FBF /* Pods */ = {
isa = PBXGroup;
children = (
323D9BB2B0A99E0408471845 /* Pods-Cuckoo_OCMock-iOS.debug.xcconfig */,
F2B26467F81DC89FAA7E0C15 /* Pods-Cuckoo_OCMock-iOS.release.xcconfig */,
F9735ACE5BF868774A356231 /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig */,
0FCC7E0CFC29DFD7C97EB8FC /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig */,
C6A3C8DF4AD4DE7807F60B62 /* Pods-Cuckoo_OCMock-macOS.debug.xcconfig */,
65F7304C5992843A0A5D3863 /* Pods-Cuckoo_OCMock-macOS.release.xcconfig */,
B6098DE536CCBA16747765FD /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig */,
FD600CEE1B82473FC8F31F06 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig */,
90AE2C9146A1126EC1109B2B /* Pods-Cuckoo_OCMock-tvOS.debug.xcconfig */,
6E4033B8F0022DDDDA758351 /* Pods-Cuckoo_OCMock-tvOS.release.xcconfig */,
D4108DD343B556BAA2BC0501 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig */,
58E1385A0AB0BD61D0DFD5C1 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
512C697A5D123B937FE97812 /* Products */ = {
isa = PBXGroup;
children = (
@ -1179,7 +1179,7 @@
29F42B443F090072DFF751FD /* NestedExtensionClassTest.swift */,
0512EFCB8EDE906B3E54057B /* NestedStructExtensionClassTest.swift */,
245F73FBA37EA0E055BA4EA2 /* NestedStructTest.swift */,
55E654F50A34B51CD16E76A2 /* NestedSubclassTests.swift */,
8C4A20137742161D649D3E3B /* NestedSubclassTest.swift */,
8FBE411D64C1D2B056E42C52 /* NSObjectProtocolInheritanceTest.swift */,
6978339A31BEDF22A4115E81 /* ProtocolTest.swift */,
40FB9A410020B1B90952823C /* StubTest.swift */,
@ -1354,12 +1354,12 @@
7AEF1D77E05D83F84ADE7A87 /* XCTest.framework */,
B81133817083F2B8122BE188 /* XCTest.framework */,
648E1DCC3FA05944AC970663 /* XCTest.framework */,
FAAC201DCB53797CB6435DB1 /* Pods_Cuckoo_OCMock_iOS.framework */,
6E045C7BF96B0FF85FAE2988 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework */,
02E7D093817E7CE04A04C2AF /* Pods_Cuckoo_OCMock_macOS.framework */,
9DD3286025BB166116AD2BAE /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework */,
CCFC4929BB6578E62C06913A /* Pods_Cuckoo_OCMock_tvOS.framework */,
3A8232B39A1033045A35B60A /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework */,
D77AB55B3A73709BDA8437F0 /* Pods_Cuckoo_OCMock_iOS.framework */,
194F548C24DA8152FAEAE7E9 /* Pods_Cuckoo_OCMock_iOS_Cuckoo_OCMock_iOSTests.framework */,
6EAF21976FCFA3343C232939 /* Pods_Cuckoo_OCMock_macOS.framework */,
6F21B45333B1857F3854D779 /* Pods_Cuckoo_OCMock_macOS_Cuckoo_OCMock_macOSTests.framework */,
F87AB6F574DC47448E8F3863 /* Pods_Cuckoo_OCMock_tvOS.framework */,
598FA7C4C26C7322B25F1358 /* Pods_Cuckoo_OCMock_tvOS_Cuckoo_OCMock_tvOSTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -1416,12 +1416,12 @@
isa = PBXNativeTarget;
buildConfigurationList = D8D9738C622AC77A0AD3C99C /* Build configuration list for PBXNativeTarget "Cuckoo_OCMock-tvOSTests" */;
buildPhases = (
D8E9D790042A7DBC669415D7 /* [CP] Check Pods Manifest.lock */,
86009F31E41824C4A0083178 /* [CP] Check Pods Manifest.lock */,
DCFCE738380747FA90A17E02 /* Sources */,
44A58B8F3B45191E95CE2650 /* Resources */,
EE7B717FA1BFB5D77F7E37E0 /* Embed Frameworks */,
52AD199FB7C4B081CEB16EB7 /* Frameworks */,
F482EEC2B5D59227E33C620A /* [CP] Embed Pods Frameworks */,
4106A0A5BDAC832E1023D35A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -1455,12 +1455,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 4975D1A314DF2F3B03921C05 /* Build configuration list for PBXNativeTarget "Cuckoo_OCMock-iOSTests" */;
buildPhases = (
B599DCB12CAA3A87441791B0 /* [CP] Check Pods Manifest.lock */,
A6DC8CD047E92A889E2B1B49 /* [CP] Check Pods Manifest.lock */,
DA8CF62D0B45947696C7CA57 /* Sources */,
9F5A861AA4A648E0AA8CBAF3 /* Resources */,
95F067D7C8E3858D9C7B1ACA /* Embed Frameworks */,
C5252DF514145309C583BC1C /* Frameworks */,
35988EE58868DFADDBA20B3B /* [CP] Embed Pods Frameworks */,
83FA9CED63612C063406E51C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -1476,7 +1476,7 @@
isa = PBXNativeTarget;
buildConfigurationList = BAD574EA9F7BD25327F418C8 /* Build configuration list for PBXNativeTarget "Cuckoo_OCMock-macOS" */;
buildPhases = (
71CADC9726153BE5F6BB2738 /* [CP] Check Pods Manifest.lock */,
95A3031C76FA53D509722E60 /* [CP] Check Pods Manifest.lock */,
289CD55941F8375304A0FA40 /* Headers */,
97824D7A6F12CE3AE9E4C89E /* Sources */,
E5B19CA15C7230C7DB4DEAE8 /* Resources */,
@ -1554,7 +1554,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 431006DE18EB78C97D35651A /* Build configuration list for PBXNativeTarget "Cuckoo_OCMock-iOS" */;
buildPhases = (
7EB54E19B0ACE9555F9F3054 /* [CP] Check Pods Manifest.lock */,
5C621A3A3586D0F695EBD0FE /* [CP] Check Pods Manifest.lock */,
36034BCF09BB5C60775B1390 /* Headers */,
54DBCB29E77138C0A8DA5AE9 /* Sources */,
3A87627B88A1B3B0BACF31A3 /* Resources */,
@ -1574,7 +1574,7 @@
isa = PBXNativeTarget;
buildConfigurationList = D5AB84ECE1C48279A3174C2F /* Build configuration list for PBXNativeTarget "Cuckoo_OCMock-tvOS" */;
buildPhases = (
6255112D1BC080CF10F6657B /* [CP] Check Pods Manifest.lock */,
9AC438C28C07FED842ABB94B /* [CP] Check Pods Manifest.lock */,
66785690DDA051B8D848078C /* Headers */,
57C722FCE701A7CB8373AF82 /* Sources */,
91DE98464C1F3EC6B841B817 /* Resources */,
@ -1612,12 +1612,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 419AB8BB7268955611576ABC /* Build configuration list for PBXNativeTarget "Cuckoo_OCMock-macOSTests" */;
buildPhases = (
E867028CA93376A28E4C9F0F /* [CP] Check Pods Manifest.lock */,
DDCFC473F52E9993F0926955 /* [CP] Check Pods Manifest.lock */,
CABDB0580E21EEBE1C06CB8E /* Sources */,
DD60C0DD6531B3CCE27D430B /* Resources */,
EBE25D5DF2CC2AF1AACF74DF /* Embed Frameworks */,
5345EBC8A03A18A6BD0A24AE /* Frameworks */,
44FEAE74934993E701CA2BF7 /* [CP] Embed Pods Frameworks */,
717E017005E63212DC015EED /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -1773,21 +1773,21 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
35988EE58868DFADDBA20B3B /* [CP] Embed Pods Frameworks */ = {
4106A0A5BDAC832E1023D35A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
42C8B15E53049F2976363441 /* Generate mocks */ = {
@ -1809,23 +1809,6 @@
shellPath = /bin/sh;
shellScript = "if [ \"$GENERATE_TEST_MOCKS\" = \"NO\" ] ; then exit; fi\n\n# Make sure the generator is up-to-date.\necho 'Building generator.'\n\"$PROJECT_DIR\"/build_generator\n\necho 'Generating mocks.'\n\"$PROJECT_DIR\"/Generator/bin/cuckoo_generator generate \\\n\t--testable Cuckoo \\\n\t--exclude ExcludedTestClass,ExcludedProtocol \\\n\t--output \"$PROJECT_DIR\"/Tests/Swift/Generated/GeneratedMocks.swift \\\n\t--glob \"$PROJECT_DIR\"/Tests/Swift/Source/*.swift";
};
44FEAE74934993E701CA2BF7 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
4D36DA407A6B4E6EFDC6DA5F /* Generate mocks */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@ -1845,51 +1828,7 @@
shellPath = /bin/sh;
shellScript = "if [ \"$GENERATE_TEST_MOCKS\" = \"NO\" ] ; then exit; fi\n\n# Make sure the generator is up-to-date.\necho 'Building generator.'\n\"$PROJECT_DIR\"/build_generator\n\necho 'Generating mocks.'\n\"$PROJECT_DIR\"/Generator/bin/cuckoo_generator generate \\\n\t--testable Cuckoo \\\n\t--exclude ExcludedTestClass,ExcludedProtocol \\\n\t--output \"$PROJECT_DIR\"/Tests/Swift/Generated/GeneratedMocks.swift \\\n\t--glob \"$PROJECT_DIR\"/Tests/Swift/Source/*.swift\n";
};
6255112D1BC080CF10F6657B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Cuckoo_OCMock-tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
71CADC9726153BE5F6BB2738 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Cuckoo_OCMock-macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
7EB54E19B0ACE9555F9F3054 /* [CP] Check Pods Manifest.lock */ = {
5C621A3A3586D0F695EBD0FE /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -1911,6 +1850,62 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
717E017005E63212DC015EED /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests/Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
83FA9CED63612C063406E51C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests/Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
86009F31E41824C4A0083178 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
8E54BA9B8385785DA0BBD4EC /* Generate mocks */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@ -1930,7 +1925,51 @@
shellPath = /bin/sh;
shellScript = "if [ \"$GENERATE_TEST_MOCKS\" = \"NO\" ] ; then exit; fi\n\n# Make sure the generator is up-to-date.\necho 'Building generator.'\n\"$PROJECT_DIR\"/build_generator\n\necho 'Generating mocks.'\n\"$PROJECT_DIR\"/Generator/bin/cuckoo_generator generate \\\n\t--testable Cuckoo \\\n\t--exclude ExcludedTestClass,ExcludedProtocol \\\n\t--output \"$PROJECT_DIR\"/Tests/Swift/Generated/GeneratedMocks.swift \\\n\t--glob \"$PROJECT_DIR\"/Tests/Swift/Source/*.swift";
};
B599DCB12CAA3A87441791B0 /* [CP] Check Pods Manifest.lock */ = {
95A3031C76FA53D509722E60 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Cuckoo_OCMock-macOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9AC438C28C07FED842ABB94B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Cuckoo_OCMock-tvOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A6DC8CD047E92A889E2B1B49 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -1952,29 +1991,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
D8E9D790042A7DBC669415D7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
E867028CA93376A28E4C9F0F /* [CP] Check Pods Manifest.lock */ = {
DDCFC473F52E9993F0926955 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -1996,23 +2013,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
F482EEC2B5D59227E33C620A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests/Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -2046,7 +2046,7 @@
AFBDD93079F30AE78FA0213A /* NestedExtensionClassTest.swift in Sources */,
541AE789BEF0830BBBB0A691 /* NestedStructExtensionClassTest.swift in Sources */,
4979C7CD6F921D3627A7DB83 /* NestedStructTest.swift in Sources */,
7357129D17477272975CBCBC /* NestedSubclassTests.swift in Sources */,
992E1CFD5221BEB55CD337FF /* NestedSubclassTest.swift in Sources */,
85BB583C1F89B50DC88999F2 /* ProtocolTest.swift in Sources */,
BC428931E53499C0EFDC802F /* ClassForStubTesting.swift in Sources */,
39B67C20D2A61BF2376634F3 /* ClassWithOptionals.swift in Sources */,
@ -2237,7 +2237,7 @@
B210B6A3EDD5F0807CB635BD /* NestedExtensionClassTest.swift in Sources */,
8805AE37A66F847C9DF3206E /* NestedStructExtensionClassTest.swift in Sources */,
24563D4813663AB15D24B790 /* NestedStructTest.swift in Sources */,
ED9646245798F318CAD33E12 /* NestedSubclassTests.swift in Sources */,
0BEB6AA4984EF02EA3A6AA00 /* NestedSubclassTest.swift in Sources */,
E22E749D0A0B44EC528CB38F /* ProtocolTest.swift in Sources */,
2D2631FF3DFEB17188A08073 /* ClassForStubTesting.swift in Sources */,
F52EE531052666CFB50523E6 /* ClassWithOptionals.swift in Sources */,
@ -2414,7 +2414,7 @@
35A2CEA0553DFBABD2391BBB /* NestedExtensionClassTest.swift in Sources */,
25611F1843D374BB1840D16B /* NestedStructExtensionClassTest.swift in Sources */,
FFCC5303B4F31B8CE8C14BA1 /* NestedStructTest.swift in Sources */,
BB289937FFF493E53DBF7FE8 /* NestedSubclassTests.swift in Sources */,
11B3F573CEAEDBC88BDC8AFF /* NestedSubclassTest.swift in Sources */,
63E990EB0DEE6A4873F30538 /* ProtocolTest.swift in Sources */,
A977B902CD0127BCD5BD272F /* ClassForStubTesting.swift in Sources */,
F09C7E5B6AD4AEB0166F871F /* ClassWithOptionals.swift in Sources */,
@ -2621,7 +2621,7 @@
/* Begin XCBuildConfiguration section */
09A17ABB9CE8D5E803DBC7E5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 58E1385A0AB0BD61D0DFD5C1 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig */;
baseConfigurationReference = 7FE031A1E54FBEBABC465F88 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.release.xcconfig */;
buildSettings = {
INFOPLIST_FILE = "Derived/InfoPlists/Cuckoo_OCMock-tvOSTests-Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
@ -2642,7 +2642,7 @@
};
0F8DD70D0BDBF0F32D3A5D2A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C6A3C8DF4AD4DE7807F60B62 /* Pods-Cuckoo_OCMock-macOS.debug.xcconfig */;
baseConfigurationReference = 1DCDA7E7A2DA0E7AD149208B /* Pods-Cuckoo_OCMock-macOS.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
@ -2751,7 +2751,7 @@
};
6788BA84E4C3F2DF4D49FDD1 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0FCC7E0CFC29DFD7C97EB8FC /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig */;
baseConfigurationReference = 2FC3CF194933ED399D9483E2 /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = "Derived/InfoPlists/Cuckoo_OCMock-iOSTests-Info.plist";
@ -2774,7 +2774,7 @@
};
68C3608166DB6A5DCC142D0A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D4108DD343B556BAA2BC0501 /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig */;
baseConfigurationReference = 18D8112F0A64A41ED070EA9F /* Pods-Cuckoo_OCMock-tvOS-Cuckoo_OCMock-tvOSTests.debug.xcconfig */;
buildSettings = {
INFOPLIST_FILE = "Derived/InfoPlists/Cuckoo_OCMock-tvOSTests-Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
@ -2828,7 +2828,7 @@
};
73511D4869AFB48ADC79B8C1 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F9735ACE5BF868774A356231 /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig */;
baseConfigurationReference = E13C3B0AD475F81DE8BBB18D /* Pods-Cuckoo_OCMock-iOS-Cuckoo_OCMock-iOSTests.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = "Derived/InfoPlists/Cuckoo_OCMock-iOSTests-Info.plist";
@ -2883,7 +2883,7 @@
};
88C896DF3C7EA2C24B2A7B9E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 323D9BB2B0A99E0408471845 /* Pods-Cuckoo_OCMock-iOS.debug.xcconfig */;
baseConfigurationReference = 02EAAA14360EE993DF2A2AA3 /* Pods-Cuckoo_OCMock-iOS.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CURRENT_PROJECT_VERSION = 1;
@ -2918,7 +2918,7 @@
};
8FC167D6E355658B5903183F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 65F7304C5992843A0A5D3863 /* Pods-Cuckoo_OCMock-macOS.release.xcconfig */;
baseConfigurationReference = 3B4C9565EA304E2CF62B1D4F /* Pods-Cuckoo_OCMock-macOS.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
@ -3184,7 +3184,7 @@
};
C7DB288DC16F2BA0020CA917 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F2B26467F81DC89FAA7E0C15 /* Pods-Cuckoo_OCMock-iOS.release.xcconfig */;
baseConfigurationReference = A83242F5AF363867836B8970 /* Pods-Cuckoo_OCMock-iOS.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CURRENT_PROJECT_VERSION = 1;
@ -3241,7 +3241,7 @@
};
D9C80FCB45BF96859CF72662 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B6098DE536CCBA16747765FD /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig */;
baseConfigurationReference = D3399F3F2FE04AE3E357B548 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
INFOPLIST_FILE = "Derived/InfoPlists/Cuckoo_OCMock-macOSTests-Info.plist";
@ -3283,7 +3283,7 @@
};
DC200B677208FA5563B50AD7 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 90AE2C9146A1126EC1109B2B /* Pods-Cuckoo_OCMock-tvOS.debug.xcconfig */;
baseConfigurationReference = 5776F80847FB1775D23C8064 /* Pods-Cuckoo_OCMock-tvOS.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CURRENT_PROJECT_VERSION = 1;
@ -3339,7 +3339,7 @@
};
F46AC1AF8E41D78201C5BDE9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6E4033B8F0022DDDDA758351 /* Pods-Cuckoo_OCMock-tvOS.release.xcconfig */;
baseConfigurationReference = 99D050972B5669B5B58E9DE7 /* Pods-Cuckoo_OCMock-tvOS.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CURRENT_PROJECT_VERSION = 1;
@ -3372,7 +3372,7 @@
};
F4E1D3C8F565E2D98246CF67 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = FD600CEE1B82473FC8F31F06 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig */;
baseConfigurationReference = B712732E2656B55EDE652691 /* Pods-Cuckoo_OCMock-macOS-Cuckoo_OCMock-macOSTests.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
INFOPLIST_FILE = "Derived/InfoPlists/Cuckoo_OCMock-macOSTests-Info.plist";

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright ©. All rights reserved.</string>
</dict>
</plist>

View File

@ -1,27 +1,63 @@
import ProjectDescription
import ProjectDescriptionHelpers
let target = Target(
name: "CuckooGenerator",
platform: .macOS,
product: .commandLineTool,
productName: "cuckoo_generator",
bundleId: "CuckooGenerator",
deploymentTarget: .macOS(targetVersion: "10.13"),
sources: "Sources/**",
dependencies: [
"FileKit",
"Stencil",
"Commandant",
"SwiftFormat",
"SwiftSyntax",
"SwiftSyntaxParser",
].map(TargetDependency.package(product:)) + [
.xcframework(path: "./lib_InternalSwiftSyntaxParser.xcframework")
],
settings: Settings.settings(
base: SettingsDictionary()
.otherLinkerFlags([
"-Xlinker",
"-dead_strip_dylibs",
"-dead_strip",
])
)
)
let testTarget = Target(
name: "GeneratorTests",
platform: .macOS,
product: .unitTests,
bundleId: "CuckooGeneratorTests",
deploymentTarget: target.deploymentTarget,
sources: SourceFilesList(globs: [
// TODO: This is wrong but testing CLI is not supported, must separate generator into CLI and internal targets.
target.sources?.globs,
["Tests/**"],
].compactMap { $0 }.flatMap { $0 }),
// TODO: This is wrong but testing CLI is not supported, must separate generator into CLI and internal targets.
dependencies: target.dependencies
)
// MARK: project definition
let project = Project(
name: "Generator",
options: .options(automaticSchemesOptions: .disabled, disableSynthesizedResourceAccessors: true),
packages: [
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.21.2")),
.package(url: "https://github.com/nvzqz/FileKit.git", .branch("develop")),
.package(url: "https://github.com/kylef/Stencil.git", .exact("0.14.2")),
.package(url: "https://github.com/nvzqz/FileKit.git", .exact("6.1.0")),
.package(url: "https://github.com/kylef/Stencil.git", .exact("0.15.1")),
.package(url: "https://github.com/Carthage/Commandant.git", .exact("0.15.0")),
.package(url: "https://github.com/apple/swift-syntax.git", .exact("0.50700.1")),
.package(url: "https://github.com/apple/swift-format.git", .exact("0.50700.1")),
],
targets: [
Target(
name: "CuckooGenerator",
platform: .macOS,
product: .commandLineTool,
productName: "cuckoo_generator",
bundleId: "CuckooGenerator",
deploymentTarget: DeploymentTarget.macOS(targetVersion: "10.13"),
sources: "Source/**",
dependencies: ["FileKit", "SourceKittenFramework", "Stencil", "Commandant"].map(TargetDependency.package(product:))
),
target,
testTarget,
],
schemes: [
Scheme(
@ -37,6 +73,7 @@ let project = Project(
],
runPostActionsOnFailure: false
),
testAction: TestAction.targets([TestableTarget(target: testTarget.reference)]),
runAction: RunAction.runAction(
executable: "CuckooGenerator",
arguments: Arguments(

View File

@ -1,24 +0,0 @@
import Foundation
import Commandant
import Result
public struct VersionCommand: CommandProtocol {
static let appVersion = Bundle.allFrameworks.filter {
$0.bundleIdentifier == "org.brightify.CuckooGeneratorFramework"
}.first?.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
public let verb = "version"
public let function = "Prints the version of this generator."
public func run(_ options: Options) -> Result<Void, CuckooGeneratorError> {
print(VersionCommand.appVersion)
return .success(())
}
public struct Options: OptionsProtocol {
public static func evaluate(_ m: CommandMode) -> Result<Options, CommandantError<CuckooGeneratorError>> {
return .success(Options())
}
}
}

View File

@ -1,87 +0,0 @@
import Foundation
import FileKit
public struct FileHeaderHandler {
public static func getHeader(of file: FileRepresentation, includeTimestamp: Bool) -> String {
let path: String
if let absolutePath = file.sourceFile.path {
path = getRelativePath(from: absolutePath)
} else {
path = "unknown"
}
let generationInfo = "// MARK: - Mocks generated from file: \(path)" + (includeTimestamp ? " at \(Date())\n" : "")
let header = getHeader(of: file)
return generationInfo + "\n" + header + "\n"
}
public static func getImports(of file: FileRepresentation, testableFrameworks: [String]) -> String {
var imports = Array(Set(file.declarations.only(Import.self).map { "import \($0.importee)\n" })).sorted().joined(separator: "")
if imports.isEmpty == false {
imports = "\n\(imports)"
}
return "import Cuckoo\n" + getTestableImports(testableFrameworks: testableFrameworks) + imports
}
private static func getRelativePath(from absolutePath: String) -> String {
let path = Path(absolutePath)
let base = path.commonAncestor(Path.current)
let components = path.components.suffix(from: base.components.endIndex)
let result = components.map { $0.rawValue }.joined(separator: Path.separator)
let difference = Path.current.components.endIndex - base.components.endIndex
return (0..<difference).reduce(result) { acc, _ in ".." + Path.separator + acc }
}
private static func getHeader(of file: FileRepresentation) -> String {
let possibleHeaderEnd = getPossibleHeaderEnd(current: file.sourceFile.contents.unicodeScalars.count, declarations: file.declarations)
let possibleHeader = String(file.sourceFile.contents.utf8.prefix(possibleHeaderEnd)) ?? ""
let singleLine = getPrefixToLastSingleLineComment(text: possibleHeader)
let multiLine = getPrefixToLastMultiLineComment(text: possibleHeader)
return singleLine.count > multiLine.count ? singleLine : multiLine
}
private static func getPossibleHeaderEnd(current: Int, declarations: [Token]) -> Int {
return declarations.reduce(current) { minimum, declaration in
let declarationMinimum: Int
switch declaration {
case let containerToken as ContainerToken:
declarationMinimum = containerToken.range.lowerBound
case let method as Method:
declarationMinimum = method.range.lowerBound
case let importToken as Import:
declarationMinimum = importToken.range.lowerBound
default:
declarationMinimum = minimum
}
return min(declarationMinimum, minimum)
}
}
private static func getPrefixToLastSingleLineComment(text: String) -> String {
if let range = text.range(of: "//", options: .backwards) {
let lastLine = text.lineRange(for: range)
return String(text[..<lastLine.upperBound])
} else {
return ""
}
}
private static func getPrefixToLastMultiLineComment(text: String) -> String {
if let range = text.range(of: "*/", options: .backwards) {
return String(text[..<range.upperBound]) + "\n"
} else {
return ""
}
}
private static func getTestableImports(testableFrameworks: [String]) -> String {
func replaceIllegalCharacters(_ char: UnicodeScalar) -> Character {
if CharacterSet.letters.contains(UnicodeScalar(char.value)!) || CharacterSet.decimalDigits.contains(UnicodeScalar(char.value)!) {
return Character(char)
} else {
return "_"
}
}
return testableFrameworks.map { String($0.unicodeScalars.map(replaceIllegalCharacters)) }.map { "@testable import \($0)\n" }.joined(separator: "")
}
}

View File

@ -1,166 +0,0 @@
import Foundation
import Stencil
public struct Generator {
private static let reservedKeywordsNotAllowedAsMethodName: Set = [
// Keywords used in declarations:
"associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import", "init", "inout", "internal", "let", "operator", "private", "precedencegroup", "protocol", "public", "rethrows", "static", "struct", "subscript", "typealias", "var",
// Keywords used in statements:
"break", "case", "catch", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", "in", "repeat", "return", "throw", "switch", "where", "while",
// Keywords used in expressions and types:
"Any", "as", "catch", "false", "is", "nil", "rethrows", "self", "super", "throw", "throws", "true", "try",
// Keywords used in patterns:
"_",
]
private let declarations: [Token]
public init(file: FileRepresentation) {
declarations = file.declarations
}
public func generate(debug: Bool = false) throws -> String {
let ext = Extension()
ext.registerFilter("genericSafe") { (value: Any?) in
guard let string = value as? String else { return value }
return self.genericSafeType(from: string)
}
ext.registerFilter("matchableGenericNames") { (value: Any?) in
guard let method = value as? Method else { return value }
return self.matchableGenericTypes(from: method)
}
ext.registerFilter("matchableGenericWhereClause") { (value: Any?) in
guard let method = value as? Method else { return value }
return self.matchableGenericsWhereClause(from: method)
}
ext.registerFilter("matchableParameterSignature") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.matchableParameterSignature(with: parameters)
}
ext.registerFilter("parameterMatchers") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.parameterMatchers(for: parameters)
}
ext.registerFilter("openNestedClosure") { (value: Any?) in
guard let method = value as? Method else { return value }
return self.openNestedClosure(for: method)
}
ext.registerFilter("closeNestedClosure") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return self.closeNestedClosure(for: parameters)
}
ext.registerFilter("escapeReservedKeywords") { (value: Any?) in
guard let name = value as? String else { return value }
return self.escapeReservedKeywords(for: name)
}
ext.registerFilter("removeClosureArgumentNames") { (value: Any?) in
guard let type = value as? String else { return value }
return self.removeClosureArgumentNames(for: type)
}
let environment = Environment(extensions: [ext])
let containers = declarations.compactMap { $0 as? ContainerToken }
.filter {
$0.parent?.areAllHierarchiesAccessible ?? true && $0.accessibility.isAccessible
}
.map { $0.serializeWithType() }
return try environment.renderTemplate(string: Templates.mock, context: ["containers": containers, "debug": debug])
}
private func matchableGenericTypes(from method: Method) -> String {
guard !method.parameters.isEmpty || !method.genericParameters.isEmpty else { return "" }
let matchableGenericParameters = method.parameters.enumerated().map { index, parameter -> String in
let type = parameter.isOptional ? "OptionalMatchable" : "Matchable"
return "M\(index + 1): Cuckoo.\(type)"
}
let methodGenericParameters = method.genericParameters.map { $0.description }
return "<\((matchableGenericParameters + methodGenericParameters).joined(separator: ", "))>"
}
private func matchableGenericsWhereClause(from method: Method) -> String {
guard method.parameters.isEmpty == false else { return "" }
let matchableWhereConstraints = method.parameters.enumerated().map { index, parameter -> String in
let type = parameter.isOptional ? "OptionalMatchedType" : "MatchedType"
return "M\(index + 1).\(type) == \(genericSafeType(from: parameter.type.withoutAttributes.unoptionaled.sugarized))"
}
let methodWhereConstraints = method.returnSignature.whereConstraints
return " where \((matchableWhereConstraints + methodWhereConstraints).joined(separator: ", "))"
}
private func matchableParameterSignature(with parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "" }
return parameters.enumerated().map { "\($1.labelAndName): M\($0 + 1)" }.joined(separator: ", ")
}
private func parameterMatchers(for parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "let matchers: [Cuckoo.ParameterMatcher<Void>] = []" }
let tupleType = parameters.map { $0.typeWithoutAttributes }.joined(separator: ", ")
let matchers = parameters.enumerated().map { "wrap(matchable: \($1.name)) { $0\(parameters.count > 1 ? ".\($0)" : "") }" }.joined(separator: ", ")
return "let matchers: [Cuckoo.ParameterMatcher<(\(genericSafeType(from: tupleType)))>] = [\(matchers)]"
}
private func genericSafeType(from type: String) -> String {
return type.replacingOccurrences(of: "!", with: "?")
}
private func openNestedClosure(for method: Method) -> String {
var fullString = ""
for (index, parameter) in method.parameters.enumerated() {
if parameter.isClosure && !parameter.isEscaping {
let indents = String(repeating: "\t", count: index)
let tries = method.isThrowing ? "try " : ""
let awaits = method.isAsync ? "await " : ""
let sugarizedReturnType = method.returnType.sugarized
let returnSignature: String
if sugarizedReturnType.isEmpty {
returnSignature = sugarizedReturnType
} else {
returnSignature = " -> \(sugarizedReturnType)"
}
fullString += "\(indents)return \(tries)\(awaits)withoutActuallyEscaping(\(parameter.name), do: { (\(parameter.name): @escaping \(parameter.type))\(returnSignature) in\n"
}
}
return fullString
}
private func closeNestedClosure(for parameters: [MethodParameter]) -> String {
var fullString = ""
for (index, parameter) in parameters.enumerated() {
if parameter.isClosure && !parameter.isEscaping {
let indents = String(repeating: "\t", count: index)
fullString += "\(indents)})\n"
}
}
return fullString
}
private func escapeReservedKeywords(for name: String) -> String {
Self.reservedKeywordsNotAllowedAsMethodName.contains(name) ? "`\(name)`" : name
}
private func removeClosureArgumentNames(for type: String) -> String {
type.replacingOccurrences(
of: "_\\s+?[_a-zA-Z]\\w*?\\s*?:",
with: "",
options: .regularExpression
)
}
}

View File

@ -1,19 +0,0 @@
import Foundation
@dynamicMemberLookup
public final class Reference<Value> {
private(set) var value: Value
public init(value: Value) {
self.value = value
}
public subscript<T>(dynamicMember keyPath: KeyPath<Value, T>) -> T {
value[keyPath: keyPath]
}
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Value, T>) -> T {
get { value[keyPath: keyPath] }
set { value[keyPath: keyPath] = newValue }
}
}

View File

@ -1,8 +0,0 @@
import Foundation
public private(set) var stderrUsed = false
func stderrPrint(_ item: Any) {
stderrUsed = true
fputs("error: \(item)\n", stderr)
}

View File

@ -1,153 +0,0 @@
import Foundation
extension Templates {
static let staticGenericParameter = "_CUCKOO$$GENERIC"
static let typeErasureClassName = "DefaultImplCaller"
static let mock = """
{% for container in containers %}
{% if debug %}
// {{ container }}
{% endif %}
{{ container.unavailablePlatformsCheck }}
{% for attribute in container.attributes %}
{{ attribute.text }}
{% endfor %}
{% if container.hasParent %}
extension {{ container.parentFullyQualifiedName }} {
{% endif %}
{{ container.accessibility }} class {{ container.mockName }}{{ container.genericParameters }}: {% if container.isNSObjectProtocol %}NSObject, {% endif %}{{ container.name }}{% if container.isImplementation %}{{ container.genericArguments }}{% endif %}, {% if container.isImplementation %}Cuckoo.ClassMock{% else %}Cuckoo.ProtocolMock{% endif %} {
{% if container.isGeneric and not container.isImplementation %}
{{ container.accessibility }} typealias MocksType = \(typeErasureClassName){{ container.genericArguments }}
{% else %}
{{ container.accessibility }} typealias MocksType = {{ container.name }}{{ container.genericArguments }}
{% endif %}
{{ container.accessibility }} typealias Stubbing = __StubbingProxy_{{ container.name }}
{{ container.accessibility }} typealias Verification = __VerificationProxy_{{ container.name }}
{{ container.accessibility }} let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: {{ container.isImplementation }})
{% if container.isGeneric and not container.isImplementation %}
\(Templates.typeErasure.indented())
private var __defaultImplStub: \(typeErasureClassName){{ container.genericArguments }}?
{{ container.accessibility }} func enableDefaultImplementation<\(staticGenericParameter): {{ container.name }}>(_ stub: \(staticGenericParameter)) where {{ container.genericProtocolIdentity }} {
var mutableStub = stub
__defaultImplStub = \(typeErasureClassName)(from: &mutableStub, keeping: mutableStub)
cuckoo_manager.enableDefaultStubImplementation()
}
{{ container.accessibility }} func enableDefaultImplementation<\(staticGenericParameter): {{ container.name }}>(mutating stub: UnsafeMutablePointer<\(staticGenericParameter)>) where {{ container.genericProtocolIdentity }} {
__defaultImplStub = \(typeErasureClassName)(from: stub, keeping: nil)
cuckoo_manager.enableDefaultStubImplementation()
}
{% else %}
private var __defaultImplStub: {{ container.name }}{{ container.genericArguments }}?
{{ container.accessibility }} func enableDefaultImplementation(_ stub: {{ container.name }}{{ container.genericArguments }}) {
__defaultImplStub = stub
cuckoo_manager.enableDefaultStubImplementation()
}
{% endif %}
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% if debug %}
// {{property}}
{% endif %}
{% for attribute in property.attributes %}
{{ attribute.text }}
{% endfor %}
{{ property.accessibility }}{% if container.isImplementation %} override{% endif %} var {{ property.name }}: {{ property.type }} {
get {
return cuckoo_manager.getter("{{ property.name }}",
superclassCall:
{% if container.isImplementation %}
super.{{ property.name }}
{% else %}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{% endif %},
defaultCall: __defaultImplStub!.{{property.name}})
}
{% ifnot property.isReadOnly %}
set {
cuckoo_manager.setter("{{ property.name }}",
value: newValue,
superclassCall:
{% if container.isImplementation %}
super.{{ property.name }} = newValue
{% else %}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{% endif %},
defaultCall: __defaultImplStub!.{{property.name}} = newValue)
}
{% endif %}
}
{% if property.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for initializer in container.initializers %}
{{ initializer.unavailablePlatformsCheck }}
{% if debug %}
// {{initializer}}
{% endif %}
{{ initializer.accessibility }}{% if container.isImplementation %} override{% endif %}{% if initializer.@type == "ProtocolMethod" %} required{% endif %} init({{initializer.parameterSignature}}) {
{% if container.isImplementation %}
super.init({{initializer.call}})
{% endif %}
}
{% if initializer.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% if debug %}
// {{method}}
{% endif %}
{% for attribute in method.attributes %}
{{ attribute.text }}
{% endfor %}
{{ method.accessibility }}{% if container.isImplementation and method.isOverriding %} override{% endif %} func {{ method.name|escapeReservedKeywords }}{{ method.genericParameters }}({{ method.parameterSignature }}) {{ method.returnSignature }} {
{{ method.self|openNestedClosure }}
return{% if method.isThrowing %} try{% endif %}{% if method.isAsync %} await{% endif %} cuckoo_manager.call{% if method.isThrowing %}{{ method.throwType|capitalize }}{% endif %}(
\"\"\"
{{method.fullyQualifiedName}}
\"\"\",
parameters: ({{method.parameterNames}}),
escapingParameters: ({{method.escapingParameterNames}}),
superclassCall:
{% if container.isImplementation %}
{% if method.isAsync %}await {% endif %}super.{{method.name}}({{method.call}})
{% else %}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{% endif %},
defaultCall: {% if method.isAsync %}await {% endif %}__defaultImplStub!.{{method.name}}{%if method.isOptional %}!{%endif%}({{method.call}}))
{{ method.parameters|closeNestedClosure }}
}
{% if method.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
\(Templates.stubbingProxy.indented())
\(Templates.verificationProxy.indented())
}
\(Templates.noImplStub)
{% if container.hasParent %}
}
{% endif %}
{% if container.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
"""
}

View File

@ -1,48 +0,0 @@
public enum Accessibility: String {
case Open = "source.lang.swift.accessibility.open"
case Public = "source.lang.swift.accessibility.public"
case Internal = "source.lang.swift.accessibility.internal"
case Private = "source.lang.swift.accessibility.private"
case FilePrivate = "source.lang.swift.accessibility.fileprivate"
public var sourceName: String {
switch self {
case .Open:
fallthrough
case .Public:
return "public"
case .Internal:
return ""
case .Private:
return "private"
case .FilePrivate:
return "fileprivate"
}
}
public var isAccessible: Bool {
return self != .Private && self != .FilePrivate
}
}
extension Accessibility: Comparable {
/// How open is this accessibility. The higher number the more accessible.
private var openness: Int {
switch self {
case .Open:
return 4
case .Public:
return 3
case .Internal:
return 2
case .FilePrivate:
return 1
case .Private:
return 0
}
}
public static func < (lhs: Accessibility, rhs: Accessibility) -> Bool {
return lhs.openness < rhs.openness
}
}

View File

@ -1,60 +0,0 @@
import Foundation
public struct Attribute: Hashable {
public enum Kind: String, Hashable {
case objc = "source.decl.attribute.objc"
case optional = "source.decl.attribute.optional"
case lazy = "source.decl.attribute.lazy"
case required = "source.decl.attribute.required"
case override = "source.decl.attribute.override"
case convenience = "source.decl.attribute.convenience"
case weak = "source.decl.attribute.weak"
case ibAction = "source.decl.attribute.ibaction"
case ibOutlet = "source.decl.attribute.iboutlet"
case available = "source.decl.attribute.available"
case final = "source.decl.attribute.final"
}
public var kind: Kind
public var text: String
public var isSupported: Bool {
switch (kind) {
case .objc, .optional, .lazy, .required, .override, .convenience, .weak, .ibAction, .ibOutlet, .final:
return false
case .available:
return true
}
}
public var unavailablePlatform: String? {
guard kind == .available,
text.hasPrefix("@available(") else {
return nil
}
let parameters = text
.dropFirst("@available(".count)
.dropLast()
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
guard parameters.count >= 2,
parameters[1] == "unavailable" else {
return nil
}
return String(parameters[0])
}
}
extension Attribute: Token {
public func isEqual(to other: Token) -> Bool {
guard let otherAttribute = other as? Attribute else { return false }
return self.kind == otherAttribute.kind && self.text == otherAttribute.text
}
public func serialize() -> [String : Any] {
return ["text": text]
}
}

View File

@ -1,5 +0,0 @@
import Foundation
public protocol ChildToken: Token {
var parent: Reference<ParentToken>? { get set }
}

View File

@ -1,37 +0,0 @@
public struct ClassDeclaration: ContainerToken, HasAccessibility {
public let implementation: Bool = true
public var name: String
public var parent: Reference<ParentToken>?
public var accessibility: Accessibility
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var bodyRange: CountableRange<Int>
public var initializers: [Initializer]
public var children: [Token]
public var inheritedTypes: [InheritanceDeclaration]
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var hasNoArgInit: Bool {
return initializers.filter { $0.parameters.isEmpty }.isEmpty
}
public func replace(children tokens: [Token]) -> ClassDeclaration {
return ClassDeclaration(
name: self.name,
parent: self.parent,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: tokens,
inheritedTypes: self.inheritedTypes,
attributes: self.attributes,
genericParameters: self.genericParameters)
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ClassDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -1,17 +0,0 @@
public struct ClassMethod: Method {
public var name: String
public var accessibility: Accessibility
public var returnSignature: ReturnSignature
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var parameters: [MethodParameter]
public var bodyRange: CountableRange<Int>
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isOptional: Bool {
return false
}
public var isOverriding: Bool {
return true
}
}

View File

@ -1,63 +0,0 @@
public protocol ContainerToken: ParentToken, ChildToken {
var initializers: [Initializer] { get }
var implementation: Bool { get }
var inheritedTypes: [InheritanceDeclaration] { get }
var genericParameters: [GenericParameter] { get }
}
extension ContainerToken {
public func serialize() -> [String : Any] {
func withAdjustedAccessibility(token: Token & HasAccessibility) -> Token & HasAccessibility {
// We only want to adjust tokens that are accessible and lower than the enclosing type
guard token.accessibility.isAccessible && token.accessibility < accessibility else { return token }
var mutableToken = token
mutableToken.accessibility = accessibility
return mutableToken
}
let accessibilityAdjustedChildren = children.map { child -> Token in
guard let childWithAccessibility = child as? HasAccessibility & Token else { return child }
return withAdjustedAccessibility(token: childWithAccessibility)
}
let properties = accessibilityAdjustedChildren.compactMap { $0 as? InstanceVariable }
.filter { $0.accessibility.isAccessible }
.map { $0.serializeWithType() }
let methods = accessibilityAdjustedChildren.compactMap { $0 as? Method }
.filter { $0.accessibility.isAccessible && !$0.isInit && !$0.isDeinit }
.map { $0.serializeWithType() }
let initializers = accessibilityAdjustedChildren.compactMap { $0 as? Method }
.filter { $0.accessibility.isAccessible && $0.isInit && !$0.isDeinit }
.map { $0.serializeWithType() }
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
let genericArgumentsString = genericParameters.map { $0.name }.joined(separator: ", ")
let genericProtocolIdentity = genericParameters.map { "\(Templates.staticGenericParameter).\($0.name) == \($0.name)" }.joined(separator: ", ")
let isGeneric = !genericParameters.isEmpty
return [
"name": name,
"accessibility": accessibility.sourceName,
"isAccessible": accessibility.isAccessible,
"hasParent": parent != nil,
"parentFullyQualifiedName": parent?.fullyQualifiedName ?? "",
"children": accessibilityAdjustedChildren.map { $0.serializeWithType() },
"properties": properties,
"methods": methods,
"initializers": implementation ? [] : initializers,
"isImplementation": implementation,
"mockName": "Mock\(name)",
"inheritedTypes": inheritedTypes,
"attributes": attributes.filter { $0.isSupported },
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
"isGeneric": isGeneric,
"genericParameters": isGeneric ? "<\(genericParametersString)>" : "",
"genericArguments": isGeneric ? "<\(genericArgumentsString)>" : "",
"genericProtocolIdentity": genericProtocolIdentity,
"isNSObjectProtocol": (self as? ProtocolDeclaration)?.isNSObjectProtocol ?? false
]
}
}

View File

@ -1,15 +0,0 @@
public struct ExtensionDeclaration: ParentToken {
// TODO Implement support for extensions
public let name: String
public var accessibility: Accessibility
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let bodyRange: CountableRange<Int>
public var attributes: [Attribute]
public let children: [Token]
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ExtensionDeclaration else { return false }
return self.range == other.range
}
}

View File

@ -1,71 +0,0 @@
import SourceKittenFramework
public struct FileRepresentation {
public let sourceFile: File
public let declarations: [Token]
public init(sourceFile: File, declarations: [Token]) {
self.sourceFile = sourceFile
self.declarations = declarations
}
}
public extension FileRepresentation {
func mergeInheritance(with files: [FileRepresentation]) -> FileRepresentation {
let tokens = self.declarations.reduce([Token]()) { list, token in
let mergeToken = token.mergeInheritance(with: files)
return list + [mergeToken]
}
return FileRepresentation(sourceFile: self.sourceFile, declarations: tokens)
}
func inheritNSObject(subjects: [ProtocolDeclaration]) -> FileRepresentation {
FileRepresentation(sourceFile: self.sourceFile, declarations: self.declarations.map { $0.inheritNSObject(subjects: subjects) })
}
}
extension Token {
func mergeInheritance(with files: [FileRepresentation]) -> Token {
guard let typeToken = self as? ContainerToken else {
return self
}
let inheritedRepresentations: [Token] = typeToken.inheritedTypes
.compactMap { Self.findToken(forClassOrProtocol: $0.name, in: files) }
.compactMap { $0.mergeInheritance(with: files) }
// Merge super declarations
let mergedTokens = inheritedRepresentations.filter { $0.isClassOrProtocolDeclaration }
.map { $0 as! ContainerToken }
.flatMap { $0.children }
.reduce(typeToken.children) { tokens, inheritedToken in
if tokens.contains(where: { $0 == inheritedToken }) {
return tokens
}
return tokens + [inheritedToken]
}
switch typeToken {
case let classToken as ClassDeclaration:
return classToken.replace(children: mergedTokens)
case let protocolToken as ProtocolDeclaration:
return protocolToken.replace(children: mergedTokens)
default:
return typeToken
}
}
func inheritNSObject(subjects: [ProtocolDeclaration]) -> Token {
guard let protocolToken = self as? ProtocolDeclaration else {
return self
}
return subjects.contains { $0.name == protocolToken.name } ? protocolToken.replace(isNSObjectProtocol: true) : self
}
static func findToken(forClassOrProtocol name: String, in files: [FileRepresentation]) -> Token? {
return files.flatMap { $0.declarations }
.filter { $0.isClassOrProtocolDeclaration }
.map { $0 as! ContainerToken }
.first { $0.name == name }
}
}

View File

@ -1,24 +0,0 @@
import Foundation
public struct GenericParameter: Token {
public let name: String
public let range: CountableRange<Int>
public let inheritedType: InheritanceDeclaration?
public var description: String {
let hasInheritedType = inheritedType != nil
return "\(name)\(hasInheritedType ? ": " : "")\(inheritedType?.name ?? "")"
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? GenericParameter else { return false }
return self.name == other.name && self.range == other.range && self.inheritedType?.name == other.inheritedType?.name
}
public func serialize() -> [String : Any] {
return [
"name": name,
"inheritedType": inheritedType,
]
}
}

View File

@ -1,5 +0,0 @@
import Foundation
public protocol HasAccessibility {
var accessibility: Accessibility { get set }
}

View File

@ -1,19 +0,0 @@
import Foundation
public protocol HasAttributes {
var attributes: [Attribute] { get }
}
extension HasAttributes {
private var unavailablePlatforms: [String] {
return attributes.lazy.compactMap { $0.unavailablePlatform }
}
var hasUnavailablePlatforms: Bool {
return !unavailablePlatforms.isEmpty
}
var unavailablePlatformsCheck: String {
return hasUnavailablePlatforms ? "#if !os(\(unavailablePlatforms.joined(separator: ") && !os(")))" : ""
}
}

View File

@ -1,30 +0,0 @@
public struct Import: Token {
public enum Importee: CustomStringConvertible {
case library(name: String)
case component(componentType: String?, library: String, name: String)
public var description: String {
switch self {
case .library(let name):
return name
case .component(let componentType, let library, let name):
return [componentType, "\(library).\(name)"].compactMap { $0 }.joined(separator: " ")
}
}
}
public let range: CountableRange<Int>
public let importee: Importee
public func isEqual(to other: Token) -> Bool {
guard let other = other as? Import, self.range == other.range else { return false }
switch (self.importee, other.importee) {
case (.library(let lhsName), .library(let rhsName)):
return lhsName == rhsName
case (.component(let lhsImportType, let lhsLibrary, let lhsName), .component(let rhsImportType, let rhsLibrary, let rhsName)):
return lhsImportType == rhsImportType && lhsLibrary == rhsLibrary && lhsName == rhsName
default:
return false
}
}
}

View File

@ -1,9 +0,0 @@
public struct InheritanceDeclaration: Token {
public static let empty = InheritanceDeclaration(name: Tokenizer.nameNotSet)
public let name: String
public func isEqual(to other: Token) -> Bool {
guard let other = other as? InheritanceDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -1,17 +0,0 @@
public struct Initializer: Method, HasAccessibility {
public var name: String
public var accessibility: Accessibility
public var returnType: WrappableType
public var returnSignature: ReturnSignature
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var parameters: [MethodParameter]
public var isOverriding: Bool
public var required: Bool
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isOptional: Bool {
return false
}
}

View File

@ -1,41 +0,0 @@
public struct InstanceVariable: Token, HasAccessibility, HasAttributes {
public var name: String
public var type: WrappableType
public var accessibility: Accessibility
public var setterAccessibility: Accessibility?
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var overriding: Bool
public var attributes: [Attribute]
public var readOnly: Bool {
if let setterAccessibility = setterAccessibility {
return !setterAccessibility.isAccessible
} else {
return true
}
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? InstanceVariable else { return false }
return self.name == other.name
}
public func serialize() -> [String : Any] {
let readOnlyString = readOnly ? "ReadOnly" : ""
let optionalString = type.isOptional && !readOnly ? "Optional" : ""
return [
"name": name,
"type": type.sugarized,
"nonOptionalType": type.unoptionaled.sugarized,
"accessibility": accessibility.sourceName,
"isReadOnly": readOnly,
"stubType": (overriding ? "Class" : "Protocol") + "ToBeStubbed\(readOnlyString)\(optionalString)Property",
"verifyType": "Verify\(readOnlyString)\(optionalString)Property",
"attributes": attributes.filter { $0.isSupported },
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
]
}
}

View File

@ -1,20 +0,0 @@
public enum Key: String {
case Substructure = "key.substructure"
case Kind = "key.kind"
case Accessibility = "key.accessibility"
case SetterAccessibility = "key.setter_accessibility"
case Name = "key.name"
case TypeName = "key.typename"
case InheritedTypes = "key.inheritedtypes"
case Attributes = "key.attributes"
case Attribute = "key.attribute"
case Length = "key.length"
case Offset = "key.offset"
case NameLength = "key.namelength"
case NameOffset = "key.nameoffset"
case BodyLength = "key.bodylength"
case BodyOffset = "key.bodyoffset"
}

View File

@ -1,12 +0,0 @@
public enum Kinds: String {
case ProtocolDeclaration = "source.lang.swift.decl.protocol"
case InstanceMethod = "source.lang.swift.decl.function.method.instance"
case MethodParameter = "source.lang.swift.decl.var.parameter"
case ClassDeclaration = "source.lang.swift.decl.class"
case StructDeclaration = "source.lang.swift.decl.struct"
case ExtensionDeclaration = "source.lang.swift.decl.extension"
case InstanceVariable = "source.lang.swift.decl.var.instance"
case GenericParameter = "source.lang.swift.decl.generic_type_param"
case AssociatedType = "source.lang.swift.decl.associatedtype"
case Optional = "source.decl.attribute.optional"
}

View File

@ -1,156 +0,0 @@
import Foundation
public protocol Method: Token, HasAccessibility, HasAttributes {
var name: String { get }
var returnSignature: ReturnSignature { get }
var range: CountableRange<Int> { get }
var nameRange: CountableRange<Int> { get }
var parameters: [MethodParameter] { get }
var isOptional: Bool { get }
var isOverriding: Bool { get }
var hasClosureParams: Bool { get }
var hasOptionalParams: Bool { get }
var genericParameters: [GenericParameter] { get }
}
public extension Method {
var rawName: String {
return name.takeUntil(occurence: "(") ?? ""
}
var isInit: Bool {
return rawName == "init"
}
var isDeinit: Bool {
return rawName == "deinit"
}
var fullyQualifiedName: String {
let parameterTypes = parameters.map { ($0.isInout ? "inout " : "") + $0.type.sugarized }
let nameParts = name.components(separatedBy: ":")
let lastNamePart = nameParts.last ?? ""
let returnSignatureDescription = returnSignature.description
let returnSignatureString = returnSignatureDescription.isEmpty ? "" : " \(returnSignatureDescription)"
return zip(nameParts.dropLast(), parameterTypes)
.map { $0 + ": " + $1 }
.joined(separator: ", ") + lastNamePart + returnSignatureString
}
var isAsync: Bool {
return returnSignature.isAsync
}
var isThrowing: Bool {
guard let throwType = returnSignature.throwType else { return false }
return throwType.isThrowing || throwType.isRethrowing
}
var returnType: WrappableType {
return returnSignature.returnType
}
var hasClosureParams: Bool {
return parameters.contains { $0.isClosure }
}
var hasOptionalParams: Bool {
return parameters.contains { $0.isOptional }
}
func isEqual(to other: Token) -> Bool {
guard let other = other as? Method else { return false }
return self.name == other.name && self.parameters == other.parameters && self.returnType == other.returnType
}
func serialize() -> [String : Any] {
let call = parameters.map {
let referencedName = "\($0.isInout ? "&" : "")\($0.name)\($0.isAutoClosure ? "()" : "")"
if let label = $0.label {
return "\(label): \(referencedName)"
} else {
return referencedName
}
}.joined(separator: ", ")
let stubFunctionPrefix = isOverriding ? "Class" : "Protocol"
let returnString = returnType.sugarized == "Void" ? "NoReturn" : ""
let throwingString = isThrowing ? "Throwing" : ""
let stubFunction = "Cuckoo.\(stubFunctionPrefix)Stub\(returnString)\(throwingString)Function"
let escapingParameterNames = parameters.map { parameter in
if parameter.isClosure && !parameter.isEscaping {
let parameterCount = parameter.closureParamCount
let parameterSignature = parameterCount > 0 ? (1...parameterCount).map { _ in "_" }.joined(separator: ", ") : "()"
// FIXME: Instead of parsing the closure return type here, Tokenizer should do it and pass the information in a data structure
let returnSignature: String
let closureReturnType = extractClosureReturnType(parameter: parameter.type.sugarized)
if let closureReturnType = closureReturnType, !closureReturnType.isEmpty && closureReturnType != "Void" {
returnSignature = " -> " + closureReturnType
} else {
returnSignature = ""
}
return "{ \(parameterSignature)\(returnSignature) in fatalError(\"This is a stub! It's not supposed to be called!\") }"
} else {
return parameter.name
}
}.joined(separator: ", ")
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
let isGeneric = !genericParameters.isEmpty
return [
"self": self,
"name": rawName,
"accessibility": accessibility.sourceName,
"returnSignature": returnSignature.description,
"parameters": parameters,
"parameterNames": parameters.map { $0.name }.joined(separator: ", "),
"escapingParameterNames": escapingParameterNames,
"isInit": isInit,
"returnType": returnType.explicitOptionalOnly.sugarized,
"isAsync": isAsync,
"isThrowing": isThrowing,
"throwType": returnSignature.throwType?.description ?? "",
"fullyQualifiedName": fullyQualifiedName,
"call": call,
"isOverriding": isOverriding,
"parameterSignature": parameters.map { "\($0.labelAndName): \($0.isInout ? "inout " : "")\($0.type)" }.joined(separator: ", "),
"parameterSignatureWithoutNames": parameters.map { "\($0.name): \($0.type)" }.joined(separator: ", "),
"argumentSignature": parameters.map { $0.type.description }.joined(separator: ", "),
"stubFunction": stubFunction,
"inputTypes": parameters.map { $0.typeWithoutAttributes }.joined(separator: ", "),
"isOptional": isOptional,
"hasClosureParams": hasClosureParams,
"hasOptionalParams": hasOptionalParams,
"attributes": attributes.filter { $0.isSupported },
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
"genericParameters": isGeneric ? "<\(genericParametersString)>" : "",
]
}
private func extractClosureReturnType(parameter: String) -> String? {
var parenLevel = 0
for i in 0..<parameter.count {
let index = parameter.index(parameter.startIndex, offsetBy: i)
let character = parameter[index]
if character == "(" {
parenLevel += 1
} else if character == ")" {
parenLevel -= 1
if parenLevel == 0 {
let returnSignature = String(parameter[parameter.index(after: index)..<parameter.endIndex])
let regex = try! NSRegularExpression(pattern: "\\s*->\\s*(.*)\\s*")
guard let result = regex.matches(in: returnSignature, range: NSRange(location: 0, length: returnSignature.count)).first else { return nil }
return returnSignature[result.range(at: 1)]
}
}
}
return nil
}
}

View File

@ -1,83 +0,0 @@
public struct MethodParameter: Token, Equatable {
public var label: String?
public var name: String
public var type: WrappableType
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>?
public var isInout: Bool
public var labelAndName: String {
if let label = label {
return label != name ? "\(label) \(name)" : name
} else {
return "_ \(name)"
}
}
public var typeWithoutAttributes: String {
return type.withoutAttributes.sugarized.trimmed
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? MethodParameter else { return false }
return label == other.label && type == other.type
}
public var isClosure: Bool {
return typeWithoutAttributes.hasPrefix("(") && typeWithoutAttributes.range(of: "->") != nil
}
public var isAutoClosure: Bool {
type.containsAttribute(named: "@autoclosure")
}
public var isOptional: Bool {
return type.isOptional
}
public var closureParamCount: Int {
// make sure that the parameter is a closure and that it's not just an empty `() -> ...` closure
guard isClosure && !"^\\s*\\(\\s*\\)".regexMatches(typeWithoutAttributes) else { return 0 }
var parenLevel = 0
var parameterCount = 1
for character in typeWithoutAttributes {
switch character {
case "(", "<":
parenLevel += 1
case ")", ">":
parenLevel -= 1
case ",":
parameterCount += parenLevel == 1 ? 1 : 0
default:
break
}
if parenLevel == 0 {
break
}
}
return parameterCount
}
public var isEscaping: Bool {
return isClosure && (type.containsAttribute(named: "@escaping") || type.isOptional)
}
public func serialize() -> [String : Any] {
return [
"label": label ?? "",
"name": name,
"type": type,
"labelAndName": labelAndName,
"typeWithoutAttributes": typeWithoutAttributes,
"isClosure": isClosure,
"isOptional": isOptional,
"isEscaping": isEscaping
]
}
}
public func ==(lhs: MethodParameter, rhs: MethodParameter) -> Bool {
return lhs.isEqual(to: rhs)
}

View File

@ -1,43 +0,0 @@
import Foundation
public protocol ParentToken: Token, HasAccessibility, HasAttributes {
var name: String { get }
var range: CountableRange<Int> { get }
var nameRange: CountableRange<Int> { get }
var bodyRange: CountableRange<Int> { get }
var children: [Token] { get }
}
extension ParentToken {
var fullyQualifiedName: String {
var names = [name]
var parent: ParentToken? = (self as? ChildToken)?.parent?.value
while let p = parent {
names.insert(p.name, at: 0)
parent = (p as? ChildToken)?.parent?.value
}
return names.joined(separator: ".")
}
var areAllHierarchiesAccessible: Bool {
guard accessibility.isAccessible else { return false }
var parent: ParentToken? = (self as? ChildToken)?.parent?.value
while let p = parent {
guard p.accessibility.isAccessible else { return false }
parent = (p as? ChildToken)?.parent?.value
}
return true
}
func adoptAllYoungerGenerations() -> [ParentToken] {
let parentReference: Reference<ParentToken> = Reference(value: self)
return children
.compactMap { child -> ParentToken? in
guard var c = child as? ContainerToken else { return nil }
c.parent = parentReference
return c
}
.flatMap { [$0] + $0.adoptAllYoungerGenerations() }
}
}

View File

@ -1,54 +0,0 @@
public struct ProtocolDeclaration: ContainerToken, HasAccessibility {
public let implementation: Bool = false
public var name: String
public var parent: Reference<ParentToken>?
public var accessibility: Accessibility
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var bodyRange: CountableRange<Int>
public var initializers: [Initializer]
public var children: [Token]
public var inheritedTypes: [InheritanceDeclaration]
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isNSObjectProtocol: Bool
public func replace(children tokens: [Token]) -> ProtocolDeclaration {
return ProtocolDeclaration(
name: self.name,
parent: self.parent,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: tokens,
inheritedTypes: self.inheritedTypes,
attributes: self.attributes,
genericParameters: self.genericParameters,
isNSObjectProtocol: self.isNSObjectProtocol
)
}
public func replace(isNSObjectProtocol: Bool) -> ProtocolDeclaration {
ProtocolDeclaration(
name: self.name,
parent: self.parent,
accessibility: self.accessibility,
range: self.range,
nameRange: self.nameRange,
bodyRange: self.bodyRange,
initializers: self.initializers,
children: self.children,
inheritedTypes: self.inheritedTypes,
attributes: self.attributes,
genericParameters: self.genericParameters,
isNSObjectProtocol: isNSObjectProtocol
)
}
public func isEqual(to other: Token) -> Bool {
guard let other = other as? ProtocolDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -1,17 +0,0 @@
public struct ProtocolMethod: Method {
public var name: String
public var accessibility: Accessibility
public var returnSignature: ReturnSignature
public var range: CountableRange<Int>
public var nameRange: CountableRange<Int>
public var parameters: [MethodParameter]
public var attributes: [Attribute]
public var genericParameters: [GenericParameter]
public var isOptional: Bool {
return attributes.map { $0.kind }.contains(.optional)
}
public var isOverriding: Bool {
return false
}
}

View File

@ -1,29 +0,0 @@
import Foundation
public struct ReturnSignature {
public var isAsync: Bool
public var throwType: ThrowType?
public var returnType: WrappableType
public var whereConstraints: [String]
public init(isAsync: Bool, throwString: String?, returnType: WrappableType, whereConstraints: [String]) {
self.isAsync = isAsync
if let throwString = throwString {
throwType = ThrowType(string: throwString)
} else {
throwType = nil
}
self.returnType = returnType
self.whereConstraints = whereConstraints
}
}
extension ReturnSignature: CustomStringConvertible {
public var description: String {
let asyncString = isAsync ? "async" : nil
let trimmedReturnType = returnType.explicitOptionalOnly.sugarized.trimmed
let returnString = trimmedReturnType.isEmpty || trimmedReturnType == "Void" ? nil : "-> \(returnType)"
let whereString = whereConstraints.isEmpty ? nil : "where \(whereConstraints.joined(separator: ", "))"
return [asyncString, throwType?.description, returnString, whereString].compactMap { $0 }.joined(separator: " ")
}
}

View File

@ -1,17 +0,0 @@
import Foundation
public struct StructDeclaration: ParentToken {
// NOTE: Purely for supporting nested classes, could be any generic parent (like extensions)
public let name: String
public var accessibility: Accessibility
public let range: CountableRange<Int>
public let nameRange: CountableRange<Int>
public let bodyRange: CountableRange<Int>
public var attributes: [Attribute]
public let children: [Token]
public func isEqual(to other: Token) -> Bool {
guard let other = other as? StructDeclaration else { return false }
return self.name == other.name
}
}

View File

@ -1,31 +0,0 @@
public enum ThrowType: CustomStringConvertible {
case throwing
case rethrowing
public init?(string: String) {
if string.trimmed.hasPrefix("throws") {
self = .throwing
} else if string.trimmed.hasPrefix("rethrows") {
self = .rethrowing
} else {
return nil
}
}
public var isThrowing: Bool {
return self == .throwing
}
public var isRethrowing: Bool {
return self == .rethrowing
}
public var description: String {
switch self {
case .throwing:
return "throws"
case .rethrowing:
return "rethrows"
}
}
}

View File

@ -1,29 +0,0 @@
public protocol Token {
func isEqual(to other: Token) -> Bool
func serialize() -> [String: Any]
}
public func ==(rhs: Token, lhs: Token) -> Bool {
return rhs.isEqual(to: lhs)
}
public extension Token {
func serialize() -> [String: Any] {
return [:]
}
func serializeWithType() -> [String: Any] {
var serialized = serialize()
serialized["@type"] = "\(type(of: self))"
return serialized
}
var isClassOrProtocolDeclaration: Bool {
return self is ProtocolDeclaration || self is ClassDeclaration
}
var isInheritanceDeclaration: Bool {
return self is InheritanceDeclaration
}
}

View File

@ -1,12 +1,12 @@
import Foundation
import FileKit
public enum CuckooGeneratorError: Error {
enum CuckooGeneratorError: Error {
case ioError(FileKitError)
case unknownError(Error)
case stderrUsed
public var description: String {
var description: String {
switch self {
case .ioError(let error):
return error.description

View File

@ -1,38 +1,40 @@
import Foundation
import Commandant
import Result
import SourceKittenFramework
import FileKit
private func curry<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R>
(_ f: @escaping (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R)
-> (P1) -> (P2) -> (P3) -> (P4) -> (P5) -> (P6) -> (P7) -> (P8) -> (P9) -> (P10) -> (P11) -> (P12) -> R {
return { p1 in { p2 in { p3 in { p4 in { p5 in { p6 in { p7 in { p8 in { p9 in { p10 in { p11 in { p12 in
f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)
} } } } } } } } } } } }
}
struct GenerateMocksCommand: CommandProtocol {
typealias TokenFilter = (Token) -> Bool
public struct GenerateMocksCommand: CommandProtocol {
let verb = "generate"
let function = "Generates mock files"
public let verb = "generate"
public let function = "Generates mock files"
public func run(_ options: Options) -> Result<Void, CuckooGeneratorError> {
let getFullPathSortedArray: ([String]) -> [String] = { stringArray in
Array(Set(stringArray.map { Path($0).standardRawValue })).sorted()
}
func run(_ options: Options) -> Result<Void, CuckooGeneratorError> {
let inputPathValues: [String]
if options.globEnabled {
inputPathValues = getFullPathSortedArray(options.files.flatMap { Glob(pattern: $0).paths })
if options.isGlobEnabled {
inputPathValues = options.files.flatMap { Glob(pattern: $0).paths }
} else {
inputPathValues = getFullPathSortedArray(options.files)
inputPathValues = options.files
}
let inputFiles = inputPathValues.map { File(path: $0) }.compactMap { $0 }
let tokens = inputFiles.map { Tokenizer(sourceFile: $0, debugMode: options.debugMode).tokenize() }
let tokensWithInheritance = options.noInheritance ? tokens : inheritNSObject(mergeInheritance(tokens))
let sortedInputPathValues = Array(Set(inputPathValues.map { Path($0).standardRawValue })).sorted()
let inputFiles = sortedInputPathValues
.map { Path($0) }
.filter { $0.exists }
.map(TextFile.init(path:))
// try! Crawler.crawl(url: URL(string: "www.google.com")!)
// return .success(())
let files: [FileRepresentation] = inputFiles.compactMap { file in
guard let crawler = try? Crawler.crawl(url: file.path.url) else { return nil }
return FileRepresentation(file: file, imports: crawler.imports, tokens: crawler.tokens)
}
let flatMappedFiles = files.map { $0.flatMappingMemberContainers() }
let finalFiles = options.noInheritance ? flatMappedFiles : inheritNSObject(mergingInheritance(flatMappedFiles))
// filter classes/protocols based on the settings passed to the generator
var typeFilters = [] as [(Token) -> Bool]
var typeFilters: [TokenFilter] = []
if options.noClassMocking {
typeFilters.append(ignoreClasses)
}
@ -40,106 +42,105 @@ public struct GenerateMocksCommand: CommandProtocol {
typeFilters.append(keepMatching(pattern: options.regex))
}
if !options.exclude.isEmpty {
typeFilters.append(ignoreIfExists(in: options.exclude))
typeFilters.append(ignoreExcluded(in: options.exclude))
}
let parsedFiles = removeTypes(from: tokensWithInheritance, using: typeFilters)
let parsedFiles = removeTypes(from: finalFiles, using: typeFilters)
let mockableFiles = parsedFiles.map { $0.replacing(tokens: $0.tokens.filter { $0.isMockable }) }
// generating headers and mocks
let headers = parsedFiles.map { options.noHeader ? "" : FileHeaderHandler.getHeader(of: $0, includeTimestamp: !options.noTimestamp) }
let imports = parsedFiles.map { FileHeaderHandler.getImports(of: $0, testableFrameworks: options.testableFrameworks) }
let mocks = parsedFiles.map { try! Generator(file: $0).generate(debug: options.debugMode) }
let mergedFiles = zip(zip(headers, imports), mocks).map { $0.0 + $0.1 + $1 }
let outputPath = Path(options.output)
let timestamp = options.noTimestamp || options.noHeader ? nil : Date().description
let generatedFileContents = try! mockableFiles.map { file in
[
options.noHeader ? nil : FileHeaderHandler.header(for: file, timestamp: timestamp),
FileHeaderHandler.imports(for: file, testableFrameworks: options.testableFrameworks),
try Generator.generate(tokens: file.tokens, debug: options.isDebug),
]
.compactMap { $0 }
.joined(separator: "\n\n")
}
do {
let outputPath = Path(options.output)
if outputPath.isDirectory {
let inputPaths = inputFiles.compactMap { $0.path }.map { Path($0) }
for (inputPath, outputText) in zip(inputPaths, mergedFiles) {
let inputPaths = inputFiles.map { $0.path }
for (inputPath, outputText) in zip(inputPaths, generatedFileContents) {
let fileName = options.filePrefix + inputPath.fileName
let outputFile = TextFile(path: outputPath + fileName)
try outputText |> outputFile
try outputFile.write(outputText)
}
} else {
let outputFile = TextFile(path: outputPath)
try mergedFiles.joined(separator: "\n") |> outputFile
try outputFile.write(generatedFileContents.joined(separator: "\n\n"))
}
} catch let error as FileKitError {
return .failure(.ioError(error))
} catch let error {
} catch {
return .failure(.unknownError(error))
}
return stderrUsed ? .failure(.stderrUsed) : .success(())
return .success(())
}
private func mergeInheritance(_ filesRepresentation: [FileRepresentation]) -> [FileRepresentation] {
return filesRepresentation.compactMap { $0.mergeInheritance(with: filesRepresentation) }
private func mergingInheritance(_ filesRepresentation: [FileRepresentation]) -> [FileRepresentation] {
return filesRepresentation.compactMap { $0.mergingInheritance(with: filesRepresentation) }
}
private func inheritNSObject(_ filesRepresentation: [FileRepresentation]) -> [FileRepresentation] {
func containsRecursively(name: String) -> Bool {
if let protocolDeclaration = protocolDeclarationDictionary[name] {
let collapsedInheritedTypesName = protocolDeclaration
.inheritedTypes
.map({ $0.name.components(separatedBy: "&") })
.joined()
.map({ $0.trimmingCharacters(in: .whitespaces) })
guard let protocolDeclaration = protocolDeclarationDictionary[name] else { return false }
let collapsedInheritedTypesName = protocolDeclaration.inheritedTypes
if collapsedInheritedTypesName.contains(where: { $0 == "NSObjectProtocol" }) {
return true
} else {
return protocolDeclaration.inheritedTypes.contains(where: { inheritanceType in
containsRecursively(name: inheritanceType.name)
})
return protocolDeclaration.inheritedTypes.contains { inheritanceType in
containsRecursively(name: inheritanceType)
}
} else {
return false
}
}
let protocolDeclarationDictionary: [String: ProtocolDeclaration] = Dictionary(
uniqueKeysWithValues: filesRepresentation.flatMap { file in
file.declarations.compactMap { token -> (name: String, protocolDeclaration: ProtocolDeclaration)? in
file.tokens.compactMap { token -> (name: String, protocolDeclaration: ProtocolDeclaration)? in
guard let protocolDeclaration = token as? ProtocolDeclaration else { return nil }
return (name: protocolDeclaration.name, protocolDeclaration: protocolDeclaration)
}
}
)
let nsObjectProtocols: [ProtocolDeclaration] = protocolDeclarationDictionary.values.reduce(into: []) { accumulator, protocolDeclaration in
let nsObjectProtocols: [ProtocolDeclaration] = protocolDeclarationDictionary.values.reduce(into: []) { protocols, protocolDeclaration in
guard containsRecursively(name: protocolDeclaration.name) else { return }
accumulator.append(protocolDeclaration)
protocols.append(protocolDeclaration)
}
return filesRepresentation.map { $0.inheritNSObject(subjects: nsObjectProtocols) }
return filesRepresentation.map { $0.inheritNSObject(protocols: nsObjectProtocols) }
}
private func removeTypes(from files: [FileRepresentation], using filters: [(Token) -> Bool]) -> [FileRepresentation] {
private func removeTypes(from files: [FileRepresentation], using filters: [TokenFilter]) -> [FileRepresentation] {
// Only keep those that pass all filters
let filter: (Token) -> Bool = { token in
!filters.contains { !$0(token) }
let filter: TokenFilter = { token in
guard token.isClass || token.isProtocol else { return true }
return !filters.contains { !$0(token) }
}
return files.compactMap { file in
let filteredDeclarations = file.declarations.filter(filter)
guard !filteredDeclarations.isEmpty else { return nil }
return FileRepresentation(sourceFile: file.sourceFile, declarations: filteredDeclarations)
let filteredTokens = file.tokens.filter(filter)
guard !filteredTokens.isEmpty else { return nil }
return file.replacing(tokens: filteredTokens)
}
}
// filter that keeps the protocols while removing all classes
private func ignoreClasses(token: Token) -> Bool {
return !(token is ClassDeclaration)
!token.isClass
}
// filter that keeps the classes/protocols that match the passed regular expression
private func keepMatching(pattern: String) -> (Token) -> Bool {
private func keepMatching(pattern: String) -> TokenFilter {
do {
let regex = try NSRegularExpression(pattern: pattern, options: [])
return { token in
guard let containerToken = token as? ContainerToken else { return true }
return regex.firstMatch(in: containerToken.name, options: [], range: NSMakeRange(0, containerToken.name.count)) != nil
guard let namedToken = token as? HasName else { return true }
return regex.firstMatch(in: namedToken.name, options: [], range: NSMakeRange(0, namedToken.name.count)) != nil
}
} catch {
fatalError("Invalid regular expression: " + (error as NSError).description)
@ -147,16 +148,16 @@ public struct GenerateMocksCommand: CommandProtocol {
}
// filter that keeps only the classes/protocols that are not supposed to be excluded
private func ignoreIfExists(in excluded: [String]) -> (Token) -> Bool {
private func ignoreExcluded(in excluded: [String]) -> TokenFilter {
let excludedSet = Set(excluded)
return { token in
guard let containerToken = token as? ContainerToken else { return true }
guard let containerToken = token as? HasName else { return true }
return !excludedSet.contains(containerToken.name)
}
}
public struct Options: OptionsProtocol {
struct Options: OptionsProtocol {
let files: [String]
let output: String
let noHeader: Bool
@ -166,11 +167,11 @@ public struct GenerateMocksCommand: CommandProtocol {
let exclude: [String]
let filePrefix: String
let noClassMocking: Bool
let debugMode: Bool
let globEnabled: Bool
let isDebug: Bool
let isGlobEnabled: Bool
let regex: String
public init(
init(
output: String,
testableFrameworks: String,
exclude: String,
@ -179,8 +180,8 @@ public struct GenerateMocksCommand: CommandProtocol {
noInheritance: Bool,
filePrefix: String,
noClassMocking: Bool,
debugMode: Bool,
globEnabled: Bool,
isDebug: Bool,
isGlobEnabled: Bool,
regex: String,
files: [String]
) {
@ -192,14 +193,14 @@ public struct GenerateMocksCommand: CommandProtocol {
self.noInheritance = noInheritance
self.filePrefix = filePrefix
self.noClassMocking = noClassMocking
self.debugMode = debugMode
self.globEnabled = globEnabled
self.isDebug = isDebug
self.isGlobEnabled = isGlobEnabled
self.regex = regex
self.files = files
}
// all options are declared here and then parsed by Commandant
public static func evaluate(_ m: CommandMode) -> Result<Options, CommandantError<CuckooGeneratorError>> {
static func evaluate(_ m: CommandMode) -> Result<Options, CommandantError<CuckooGeneratorError>> {
let output: Result<String, CommandantError<ClientError>> = m <| Option(key: "output", defaultValue: "GeneratedMocks.swift", usage: "Where to put the generated mocks.\nIf a path to a directory is supplied, each input file will have a respective output file with mocks.\nIf a path to a Swift file is supplied, all mocks will be in a single file.\nDefault value is `GeneratedMocks.swift`.")
let testable: Result<String, CommandantError<ClientError>> = m <| Option(key: "testable", defaultValue: "", usage: "A comma separated list of frameworks that should be imported as @testable in the mock files.")
@ -216,14 +217,16 @@ public struct GenerateMocksCommand: CommandProtocol {
let noClassMocking: Result<Bool, CommandantError<ClientError>> = m <| Option(key: "no-class-mocking", defaultValue: false, usage: "Do not generate mocks for classes.")
let debugMode: Result<Bool, CommandantError<ClientError>> = m <| Switch(flag: "d", key: "debug", usage: "Run generator in debug mode.")
let isDebug: Result<Bool, CommandantError<ClientError>> = m <| Switch(flag: "d", key: "debug", usage: "Run generator in debug mode.")
let globEnabled: Result<Bool, CommandantError<ClientError>> = m <| Switch(flag: "g", key: "glob", usage: "Use glob for specifying input paths.")
let isGlobEnabled: Result<Bool, CommandantError<ClientError>> = m <| Switch(flag: "g", key: "glob", usage: "Use glob for specifying input paths.")
let regex: Result<String, CommandantError<ClientError>> = m <| Option(key: "regex", defaultValue: "", usage: "A regular expression pattern that is used to match Classes and Protocols.\nAll that do not match are excluded.\nCan be used alongside `--exclude`.")
let input: Result<[String], CommandantError<ClientError>> = m <| Argument(usage: "Files to parse and generate mocks for.")
// If you want to add an option, make sure to extend the `curry` function below.
return curry(Options.init)
<*> output
<*> testable
@ -233,10 +236,19 @@ public struct GenerateMocksCommand: CommandProtocol {
<*> noInheritance
<*> filePrefix
<*> noClassMocking
<*> debugMode
<*> globEnabled
<*> isDebug
<*> isGlobEnabled
<*> regex
<*> input
}
}
}
// Unfortunately, Swift doesn't support variadic generic parameters as of now, so this monstrosity is necessary.
private func curry<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R>
(_ f: @escaping (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R)
->(P1)->(P2)->(P3)->(P4)->(P5)->(P6)->(P7)->(P8)->(P9)->(P10)->(P11)->(P12) -> R {
return { p1 in { p2 in { p3 in { p4 in { p5 in { p6 in { p7 in { p8 in { p9 in { p10 in { p11 in { p12 in
f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)
} } } } } } } } } } } }
}

View File

@ -0,0 +1,24 @@
import Foundation
import Commandant
import Result
struct VersionCommand: CommandProtocol {
static let appVersion = Bundle.allFrameworks.filter {
$0.bundleIdentifier == "org.brightify.CuckooGeneratorFramework"
}.first?.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
let verb = "version"
let function = "Prints the version of this generator."
func run(_ options: Options) -> Result<Void, CuckooGeneratorError> {
print(VersionCommand.appVersion)
return .success(())
}
struct Options: OptionsProtocol {
static func evaluate(_ m: CommandMode) -> Result<Options, CommandantError<CuckooGeneratorError>> {
return .success(Options())
}
}
}

View File

@ -0,0 +1,458 @@
import Foundation
import SwiftSyntax
import SwiftSyntaxParser
final class Crawler: SyntaxVisitor {
static func crawl(url: URL) throws -> Crawler {
let syntaxTree = try SyntaxParser.parse(url)
#if DEBUG
// Comment out the line above and uncomment the one below to test specific strings.
// The `testString` is at the bottom of this file.
// let syntaxTree = try SyntaxParser.parse(source: testString)
#endif
let crawler = Self(container: nil)
crawler.walk(syntaxTree)
return crawler
}
var imports: [Import] = []
var tokens: [Token] = []
private var container: Reference<Token>?
private init(container: Reference<Token>?) {
self.container = container
}
override func visit(_ node: ImportDeclSyntax) -> SyntaxVisitorContinueKind {
let path = node.path.description
if let importKind = node.importKind?.withoutTrivia().description {
// Component import.
imports.append(.component(kind: importKind, name: path))
} else {
// Target import.
imports.append(.library(name: path))
}
return .skipChildren
}
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
log(node)
// Skip `final` classes.
guard !node.modifiers.isFinal else { return .skipChildren }
var token = ClassDeclaration(
parent: container,
attributes: attributes(from: node.attributes),
accessibility: accessibility(from: node.modifiers) ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: node.identifier.withoutTrivia().description,
genericParameters: genericParameters(from: node.genericParameterClause?.genericParameterList),
genericRequirements: genericRequirements(from: node.genericWhereClause?.requirementList),
inheritedTypes: inheritedTypes(from: node.inheritanceClause?.inheritedTypeCollection),
members: []
)
// Early return for private namespace.
guard token.accessibility.isAccessible else { return .skipChildren }
let crawler = Crawler(container: Reference(token))
crawler.walk(members: node.members)
token.members = crawler.tokens
tokens.append(token)
return .skipChildren
}
override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
log(node)
let inheritedTypes = inheritedTypes(from: node.inheritanceClause?.inheritedTypeCollection)
var token = ProtocolDeclaration(
parent: container,
attributes: attributes(from: node.attributes),
accessibility: accessibility(from: node.modifiers) ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: node.identifier.withoutTrivia().description,
genericParameters: genericParameters(from: node.primaryAssociatedTypeClause?.primaryAssociatedTypeList) + associatedTypes(from: node.members.members),
genericRequirements: genericRequirements(from: node.genericWhereClause?.requirementList),
inheritedTypes: inheritedTypes,
members: []
)
// Early return for private namespace.
guard token.accessibility.isAccessible else { return .skipChildren }
let crawler = Crawler(container: Reference(token))
crawler.walk(members: node.members)
token.members = crawler.tokens
tokens.append(token)
return .skipChildren
}
// Enum mocking is not supported, this is used to parse nested classes.
override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
log(node)
var token = NamespaceDeclaration(
parent: container,
attributes: attributes(from: node.attributes),
accessibility: accessibility(from: node.modifiers) ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: node.identifier.withoutTrivia().description,
members: []
)
// Early return for private namespace.
guard token.accessibility.isAccessible else { return .skipChildren }
let crawler = Crawler(container: Reference(token))
crawler.walk(members: node.members)
token.members = crawler.tokens
tokens.append(token)
return .skipChildren
}
// Extension mocking is not supported, this is used to parse nested classes.
override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
log(node)
var token = NamespaceDeclaration(
parent: container,
attributes: attributes(from: node.attributes),
accessibility: accessibility(from: node.modifiers) ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: node.extendedType.withoutTrivia().description,
members: []
)
// Early return for private namespace.
guard token.accessibility.isAccessible else { return .skipChildren }
let crawler = Crawler(container: Reference(token))
crawler.walk(members: node.members)
token.members = crawler.tokens
tokens.append(token)
return .skipChildren
}
// Struct mocking is not supported, this is used to parse nested classes.
override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
log(node)
var token = NamespaceDeclaration(
parent: container,
attributes: attributes(from: node.attributes),
accessibility: accessibility(from: node.modifiers) ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: node.identifier.withoutTrivia().description,
members: []
)
// Early return for private namespace.
guard token.accessibility.isAccessible else { return .skipChildren }
let crawler = Crawler(container: Reference(token))
crawler.walk(members: node.members)
token.members = crawler.tokens
tokens.append(token)
return .skipChildren
}
override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
tokens.append(contentsOf: parse(node.withoutTrivia()))
return .skipChildren
}
override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
// TODO: Print the error.
if let initializer = try! parse(node.withoutTrivia()) {
tokens.append(initializer)
}
return .skipChildren
}
override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
// TODO: Print the error.
if let method = try! parse(node.withoutTrivia()) {
tokens.append(method)
}
return .skipChildren
}
private func walk(members: MemberDeclBlockSyntax) {
for member in members.members {
walk(member.withoutTrivia())
}
}
private func log(_ node: DeclSyntaxProtocol, additionalInfo: String? = nil) {
#if !DEBUG
return
#endif
let description: String
switch node {
case let node as ClassDeclSyntax:
description = "class \(node.identifier.withoutTrivia().description)"
case let node as ProtocolDeclSyntax:
description = "protocol \(node.identifier.withoutTrivia().description)"
case let node as StructDeclSyntax:
description = "struct \(node.identifier.withoutTrivia().description)"
case let node as ExtensionDeclSyntax:
description = "extension \(node.extendedType.withoutTrivia().description)"
default:
description = "Unknown declaration \(node.withoutTrivia().description)"
}
print([description, additionalInfo].compactMap { $0 }.joined(separator: " "))
}
}
// MARK: - Variable crawling.
extension Crawler {
private func parse(_ variableGroup: VariableDeclSyntax) -> [Variable] {
let isConstant = variableGroup.letOrVarKeyword.tokenKind == .letKeyword
guard !isConstant && !variableGroup.modifiers.isStatic && !variableGroup.modifiers.isFinal else { return [] }
let attributes = attributes(from: variableGroup.attributes)
var accessibility = Accessibility.internal
var setterAccessibility: Accessibility?
if let modifiers = variableGroup.modifiers {
for modifier in modifiers {
let tokenKind = modifier.name.tokenKind
guard let parsedAccessibility = Accessibility(tokenKind: tokenKind) else {
continue
}
if case .identifier(let detail) = modifier.detail?.tokenKind, detail == "set" {
setterAccessibility = parsedAccessibility
} else {
accessibility = parsedAccessibility
}
}
}
// Unnecessary now, but might come in handy later.
// let isOverriding = variableGroup.modifiers?.contains { $0.name.tokenKind == .identifier("override") } ?? false
return variableGroup.bindings
.compactMap(variable(from:))
.map {
Variable(
parent: container,
attributes: attributes,
accessibility: accessibility,
setterAccessibility: $0.isReadOnly ? nil : setterAccessibility ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: $0.identifier,
type: $0.type,
isOverriding: container?.isClass ?? false
)
}
}
private func variable(from binding: PatternBindingSyntax) -> VariablePart? {
guard case .identifier(let identifier) = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier.tokenKind else { return nil }
let type: String
if let explicitType = binding.typeAnnotation?.type.withoutTrivia().description {
type = explicitType
} else if let initializer = binding.initializer?.value.withoutTrivia().description {
type = TypeGuesser.guessType(from: initializer)!
} else {
fatalError("TODO: Can't infer type.")
}
let isReadOnly: Bool
if let accessor = binding.accessor {
let accessorsContainSet = accessor.as(AccessorBlockSyntax.self)?.accessors
.contains { $0.accessorKind.tokenKind == .contextualKeyword("set") } ?? false
isReadOnly = !accessorsContainSet
} else {
isReadOnly = false
}
return VariablePart(
identifier: identifier,
type: WrappableType(parsing: type),
isReadOnly: isReadOnly
)
}
private struct VariablePart {
var identifier: String
var type: WrappableType
var isReadOnly: Bool
}
}
extension Crawler {
private func parse(_ initializer: InitializerDeclSyntax) throws -> Initializer? {
Initializer(
parent: container,
attributes: attributes(from: initializer.attributes),
accessibility: initializer.modifiers?.lazy.compactMap { Accessibility(tokenKind: $0.name.tokenKind) }.first ?? (container as? HasAccessibility)?.accessibility ?? .internal,
signature: Method.Signature(
genericParameters: genericParameters(from: initializer.genericParameterClause?.genericParameterList),
parameters: try parameters(from: initializer.parameters.parameterList),
asyncType: nil,
throwType: initializer.throwsOrRethrowsKeyword.flatMap { ThrowType(rawValue: $0.withoutTrivia().description) },
returnType: nil,
whereConstraints: genericRequirements(from: initializer.genericWhereClause?.requirementList)
),
isRequired: initializer.modifiers?.contains { $0.name.tokenKind == .identifier("required") } ?? false,
isOptional: initializer.optionalMark?.isPresent == true
)
}
}
// MARK: - Method crawling.
extension Crawler {
private func parse(_ method: FunctionDeclSyntax) throws -> Method? {
// Can't mock static and final members.
guard !method.modifiers.isStatic && !method.modifiers.isFinal else { return nil }
guard case .identifier(let identifier) = method.identifier.tokenKind else { return nil }
return Method(
parent: container,
attributes: attributes(from: method.attributes),
accessibility: method.modifiers?.lazy.compactMap { Accessibility(tokenKind: $0.name.tokenKind) }.first ?? (container as? HasAccessibility)?.accessibility ?? .internal,
name: identifier,
signature: Method.Signature(
genericParameters: genericParameters(from: method.genericParameterClause?.genericParameterList),
parameters: try parameters(from: method.signature.input.parameterList),
asyncType: method.signature.asyncOrReasyncKeyword.flatMap { AsyncType(rawValue: $0.withoutTrivia().description) },
throwType: method.signature.throwsOrRethrowsKeyword.flatMap { ThrowType(rawValue: $0.withoutTrivia().description) },
returnType: method.signature.output.map { WrappableType(parsing: $0.returnType.withoutTrivia().description) } ?? WrappableType.type("Void"),
whereConstraints: genericRequirements(from: method.genericWhereClause?.requirementList)
),
isOptional: method.modifiers?.contains { $0.name.tokenKind == .identifier("optional") } ?? false,
isOverriding: container?.isClass ?? false
)
}
}
extension Crawler {
private func parameters(from parameterList: FunctionParameterListSyntax) throws -> [MethodParameter] {
try parameterList.map { parameter in
guard let name = parameter.firstName?.withoutTrivia().description else { throw CrawlError.parameterNameMissing }
guard let type = parameter.type else { throw CrawlError.parameterTypeMissing }
let bareType: String
let isInout: Bool
if let attributedType = type.as(AttributedTypeSyntax.self) {
isInout = attributedType.specifier?.tokenKind == .inoutKeyword
bareType = attributedType.withSpecifier(nil).description
} else {
isInout = false
bareType = type.description
}
let fullType = "\(bareType)\((parameter.ellipsis?.isPresent ?? false) ? "..." : "")"
return MethodParameter(
name: name,
innerName: nil,
type: WrappableType(parsing: fullType),
isInout: isInout
)
}
}
private func attributes(from attributeList: AttributeListSyntax?) -> [Attribute] {
attributeList?.children.compactMap { attribute in
guard let attribute = attribute.as(AttributeSyntax.self) else { return nil }
switch attribute.attributeName.tokenKind {
case .identifier("available"):
return .available(
arguments: attribute.argument?.description
.split(separator: ",")
.map { String($0).trimmed } ?? []
)
default:
print("Unsupported attribute '\(attribute.attributeName.text)'")
return nil
}
} ?? []
}
private func accessibility(from modifierList: ModifierListSyntax?) -> Accessibility? {
modifierList?.lazy.compactMap { Accessibility(tokenKind: $0.name.tokenKind) }.first
}
private func genericParameters(from genericParameterList: GenericParameterListSyntax?) -> [GenericParameter] {
genericParameterList?.map { genericParameter in
GenericParameter(
name: genericParameter.name.description,
inheritedTypes: genericParameter.inheritedType.map(inheritedTypes(from:)) ?? []
)
} ?? []
}
private func genericParameters(from primaryAssociatedTypeList: PrimaryAssociatedTypeListSyntax?) -> [GenericParameter] {
primaryAssociatedTypeList?.compactMap { associatedType in
guard case .identifier(let identifier) = associatedType.name.tokenKind else { return nil }
return GenericParameter(
name: identifier,
inheritedTypes: associatedType.inheritedType.map(inheritedTypes(from:)) ?? []
)
} ?? []
}
private func associatedTypes(from memberList: MemberDeclListSyntax) -> [GenericParameter] {
memberList
.compactMap { member in
guard let associatedType = member.decl.as(AssociatedtypeDeclSyntax.self),
case .identifier(let identifier) = associatedType.identifier.tokenKind else { return nil }
return GenericParameter(
name: identifier,
inheritedTypes: inheritedTypes(from: associatedType.inheritanceClause?.inheritedTypeCollection)
)
}
}
private func genericRequirements(from genericRequirementList: GenericRequirementListSyntax?) -> [String] {
genericRequirementList?.map { $0.body.withoutTrivia().description } ?? []
}
private func inheritedTypes(from inheritedTypesList: InheritedTypeListSyntax?) -> [String] {
inheritedTypesList?.flatMap { inheritedType -> [String] in
inheritedTypes(from: inheritedType.typeName)
} ?? []
}
private func inheritedTypes(from inheritedType: TypeSyntax) -> [String] {
if let simpleType = inheritedType.as(SimpleTypeIdentifierSyntax.self) {
return [simpleType.withoutTrivia().description]
} else if let compositeType = inheritedType.as(CompositionTypeSyntax.self) {
return compositeType.elements.compactMap { element in
guard let simpleType = element.type
.as(SimpleTypeIdentifierSyntax.self) else {
return nil
}
return simpleType.withoutTrivia().description
}
} else {
return []
}
}
}
extension Crawler {
enum CrawlError: Error {
case parameterNameMissing
case parameterTypeMissing
}
}
#if DEBUG
extension Crawler {
private static let testString =
"""
class Multi {
@available(iOS 42.0, *)
var gg: Bool = false
}
protocol Brek {
func drak()
}
"""
}
#endif

View File

@ -0,0 +1,21 @@
import SwiftSyntax
extension Optional where Wrapped == ModifierListSyntax {
var isFinal: Bool {
self?.isFinal ?? false
}
var isStatic: Bool {
self?.isStatic ?? false
}
}
extension ModifierListSyntax {
var isFinal: Bool {
contains { $0.name.tokenKind == .identifier("final") }
}
var isStatic: Bool {
contains { $0.name.tokenKind == .staticKeyword }
}
}

View File

@ -0,0 +1,39 @@
import Foundation
import FileKit
struct FileHeaderHandler {
static func header(for file: FileRepresentation, timestamp: String?) -> String {
let path = getRelativePath(to: file)
return [
"// MARK: - Mocks generated from file: '\(path)'",
timestamp.map { "at \($0)" },
]
.compactMap { $0 }
.joined(separator: " ")
}
static func imports(for file: FileRepresentation, testableFrameworks: [String]) -> String {
let testableImports = testableFrameworks
.map { frameworkName in
String(frameworkName.map { $0.isLetter || $0.isWholeNumber ? $0 : "_" })
}
.map { "@testable import \($0)" }
return [
["import Cuckoo"],
OrderedSet(file.imports).values.map { "import \($0)" },
testableImports,
]
.flatMap { $0 }
.joined(separator: "\n")
}
private static func getRelativePath(to file: FileRepresentation) -> String {
let path = file.file.path.absolute
let base = path.commonAncestor(Path.current)
let components = path.components.suffix(from: base.components.endIndex)
let result = components.map { $0.rawValue }.joined(separator: Path.separator)
let difference = Path.current.components.endIndex - base.components.endIndex
return (0..<difference).reduce(result) { acc, _ in ".." + Path.separator + acc }
}
}

View File

@ -0,0 +1,204 @@
import Foundation
import Stencil
struct Generator {
private static let reservedKeywordsNotAllowedAsMethodName: Set = [
// Keywords used in declarations:
"associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import", "init", "inout", "internal", "let", "operator", "private", "precedencegroup", "protocol", "public", "rethrows", "static", "struct", "subscript", "typealias", "var",
// Keywords used in statements:
"break", "case", "catch", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", "in", "repeat", "return", "throw", "switch", "where", "while",
// Keywords used in expressions and types:
"Any", "as", "catch", "false", "is", "nil", "rethrows", "self", "super", "throw", "throws", "true", "try",
// Keywords used in patterns:
"_",
]
private static let extensions = createExtensions()
static func generate(tokens: [Token], debug: Bool = false) throws -> String {
let containers = tokens.map { $0.serialize() }
let environment = Environment(
extensions: extensions,
trimBehaviour: .smart
)
return try environment.renderTemplate(string: Templates.mock, context: ["containers": containers, "debug": debug])
}
private static func matchableGenericTypes(from method: Method) -> String {
guard !method.signature.parameters.isEmpty || !method.signature.genericParameters.isEmpty else { return "" }
let matchableGenericParameters = method.signature.parameters.enumerated().map { index, parameter -> String in
let type = parameter.isOptional ? "OptionalMatchable" : "Matchable"
return "M\(index + 1): Cuckoo.\(type)"
}
let methodGenericParameters = method.signature.genericParameters.map { $0.description }
return "<\((matchableGenericParameters + methodGenericParameters).joined(separator: ", "))>"
}
private static func matchableGenericsWhereClause(from method: Method) -> String {
guard method.signature.parameters.isEmpty == false else { return "" }
let matchableWhereConstraints = method.signature.parameters.enumerated().map { index, parameter -> String in
let type = parameter.isOptional ? "OptionalMatchedType" : "MatchedType"
return "M\(index + 1).\(type) == \(genericSafeType(from: parameter.type.withoutAttributes.unoptionaled.sugarized))"
}
let methodWhereConstraints = method.signature.whereConstraints
return " where \((matchableWhereConstraints + methodWhereConstraints).joined(separator: ", "))"
}
private static func matchableParameterSignature(with parameters: [MethodParameter]) -> String {
guard !parameters.isEmpty else { return "" }
return parameters.enumerated()
.map { "\($1.nameAndInnerName): M\($0 + 1)" }
.joined(separator: ", ")
}
private static func parameterMatchers(for parameters: [MethodParameter]) -> String {
guard parameters.isEmpty == false else { return "let matchers: [Cuckoo.ParameterMatcher<Void>] = []" }
let tupleType = parameters.map { $0.typeWithoutAttributes }.joined(separator: ", ")
let matchers = parameters
.compactMap { parameter -> MethodParameter? in
if parameter.usableName == nil {
return nil
} else {
return parameter
}
}
// Enumeration is done after filtering out parameters without usable names.
.enumerated()
.compactMap { index, parameter in
"wrap(matchable: \(parameter.usableName)) { $0\(parameters.count > 1 ? ".\(index)" : "") }"
}
.joined(separator: ", ")
return "let matchers: [Cuckoo.ParameterMatcher<(\(genericSafeType(from: tupleType)))>] = [\(matchers)]"
}
private static func genericSafeType(from type: String) -> String {
return type.replacingOccurrences(of: "!", with: "?")
}
private static func openNestedClosure(for method: Method) -> String {
var fullString = ""
for (index, parameter) in method.signature.parameters.enumerated() {
if parameter.isClosure && !parameter.isEscaping {
let indents = String(repeating: "\t", count: index)
let tries = method.isThrowing ? "try " : ""
let awaits = method.isAsync ? "await " : ""
let sugarizedReturnType = method.returnType?.sugarized
let returnSignature: String
if let sugarizedReturnType {
if sugarizedReturnType.isEmpty {
returnSignature = sugarizedReturnType
} else {
returnSignature = " -> \(sugarizedReturnType)"
}
} else {
returnSignature = ""
}
fullString += "\(indents)return \(tries)\(awaits)withoutActuallyEscaping(\(parameter.usableName), do: { (\(parameter.usableName): @escaping \(parameter.type))\(returnSignature) in\n"
}
}
return fullString
}
private static func closeNestedClosure(for parameters: [MethodParameter]) -> String {
var fullString = ""
for (index, parameter) in parameters.enumerated() {
if parameter.isClosure && !parameter.isEscaping {
let indents = String(repeating: "\t", count: index)
fullString += "\(indents)})\n"
}
}
return fullString
}
private static func escapeReservedKeywords(for name: String) -> String {
Self.reservedKeywordsNotAllowedAsMethodName.contains(name) ? "`\(name)`" : name
}
private static func removeClosureArgumentNames(for type: String) -> String {
type.replacingOccurrences(
of: "_\\s+?[_a-zA-Z]\\w*?\\s*?:",
with: "",
options: .regularExpression
)
}
}
extension Generator {
private static func createExtensions() -> [Extension] {
let stencilExtension = Extension()
stencilExtension
.registeringFilter("genericSafe") { (value: Any?) in
guard let string = value as? String else { return value }
return genericSafeType(from: string)
}
.registeringFilter("matchableGenericNames") { (value: Any?) in
guard let method = value as? Method else { return value }
return matchableGenericTypes(from: method)
}
.registeringFilter("matchableGenericWhereClause") { (value: Any?) in
guard let method = value as? Method else { return value }
return matchableGenericsWhereClause(from: method)
}
.registeringFilter("matchableParameterSignature") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return matchableParameterSignature(with: parameters)
}
.registeringFilter("parameterMatchers") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return parameterMatchers(for: parameters)
}
.registeringFilter("openNestedClosure") { (value: Any?) in
guard let method = value as? Method else { return value }
return openNestedClosure(for: method)
}
.registeringFilter("closeNestedClosure") { (value: Any?) in
guard let parameters = value as? [MethodParameter] else { return value }
return closeNestedClosure(for: parameters)
}
.registeringFilter("escapeReservedKeywords") { (value: Any?) in
guard let name = value as? String else { return value }
return escapeReservedKeywords(for: name)
}
.registeringFilter("removeClosureArgumentNames") { (value: Any?) in
guard let type = value as? String else { return value }
return removeClosureArgumentNames(for: type)
}
.registeringFilter("withSpace") { (value: Any?) in
if let value = value as? String, !value.isEmpty {
return "\(value) "
} else {
return ""
}
}
return [stencilExtension]
}
}
extension Extension {
@discardableResult
fileprivate func registeringFilter(_ name: String, filter: @escaping (Any?) throws -> Any?) -> Self {
registerFilter(name, filter: filter)
return self
}
fileprivate func registeringFilter(_ name: String, filter: @escaping (Any?, [Any?]) throws -> Any?) -> Self {
registerFilter(name, filter: filter)
return self
}
fileprivate func registeringFilter(_ name: String, filter: @escaping (Any?, [Any?], Context) throws -> Any?) -> Self {
registerFilter(name, filter: filter)
return self
}
}

View File

@ -0,0 +1,34 @@
import Foundation
extension String {
var nilIfEmpty: String? {
isEmpty ? nil : self
}
}
extension String {
subscript(range: NSRange) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: range.location)
let toIndex = self.index(fromIndex, offsetBy: range.length)
return String(self[fromIndex..<toIndex])
}
}
extension String {
func stringMatch(from match: NSTextCheckingResult, at range: Int = 0) -> String {
let matchRange = match.range(at: range)
let fromIndex = index(startIndex, offsetBy: matchRange.location)
let toIndex = index(fromIndex, offsetBy: matchRange.length)
return String(self[fromIndex..<toIndex])
}
func removing(match: NSTextCheckingResult, at range: Int = 0) -> String {
let matchRange = match.range(at: range)
let fromIndex = index(startIndex, offsetBy: matchRange.location)
let toIndex = index(fromIndex, offsetBy: matchRange.length)
var mutableString = self
mutableString.removeSubrange(fromIndex..<toIndex)
return mutableString
}
}

View File

@ -0,0 +1,55 @@
import Foundation
struct OrderedSet<Element: Hashable>: ExpressibleByArrayLiteral {
var values: [Element] {
orderedSet.array as! [Element]
}
private let orderedSet: NSMutableOrderedSet
init() {
orderedSet = NSMutableOrderedSet()
}
init(arrayLiteral elements: Element...) {
self.init(elements)
}
init(_ array: [Element]) {
orderedSet = NSMutableOrderedSet(array: array)
}
private init(orderedSet: NSMutableOrderedSet) {
self.orderedSet = orderedSet
}
func contains(_ member: Element) -> Bool {
orderedSet.contains(member)
}
mutating func insert(_ newMember: Element) {
orderedSet.add(newMember)
}
mutating func remove(_ member: Element) {
orderedSet.remove(member)
}
func union(_ other: OrderedSet<Element>) -> OrderedSet<Element> {
withoutMutating { orderedSet in
orderedSet.union(other.orderedSet)
}
}
func intersection(_ other: OrderedSet<Element>) -> OrderedSet<Element> {
withoutMutating { orderedSet in
orderedSet.intersect(other.orderedSet)
}
}
private func withoutMutating(work: (NSMutableOrderedSet) -> Void) -> OrderedSet<Element> {
let orderedSetCopy = orderedSet.mutableCopy() as! NSMutableOrderedSet
work(orderedSetCopy)
return OrderedSet(orderedSet: orderedSetCopy)
}
}

View File

@ -0,0 +1,25 @@
import Foundation
@dynamicMemberLookup
final class Reference<Value> {
private(set) var value: Value
init(_ value: Value) {
self.value = value
}
subscript<T>(dynamicMember keyPath: KeyPath<Value, T>) -> T {
value[keyPath: keyPath]
}
subscript<T>(dynamicMember keyPath: WritableKeyPath<Value, T>) -> T {
get { value[keyPath: keyPath] }
set { value[keyPath: keyPath] = newValue }
}
}
extension Reference: Equatable where Value: Equatable {
static func == (lhs: Reference<Value>, rhs: Reference<Value>) -> Bool {
lhs.value == rhs.value
}
}

View File

@ -1,19 +1,20 @@
#if NO_COMPILE
import Foundation
import SourceKittenFramework
public struct Tokenizer {
struct SourceKittenTokenizer {
private let file: File
private let source: String
private let debugMode: Bool
public init(sourceFile: File, debugMode: Bool) {
init(sourceFile: File, debugMode: Bool) {
self.file = sourceFile
self.debugMode = debugMode
source = sourceFile.contents
}
public func tokenize() -> FileRepresentation {
func tokenize() -> FileRepresentation {
do {
let structure = try Structure(file: file)
@ -43,8 +44,8 @@ public struct Tokenizer {
guard let dictionary = representable as? [String: SourceKitRepresentable] else { return nil }
// Common fields
let name = dictionary[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Tokenizer.unknownType
let name = dictionary[Key.Name.rawValue] as? String ?? Self.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Self.unknownType
// Inheritance
let inheritedTypes = dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []
@ -52,7 +53,7 @@ public struct Tokenizer {
guard let typeDict = type as? [String: SourceKitRepresentable] else {
return InheritanceDeclaration.empty
}
let name = typeDict[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
let name = typeDict[Key.Name.rawValue] as? String ?? Self.nameNotSet
return InheritanceDeclaration(name: name)
}
@ -103,9 +104,9 @@ public struct Tokenizer {
return ProtocolDeclaration(
name: name,
accessibility: accessibility,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
// range: range!,
// nameRange: nameRange!,
// bodyRange: bodyRange!,
initializers: initializers,
children: children,
inheritedTypes: tokenizedInheritedTypes,
@ -150,9 +151,9 @@ public struct Tokenizer {
return StructDeclaration(
name: name,
accessibility: accessibility,
range: range!,
nameRange: nameRange!,
bodyRange: bodyRange!,
// range: range!,
// nameRange: nameRange!,
// bodyRange: bodyRange!,
attributes: attributes,
children: children
)
@ -172,7 +173,7 @@ public struct Tokenizer {
)
case Kinds.InstanceVariable.rawValue:
let setterAccessibility = (dictionary[Key.SetterAccessibility.rawValue] as? String).flatMap(Accessibility.init)
let setterAccessibility = (dictionary[Key.SetterAccessibility.rawValue] as? String).flatMap(Accessibility.init(string:))
if String(source.utf8.dropFirst(range!.startIndex))?.takeUntil(occurence: name)?.trimmed.hasPrefix("let") == true {
return nil
@ -207,9 +208,9 @@ public struct Tokenizer {
returnSignature = parseReturnSignature(source: source.utf8[nameRange!.endIndex..<range!.endIndex].trimmed)
}
// methods can specify an empty public name of a parameter without any private name - `fun(_: String)`
// methods can specify an empty name of a parameter without any private name - `fun(_: String)`
let namedParameters = parameters.enumerated().map { index, parameter -> MethodParameter in
if parameter.name == Tokenizer.nameNotSet {
if parameter.name == Self.nameNotSet {
var mutableParameter = parameter
mutableParameter.name = "parameter\(index)"
return mutableParameter
@ -239,8 +240,8 @@ public struct Tokenizer {
name: name,
accessibility: accessibility,
returnSignature: returnSignature,
range: range!,
nameRange: nameRange!,
// range: range!,
// nameRange: nameRange!,
parameters: namedParameters,
attributes: attributes,
genericParameters: fixedGenericParameters
@ -265,8 +266,8 @@ public struct Tokenizer {
let fullRange = range.lowerBound..<(range.upperBound + inheritanceMatch.range.length)
return GenericParameter(
name: name,
range: fullRange,
inheritedType: InheritanceDeclaration(name: inheritance)
// range: fullRange,
inheritedType: inheritance
)
default:
@ -297,8 +298,8 @@ public struct Tokenizer {
private func tokenize(parameterLabel: String?, parameter: SourceKitRepresentable) -> Token? {
guard let dictionary = parameter as? [String: SourceKitRepresentable] else { return nil }
let name = dictionary[Key.Name.rawValue] as? String ?? Tokenizer.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Tokenizer.unknownType
let name = dictionary[Key.Name.rawValue] as? String ?? Self.nameNotSet
let kind = dictionary[Key.Kind.rawValue] as? String ?? Self.unknownType
let range = extractRange(from: dictionary, offset: .Offset, length: .Length)
let nameRange = extractRange(from: dictionary, offset: .NameOffset, length: .NameLength)
let type = dictionary[Key.TypeName.rawValue] as? String
@ -328,7 +329,12 @@ public struct Tokenizer {
let wrappableType = WrappableType(parsing: inoutSeparatedType)
return MethodParameter(label: parameterLabel, name: name, type: wrappableType, range: range!, nameRange: nameRange, isInout: isInout)
return MethodParameter(
label: parameterLabel,
name: name,
type: wrappableType,
isInout: isInout
)
case Kinds.GenericParameter.rawValue:
let inheritedTypeElement = (dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []).first
@ -375,7 +381,7 @@ public struct Tokenizer {
.map { result -> Import in
let range = result.range.location..<(result.range.location + result.range.length)
let library = source.stringMatch(from: result, at: 1)
return Import(range: range, importee: .library(name: library))
return Import(range: range, kind: .library(name: library))
}
let components = componentRegex.matches(in: source, range: NSRange(location: 0, length: source.count))
.filter { result in
@ -387,7 +393,7 @@ public struct Tokenizer {
let library = source[result.range(at: 2)]
let component = source[result.range(at: 3)]
let range = result.range.location..<(result.range.location + result.range.length)
return Import(range: range, importee: .component(componentType: componentType, library: library, name: component))
return Import(range: range, kind: .component(componentType: componentType, library: library, name: component))
}
return libraries + components
@ -515,7 +521,12 @@ public struct Tokenizer {
index = source.index(after: index)
}
return ReturnSignature(isAsync: isAsync, throwString: throwString, returnType: returnType ?? WrappableType.type("Void"), whereConstraints: whereConstraints)
return ReturnSignature(
asyncType: isAsync ? .async : nil,
throwType: throwString.flatMap(ThrowType.init(string:)),
returnType: returnType ?? WrappableType.type("Void"),
whereConstraints: whereConstraints
)
}
// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
@ -539,29 +550,10 @@ public struct Tokenizer {
}
}
extension String {
subscript(range: NSRange) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: range.location)
let toIndex = self.index(fromIndex, offsetBy: range.length)
return String(self[fromIndex..<toIndex])
}
}
extension String {
func stringMatch(from match: NSTextCheckingResult, at range: Int = 0) -> String {
let matchRange = match.range(at: range)
let fromIndex = index(startIndex, offsetBy: matchRange.location)
let toIndex = index(fromIndex, offsetBy: matchRange.length)
return String(self[fromIndex..<toIndex])
}
func removing(match: NSTextCheckingResult, at range: Int = 0) -> String {
let matchRange = match.range(at: range)
let fromIndex = index(startIndex, offsetBy: matchRange.location)
let toIndex = index(fromIndex, offsetBy: matchRange.length)
var mutableString = self
mutableString.removeSubrange(fromIndex..<toIndex)
return mutableString
}
private(set) var stderrUsed = false
func stderrPrint(_ item: Any) {
stderrUsed = true
fputs("error: \(item)\n", stderr)
}
#endif

View File

@ -0,0 +1,3 @@
//{{ start }}
// {{ content }}
//{{ end }}

View File

@ -0,0 +1,129 @@
import Foundation
extension Templates {
static let staticGenericParameter = "_CUCKOO$$GENERIC"
static let typeErasureClassName = "DefaultImplCaller"
static let mock = """
{% for container in containers %}
{% if debug %}
// {{ container }}
{% endif %}
{% for attribute in container.attributes %}
{{ attribute }}
{% endfor %}
{% if container.hasParent %}
extension {{ container.parentFullyQualifiedName }} {
{% endif %}
{{ container.accessibility|withSpace }}class {{ container.mockName }}{{ container.genericParameters }}:{% if container.isNSObjectProtocol %} NSObject,{% endif %} {{ container.name }}{% if container.isImplementation %}{{ container.genericArguments }}{% endif %},{% if container.isImplementation %} Cuckoo.ClassMock{% else %} Cuckoo.ProtocolMock{% endif %} {
{% if container.isGeneric and not container.isImplementation %}
{{ container.accessibility|withSpace }}typealias MocksType = \(typeErasureClassName){{ container.genericArguments }}
{% else %}
{{ container.accessibility|withSpace }}typealias MocksType = {{ container.name }}{{ container.genericArguments }}
{% endif %}
{{ container.accessibility|withSpace }}typealias Stubbing = __StubbingProxy_{{ container.name }}
{{ container.accessibility|withSpace }}typealias Verification = __VerificationProxy_{{ container.name }}
{{ container.accessibility|withSpace }}let cuckoo_manager = Cuckoo.MockManager.preconfiguredManager ?? Cuckoo.MockManager(hasParent: {{ container.isImplementation }})
{% if container.isGeneric and not container.isImplementation %}
\(Templates.typeErasure.indented())
private var __defaultImplStub: \(typeErasureClassName){{ container.genericArguments }}?
{{ container.accessibility|withSpace }}func enableDefaultImplementation<\(staticGenericParameter): {{ container.name }}>(_ stub: \(staticGenericParameter)) where {{ container.genericProtocolIdentity }} {
var mutableStub = stub
__defaultImplStub = \(typeErasureClassName)(from: &mutableStub, keeping: mutableStub)
cuckoo_manager.enableDefaultStubImplementation()
}
{{ container.accessibility|withSpace }}func enableDefaultImplementation<\(staticGenericParameter): {{ container.name }}>(mutating stub: UnsafeMutablePointer<\(staticGenericParameter)>) where {{ container.genericProtocolIdentity }} {
__defaultImplStub = \(typeErasureClassName)(from: stub, keeping: nil)
cuckoo_manager.enableDefaultStubImplementation()
}
{% else %}
private var __defaultImplStub: {{ container.name }}{{ container.genericArguments }}?
{{ container.accessibility|withSpace }}func enableDefaultImplementation(_ stub: {{ container.name }}{{ container.genericArguments }}) {
__defaultImplStub = stub
cuckoo_manager.enableDefaultStubImplementation()
}
{% endif -%}
{% for property in container.properties %}
{% if debug %}
// {{property}}
{% endif %}
{% for attribute in property.attributes %}
{{ attribute }}
{% endfor %}
{{ property.accessibility|withSpace }}{% if property.isOverriding %}override {% endif %} var {{ property.name }}: {{ property.type }} {
get {
return cuckoo_manager.getter(
"{{ property.name }}",
superclassCall: {%+ if container.isImplementation -%}
super.{{ property.name }}
{%- else -%}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{%- endif -%},
defaultCall: __defaultImplStub!.{{property.name}}
)
}
{% ifnot property.isReadOnly %}
set {
cuckoo_manager.setter(
"{{ property.name }}",
value: newValue,
superclassCall: {%+ if container.isImplementation -%}
super.{{ property.name }} = newValue
{%- else -%}
Cuckoo.MockManager.crashOnProtocolSuperclassCall()
{%- endif -%},
defaultCall: __defaultImplStub!.{{property.name}} = newValue)
}
{% endif %}
}
{% endfor %}
{% for initializer in container.initializers %}
{% if debug %}
// {{initializer}}
{% endif %}
{{ initializer.accessibility|withSpace }}required init{{initializer.signature}} {}
{% endfor %}
{% for method in container.methods %}
{% if debug %}
// {{method}}
{% endif %}
{% for attribute in method.attributes %}
{{ attribute }}
{% endfor %}
{{ method.accessibility|withSpace }}{% if method.isOverriding %}override {%+ endif %}func {{ method.name|escapeReservedKeywords }}{{ method.signature }} {
{{ method.self|openNestedClosure }}
return{% if method.isThrowing %} try{% endif %}{% if method.isAsync %} await{% endif %} cuckoo_manager.call{% if method.isThrowing %}{{ method.throwType|capitalize }}{% endif %}(
\"\"\"
{{method.fullyQualifiedName}}
\"\"\",
parameters: ({{method.parameterNames}}),
escapingParameters: ({{method.escapingParameterNames}}),
superclassCall: {%+ if container.isImplementation %}{% if method.isAsync %}await {%+ endif %}super.{{method.name}}({{method.call}}){% else %}Cuckoo.MockManager.crashOnProtocolSuperclassCall(){% endif %},
defaultCall: {%+ if method.isAsync %}await {%+ endif %}__defaultImplStub!.{{method.name}}{%if method.isOptional %}!{%endif%}({{method.call}})
)
{{ method.parameters|closeNestedClosure }}
}
{% endfor %}
\(Templates.stubbingProxy.indented())
\(Templates.verificationProxy.indented())
}
\(Templates.noImplStub)
{% if container.hasParent %}
}
{% endif %}
{% endfor %}
"""
}

View File

@ -1,23 +1,23 @@
extension Templates {
static let noImplStub = """
{% for attribute in container.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
{{container.accessibility}} class {{ container.name }}Stub{{ container.genericParameters }}: {% if container.isNSObjectProtocol %}NSObject, {% endif %}{{ container.name }}{% if container.isImplementation %}{{ container.genericArguments }}{% endif %} {
{{container.accessibility|withSpace}}class {{ container.name }}Stub{{ container.genericParameters }}: {% if container.isNSObjectProtocol %}NSObject, {% endif %}{{ container.name }}{% if container.isImplementation %}{{ container.genericArguments }}{% endif %} {
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% if debug %}
// {{property}}
{% endif %}
{% for attribute in property.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
{{ property.accessibility }}{% if container.@type == "ClassDeclaration" %} override{% endif %} var {{ property.name }}: {{ property.type }} {
{{ property.accessibility|withSpace }}{% if property.isOverriding %}override{% endif %} var {{ property.name }}: {{ property.type }} {
get {
return DefaultValueRegistry.defaultValue(for: ({{property.type|genericSafe|removeClosureArgumentNames}}).self)
}
{% ifnot property.isReadOnly %}
set { }
set {}
{% endif %}
}
{% if property.hasUnavailablePlatforms %}
@ -27,11 +27,7 @@ extension Templates {
{% for initializer in container.initializers %}
{{ initializer.unavailablePlatformsCheck }}
{{ initializer.accessibility }}{% if container.@type == "ClassDeclaration" %} override{% endif %}{% if initializer.@type == "ProtocolMethod" %} required{%endif%} init({{initializer.parameterSignature}}) {
{% if container.@type == "ClassDeclaration" %}
super.init({{initializer.call}})
{% endif %}
}
{{ initializer.accessibility|withSpace }}required init{{initializer.signature}} {}
{% if initializer.hasUnavailablePlatforms %}
#endif
{% endif %}
@ -43,9 +39,9 @@ extension Templates {
// {{method}}
{% endif %}
{% for attribute in method.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
{{ method.accessibility }}{% if container.@type == "ClassDeclaration" and method.isOverriding %} override{% endif %} func {{ method.name|escapeReservedKeywords }}{{ method.genericParameters }}({{ method.parameterSignature }}) {{ method.returnSignature }} {{ method.whereClause }} {
{{ method.accessibility|withSpace }}{% if method.isOverriding %}override{% endif %} func {{ method.name|escapeReservedKeywords }}{{ method.signature }} {
return DefaultValueRegistry.defaultValue(for: ({{method.returnType|genericSafe}}).self)
}
{% if method.hasUnavailablePlatforms %}

View File

@ -2,16 +2,16 @@ import Foundation
extension Templates {
static let stubbingProxy = """
{{ container.accessibility }} struct __StubbingProxy_{{ container.name }}: Cuckoo.StubbingProxy {
{{ container.accessibility|withSpace }}struct __StubbingProxy_{{ container.name }}: Cuckoo.StubbingProxy {
private let cuckoo_manager: Cuckoo.MockManager
{{ container.accessibility }} init(manager: Cuckoo.MockManager) {
{{ container.accessibility|withSpace }}init(manager: Cuckoo.MockManager) {
self.cuckoo_manager = manager
}
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% for attribute in property.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
var {{property.name}}: Cuckoo.{{ property.stubType }}<{{ container.mockName }}, {% if property.isReadOnly %}{{property.type|genericSafe}}{% else %}{{property.nonOptionalType|genericSafe}}{% endif %}> {
return .init(manager: cuckoo_manager, name: "{{property.name}}")
@ -23,14 +23,16 @@ extension Templates {
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% for attribute in method.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
func {{method.name|escapeReservedKeywords}}{{method.self|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> {{method.stubFunction}}<({{method.inputTypes|genericSafe}}){%if method.returnType != "Void" %}, {{method.returnType|genericSafe}}{%endif%}>{{method.self|matchableGenericWhereClause}} {
{{method.parameters|parameterMatchers}}
return .init(stub: cuckoo_manager.createStub(for: {{ container.mockName }}.self, method:
\"\"\"
{{method.fullyQualifiedName}}
\"\"\", parameterMatchers: matchers))
return .init(stub: cuckoo_manager.createStub(for: {{ container.mockName }}.self,
method: \"\"\"
{{method.fullyQualifiedName}}
\"\"\",
parameterMatchers: matchers
))
}
{% if method.hasUnavailablePlatforms %}
#endif

View File

@ -2,14 +2,19 @@ import Foundation
extension Templates {
static let typeErasure = """
{{ container.accessibility }} class \(typeErasureClassName){{ container.genericParameters }}: {{ container.name }} {
{{ container.accessibility|withSpace }}class \(typeErasureClassName){{ container.genericParameters }}: {{ container.name }} {
private let reference: Any
{% for property in container.properties %}private let _getter_storage$${{ property.name }}: () -> {{ property.type }}{% if not property.isReadOnly %}
private let _setter_storage$${{ property.name }}: ({{ property.type }}) -> Void{% endif %}
{{ container.accessibility }} var {{ property.name }}: {{ property.type }} {
get { return _getter_storage$${{ property.name }}() }{% if not property.isReadOnly %}
set { _setter_storage$${{ property.name }}(newValue) }{% endif %}
{% for property in container.properties %}
private let _getter_storage$${{ property.name }}: () -> {{ property.type }}
{% if not property.isReadOnly %}
private let _setter_storage$${{ property.name }}: ({{ property.type }}) -> Void
{% endif %}
{{ container.accessibility|withSpace }}var {{ property.name }}: {{ property.type }} {
get { return _getter_storage$${{ property.name }}() }
{% if not property.isReadOnly %}
set { _setter_storage$${{ property.name }}(newValue) }
{% endif %}
}
{% endfor %}
@ -18,22 +23,28 @@ extension Templates {
init<\(staticGenericParameter): {{ container.name }}>(from defaultImpl: UnsafeMutablePointer<\(staticGenericParameter)>, keeping reference: @escaping @autoclosure () -> Any?) where {{ container.genericProtocolIdentity }} {
self.reference = reference
{% for property in container.properties %}_getter_storage$${{ property.name }} = { defaultImpl.pointee.{{ property.name }} }
{% if not property.isReadOnly %}_setter_storage$${{ property.name }} = { defaultImpl.pointee.{{ property.name }} = $0 }{% endif %}
{% for property in container.properties %}
_getter_storage$${{ property.name }} = { defaultImpl.pointee.{{ property.name }} }
{% if not property.isReadOnly %}
_setter_storage$${{ property.name }} = { defaultImpl.pointee.{{ property.name }} = $0 }
{% endif %}
{% endfor %}
{% for method in container.methods %}_storage${{ forloop.counter }}${{ method.name }} = defaultImpl.pointee.{{ method.name }}
{% for method in container.methods %}
_storage${{ forloop.counter }}${{ method.name }} = defaultImpl.pointee.{{ method.name }}
{% endfor %}
}
{% if container.initializers %}
/// MARK:- ignored required initializers{% endif %}
{% for initializer in container.initializers %}{{ container.accessibility }} required init({{ initializer.parameterSignature }}) {
/// MARK:- ignored required initializers
{% endif %}
{% for initializer in container.initializers %}
{{ container.accessibility|withSpace }}required init{{initializer.signature}} {
fatalError("`DefaultImplCaller` class is only used for calling default implementation and can't be initialized on its own.")
}
{% endfor %}
{% for method in container.methods %}
{% for method in container.methods +%}
private let _storage${{ forloop.counter }}${{ method.name }}: ({{ method.inputTypes }}) {% if method.isAsync %} async{% endif %} -> {{ method.returnType }}
{{ container.accessibility }} func {{ method.name|escapeReservedKeywords }}({{ method.parameterSignature }}) {{ method.returnSignature }} {
{{ container.accessibility|withSpace }}func {{ method.name|escapeReservedKeywords }}{{ method.signature }} {
return {% if method.isAsync %} await{% endif %} _storage${{ forloop.counter }}${{ method.name }}({{ method.parameterNames }})
}
{% endfor %}

View File

@ -2,42 +2,42 @@ import Foundation
extension Templates {
static let verificationProxy = """
{{ container.accessibility }} struct __VerificationProxy_{{ container.name }}: Cuckoo.VerificationProxy {
{{ container.accessibility|withSpace }}struct __VerificationProxy_{{ container.name }}: Cuckoo.VerificationProxy {
private let cuckoo_manager: Cuckoo.MockManager
private let callMatcher: Cuckoo.CallMatcher
private let sourceLocation: Cuckoo.SourceLocation
{{ container.accessibility }} init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) {
{{ container.accessibility|withSpace }}init(manager: Cuckoo.MockManager, callMatcher: Cuckoo.CallMatcher, sourceLocation: Cuckoo.SourceLocation) {
self.cuckoo_manager = manager
self.callMatcher = callMatcher
self.sourceLocation = sourceLocation
}
{% for property in container.properties %}
{{ property.unavailablePlatformsCheck }}
{% for attribute in property.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
var {{property.name}}: Cuckoo.{{property.verifyType}}<{% if property.isReadOnly %}{{property.type|genericSafe}}{% else %}{{property.nonOptionalType|genericSafe}}{% endif %}> {
return .init(manager: cuckoo_manager, name: "{{property.name}}", callMatcher: callMatcher, sourceLocation: sourceLocation)
}
{% if property.hasUnavailablePlatforms %}
#endif
{% endif %}
{% endfor %}
{% for method in container.methods %}
{{ method.unavailablePlatformsCheck }}
{% for attribute in method.attributes %}
{{ attribute.text }}
{{ attribute }}
{% endfor %}
@discardableResult
func {{method.name|escapeReservedKeywords}}{{method.self|matchableGenericNames}}({{method.parameters|matchableParameterSignature}}) -> Cuckoo.__DoNotUse<({{method.inputTypes|genericSafe}}), {{method.returnType|genericSafe}}>{{method.self|matchableGenericWhereClause}} {
{{method.parameters|parameterMatchers}}
return cuckoo_manager.verify(
\"\"\"
{{method.fullyQualifiedName}}
\"\"\", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation)
\"\"\"
{{method.fullyQualifiedName}}
\"\"\",
callMatcher: callMatcher,
parameterMatchers: matchers,
sourceLocation: sourceLocation
)
}
{% if method.hasUnavailablePlatforms %}
#endif

View File

@ -0,0 +1,69 @@
import SwiftSyntax
enum Accessibility: String, Equatable {
case `open`
case `public`
case `internal`
case `private`
case `fileprivate`
var sourceName: String {
switch self {
case .open:
fallthrough
case .public:
return "public"
case .internal:
return ""
case .private:
return "private"
case .fileprivate:
return "fileprivate"
}
}
var isAccessible: Bool {
self != .private && self != .fileprivate
}
}
extension Accessibility {
init?(tokenKind: TokenKind) {
switch tokenKind {
case .publicKeyword:
self = .public
case .internalKeyword:
self = .internal
case .privateKeyword:
self = .private
case .fileprivateKeyword:
self = .fileprivate
case .identifier("open"):
self = .open
default:
return nil
}
}
}
extension Accessibility: Comparable {
static func < (lhs: Accessibility, rhs: Accessibility) -> Bool {
lhs.openness < rhs.openness
}
/// How open is this accessibility. The higher number the more accessible.
private var openness: Int {
switch self {
case .open:
return 4
case .public:
return 3
case .internal:
return 2
case .fileprivate:
return 1
case .private:
return 0
}
}
}

View File

@ -0,0 +1,16 @@
enum AsyncType: String, CustomStringConvertible, Equatable {
case `async`
case `reasync`
var isAsync: Bool {
self == .async
}
var isReasync: Bool {
self == .reasync
}
var description: String {
rawValue
}
}

View File

@ -0,0 +1,22 @@
import Foundation
enum Attribute: Hashable, CustomStringConvertible {
case available(arguments: [String])
var description: String {
switch self {
case .available(let arguments):
return "@available(\(arguments.joined(separator: ", ")))"
}
}
var unavailablePlatform: String? {
guard case .available(let arguments) = self,
arguments.count == 2,
arguments[1] == "unavailable" else {
return nil
}
return String(arguments[0])
}
}

View File

@ -0,0 +1,15 @@
protocol HasAccessibility: Token {
var accessibility: Accessibility { get set }
}
extension HasAccessibility {
var areAllHierarchiesAccessible: Bool {
guard accessibility.isAccessible else { return false }
var parent: Token? = parent?.value
while let p = parent as? HasAccessibility {
guard p.accessibility.isAccessible else { return false }
parent = p.parent?.value
}
return true
}
}

View File

@ -0,0 +1,17 @@
protocol HasAttributes: Token {
var attributes: [Attribute] { get }
}
extension HasAttributes {
private var unavailablePlatforms: [String] {
attributes.compactMap { $0.unavailablePlatform }
}
var hasUnavailablePlatforms: Bool {
!unavailablePlatforms.isEmpty
}
var unavailablePlatformsCheck: String {
hasUnavailablePlatforms ? "#if !os(\(unavailablePlatforms.joined(separator: ") && !os(")))" : ""
}
}

View File

@ -0,0 +1,4 @@
protocol HasGenerics: Token {
var genericParameters: [GenericParameter] { get }
var genericRequirements: [String] { get }
}

View File

@ -0,0 +1,3 @@
protocol HasInheritance: Token {
var inheritedTypes: [String] { get }
}

View File

@ -0,0 +1,5 @@
protocol HasMembers: Token {
var members: [Token] { get set }
func replacing(members: [Token]) -> Self
}

View File

@ -0,0 +1,19 @@
protocol HasName: Token {
var name: String { get }
}
extension HasName {
var mockName: String {
"Mock\(name)"
}
var fullyQualifiedName: String {
var names = [name]
var parent: Token? = parent?.value
while let p = parent as? HasName {
names.insert(p.name, at: 0)
parent = p.parent?.value
}
return names.joined(separator: ".")
}
}

View File

@ -0,0 +1,5 @@
import Foundation
//protocol ChildToken: Token {
//
//}

View File

@ -0,0 +1,24 @@
struct ClassDeclaration: ContainerToken {
var parent: Reference<Token>?
var attributes: [Attribute]
var accessibility: Accessibility
var name: String
var genericParameters: [GenericParameter]
var genericRequirements: [String]
var inheritedTypes: [String]
var members: [Token]
func replacing(members: [Token]) -> ClassDeclaration {
ClassDeclaration(
parent: parent,
attributes: attributes,
accessibility: accessibility,
name: name,
genericParameters: genericParameters,
genericRequirements: genericRequirements,
inheritedTypes: inheritedTypes,
members: members
)
}
}

View File

@ -0,0 +1,41 @@
protocol ContainerToken: Token, HasAttributes, HasAccessibility, HasName, HasGenerics, HasMembers, HasInheritance {}
extension ContainerToken {
func containerSerialize() -> GeneratorContext {
func withAdjustedAccessibility<TokenType: HasAccessibility>(token: TokenType) -> TokenType {
// We only want to adjust tokens that are accessible and lower than the enclosing type
guard token.accessibility.isAccessible && token.accessibility < accessibility else { return token }
var mutableToken = token
mutableToken.accessibility = accessibility
return mutableToken
}
let accessibilityAdjustedMembers = members.map { child -> Token in
guard let memberWithAccessibility = child as? Token & HasAccessibility else { return child }
return withAdjustedAccessibility(token: memberWithAccessibility)
}
let properties = accessibilityAdjustedMembers.compactMap { $0 as? Variable }
.filter { $0.accessibility.isAccessible }
.map { $0.serialize() }
let methods = accessibilityAdjustedMembers.compactMap { $0 as? Method }
.filter { $0.accessibility.isAccessible }
.map { $0.serialize() }
let initializers = accessibilityAdjustedMembers.compactMap { $0 as? Initializer }
.filter { $0.accessibility.isAccessible }
.map { $0.serialize() }
return [
"accessibility": accessibility.sourceName,
// "isAccessible": accessibility.isAccessible,
// "children": accessibilityAdjustedMembers.map { $0.serialize() },
"properties": properties,
"initializers": isClass ? [] : initializers,
"methods": methods,
"attributes": attributes,
]
.compactMapValues { $0 }
}
}

View File

@ -0,0 +1,5 @@
struct Deinitializer: Token, HasAttributes {
var parent: Reference<Token>?
var attributes: [Attribute]
}

View File

@ -0,0 +1,95 @@
import Foundation
import FileKit
struct FileRepresentation {
let file: TextFile
let imports: [Import]
let tokens: [Token]
init(file: TextFile, imports: [Import], tokens: [Token]) {
self.file = file
self.imports = imports
self.tokens = tokens
}
func replacing(tokens: [Token]) -> FileRepresentation {
FileRepresentation(file: file, imports: imports, tokens: tokens)
}
}
extension FileRepresentation {
func mergingInheritance(with files: [FileRepresentation]) -> FileRepresentation {
let mergedTokens = tokens.reduce([] as [Token]) { list, token in
let mergeToken = token.mergingInheritance(with: files)
return list + [mergeToken]
}
return replacing(tokens: mergedTokens)
}
func inheritNSObject(protocols: [ProtocolDeclaration]) -> FileRepresentation {
replacing(tokens: tokens.map { $0.inheritingNSObject(protocols: protocols) })
}
func flatMappingMemberContainers() -> FileRepresentation {
replacing(tokens: tokens.flatMap { $0.flatMappingMemberContainers() })
}
}
extension Token {
// TODO: This would be much better as a dictionary instead of going through all the files for every inheritance type.
private static func findToken(forClassOrProtocol name: String, in files: [FileRepresentation]) -> Token? {
files.lazy
.flatMap { $0.tokens }
.filter { $0.isClass || $0.isProtocol }
.compactMap { $0 as? HasName }
.first { $0.name == name }
}
fileprivate func mergingInheritance(with files: [FileRepresentation]) -> Token {
guard let token = self as? Token & HasMembers & HasInheritance else { return self }
let inheritedRepresentations = token.inheritedTypes
.compactMap { Self.findToken(forClassOrProtocol: $0, in: files) }
.compactMap { $0.mergingInheritance(with: files) }
let mergedTokens = inheritedRepresentations
.compactMap { $0 as? HasMembers }
.flatMap { $0.members }
.reduce(token.members) { tokens, inheritedToken in
if let inheritedInheritable = inheritedToken as? Inheritable,
tokens.compactMap({ $0 as? Inheritable }).contains(where: { $0.isEqual(to: inheritedInheritable) }) {
return tokens
} else {
return tokens + [inheritedToken]
}
}
switch token {
case let classToken as ClassDeclaration:
return classToken.replacing(members: mergedTokens)
case let protocolToken as ProtocolDeclaration:
return protocolToken.replacing(members: mergedTokens)
default:
assertionFailure("This case should not be possible.")
return token
}
}
fileprivate func inheritingNSObject(protocols: [ProtocolDeclaration]) -> Token {
guard let protocolToken = self as? ProtocolDeclaration, !protocolToken.isNSObjectProtocol else { return self }
return protocols.contains { $0.name == protocolToken.name } ? protocolToken.replacing(isNSObjectProtocol: true) : self
}
}
extension Token {
fileprivate func flatMappingMemberContainers() -> [Token] {
guard let selfHasMembers = self as? HasMembers else { return [self] }
return [self] + selfHasMembers.members.flatMap { token in
if let hasMembers = token as? HasMembers {
return hasMembers.flatMappingMemberContainers()
} else {
return []
}
}
}
}

View File

@ -0,0 +1,20 @@
import Foundation
struct GenericParameter: Equatable {
let name: String
let inheritedTypes: [String]
var description: String {
if inheritedTypes.isEmpty {
return name
} else {
return "\(name): \(inheritedTypes.joined(separator: " & "))"
}
}
}
extension Array where Element == GenericParameter {
var sourceDescription: String {
"<\(map { $0.description }.joined(separator: ", "))>"
}
}

View File

@ -0,0 +1,23 @@
enum Import: Hashable, CustomStringConvertible {
case library(name: String)
case component(kind: String, name: String)
var description: String {
switch self {
case .library(let name):
return name
case .component(let kind, let name):
return "\(kind) \(name)"
}
}
}
//extension Import: Hashable {
// func hash(into hasher: inout Hasher) {
// hasher.combine(kind)
// }
//
// static func == (lhs: Import, rhs: Import) -> Bool {
// lhs.kind == rhs.kind
// }
//}

View File

@ -0,0 +1,5 @@
import Foundation
protocol Inheritable {
func isEqual(to other: Inheritable) -> Bool
}

View File

@ -0,0 +1,32 @@
struct Initializer: Token, HasAttributes, HasAccessibility {
var parent: Reference<Token>?
var attributes: [Attribute]
var accessibility: Accessibility
var signature: Method.Signature
var isRequired: Bool
var isOptional: Bool
}
extension Initializer: Inheritable {
func isEqual(to other: Inheritable) -> Bool {
guard let other = other as? Initializer else { return false }
return signature.isApiEqual(to: other.signature)
}
}
extension Initializer: Serializable {
func serialize() -> GeneratorContext {
let accessibility: Accessibility
if let parentProtocol = parent?.asProtocol {
accessibility = parentProtocol.accessibility
} else {
accessibility = self.accessibility
}
return [
"accessibility": accessibility.sourceName,
"attributes": attributes,
"signature": signature.description,
]
}
}

View File

@ -0,0 +1,144 @@
import Foundation
struct Method: Token, HasAttributes, HasAccessibility, HasName {
var parent: Reference<Token>?
var attributes: [Attribute]
var accessibility: Accessibility
var name: String
var signature: Signature
var isOptional: Bool
var isOverriding: Bool
var fullSignature: String {
[
accessibility.sourceName,
"\(name)\(signature.description)",
]
.compactMap { $0.nilIfEmpty }
.joined(separator: " ")
}
}
extension Method: Inheritable {
func isEqual(to other: Inheritable) -> Bool {
guard let other = other as? Method else { return false }
return name == other.name && signature.isApiEqual(to: other.signature)
}
}
extension Method {
var fullyQualifiedName: String {
"\(name)\(signature.description.indented(times: 3).trimmed)"
}
var isAsync: Bool {
signature.asyncType.map { $0.isAsync || $0.isReasync } ?? false
}
var isThrowing: Bool {
signature.throwType.map { $0.isThrowing || $0.isRethrowing } ?? false
}
var returnType: WrappableType? {
signature.returnType
}
var hasClosureParams: Bool {
signature.parameters.contains { $0.isClosure }
}
var hasOptionalParams: Bool {
signature.parameters.contains { $0.isOptional }
}
func serialize() -> [String : Any] {
let call = signature.parameters
.map { parameter in
let value = "\(parameter.isInout ? "&" : "")\(parameter.usableName)\(parameter.isAutoClosure ? "()" : "")"
if parameter.name == "_" {
return value
} else {
return "\(parameter.name): \(value)"
}
}
.joined(separator: ", ")
guard let parent else {
fatalError("Failed to find parent of method \(fullSignature). Please file a bug.")
}
let stubFunctionPrefix = parent.isClass ? "Class" : "Protocol"
let returnString = returnType == nil || returnType?.sugarized == "Void" ? "NoReturn" : ""
let throwingString = isThrowing ? "Throwing" : ""
let stubFunction = "Cuckoo.\(stubFunctionPrefix)Stub\(returnString)\(throwingString)Function"
let escapingParameterNames = signature.parameters.map { parameter in
if parameter.isClosure && !parameter.isEscaping {
let parameterCount = parameter.closureParamCount
let parameterSignature = parameterCount > 0 ? (1...parameterCount).map { _ in "_" }.joined(separator: ", ") : "()"
// FIXME: Instead of parsing the closure return type here, Tokenizer should do it and pass the information in a data structure
let returnSignature: String
let closureReturnType = extractClosureReturnType(parameter: parameter.type.sugarized)
if let closureReturnType = closureReturnType, !closureReturnType.isEmpty && closureReturnType != "Void" {
returnSignature = " -> " + closureReturnType
} else {
returnSignature = ""
}
return "{ \(parameterSignature)\(returnSignature) in fatalError(\"This is a stub! It's not supposed to be called!\") }"
} else {
return parameter.usableName
}
}.joined(separator: ", ")
return [
"self": self,
"isOverriding": isOverriding,
"name": name,
"accessibility": accessibility.sourceName,
"signature": signature.description,
"parameters": signature.parameters,
"parameterNames": signature.parameters.map { $0.usableName }.joined(separator: ", "),
"escapingParameterNames": escapingParameterNames,
"returnType": returnType?.explicitOptionalOnly.sugarized ?? "",
"isAsync": isAsync,
"isThrowing": isThrowing,
"throwType": signature.throwType?.description ?? "",
"fullyQualifiedName": fullyQualifiedName,
"call": call,
"parameterSignature": signature.parameters.map { $0.description }.joined(separator: ", "),
"parameterSignatureWithoutNames": signature.parameters.map { "\($0.name): \($0.type)" }.joined(separator: ", "),
"argumentSignature": signature.parameters.map { $0.type.description }.joined(separator: ", "),
"stubFunction": stubFunction,
"inputTypes": signature.parameters.map { $0.typeWithoutAttributes }.joined(separator: ", "),
"isOptional": isOptional,
"hasClosureParams": hasClosureParams,
"hasOptionalParams": hasOptionalParams,
"attributes": attributes,
"genericParameters": signature.genericParameters.sourceDescription,
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
]
}
private func extractClosureReturnType(parameter: String) -> String? {
var parenLevel = 0
for i in 0..<parameter.count {
let index = parameter.index(parameter.startIndex, offsetBy: i)
let character = parameter[index]
if character == "(" {
parenLevel += 1
} else if character == ")" {
parenLevel -= 1
if parenLevel == 0 {
let returnSignature = String(parameter[parameter.index(after: index)..<parameter.endIndex])
let regex = try! NSRegularExpression(pattern: "\\s*->\\s*(.*)\\s*")
guard let result = regex.matches(in: returnSignature, range: NSRange(location: 0, length: returnSignature.count)).first else { return nil }
return returnSignature[result.range(at: 1)]
}
}
}
return nil
}
}

View File

@ -0,0 +1,86 @@
struct MethodParameter: Token {
var parent: Reference<Token>?
var name: String
var innerName: String?
var type: WrappableType
var isInout: Bool
var nameAndInnerName: String {
[name, innerName].compactMap { $0 }.joined(separator: " ")
}
var usableName: String {
innerName ?? name
// if name == "_" {
// guard let innerName else {
// fatalError("Parameter inner name shouldn't be empty if name is an underscore. Please file a bug.")
// }
// return innerName
// } else {
// return name
// }
}
var description: String {
"\(nameAndInnerName): \(isInout ? "inout " : "")\(type)"
}
var typeWithoutAttributes: String {
type.withoutAttributes.sugarized.trimmed
}
var isClosure: Bool {
typeWithoutAttributes.hasPrefix("(") && typeWithoutAttributes.range(of: "->") != nil
}
var isAutoClosure: Bool {
type.containsAttribute(named: "@autoclosure")
}
var isOptional: Bool {
type.isOptional
}
var closureParamCount: Int {
// make sure that the parameter is a closure and that it's not just an empty `() -> ...` closure
guard isClosure && !"^\\s*\\(\\s*\\)".regexMatches(typeWithoutAttributes) else { return 0 }
var parenLevel = 0
var parameterCount = 1
for character in typeWithoutAttributes {
switch character {
case "(", "<":
parenLevel += 1
case ")", ">":
parenLevel -= 1
case ",":
parameterCount += parenLevel == 1 ? 1 : 0
default:
break
}
if parenLevel == 0 {
break
}
}
return parameterCount
}
var isEscaping: Bool {
isClosure && (type.containsAttribute(named: "@escaping") || type.isOptional)
}
func serialize() -> [String: Any] {
return [
"name": name,
"innerName": innerName ?? "",
"type": type,
"nameAndInnerName": nameAndInnerName,
"typeWithoutAttributes": typeWithoutAttributes,
"isClosure": isClosure,
"isOptional": isOptional,
"isEscaping": isEscaping
]
}
}

View File

@ -0,0 +1,70 @@
import Foundation
extension Method {
struct Signature {
let genericParameters: [GenericParameter]
let parameters: [MethodParameter]
let asyncType: AsyncType?
let throwType: ThrowType?
let returnType: WrappableType?
let whereConstraints: [String]
init(
genericParameters: [GenericParameter],
parameters: [MethodParameter],
asyncType: AsyncType? = nil,
throwType: ThrowType? = nil,
returnType: WrappableType? = nil,
whereConstraints: [String]
) {
self.genericParameters = genericParameters
self.parameters = parameters.enumerated().map { index, parameter in
MethodParameter(
parent: parameter.parent,
name: parameter.name,
innerName: "p\(index)",
type: parameter.type,
isInout: parameter.isInout
)
}
self.asyncType = asyncType
self.throwType = throwType
self.returnType = returnType
self.whereConstraints = whereConstraints
}
var description: String {
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
let returnString: String?
if let returnType {
let trimmedReturnType = returnType.explicitOptionalOnly.sugarized.trimmed
let returnsVoid = trimmedReturnType.isEmpty || trimmedReturnType == "Void"
returnString = returnsVoid ? nil : "-> \(returnType)"
} else {
returnString = nil
}
let whereString = whereConstraints.isEmpty ? nil : "where \(whereConstraints.joined(separator: ", "))"
return [
genericParametersString.isEmpty ? nil : "<\(genericParametersString)>",
"(\(parameters.map { $0.description }.joined(separator: ", ")))",
asyncType?.description,
throwType?.description,
returnString,
whereString,
]
.compactMap { $0 }
.joined(separator: " ")
}
}
}
extension Method.Signature {
func isApiEqual(to other: Method.Signature) -> Bool {
genericParameters == other.genericParameters
&& parameters.elementsEqual(other.parameters) { $0.name == $1.name && $0.type == $1.type }
&& asyncType == other.asyncType
&& throwType == other.throwType
&& returnType == other.returnType
&& whereConstraints == other.whereConstraints
}
}

View File

@ -0,0 +1,22 @@
import Foundation
/// This structure exists purely for supporting nested classes,
/// it could be any container (like `struct` or `extension`).
struct NamespaceDeclaration: Token, HasAccessibility, HasName, HasMembers {
var parent: Reference<Token>?
var attributes: [Attribute]
var accessibility: Accessibility
var name: String
var members: [Token]
func replacing(members: [Token]) -> NamespaceDeclaration {
NamespaceDeclaration(
parent: parent,
attributes: attributes,
accessibility: accessibility,
name: name,
members: members
)
}
}

View File

@ -0,0 +1,40 @@
struct ProtocolDeclaration: ContainerToken {
var parent: Reference<Token>?
var attributes: [Attribute]
var accessibility: Accessibility
var name: String
var genericParameters: [GenericParameter]
var genericRequirements: [String]
var inheritedTypes: [String]
var members: [Token]
var isNSObjectProtocol = false
func replacing(members: [Token]) -> ProtocolDeclaration {
ProtocolDeclaration(
parent: parent,
attributes: attributes,
accessibility: accessibility,
name: name,
genericParameters: genericParameters,
genericRequirements: genericRequirements,
inheritedTypes: inheritedTypes,
members: members,
isNSObjectProtocol: isNSObjectProtocol
)
}
func replacing(isNSObjectProtocol: Bool) -> ProtocolDeclaration {
ProtocolDeclaration(
parent: parent,
attributes: attributes,
accessibility: accessibility,
name: name,
genericParameters: genericParameters,
genericRequirements: genericRequirements,
inheritedTypes: inheritedTypes,
members: members,
isNSObjectProtocol: isNSObjectProtocol
)
}
}

View File

@ -0,0 +1,19 @@
protocol Serializable {
func serialize() -> GeneratorContext
}
typealias GeneratorContext = [String: Any]
extension GeneratorContext {
mutating func merge(_ other: GeneratorContext) {
merge(other, uniquingKeysWith: { $1 })
}
}
extension Array where Element == GeneratorContext {
func merge() -> GeneratorContext {
var context: GeneratorContext = [:]
forEach { context.merge($0) }
return context
}
}

View File

@ -0,0 +1,26 @@
enum ThrowType: String, CustomStringConvertible, Equatable {
case `throws`
case `rethrows`
init?(string: String) {
if string.trimmed.hasPrefix(ThrowType.throws.rawValue) {
self = .throws
} else if string.trimmed.hasPrefix(ThrowType.rethrows.rawValue) {
self = .rethrows
} else {
return nil
}
}
var isThrowing: Bool {
self == .throws
}
var isRethrowing: Bool {
self == .rethrows
}
var description: String {
rawValue
}
}

View File

@ -0,0 +1,97 @@
protocol Token: Serializable {
var parent: Reference<Token>? { get set }
}
extension Token {
func serialize() -> GeneratorContext {
commonSerialize()
}
func commonSerialize() -> GeneratorContext {
[
[
"@type": "\(type(of: self))",
"isImplementation": isClass,
"hasParent": parent != nil,
],
(self as? ContainerToken)?.containerSerialize(),
(self as? HasName)?.nameSerialize(),
(parent?.value as? HasName).map { ["parentFullyQualifiedName": $0.fullyQualifiedName] },
(self as? HasGenerics)?.genericsSerialize(),
asProtocol.map { ["isNSObjectProtocol": $0.isNSObjectProtocol] },
(self as? HasInheritance)?.inheritanceSerialize(),
]
.compactMap { $0 }
.merge()
}
var isMockable: Bool {
[isClass, isProtocol, isVariable, isMethod].contains(true)
}
var isVariable: Bool {
self is Variable
}
var isMethod: Bool {
self is Method
}
var isClass: Bool {
self is ClassDeclaration
}
var asClass: ClassDeclaration? {
self as? ClassDeclaration
}
var isProtocol: Bool {
self is ProtocolDeclaration
}
var asProtocol: ProtocolDeclaration? {
self as? ProtocolDeclaration
}
}
extension Token where Self: HasName {
func nameSerialize() -> GeneratorContext {
[
"name": name,
"mockName": mockName,
]
}
}
extension Token where Self: HasGenerics {
func genericsSerialize() -> GeneratorContext {
let genericParametersString = genericParameters.map { $0.description }.joined(separator: ", ")
let genericArgumentsString = genericParameters.map { $0.name }.joined(separator: ", ")
let genericProtocolIdentity = isProtocol ? genericParameters.map { "\(Templates.staticGenericParameter).\($0.name) == \($0.name)" }.joined(separator: ", ") : nil
let isGeneric = !genericParameters.isEmpty
return [
"isGeneric": isGeneric,
"genericParameters": isGeneric ? "<\(genericParametersString)>" : "",
"genericArguments": isGeneric ? "<\(genericArgumentsString)>" : "",
"genericProtocolIdentity": genericProtocolIdentity,
]
.compactMapValues { $0 }
}
}
extension Token where Self: HasInheritance {
func inheritanceSerialize() -> GeneratorContext {
[
"inheritedTypes": inheritedTypes,
]
}
}
extension Token where Self: HasAttributes {
func attributesSerialize() -> GeneratorContext {
[
"attributes": attributes,
]
}
}

View File

@ -0,0 +1,43 @@
struct Variable: Token, HasAccessibility, HasAttributes {
var parent: Reference<Token>?
var attributes: [Attribute]
var accessibility: Accessibility
var setterAccessibility: Accessibility?
var name: String
var type: WrappableType
var isOverriding: Bool
var isReadOnly: Bool {
setterAccessibility?.isAccessible != true
}
func serialize() -> [String: Any] {
let readOnlyString = isReadOnly ? "ReadOnly" : ""
let optionalString = type.isOptional && !isReadOnly ? "Optional" : ""
guard let parent else {
fatalError("Failed to find parent of variable \(name). Please file a bug.")
}
return [
"isOverriding": isOverriding,
"name": name,
"type": type.sugarized,
"nonOptionalType": type.unoptionaled.sugarized,
"accessibility": accessibility.sourceName,
"isReadOnly": isReadOnly,
"stubType": (parent.isClass ? "Class" : "Protocol") + "ToBeStubbed\(readOnlyString)\(optionalString)Property",
"verifyType": "Verify\(readOnlyString)\(optionalString)Property",
"attributes": attributes,
"hasUnavailablePlatforms": hasUnavailablePlatforms,
"unavailablePlatformsCheck": unavailablePlatformsCheck,
]
}
}
extension Variable: Inheritable {
func isEqual(to other: Inheritable) -> Bool {
guard let other = other as? Variable else { return false }
return name == other.name
}
}

View File

@ -1,10 +1,10 @@
public enum WrappableType {
enum WrappableType {
indirect case optional(WrappableType)
indirect case implicitlyUnwrappedOptional(WrappableType)
indirect case attributed(WrappableType, attributes: [String])
case type(String)
public var sugarized: String {
var sugarized: String {
switch self {
case .optional(let wrapped):
return "\(wrapped.sugarized)?"
@ -17,7 +17,7 @@ public enum WrappableType {
}
}
public var desugarized: String {
var desugarized: String {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return "Optional<\(wrapped.desugarized)>"
@ -28,7 +28,7 @@ public enum WrappableType {
}
}
public var explicitOptionalOnly: WrappableType {
var explicitOptionalOnly: WrappableType {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return .optional(wrapped.explicitOptionalOnly)
@ -39,7 +39,7 @@ public enum WrappableType {
}
}
public var unoptionaled: WrappableType {
var unoptionaled: WrappableType {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return wrapped.unoptionaled
@ -50,7 +50,7 @@ public enum WrappableType {
}
}
public var unwrapped: WrappableType {
var unwrapped: WrappableType {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return wrapped
@ -61,7 +61,7 @@ public enum WrappableType {
}
}
public var withoutAttributes: WrappableType {
var withoutAttributes: WrappableType {
switch self {
case .optional(let wrapped):
return .optional(wrapped.withoutAttributes)
@ -74,7 +74,7 @@ public enum WrappableType {
}
}
public var isOptional: Bool {
var isOptional: Bool {
switch self {
case .optional, .implicitlyUnwrappedOptional:
return true
@ -85,7 +85,7 @@ public enum WrappableType {
}
}
public init(parsing value: String) {
init(parsing value: String) {
let trimmedValue = value.trimmed
let optionalPrefix = "Optional<"
if trimmedValue.hasPrefix("@") {
@ -113,7 +113,7 @@ public enum WrappableType {
}
}
public func containsAttribute(named attribute: String) -> Bool {
func containsAttribute(named attribute: String) -> Bool {
switch self {
case .optional(let wrapped), .implicitlyUnwrappedOptional(let wrapped):
return wrapped.containsAttribute(named: attribute)
@ -126,13 +126,13 @@ public enum WrappableType {
}
extension WrappableType: CustomStringConvertible {
public var description: String {
return sugarized
var description: String {
sugarized
}
}
extension WrappableType: Equatable {
public static func ==(lhs: WrappableType, rhs: WrappableType) -> Bool {
static func ==(lhs: WrappableType, rhs: WrappableType) -> Bool {
switch (lhs, rhs) {
case (.optional(let lhsWrapped), .optional(let rhsWrapped)),
(.implicitlyUnwrappedOptional(let lhsWrapped), .implicitlyUnwrappedOptional(let rhsWrapped)):

View File

@ -2,6 +2,7 @@ import Foundation
struct TypeGuesser {
static func guessType(from value: String) -> String? {
guard !value.trimmed.isEmpty else { return nil }
let value = value.trimmed
let casting = checkCasting(from: value)
guard casting == nil else { return casting }

View File

@ -1,5 +1,4 @@
import Foundation
import SourceKittenFramework
extension String {
var trimmed: String {
@ -31,26 +30,19 @@ extension String {
}
}
extension Sequence {
#if !swift(>=4.1)
public func compactMap<O>(_ transform: (Element) -> O?) -> [O] {
return self.flatMap(transform)
}
#endif
func only<T>(_ type: T.Type) -> [T] {
extension Sequence where Element: Token {
func only<T: Token>(_ type: T.Type) -> [T] {
return compactMap { $0 as? T }
}
func noneOf<T>(_ type: T.Type) -> [Iterator.Element] {
func noneOf<T: Token>(_ type: T.Type) -> [Iterator.Element] {
return filter { !($0 is T) }
}
}
internal func extractRange(from dictionary: [String: SourceKitRepresentable], offset: Key, length: Key) -> CountableRange<Int>? {
guard let offset = (dictionary[offset.rawValue] as? Int64).map(Int.init),
let length = (dictionary[length.rawValue] as? Int64).map(Int.init) else { return nil }
return offset..<offset.advanced(by: length)
}
//func extractRange(from dictionary: [String: SourceKitRepresentable], offset: Key, length: Key) -> CountableRange<Int>? {
// guard let offset = (dictionary[offset.rawValue] as? Int64).map(Int.init),
// let length = (dictionary[length.rawValue] as? Int64).map(Int.init) else { return nil }
//
// return offset..<offset.advanced(by: length)
//}

View File

@ -0,0 +1,77 @@
import XCTest
final class OrderedSetTest: XCTestCase {
func testInitializers() {
_ = OrderedSet<Int>()
_ = [] as OrderedSet<String>
_ = ["1", "2", "4"] as OrderedSet<String>
}
func testEmpty() {
let set = OrderedSet<Double>()
XCTAssertEqual(set.values, [])
}
func testBasicUsage() {
var set = OrderedSet<Int>()
set.insert(2)
XCTAssertEqual(set.values, [2])
set.insert(0)
XCTAssertEqual(set.values, [2, 0])
set.insert(1)
XCTAssertEqual(set.values, [2, 0, 1])
}
func testDeduplicationInit() {
let set: OrderedSet<Int> = [1, 2, 3, 2, 0, 1]
XCTAssertEqual(set.values, [1, 2, 3, 0])
}
func testDeduplicationInsert() {
var set = OrderedSet<String>()
set.insert("1")
XCTAssertEqual(set.values, ["1"])
set.insert("11")
XCTAssertEqual(set.values, ["1", "11"])
set.insert("111")
XCTAssertEqual(set.values, ["1", "11", "111"])
set.insert("11")
XCTAssertEqual(set.values, ["1", "11", "111"])
set.insert("1")
XCTAssertEqual(set.values, ["1", "11", "111"])
}
func testRemove() {
var set: OrderedSet<String> = ["gg", "bg", "wp", "ez"]
set.remove("ez")
XCTAssertEqual(set.values, ["gg", "bg", "wp"])
set.remove("bg")
XCTAssertEqual(set.values, ["gg", "wp"])
}
func testContains() {
var set: OrderedSet<Int> = [1, 2, 3, 4, 5]
XCTAssertFalse(set.contains(6))
XCTAssertTrue(set.contains(1))
set.insert(6)
XCTAssertTrue(set.contains(6))
set.remove(2)
XCTAssertFalse(set.contains(2))
}
func testIntersection() {
let set1: OrderedSet<Int> = [1, 2, 3, 4]
let set2: OrderedSet<Int> = [2, 3, 4, 5]
XCTAssertEqual(set1.intersection(set2).values, [2, 3, 4])
XCTAssertEqual(set1.values, [1, 2, 3, 4])
XCTAssertEqual(set2.values, [2, 3, 4, 5])
}
func testUnion() {
let set1: OrderedSet<Int> = [1, 2, 3, 4]
let set2: OrderedSet<Int> = [2, 3, 4, 5]
XCTAssertEqual(set1.union(set2).values, [1, 2, 3, 4, 5])
XCTAssertEqual(set1.values, [1, 2, 3, 4])
XCTAssertEqual(set2.values, [2, 3, 4, 5])
}
}

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:feb332ba0a027812b1ee7f552321d6069a46207e5cd0f64fa9bb78e2a261b366
size 36606619

View File

@ -2,6 +2,9 @@
dev:
(killall Xcode || true)
# Unzip SwiftSyntax XCFramework.
pushd Generator; unzip -o lib_InternalSwiftSyntaxParser.xcframework.zip; popd
# Generate Xcode structure.
tuist generate --no-open
# Use Bundler if available, otherwise just call system-wide CocoaPods.
if ! command -v bundle &> /dev/null; then bundle install && bundle exec pod install; else pod install; fi

View File

@ -1,10 +1,3 @@
//
// Cuckoo-BridgingHeader.h
// Cuckoo
//
// Created by Matyáš Kříž on 28/05/2019.
//
#ifndef Cuckoo_BridgingHeader_h
#define Cuckoo_BridgingHeader_h

View File

@ -1,10 +1,3 @@
//
// NSValueConvertible.swift
// Cuckoo+OCMock-iOS
//
// Created by Matyáš Kříž on 28/05/2019.
//
import Foundation
import CoreGraphics

View File

@ -1,11 +1,3 @@
//
// NSInvocation+OCMockWrapper.h
// Cuckoo-CocoaPodsTests
//
// Created by Matyáš Kříž on 27/05/2019.
// Copyright © 2019 Cuckoo. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN

View File

@ -1,11 +1,3 @@
//
// NSInvocation+OCMockWrapper.m
// Cuckoo-CocoaPodsTests
//
// Created by Matyáš Kříž on 27/05/2019.
// Copyright © 2019 Cuckoo. All rights reserved.
//
#import "NSInvocation+OCMockWrapper.h"
#import <OCMock/OCMFunctions.h>

View File

@ -1,11 +1,3 @@
//
// NSObject+TrustMe.h
// Cuckoo-CocoaPodsTests
//
// Created by Tadeáš Kříž on 28/05/2019.
// Copyright © 2019 Cuckoo. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN

View File

@ -1,11 +1,3 @@
//
// NSObject+TrustMe.m
// Cuckoo-CocoaPodsTests
//
// Created by Tadeáš Kříž on 28/05/2019.
// Copyright © 2019 Cuckoo. All rights reserved.
//
#import "NSObject+TrustMe.h"
#import <OCMock/OCMock.h>

View File

@ -1,10 +1,3 @@
//
// OCMockObject+CuckooMockObject.h
// Cuckoo+OCMock-iOS
//
// Created by Matyáš Kříž on 28/05/2019.
//
#import <OCMock/OCMock.h>
NS_ASSUME_NONNULL_BEGIN

View File

@ -1,10 +1,3 @@
//
// OCMockObject+CuckooMockObject.m
// Cuckoo+OCMock-iOS
//
// Created by Matyáš Kříž on 28/05/2019.
//
#import "OCMockObject+CuckooMockObject.h"
@implementation CuckooMockObject

Some files were not shown because too many files have changed in this diff Show More