Skip to content

Commit 0d2ae3e

Browse files
marosoaieMihai Arosoaie
andauthored
Extend User api (#199)
* Extend User api - allow fetching user by its unique id * add tests for new user API --------- Co-authored-by: Mihai Arosoaie <[email protected]>
1 parent 79b5ece commit 0d2ae3e

File tree

2 files changed

+91
-12
lines changed

2 files changed

+91
-12
lines changed

OctoKit/User.swift

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,45 @@ open class User: Codable {
169169
// MARK: request
170170

171171
public extension Octokit {
172+
/**
173+
Fetches a user or organization
174+
- parameter id: The id of the user or organization.
175+
- parameter completion: Callback for the outcome of the fetch.
176+
*/
177+
@discardableResult
178+
func user(id: Int, completion: @escaping (_ response: Result<User, Error>) -> Void) -> URLSessionDataTaskProtocol? {
179+
let router = UserRouter.readUserById(id, configuration)
180+
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self) { user, error in
181+
if let error = error {
182+
completion(.failure(error))
183+
} else {
184+
if let user = user {
185+
completion(.success(user))
186+
}
187+
}
188+
}
189+
}
190+
191+
#if compiler(>=5.5.2) && canImport(_Concurrency)
192+
/**
193+
Fetches a user or organization
194+
- parameter id: The identifier of the user or organization.
195+
*/
196+
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
197+
func user(id: Int) async throws -> User {
198+
let router = UserRouter.readUserById(id, configuration)
199+
return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self)
200+
}
201+
#endif
202+
172203
/**
173204
Fetches a user or organization
174205
- parameter name: The name of the user or organization.
175206
- parameter completion: Callback for the outcome of the fetch.
176207
*/
177208
@discardableResult
178209
func user(name: String, completion: @escaping (_ response: Result<User, Error>) -> Void) -> URLSessionDataTaskProtocol? {
179-
let router = UserRouter.readUser(name, configuration)
210+
let router = UserRouter.readUserByName(name, configuration)
180211
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self) { user, error in
181212
if let error = error {
182213
completion(.failure(error))
@@ -195,7 +226,7 @@ public extension Octokit {
195226
*/
196227
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
197228
func user(name: String) async throws -> User {
198-
let router = UserRouter.readUser(name, configuration)
229+
let router = UserRouter.readUserByName(name, configuration)
199230
return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self)
200231
}
201232
#endif
@@ -234,12 +265,14 @@ public extension Octokit {
234265

235266
enum UserRouter: Router {
236267
case readAuthenticatedUser(Configuration)
237-
case readUser(String, Configuration)
268+
case readUserById(Int, Configuration)
269+
case readUserByName(String, Configuration)
238270

239271
var configuration: Configuration {
240272
switch self {
241273
case let .readAuthenticatedUser(config): return config
242-
case let .readUser(_, config): return config
274+
case let .readUserById(_, config): return config
275+
case let .readUserByName(_, config): return config
243276
}
244277
}
245278

@@ -255,7 +288,9 @@ enum UserRouter: Router {
255288
switch self {
256289
case .readAuthenticatedUser:
257290
return "user"
258-
case let .readUser(username, _):
291+
case let .readUserById(id, _):
292+
return "user/\(id)"
293+
case let .readUserByName(username, _):
259294
return "users/\(username)"
260295
}
261296
}

Tests/OctoKitTests/UserTests.swift

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import XCTest
44
class UserTests: XCTestCase {
55
// MARK: Actual Request tests
66

7-
func testGetUser() {
7+
func testGetUserByName() {
88
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/users/mietzmithut", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
99
let username = "mietzmithut"
1010
let task = Octokit(session: session).user(name: username) { response in
@@ -20,7 +20,7 @@ class UserTests: XCTestCase {
2020
XCTAssertTrue(session.wasCalled)
2121
}
2222

23-
func testFailingToGetUser() {
23+
func testFailingToGetUserByName() {
2424
let username = "notexisting"
2525
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/users/notexisting", expectedHTTPMethod: "GET", jsonFile: nil, statusCode: 404)
2626
let task = Octokit(session: session).user(name: username) { response in
@@ -38,11 +38,55 @@ class UserTests: XCTestCase {
3838

3939
#if compiler(>=5.5.2) && canImport(_Concurrency)
4040
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
41-
func testGetUserAsync() async throws {
42-
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/users/mietzmithut", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
43-
let username = "mietzmithut"
44-
let user = try await Octokit(session: session).user(name: username)
45-
XCTAssertEqual(user.login, username)
41+
func testGetUserByNameAsync() async throws {
42+
let expectedUserId = 4672699
43+
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(expectedUserId)", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
44+
let user = try await Octokit(session: session).user(id: expectedUserId)
45+
XCTAssertEqual(user.id, expectedUserId)
46+
XCTAssertNotNil(user.createdAt)
47+
XCTAssertTrue(session.wasCalled)
48+
}
49+
#endif
50+
51+
func testGetUserById() {
52+
let expectedUserId = 4672699
53+
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(expectedUserId)", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
54+
let task = Octokit(session: session).user(id: expectedUserId) { response in
55+
switch response {
56+
case let .success(user):
57+
XCTAssertEqual(user.id, expectedUserId)
58+
XCTAssertNotNil(user.createdAt)
59+
case .failure:
60+
XCTFail("should get a user")
61+
}
62+
}
63+
XCTAssertNotNil(task)
64+
XCTAssertTrue(session.wasCalled)
65+
}
66+
67+
func testFailingToGetUserById() {
68+
let userId = 123456
69+
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(userId)", expectedHTTPMethod: "GET", jsonFile: nil, statusCode: 404)
70+
let task = Octokit(session: session).user(id: userId) { response in
71+
switch response {
72+
case .success:
73+
XCTAssert(false, "should not retrieve user")
74+
case let .failure(error as NSError):
75+
XCTAssertEqual(error.code, 404)
76+
XCTAssertEqual(error.domain, OctoKitErrorDomain)
77+
}
78+
}
79+
XCTAssertNotNil(task)
80+
XCTAssertTrue(session.wasCalled)
81+
}
82+
83+
#if compiler(>=5.5.2) && canImport(_Concurrency)
84+
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
85+
func testGetUserByIdAsync() async throws {
86+
let expectedUserId = 4672699
87+
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(expectedUserId)", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
88+
let user = try await Octokit(session: session).user(id: expectedUserId)
89+
XCTAssertEqual(user.id, expectedUserId)
4690
XCTAssertNotNil(user.createdAt)
4791
XCTAssertTrue(session.wasCalled)
4892
}

0 commit comments

Comments
 (0)