Skip to content

Commit

Permalink
Enable swift PM tests on Linux and macOS (#118)
Browse files Browse the repository at this point in the history
* Fix cycle in Mocker build steps

* Fix `swift test` on Linux and macOS, introduce a simple Github Action
  • Loading branch information
vox-humana committed May 25, 2022
1 parent 068745f commit f887c0e
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 64 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: "Mocker SPM CI"

on:
push:
branches:
- master
pull_request:
branches:
- '*'

jobs:
macos-run-tests:
name: Unit Tests (macOS)
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Run Tests
run: swift test

linux-run-tests:
name: Unit Tests (Linux)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run Tests
run: swift test
34 changes: 29 additions & 5 deletions Mocker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
50D4606E20653F1F00A85D93 /* Mocker.h in Headers */ = {isa = PBXBuildFile; fileRef = 50D4606B20653F1F00A85D93 /* Mocker.h */; settings = {ATTRIBUTES = (Public, ); }; };
50D4607020653F2500A85D93 /* MockedData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D4605B20653EAF00A85D93 /* MockedData.swift */; };
50D4607120653F2700A85D93 /* MockerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D4605C20653EAF00A85D93 /* MockerTests.swift */; };
50D4607320653F4500A85D93 /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 50D4607220653F4500A85D93 /* Resources */; };
8ED91F36283AFDC300EA8E99 /* wetransfer_bot_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 8ED91F32283AFDC300EA8E99 /* wetransfer_bot_avatar.png */; };
8ED91F37283AFDC300EA8E99 /* example.json in Resources */ = {isa = PBXBuildFile; fileRef = 8ED91F34283AFDC300EA8E99 /* example.json */; };
8ED91F38283AFDC300EA8E99 /* sample-redirect-get.data in Resources */ = {isa = PBXBuildFile; fileRef = 8ED91F35283AFDC300EA8E99 /* sample-redirect-get.data */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -43,7 +45,9 @@
50D4606320653EAF00A85D93 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50D4606B20653F1F00A85D93 /* Mocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mocker.h; sourceTree = "<group>"; };
50D4606D20653F1F00A85D93 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50D4607220653F4500A85D93 /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Resources; sourceTree = "<group>"; };
8ED91F32283AFDC300EA8E99 /* wetransfer_bot_avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wetransfer_bot_avatar.png; sourceTree = "<group>"; };
8ED91F34283AFDC300EA8E99 /* example.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example.json; sourceTree = "<group>"; };
8ED91F35283AFDC300EA8E99 /* sample-redirect-get.data */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "sample-redirect-get.data"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -101,9 +105,9 @@
50D4605A20653EAF00A85D93 /* MockerTests */ = {
isa = PBXGroup;
children = (
8ED91F31283AFDC300EA8E99 /* Resources */,
50D4605B20653EAF00A85D93 /* MockedData.swift */,
50D4605C20653EAF00A85D93 /* MockerTests.swift */,
50D4607220653F4500A85D93 /* Resources */,
50D4606220653EAF00A85D93 /* Supporting Files */,
);
path = MockerTests;
Expand Down Expand Up @@ -134,6 +138,24 @@
path = "Supporting Files";
sourceTree = "<group>";
};
8ED91F31283AFDC300EA8E99 /* Resources */ = {
isa = PBXGroup;
children = (
8ED91F32283AFDC300EA8E99 /* wetransfer_bot_avatar.png */,
8ED91F33283AFDC300EA8E99 /* JSON Files */,
8ED91F35283AFDC300EA8E99 /* sample-redirect-get.data */,
);
path = Resources;
sourceTree = "<group>";
};
8ED91F33283AFDC300EA8E99 /* JSON Files */ = {
isa = PBXGroup;
children = (
8ED91F34283AFDC300EA8E99 /* example.json */,
);
path = "JSON Files";
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand All @@ -152,9 +174,9 @@
isa = PBXNativeTarget;
buildConfigurationList = 501E26A81F3DAE370048F39E /* Build configuration list for PBXNativeTarget "Mocker" */;
buildPhases = (
501E26911F3DAE370048F39E /* Headers */,
501E268F1F3DAE370048F39E /* Sources */,
501E26901F3DAE370048F39E /* Frameworks */,
501E26911F3DAE370048F39E /* Headers */,
501E26921F3DAE370048F39E /* Resources */,
503446441F3DE70C0039D5E4 /* SwiftLint */,
);
Expand Down Expand Up @@ -240,7 +262,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50D4607320653F4500A85D93 /* Resources in Resources */,
8ED91F36283AFDC300EA8E99 /* wetransfer_bot_avatar.png in Resources */,
8ED91F38283AFDC300EA8E99 /* sample-redirect-get.data in Resources */,
8ED91F37283AFDC300EA8E99 /* example.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
13 changes: 9 additions & 4 deletions MockerTests/MockedData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
//

import Foundation
import UIKit

/// Contains all available Mocked data.
public final class MockedData {
public static let botAvatarImageFileUrl: URL = Bundle(for: MockedData.self).url(forResource: "wetransfer_bot_avatar", withExtension: "png")!
public static let exampleJSON: URL = Bundle(for: MockedData.self).url(forResource: "Resources/JSON Files/example", withExtension: "json")!
public static let redirectGET: URL = Bundle(for: MockedData.self).url(forResource: "Resources/sample-redirect-get", withExtension: "data")!
public static let botAvatarImageFileUrl: URL = Bundle.module.url(forResource: "wetransfer_bot_avatar", withExtension: "png")!
public static let exampleJSON: URL = Bundle.module.url(forResource: "example", withExtension: "json")!
public static let redirectGET: URL = Bundle.module.url(forResource: "sample-redirect-get", withExtension: "data")!
}

extension Bundle {
#if !SWIFT_PACKAGE
static let module = Bundle(for: MockedData.self)
#endif
}

internal extension URL {
Expand Down
91 changes: 37 additions & 54 deletions MockerTests/MockerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
//

import XCTest
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
@testable import Mocker

final class MockerTests: XCTestCase {
Expand Down Expand Up @@ -36,17 +39,15 @@ final class MockerTests: XCTestCase {
let expectation = self.expectation(description: "Data request should succeed")
let originalURL = URL(string: "https://avatars3.githubusercontent.com/u/26250426?v=4&s=400")!

let mockedData = MockedData.botAvatarImageFileUrl.data
let mock = Mock(url: originalURL, dataType: .imagePNG, statusCode: 200, data: [
.get: MockedData.botAvatarImageFileUrl.data
.get: mockedData
])

mock.register()
URLSession.shared.dataTask(with: originalURL) { (data, _, error) in
XCTAssertNil(error)
let image: UIImage = UIImage(data: data!)!
let sampleImage: UIImage = UIImage(contentsOfFile: MockedData.botAvatarImageFileUrl.path)!

XCTAssertEqual(image.size, sampleImage.size, "Image should be returned mocked")
XCTAssertEqual(data, mockedData, "Image should be returned mocked")
expectation.fulfill()
}.resume()

Expand All @@ -58,16 +59,14 @@ final class MockerTests: XCTestCase {
let expectation = self.expectation(description: "Data request should succeed")
let originalURL = URL(string: "https://www.wetransfer.com/sample-image.png")

let mockedData = MockedData.botAvatarImageFileUrl.data
Mock(fileExtensions: "png", dataType: .imagePNG, statusCode: 200, data: [
.get: MockedData.botAvatarImageFileUrl.data
.get: mockedData
]).register()

URLSession.shared.dataTask(with: originalURL!) { (data, _, error) in
XCTAssertNil(error)
let image: UIImage = UIImage(data: data!)!
let sampleImage: UIImage = UIImage(contentsOfFile: MockedData.botAvatarImageFileUrl.path)!

XCTAssertEqual(image.size, sampleImage.size, "Image should be returned mocked")
XCTAssertEqual(data, mockedData, "Image should be returned mocked")
expectation.fulfill()
}.resume()

Expand All @@ -82,23 +81,15 @@ final class MockerTests: XCTestCase {
Mock(fileExtensions: "png", dataType: .imagePNG, statusCode: 400, data: [
.get: Data()
]).register()

let mockedData = MockedData.botAvatarImageFileUrl.data
Mock(url: originalURL, ignoreQuery: true, dataType: .imagePNG, statusCode: 200, data: [
.get: MockedData.botAvatarImageFileUrl.data
.get: mockedData
]).register()

URLSession.shared.dataTask(with: originalURL) { (data, _, error) in
XCTAssertNil(error)
guard let data = data else {
XCTFail("Data is nil")
return
}
guard let image: UIImage = UIImage(data: data) else {
XCTFail("Invalid data \(String(describing: data))")
return
}
let sampleImage: UIImage = UIImage(contentsOfFile: MockedData.botAvatarImageFileUrl.path)!

XCTAssertEqual(image.size, sampleImage.size, "Image should be returned mocked")
XCTAssertEqual(data, mockedData, "Image should be returned mocked")
expectation.fulfill()
}.resume()

Expand All @@ -110,27 +101,17 @@ final class MockerTests: XCTestCase {
let expectation = self.expectation(description: "Data request should succeed")
let originalURL = URL(string: "https://www.wetransfer.com/sample-image.png?width=200&height=200")!

let mockedData = MockedData.botAvatarImageFileUrl.data
Mock(url: originalURL, ignoreQuery: true, dataType: .imagePNG, statusCode: 200, data: [
.get: MockedData.botAvatarImageFileUrl.data
.get: mockedData
]).register()

/// Make it different compared to the mocked URL.
let customURL = URL(string: originalURL.absoluteString + "&" + UUID().uuidString)!

URLSession.shared.dataTask(with: customURL) { (data, _, error) in
XCTAssertNil(error)
guard let data = data else {
XCTFail("Data is nil")
return
}

guard let image: UIImage = UIImage(data: data) else {
XCTFail("Invalid data \(String(describing: data))")
return
}
let sampleImage: UIImage = UIImage(contentsOfFile: MockedData.botAvatarImageFileUrl.path)!

XCTAssertEqual(image.size, sampleImage.size, "Image should be returned mocked")
XCTAssertEqual(data, mockedData, "Image should be returned mocked")
expectation.fulfill()
}.resume()

Expand Down Expand Up @@ -173,13 +154,13 @@ final class MockerTests: XCTestCase {
/// It should return the additional headers.
func testAdditionalHeaders() {
let expectation = self.expectation(description: "Data request should succeed")
let headers = ["testkey": "testvalue"]
let headers = ["Testkey": "testvalue"]
let mock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: headers)
mock.register()

URLSession.shared.dataTask(with: mock.request) { (_, response, error) in
XCTAssertNil(error)
XCTAssertEqual(((response as? HTTPURLResponse)?.allHeaderFields["testkey"] as? String), "testvalue", "Additional headers should be added.")
XCTAssertEqual(((response as? HTTPURLResponse)?.allHeaderFields["Testkey"] as? String), "testvalue", "Additional headers should be added.")
expectation.fulfill()
}.resume()

Expand All @@ -192,12 +173,12 @@ final class MockerTests: XCTestCase {
let mock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["testkey": "testvalue"])
mock.register()

let newMock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["newkey": "newvalue"])
let newMock = Mock(dataType: .json, statusCode: 200, data: [.get: Data()], additionalHeaders: ["Newkey": "newvalue"])
newMock.register()

URLSession.shared.dataTask(with: mock.request) { (_, response, error) in
XCTAssertNil(error)
XCTAssertEqual(((response as? HTTPURLResponse)?.allHeaderFields["newkey"] as? String), "newvalue", "Additional headers should be added.")
XCTAssertEqual(((response as? HTTPURLResponse)?.allHeaderFields["Newkey"] as? String), "newvalue", "Additional headers should be added.")
expectation.fulfill()
}.resume()

Expand All @@ -209,8 +190,9 @@ final class MockerTests: XCTestCase {
let expectation = self.expectation(description: "Data request should succeed")
let originalURL = URL(string: "https://www.wetransfer.com/sample-image.png")

let mockedData = MockedData.botAvatarImageFileUrl.data
Mock(fileExtensions: "png", dataType: .imagePNG, statusCode: 200, data: [
.get: MockedData.botAvatarImageFileUrl.data
.get: mockedData
]).register()

let configuration = URLSessionConfiguration.default
Expand All @@ -219,18 +201,7 @@ final class MockerTests: XCTestCase {

urlSession.dataTask(with: originalURL!) { (data, _, error) in
XCTAssertNil(error)
guard let data = data else {
XCTFail("Data is nil")
return
}

guard let image: UIImage = UIImage(data: data) else {
XCTFail("Invalid data \(String(describing: data))")
return
}
let sampleImage: UIImage = UIImage(contentsOfFile: MockedData.botAvatarImageFileUrl.path)!

XCTAssertEqual(image.size, sampleImage.size, "Image should be returned mocked")
XCTAssertEqual(data, mockedData, "Image should be returned mocked")
expectation.fulfill()
}.resume()

Expand Down Expand Up @@ -258,7 +229,10 @@ final class MockerTests: XCTestCase {
}

/// It should correctly handle redirect responses.
func testRedirectResponse() {
func testRedirectResponse() throws {
#if os(Linux)
throw XCTSkip("The URLSession swift-corelibs-foundation implementation doesn't currently handle redirects directly")
#endif
let expectation = self.expectation(description: "Data request should be cancelled")
let urlWhichRedirects: URL = URL(string: "https://we.tl/redirect")!
Mock(url: urlWhichRedirects, dataType: .html, statusCode: 200, data: [.get: MockedData.redirectGET.data]).register()
Expand Down Expand Up @@ -447,10 +421,14 @@ final class MockerTests: XCTestCase {
XCTAssertNil(urlresponse)
XCTAssertNotNil(error)
if let error = error {
#if os(Linux)
XCTAssertEqual(error as? TestExampleError, .example)
#else
// there's not a particularly elegant way to verify an instance
// of an error, but this is a convenient workaround for testing
// purposes
XCTAssertTrue(String(describing: error).contains("TestExampleError"))
#endif
}

expectation.fulfill()
Expand All @@ -460,7 +438,10 @@ final class MockerTests: XCTestCase {
}

/// It should cache response
func testMockCachePolicy() {
func testMockCachePolicy() throws {
#if os(Linux)
throw XCTSkip("URLSessionTask in swift-corelibs-foundation doesn't cache response for custom protocols")
#endif
let expectation = self.expectation(description: "Data request should succeed")
let originalURL = URL(string: "https://www.wetransfer.com/example.json")!

Expand All @@ -471,7 +452,9 @@ final class MockerTests: XCTestCase {
).register()

let configuration = URLSessionConfiguration.default
#if !os(Linux)
configuration.urlCache = URLCache()
#endif
configuration.protocolClasses = [MockingURLProtocol.self]
let urlSession = URLSession(configuration: configuration)

Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ let package = Package(name: "Mocker",
// dev .product(name: "WeTransferPRLinter", package: "WeTransferPRLinter")
// dev ], path: "Submodules/WeTransfer-iOS-CI/DangerFakeSources", sources: ["DangerFakeSource.swift"]),
.target(name: "Mocker", path: "Sources"),
.testTarget(name: "MockerTests", dependencies: ["Mocker"], path: "MockerTests")
.testTarget(name: "MockerTests", dependencies: ["Mocker"], path: "MockerTests", resources: [.process("Resources")])
],
swiftLanguageVersions: [.v5])

0 comments on commit f887c0e

Please sign in to comment.