From cfe92f8803f8970a887a27bcfe959c7377f798b5 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Thu, 24 Sep 2020 11:00:46 -0700 Subject: [PATCH 01/15] Added SwiftPM support. --- Package.swift | 33 ++++++++++++++++++ Sources/Mockingjay/MockingjayProtocol.swift | 4 ++- .../MockingjayURLSessionConfiguration.m | 23 ------------ .../MockingjayURLSessionConfiguration.swift | 16 +++++++++ .../Media.xcassets/Contents.json | 6 ++++ .../TestAudio.dataset/Contents.json | 16 +++++++++ .../TestAudio.dataset}/TestAudio.m4a | Bin .../MockingjayAsyncProtocolTests.swift | 20 +++++++++-- 8 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 Package.swift delete mode 100644 Sources/Mockingjay/MockingjayURLSessionConfiguration.m create mode 100644 Sources/Mockingjay/MockingjayURLSessionConfiguration.swift create mode 100644 Tests/MockingjayTests/Media.xcassets/Contents.json create mode 100644 Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json rename Tests/MockingjayTests/{ => Media.xcassets/TestAudio.dataset}/TestAudio.m4a (100%) diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..d4d4eca --- /dev/null +++ b/Package.swift @@ -0,0 +1,33 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Mockingjay", + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "Mockingjay", + targets: ["Mockingjay"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(name: "URITemplate", url: "https://github.com/kylef/URITemplate.swift.git", .branch("master")), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "Mockingjay", + dependencies: [ + .product(name: "URITemplate", package: "URITemplate"), + ]), + .testTarget( + name: "MockingjayTests", + dependencies: [ + "Mockingjay", + .product(name: "URITemplate", package: "URITemplate"), + ]), + ] +) diff --git a/Sources/Mockingjay/MockingjayProtocol.swift b/Sources/Mockingjay/MockingjayProtocol.swift index 0d224e9..a175326 100644 --- a/Sources/Mockingjay/MockingjayProtocol.swift +++ b/Sources/Mockingjay/MockingjayProtocol.swift @@ -40,7 +40,9 @@ public class MockingjayProtocol: URLProtocol { stubs.append(stub) if !registered { - URLProtocol.registerClass(MockingjayProtocol.self) + MockingjayURLSessionConfiguration.swizzleDefaultSessionConfiguration() + URLProtocol.registerClass(MockingjayProtocol.self) + registered = true } return stub diff --git a/Sources/Mockingjay/MockingjayURLSessionConfiguration.m b/Sources/Mockingjay/MockingjayURLSessionConfiguration.m deleted file mode 100644 index f83735a..0000000 --- a/Sources/Mockingjay/MockingjayURLSessionConfiguration.m +++ /dev/null @@ -1,23 +0,0 @@ -// -// MockingjayURLSessionConfiguration.m -// Mockingjay -// -// Created by Kyle Fuller on 10/05/2016. -// Copyright © 2016 Cocode. All rights reserved. -// - -#import -#import - - -@interface MockingjayURLConfiguration : NSObject - -@end - -@implementation MockingjayURLConfiguration - -+ (void)load { - [NSURLSessionConfiguration mockingjaySwizzleDefaultSessionConfiguration]; -} - -@end \ No newline at end of file diff --git a/Sources/Mockingjay/MockingjayURLSessionConfiguration.swift b/Sources/Mockingjay/MockingjayURLSessionConfiguration.swift new file mode 100644 index 0000000..a7a44f4 --- /dev/null +++ b/Sources/Mockingjay/MockingjayURLSessionConfiguration.swift @@ -0,0 +1,16 @@ +// +// MockingjayURLSessionConfiguration.m +// Mockingjay +// +// Created by Kyle Fuller on 10/05/2016. +// Copyright © 2016 Cocode. All rights reserved. +// + +import Foundation + +public class MockingjayURLSessionConfiguration: NSObject { + + public class func swizzleDefaultSessionConfiguration() { + URLSessionConfiguration.mockingjaySwizzleDefaultSessionConfiguration() + } +} diff --git a/Tests/MockingjayTests/Media.xcassets/Contents.json b/Tests/MockingjayTests/Media.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Tests/MockingjayTests/Media.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json b/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json new file mode 100644 index 0000000..c5ec62b --- /dev/null +++ b/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json @@ -0,0 +1,16 @@ +{ + "data" : [ + { + "filename" : "TestAudio.m4a", + "idiom" : "universal", + "universal-type-identifier" : "com.apple.m4a-audio" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "compression-type" : "none" + } +} diff --git a/Tests/MockingjayTests/TestAudio.m4a b/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/TestAudio.m4a similarity index 100% rename from Tests/MockingjayTests/TestAudio.m4a rename to Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/TestAudio.m4a diff --git a/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift b/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift index 555e56d..df7d4bd 100644 --- a/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift +++ b/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift @@ -10,6 +10,20 @@ import Foundation import XCTest import Mockingjay +extension Bundle { + var testBundle: Bundle? { + guard self.bundlePath.hasSuffix("xctest"), + let contents = try? FileManager.default.contentsOfDirectory(atPath: bundleURL.deletingLastPathComponent().path), + let testBundlePath: String = contents.first(where: { (path: String) -> Bool in + path.hasSuffix("bundle") + }), + let result = Bundle.init(url: bundleURL.deletingLastPathComponent().appendingPathComponent(testBundlePath)) + else { return nil } + + return result + } +} + class MockingjayAsyncProtocolTests: XCTestCase, URLSessionDataDelegate { typealias DidReceiveDataHandler = (_ session: Foundation.URLSession, _ dataTask: URLSessionDataTask, _ data: Data) -> () @@ -61,7 +75,7 @@ class MockingjayAsyncProtocolTests: XCTestCase, URLSessionDataDelegate { func testDownloadOfAudioFileInChunks() { let request = URLRequest(url: URL(string: "https://fuller.li/")!) - let path = Bundle(for: self.classForCoder).path(forResource: "TestAudio", ofType: "m4a") + let path = Bundle(for: self.classForCoder).testBundle!.path(forResource: "TestAudio", ofType: "m4a") let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) let stubResponse = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: ["Content-Length" : String(data.count)])! @@ -91,14 +105,14 @@ class MockingjayAsyncProtocolTests: XCTestCase, URLSessionDataDelegate { let length = 100000 var request = URLRequest(url: URL(string: "https://fuller.li/")!) request.addValue("bytes=50000-149999", forHTTPHeaderField: "Range") - let path = Bundle(for: self.classForCoder).path(forResource: "TestAudio", ofType: "m4a") + let path = Bundle(for: self.classForCoder).testBundle!.path(forResource: "TestAudio", ofType: "m4a") let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) let stubResponse = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: ["Content-Length" : String(length)])! MockingjayProtocol.addStub(matcher: { (requestedRequest) -> (Bool) in return true }) { (request) -> (Response) in - return Response.success(stubResponse, .streamContent(data: data, inChunksOf: 2000)) + return Response.success(stubResponse, .streamContent(data: data, inChunksOf: 2000)) } let urlSession = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue.current) From 557b97ca9b120df0aee46d9678af552f2c1689e2 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Mon, 5 Oct 2020 21:44:04 -0700 Subject: [PATCH 02/15] Fixed swift build warnings --- .gitignore | 1 + Package.swift | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e0ae851..cea0fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Xcode # build/ +.build *.pbxuser !default.pbxuser *.mode1v3 diff --git a/Package.swift b/Package.swift index d4d4eca..c428b1b 100644 --- a/Package.swift +++ b/Package.swift @@ -22,12 +22,17 @@ let package = Package( name: "Mockingjay", dependencies: [ .product(name: "URITemplate", package: "URITemplate"), - ]), + ], + exclude: ["Info.plist"] + ), + .testTarget( name: "MockingjayTests", dependencies: [ "Mockingjay", .product(name: "URITemplate", package: "URITemplate"), - ]), + ], + exclude: ["Info.plist"] + ), ] ) From 3ac912bdf3aa0f43bf92662cd3da762428cbb1e1 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Mon, 5 Oct 2020 22:58:31 -0700 Subject: [PATCH 03/15] Remove asset catalog --- .travis.yml | 5 ++--- Package.swift | 3 ++- .../Media.xcassets/Contents.json | 6 ------ .../TestAudio.dataset/Contents.json | 16 ---------------- .../MockingjayAsyncProtocolTests.swift | 18 ++---------------- .../TestAudio.dataset => }/TestAudio.m4a | Bin 6 files changed, 6 insertions(+), 42 deletions(-) delete mode 100644 Tests/MockingjayTests/Media.xcassets/Contents.json delete mode 100644 Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json rename Tests/MockingjayTests/{Media.xcassets/TestAudio.dataset => }/TestAudio.m4a (100%) diff --git a/.travis.yml b/.travis.yml index ad100f7..f53bb73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,5 @@ matrix: - os: osx osx_image: xcode10.2 script: - - cd URITemplate && swift package generate-xcodeproj && cd .. - - xcodebuild -project Mockingjay.xcodeproj -scheme Mockingjay test - - pod lib lint --quick + - swift package update + - swift test diff --git a/Package.swift b/Package.swift index c428b1b..9400eef 100644 --- a/Package.swift +++ b/Package.swift @@ -32,7 +32,8 @@ let package = Package( "Mockingjay", .product(name: "URITemplate", package: "URITemplate"), ], - exclude: ["Info.plist"] + exclude: ["Info.plist"], + resources: [.process("TestAudio.m4a")] ), ] ) diff --git a/Tests/MockingjayTests/Media.xcassets/Contents.json b/Tests/MockingjayTests/Media.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/Tests/MockingjayTests/Media.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json b/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json deleted file mode 100644 index c5ec62b..0000000 --- a/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "data" : [ - { - "filename" : "TestAudio.m4a", - "idiom" : "universal", - "universal-type-identifier" : "com.apple.m4a-audio" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "compression-type" : "none" - } -} diff --git a/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift b/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift index df7d4bd..e5fe8dd 100644 --- a/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift +++ b/Tests/MockingjayTests/MockingjayAsyncProtocolTests.swift @@ -10,20 +10,6 @@ import Foundation import XCTest import Mockingjay -extension Bundle { - var testBundle: Bundle? { - guard self.bundlePath.hasSuffix("xctest"), - let contents = try? FileManager.default.contentsOfDirectory(atPath: bundleURL.deletingLastPathComponent().path), - let testBundlePath: String = contents.first(where: { (path: String) -> Bool in - path.hasSuffix("bundle") - }), - let result = Bundle.init(url: bundleURL.deletingLastPathComponent().appendingPathComponent(testBundlePath)) - else { return nil } - - return result - } -} - class MockingjayAsyncProtocolTests: XCTestCase, URLSessionDataDelegate { typealias DidReceiveDataHandler = (_ session: Foundation.URLSession, _ dataTask: URLSessionDataTask, _ data: Data) -> () @@ -75,7 +61,7 @@ class MockingjayAsyncProtocolTests: XCTestCase, URLSessionDataDelegate { func testDownloadOfAudioFileInChunks() { let request = URLRequest(url: URL(string: "https://fuller.li/")!) - let path = Bundle(for: self.classForCoder).testBundle!.path(forResource: "TestAudio", ofType: "m4a") + let path = Bundle.module.path(forResource: "TestAudio", ofType: "m4a") let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) let stubResponse = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: ["Content-Length" : String(data.count)])! @@ -105,7 +91,7 @@ class MockingjayAsyncProtocolTests: XCTestCase, URLSessionDataDelegate { let length = 100000 var request = URLRequest(url: URL(string: "https://fuller.li/")!) request.addValue("bytes=50000-149999", forHTTPHeaderField: "Range") - let path = Bundle(for: self.classForCoder).testBundle!.path(forResource: "TestAudio", ofType: "m4a") + let path = Bundle.module.path(forResource: "TestAudio", ofType: "m4a") let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) let stubResponse = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: ["Content-Length" : String(length)])! diff --git a/Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/TestAudio.m4a b/Tests/MockingjayTests/TestAudio.m4a similarity index 100% rename from Tests/MockingjayTests/Media.xcassets/TestAudio.dataset/TestAudio.m4a rename to Tests/MockingjayTests/TestAudio.m4a From b258f4b495ff55d10f534a8d002e9156e46570e3 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Mon, 5 Oct 2020 23:09:49 -0700 Subject: [PATCH 04/15] Updated travis --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f53bb73..dad9388 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ -matrix: - include: - - os: osx - osx_image: xcode10.2 +language: swift +osx_image: xcode12u script: - - swift package update - - swift test +- swift --version +- swift package update +- swift test \ No newline at end of file From f0be8d04222601aaac68cb86f58390c7d182c89d Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Tue, 6 Oct 2020 10:14:05 -0700 Subject: [PATCH 05/15] added .swiftpm for ci --- .swiftpm/.DS_Store | Bin 0 -> 6148 bytes .swiftpm/xcode/.DS_Store | Bin 0 -> 6148 bytes .../contents.xcworkspacedata | 7 ++ .../UserInterfaceState.xcuserstate | Bin 0 -> 37578 bytes .swiftpm/xcode/xcuserdata/.DS_Store | Bin 0 -> 6148 bytes .../joelsaltzman.xcuserdatad/.DS_Store | Bin 0 -> 6148 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + .../xcschemes/xcschememanagement.plist | 116 ++++++++++++++++++ 8 files changed, 129 insertions(+) create mode 100644 .swiftpm/.DS_Store create mode 100644 .swiftpm/xcode/.DS_Store create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 .swiftpm/xcode/package.xcworkspace/xcuserdata/joelsaltzman.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 .swiftpm/xcode/xcuserdata/.DS_Store create mode 100644 .swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/.DS_Store create mode 100644 .swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 .swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/.swiftpm/.DS_Store b/.swiftpm/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..84eb2cdf0a577e69f804226d173e5c4e66e855a7 GIT binary patch literal 6148 zcmeH~J&FS{427Ta1A%Q)Zs}$ZkQ zSByshY=0Yez!t!U?usuTCT5J+xZ{Em1Ad0z%k?~tS5IS+dp)4@8qe#wED-?_5CIVo z0TGxHfjGo@{(sEqne-?kAOiCs;NOQrcdeM&F&)Nv^b*wK32IGkU74X- zb`O@N7Hx>qlW;H~E2#COhz_Q0%KmU*PSN;E_ zM4#YDCGY^==@Whc literal 0 HcmV?d00001 diff --git a/.swiftpm/xcode/.DS_Store b/.swiftpm/xcode/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0998a6fb59d195322def70c15ce173cd7c5ab263 GIT binary patch literal 6148 zcmeHKy-ve05I&b81z0MvF!~9Qx-x|-JV7Tm@~2iJkt0e43sPntfSEVo9atGycpDbJ zvrmO8Adv;3=uSF+&e>nw`yAOlA~LgeF(sN1Q3Pik?V=}*`|0icz3RnomS2DMBbKFo|9!5JS&0k_WPMF(vC6B=xe6b$nkt|Qr~*S* zK#scTVCaczeyV^f&|3jMA1s_P7Hk9hqXUgE0f1wKy`j&w1aqulEZ7Fb2+Ra3Fi?$@ z7$(pWw=yplYy$>587V%DtZbx0F@ANt-}>of;(*$!0;<5a0z2Vx!uS8#&-MQ{NuN{! zRbWsGm~k>sW=Kiy)=qMK*IM`moQ>zT0XGzM{8fy(d=($Ty&-P71B?aRfQZ2KkARm! K8&%*>75D((fk~wR literal 0 HcmV?d00001 diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/joelsaltzman.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/joelsaltzman.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..2f912c490fd298520b9aa2c89ca574e7fad43933 GIT binary patch literal 37578 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 literal 0 HcmV?d00001 diff --git a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/.DS_Store b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c2e893fa93ba5e25312a5cb0459ba29849a846a6 GIT binary patch literal 6148 zcmeHKyKVwO477oQM?;x%e<6RcLhuFr0D_C4AVSIsiSoMqcE*oHhwjp*h{njCTd!wV zH^mu?h;Hu9tH@eJ=5Ry#v@kT=Hy_v}GluGC9OW)&{NChaP(7Y7?ou9dk_N0EziCg` zS-a2?W>$L@bfPWim oy&SPx# literal 0 HcmV?d00001 diff --git a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..46e30f0 --- /dev/null +++ b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..7280dce --- /dev/null +++ b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,116 @@ + + + + + SchemeUserState + + Mockingjay.xcscheme_^#shared#^_ + + orderHint + 0 + + Spectre (Playground) 1.xcscheme + + isShown + + orderHint + 2 + + Spectre (Playground) 10.xcscheme + + isShown + + orderHint + 11 + + Spectre (Playground) 11.xcscheme + + isShown + + orderHint + 12 + + Spectre (Playground) 2.xcscheme + + isShown + + orderHint + 3 + + Spectre (Playground) 3.xcscheme + + isShown + + orderHint + 4 + + Spectre (Playground) 4.xcscheme + + isShown + + orderHint + 5 + + Spectre (Playground) 5.xcscheme + + isShown + + orderHint + 6 + + Spectre (Playground) 6.xcscheme + + isShown + + orderHint + 7 + + Spectre (Playground) 7.xcscheme + + isShown + + orderHint + 8 + + Spectre (Playground) 8.xcscheme + + isShown + + orderHint + 9 + + Spectre (Playground) 9.xcscheme + + isShown + + orderHint + 10 + + Spectre (Playground).xcscheme + + isShown + + orderHint + 1 + + + SuppressBuildableAutocreation + + Mockingjay + + primary + + + MockingjayTests + + primary + + + Mockingjay_MockingjayTests + + primary + + + + + From f48f1c5522007dcdfb5e99a922ebba105acf9549 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Tue, 6 Oct 2020 10:14:47 -0700 Subject: [PATCH 06/15] removed user files --- .../UserInterfaceState.xcuserstate | Bin 37578 -> 0 bytes .swiftpm/xcode/xcuserdata/.DS_Store | Bin 6148 -> 0 bytes .../joelsaltzman.xcuserdatad/.DS_Store | Bin 6148 -> 0 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 - .../xcschemes/xcschememanagement.plist | 116 ------------------ 5 files changed, 122 deletions(-) delete mode 100644 .swiftpm/xcode/package.xcworkspace/xcuserdata/joelsaltzman.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 .swiftpm/xcode/xcuserdata/.DS_Store delete mode 100644 .swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/.DS_Store delete mode 100644 .swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 .swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/joelsaltzman.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/joelsaltzman.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 2f912c490fd298520b9aa2c89ca574e7fad43933..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37578 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 diff --git a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/.DS_Store b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/.DS_Store deleted file mode 100644 index c2e893fa93ba5e25312a5cb0459ba29849a846a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyKVwO477oQM?;x%e<6RcLhuFr0D_C4AVSIsiSoMqcE*oHhwjp*h{njCTd!wV zH^mu?h;Hu9tH@eJ=5Ry#v@kT=Hy_v}GluGC9OW)&{NChaP(7Y7?ou9dk_N0EziCg` zS-a2?W>$L@bfPWim oy&SPx# diff --git a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index 46e30f0..0000000 --- a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 7280dce..0000000 --- a/.swiftpm/xcode/xcuserdata/joelsaltzman.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,116 +0,0 @@ - - - - - SchemeUserState - - Mockingjay.xcscheme_^#shared#^_ - - orderHint - 0 - - Spectre (Playground) 1.xcscheme - - isShown - - orderHint - 2 - - Spectre (Playground) 10.xcscheme - - isShown - - orderHint - 11 - - Spectre (Playground) 11.xcscheme - - isShown - - orderHint - 12 - - Spectre (Playground) 2.xcscheme - - isShown - - orderHint - 3 - - Spectre (Playground) 3.xcscheme - - isShown - - orderHint - 4 - - Spectre (Playground) 4.xcscheme - - isShown - - orderHint - 5 - - Spectre (Playground) 5.xcscheme - - isShown - - orderHint - 6 - - Spectre (Playground) 6.xcscheme - - isShown - - orderHint - 7 - - Spectre (Playground) 7.xcscheme - - isShown - - orderHint - 8 - - Spectre (Playground) 8.xcscheme - - isShown - - orderHint - 9 - - Spectre (Playground) 9.xcscheme - - isShown - - orderHint - 10 - - Spectre (Playground).xcscheme - - isShown - - orderHint - 1 - - - SuppressBuildableAutocreation - - Mockingjay - - primary - - - MockingjayTests - - primary - - - Mockingjay_MockingjayTests - - primary - - - - - From ecc2dbc6a2137b0aa60654ec3ff3cc57a50dd260 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Mon, 2 Nov 2020 09:06:03 -0800 Subject: [PATCH 07/15] Added content builder --- Sources/Mockingjay/Builders.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/Mockingjay/Builders.swift b/Sources/Mockingjay/Builders.swift index d390a9b..5fe1207 100644 --- a/Sources/Mockingjay/Builders.swift +++ b/Sources/Mockingjay/Builders.swift @@ -24,6 +24,9 @@ public func http(_ status:Int = 200, headers:[String:String]? = nil, download:Do return .failure(NSError(domain: NSExceptionName.internalInconsistencyException.rawValue, code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to construct response for stub."])) } } +public func content(_ data: Data) -> (_ request: URLRequest) -> Response { + return http(200, headers: nil, download: .content(data)) +} public func json(_ body: Any, status:Int = 200, headers:[String:String]? = nil) -> (_ request: URLRequest) -> Response { return { (request:URLRequest) in From 5ada890ce1f9e74a91651e50668e9c7a5441b910 Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Fri, 6 Nov 2020 08:14:50 -0800 Subject: [PATCH 08/15] Added headers to content builder --- Sources/Mockingjay/Builders.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Mockingjay/Builders.swift b/Sources/Mockingjay/Builders.swift index 5fe1207..5777153 100644 --- a/Sources/Mockingjay/Builders.swift +++ b/Sources/Mockingjay/Builders.swift @@ -24,7 +24,7 @@ public func http(_ status:Int = 200, headers:[String:String]? = nil, download:Do return .failure(NSError(domain: NSExceptionName.internalInconsistencyException.rawValue, code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to construct response for stub."])) } } -public func content(_ data: Data) -> (_ request: URLRequest) -> Response { +public func content(_ data: Data, headers: [String:String]? = nil) -> (_ request: URLRequest) -> Response { return http(200, headers: nil, download: .content(data)) } From a1d61f0e90c738dda2d6dc96bec98f55f27b731d Mon Sep 17 00:00:00 2001 From: Joel Saltzman Date: Fri, 6 Nov 2020 08:20:31 -0800 Subject: [PATCH 09/15] Fixed content builder headers not being sent --- Sources/Mockingjay/Builders.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Mockingjay/Builders.swift b/Sources/Mockingjay/Builders.swift index 5777153..3d6e96e 100644 --- a/Sources/Mockingjay/Builders.swift +++ b/Sources/Mockingjay/Builders.swift @@ -25,7 +25,7 @@ public func http(_ status:Int = 200, headers:[String:String]? = nil, download:Do } } public func content(_ data: Data, headers: [String:String]? = nil) -> (_ request: URLRequest) -> Response { - return http(200, headers: nil, download: .content(data)) + return http(200, headers: headers, download: .content(data)) } public func json(_ body: Any, status:Int = 200, headers:[String:String]? = nil) -> (_ request: URLRequest) -> Response { From 11053196a37459758688f047afd6ce0526c0a9b9 Mon Sep 17 00:00:00 2001 From: Pedro Paulo de Amorim Date: Mon, 17 May 2021 01:38:27 +0100 Subject: [PATCH 10/15] Fix MockingjayURLSessionConfiguration.swift --- Mockingjay.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mockingjay.podspec b/Mockingjay.podspec index 0ae36a8..668eadf 100644 --- a/Mockingjay.podspec +++ b/Mockingjay.podspec @@ -18,7 +18,7 @@ Pod::Spec.new do |spec| 'Sources/Mockingjay/MockingjayProtocol.swift', 'Sources/Mockingjay/{Matchers,Builders}.swift', 'Sources/Mockingjay/NSURLSessionConfiguration.swift', - 'Sources/Mockingjay/MockingjayURLSessionConfiguration.m' + 'Sources/Mockingjay/MockingjayURLSessionConfiguration.{m,swift}' end spec.subspec 'XCTest' do |xctest_spec| From 3468185b6af40126542d47358549f1ddc38bc03e Mon Sep 17 00:00:00 2001 From: Dennis Collaris Date: Thu, 23 Sep 2021 22:03:31 +0200 Subject: [PATCH 11/15] fix: ambiguous XCTest.tearDown swizzle --- Sources/Mockingjay/XCTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Mockingjay/XCTest.swift b/Sources/Mockingjay/XCTest.swift index 8e2905a..ad0e2f7 100644 --- a/Sources/Mockingjay/XCTest.swift +++ b/Sources/Mockingjay/XCTest.swift @@ -10,7 +10,7 @@ import ObjectiveC import XCTest let swizzleTearDown: Void = { - let tearDown = class_getInstanceMethod(XCTest.self, #selector(XCTest.tearDown)) + let tearDown = class_getInstanceMethod(XCTest.self, #selector(XCTest.tearDown as (XCTest) -> () -> Void)) let mockingjayTearDown = class_getInstanceMethod(XCTest.self, #selector(XCTest.mockingjayTearDown)) method_exchangeImplementations(tearDown!, mockingjayTearDown!) }() From 6d253785c55801abaefc5a76930c70900f221f6e Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 4 Oct 2021 11:42:20 +0100 Subject: [PATCH 12/15] feat: allow providing default error to failure --- Sources/Mockingjay/Builders.swift | 12 ++++++++++-- Sources/Mockingjay/Mockingjay.swift | 4 ++-- Tests/MockingjayTests/BuildersTests.swift | 15 ++++++++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Sources/Mockingjay/Builders.swift b/Sources/Mockingjay/Builders.swift index 3d6e96e..808b746 100644 --- a/Sources/Mockingjay/Builders.swift +++ b/Sources/Mockingjay/Builders.swift @@ -10,9 +10,17 @@ import Foundation // Collection of generic builders +internal struct MockingjayFailure: Error {} + /// Generic builder for returning a failure -public func failure(_ error: NSError) -> (_ request: URLRequest) -> Response { - return { _ in return .failure(error) } +public func failure(_ error: Error? = nil) -> (_ request: URLRequest) -> Response { + return { _ in + if let error = error { + return .failure(error) + } + + return .failure(MockingjayFailure()) + } } public func http(_ status:Int = 200, headers:[String:String]? = nil, download:Download=nil) -> (_ request: URLRequest) -> Response { diff --git a/Sources/Mockingjay/Mockingjay.swift b/Sources/Mockingjay/Mockingjay.swift index 4bd8e17..b833723 100644 --- a/Sources/Mockingjay/Mockingjay.swift +++ b/Sources/Mockingjay/Mockingjay.swift @@ -38,13 +38,13 @@ public func ==(lhs:Download, rhs:Download) -> Bool { public enum Response : Equatable { case success(URLResponse, Download) - case failure(NSError) + case failure(Error) } public func ==(lhs:Response, rhs:Response) -> Bool { switch (lhs, rhs) { case let (.failure(lhsError), .failure(rhsError)): - return lhsError == rhsError + return (lhsError as NSError) == (rhsError as NSError) case let (.success(lhsResponse, lhsDownload), .success(rhsResponse, rhsDownload)): return lhsResponse == rhsResponse && lhsDownload == rhsDownload default: diff --git a/Tests/MockingjayTests/BuildersTests.swift b/Tests/MockingjayTests/BuildersTests.swift index 6b97f97..119aced 100644 --- a/Tests/MockingjayTests/BuildersTests.swift +++ b/Tests/MockingjayTests/BuildersTests.swift @@ -20,6 +20,19 @@ class FailureBuilderTests : XCTestCase { XCTAssertEqual(response, Response.failure(error)) } + + func testUnspecifiedFailure() { + let request = URLRequest(url: URL(string: "http://test.com/")!) + + let response = failure()(request) + + switch response { + case .success(_, _): + XCTFail("Unexpected success") + case .failure(_): + break + } + } func testHTTP() { let request = URLRequest(url: URL(string: "http://test.com/")!) @@ -51,7 +64,7 @@ class FailureBuilderTests : XCTestCase { XCTFail("Test Failure") } case let .failure(error): - XCTFail("Test Failure: " + error.debugDescription) + XCTFail("Test Failure: " + (error as NSError).debugDescription) } } From 11f5a44a84aad76ddaccbeeddfccc981a692a83b Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 4 Oct 2021 11:48:47 +0100 Subject: [PATCH 13/15] feat: add text builder --- Sources/Mockingjay/Builders.swift | 13 +++++++++++ Tests/MockingjayTests/BuildersTests.swift | 27 ++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Sources/Mockingjay/Builders.swift b/Sources/Mockingjay/Builders.swift index 808b746..31552e7 100644 --- a/Sources/Mockingjay/Builders.swift +++ b/Sources/Mockingjay/Builders.swift @@ -36,6 +36,19 @@ public func content(_ data: Data, headers: [String:String]? = nil) -> (_ reques return http(200, headers: headers, download: .content(data)) } +public func text(_ body: String, using encoding: String.Encoding, status: Int = 200, headers: [String: String]? = nil) -> (_ request: URLRequest) -> Response { + var headers = headers ?? [String:String]() + if headers["Content-Type"] == nil && encoding == .utf8 { + headers["Content-Type"] = "text/plain; charset=utf-8" + } + + if let data = body.data(using: encoding) { + return http(status, headers: headers, download: .content(data)) + } + + return failure() +} + public func json(_ body: Any, status:Int = 200, headers:[String:String]? = nil) -> (_ request: URLRequest) -> Response { return { (request:URLRequest) in do { diff --git a/Tests/MockingjayTests/BuildersTests.swift b/Tests/MockingjayTests/BuildersTests.swift index 119aced..3b50ef8 100644 --- a/Tests/MockingjayTests/BuildersTests.swift +++ b/Tests/MockingjayTests/BuildersTests.swift @@ -67,7 +67,32 @@ class FailureBuilderTests : XCTestCase { XCTFail("Test Failure: " + (error as NSError).debugDescription) } } - + + func testText() { + let request = URLRequest(url: URL(string: "http://test.com/")!) + let response = text("Hello World", using: .utf8)(request) + + switch response { + case let .success(response, download): + switch download { + case .content(let data): + if let response = response as? HTTPURLResponse { + XCTAssertEqual(response.statusCode, 200) + XCTAssertEqual(response.mimeType, "text/plain") + XCTAssertEqual(response.textEncodingName, "utf-8") + let body = NSString(data:data, encoding: String.Encoding.utf8.rawValue) + XCTAssertEqual(body, "Hello World") + } else { + XCTFail("Test Failure") + } + default: + XCTFail("Test Failure") + } + default: + XCTFail("Test Failure") + } + } + func testJSON() { let request = URLRequest(url: URL(string: "http://test.com/")!) let response = json(["A"])(request) From 1ea0efa3acff1f472be88297080ca45c99e377a6 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 4 Oct 2021 12:20:15 +0100 Subject: [PATCH 14/15] feat: add support for redirect responses Closes #101 --- CHANGELOG.md | 6 ++ Sources/Mockingjay/MockingjayProtocol.swift | 22 +++++++ .../MockingjayProtocolTests.swift | 57 ++++++++++++++++++- 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32dc9bc..cbd402f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Mockingjay Changelog +## TBD + +### Enhancements + +- Support for redirect responses (3xx). + ## 3.0.0-alpha.1 ### Breaking diff --git a/Sources/Mockingjay/MockingjayProtocol.swift b/Sources/Mockingjay/MockingjayProtocol.swift index a175326..6cf6ee5 100644 --- a/Sources/Mockingjay/MockingjayProtocol.swift +++ b/Sources/Mockingjay/MockingjayProtocol.swift @@ -111,6 +111,23 @@ public class MockingjayProtocol: URLProtocol { } // MARK: Private Methods + + func isRedirect(request: URLRequest, response: URLResponse) -> URLRequest? { + guard + let response = response as? HTTPURLResponse, + response.statusCode == 301 || response.statusCode == 302 || response.statusCode == 303 || response.statusCode == 307, + let location = response.allHeaderFields["Location"] as? String, + let locationURL = URL(string: location, relativeTo: response.url) + else { return nil } + + if response.statusCode == 307 { + var redirectRequest = request + redirectRequest.url = locationURL + return redirectRequest + } + + return URLRequest(url: locationURL) + } fileprivate func sendResponse(_ response: Response) { switch response { @@ -118,6 +135,11 @@ public class MockingjayProtocol: URLProtocol { client?.urlProtocol(self, didFailWithError: error) case .success(var response, let download): let headers = self.request.allHTTPHeaderFields + + if let redirectRequest = isRedirect(request: self.request, response: response) { + client?.urlProtocol(self, wasRedirectedTo: redirectRequest, redirectResponse: response) + return + } switch(download) { case .content(var data): diff --git a/Tests/MockingjayTests/MockingjayProtocolTests.swift b/Tests/MockingjayTests/MockingjayProtocolTests.swift index 43960ec..871c8f3 100644 --- a/Tests/MockingjayTests/MockingjayProtocolTests.swift +++ b/Tests/MockingjayTests/MockingjayProtocolTests.swift @@ -165,5 +165,60 @@ class MockingjayProtocolTests : XCTestCase { XCTAssert(startDate.addingTimeInterval(0.95).compare(Date()) == .orderedAscending) } - + + func testRedirect() { + let request = URLRequest(url: URL(string: "http://example.com")!) + + MockingjayProtocol.addStub( + matcher: { $0.url?.absoluteString == "https://example.com" }, + builder: http(204, download: .noContent) + ) + + MockingjayProtocol.addStub( + matcher: { $0.url?.absoluteString == "http://example.com" }, + builder: http(301, headers: ["Location": "https://example.com"], download: .noContent) + ) + + let expectation = self.expectation(description: #function) + + urlSession = URLSession(configuration: URLSessionConfiguration.default) + let dataTask = urlSession.dataTask(with: request) { _, response, _ in + XCTAssertEqual(response?.url?.absoluteString, "https://example.com") + expectation.fulfill() + } + dataTask.resume() + + waitForExpectations(timeout: 2.0, handler: nil) + } + + func testRedirect307() { + var request = URLRequest(url: URL(string: "http://example.com")!) + request.httpMethod = "PUT" + request.setValue("text/plain", forHTTPHeaderField: "Content-Type") + + MockingjayProtocol.addStub( + matcher: { $0.url?.absoluteString == "https://example.com" }, + builder: http(204, download: .noContent) + ) + + MockingjayProtocol.addStub( + matcher: { $0.url?.absoluteString == "http://example.com" }, + builder: { request in + XCTAssertEqual(request.httpMethod, "PUT") + XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "text/plain") + return http(307, headers: ["Location": "https://example.com"], download: .noContent)(request) + } + ) + + let expectation = self.expectation(description: #function) + + urlSession = URLSession(configuration: URLSessionConfiguration.default) + let dataTask = urlSession.dataTask(with: request) { _, response, _ in + XCTAssertEqual(response?.url?.absoluteString, "https://example.com") + expectation.fulfill() + } + dataTask.resume() + + waitForExpectations(timeout: 2.0, handler: nil) + } } From 98d39a2c9b4951a86a7e9fe0000d3d7e94bf776b Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 4 Oct 2021 12:44:51 +0100 Subject: [PATCH 15/15] feat: add redirect(to:) builder --- Sources/Mockingjay/Builders.swift | 10 ++++++ Tests/MockingjayTests/BuildersTests.swift | 38 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/Sources/Mockingjay/Builders.swift b/Sources/Mockingjay/Builders.swift index 31552e7..e04b958 100644 --- a/Sources/Mockingjay/Builders.swift +++ b/Sources/Mockingjay/Builders.swift @@ -70,3 +70,13 @@ public func jsonData(_ data: Data, status: Int = 200, headers: [String:String]? return http(status, headers: headers, download: .content(data))(request) } } + +public func redirect(to url: URL, status: Int = 301, headers: [String:String]? = nil) -> (_ request: URLRequest) -> Response { + var headers = headers ?? [:] + headers["Location"] = url.absoluteString + + let resoponse = HTTPURLResponse(url: url, statusCode: status, httpVersion: nil, headerFields: headers)! + return { request in + return .success(resoponse, .noContent) + } +} diff --git a/Tests/MockingjayTests/BuildersTests.swift b/Tests/MockingjayTests/BuildersTests.swift index 3b50ef8..a440471 100644 --- a/Tests/MockingjayTests/BuildersTests.swift +++ b/Tests/MockingjayTests/BuildersTests.swift @@ -145,4 +145,42 @@ class FailureBuilderTests : XCTestCase { XCTFail("Test Failure") } } + + func testRedirect() { + let request = URLRequest(url: URL(string: "http://example.com")!) + let response = redirect(to: URL(string: "https://example.com")!)(request) + + switch response { + case let .success(response, _): + guard let response = response as? HTTPURLResponse else { + XCTFail("Test Failure") + return + } + + + XCTAssertEqual(response.statusCode, 301) + XCTAssertEqual(response.allHeaderFields["Location"] as? String, "https://example.com") + default: + XCTFail("Test Failure") + } + } + + func testRelativeRedirect() { + let request = URLRequest(url: URL(string: "https://example.com")!) + let response = redirect(to: URL(string: "/authorize")!)(request) + + switch response { + case let .success(response, _): + guard let response = response as? HTTPURLResponse else { + XCTFail("Test Failure") + return + } + + + XCTAssertEqual(response.statusCode, 301) + XCTAssertEqual(response.allHeaderFields["Location"] as? String, "/authorize") + default: + XCTFail("Test Failure") + } + } }