Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend User api #199

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions OctoKit/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,45 @@ open class User: Codable {
// MARK: request

public extension Octokit {
/**
Fetches a user or organization
- parameter id: The id of the user or organization.
- parameter completion: Callback for the outcome of the fetch.
*/
@discardableResult
func user(id: Int, completion: @escaping (_ response: Result<User, Error>) -> Void) -> URLSessionDataTaskProtocol? {
let router = UserRouter.readUserById(id, configuration)
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self) { user, error in
if let error = error {
completion(.failure(error))
} else {
if let user = user {
completion(.success(user))
}
}
}
}

#if compiler(>=5.5.2) && canImport(_Concurrency)
/**
Fetches a user or organization
- parameter id: The identifier of the user or organization.
*/
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func user(id: Int) async throws -> User {
let router = UserRouter.readUserById(id, configuration)
return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self)
}
#endif

/**
Fetches a user or organization
- parameter name: The name of the user or organization.
- parameter completion: Callback for the outcome of the fetch.
*/
@discardableResult
func user(name: String, completion: @escaping (_ response: Result<User, Error>) -> Void) -> URLSessionDataTaskProtocol? {
let router = UserRouter.readUser(name, configuration)
let router = UserRouter.readUserByName(name, configuration)
return router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self) { user, error in
if let error = error {
completion(.failure(error))
Expand All @@ -195,7 +226,7 @@ public extension Octokit {
*/
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func user(name: String) async throws -> User {
let router = UserRouter.readUser(name, configuration)
let router = UserRouter.readUserByName(name, configuration)
return try await router.load(session, dateDecodingStrategy: .formatted(Time.rfc3339DateFormatter), expectedResultType: User.self)
}
#endif
Expand Down Expand Up @@ -234,12 +265,14 @@ public extension Octokit {

enum UserRouter: Router {
case readAuthenticatedUser(Configuration)
case readUser(String, Configuration)
case readUserById(Int, Configuration)
case readUserByName(String, Configuration)

var configuration: Configuration {
switch self {
case let .readAuthenticatedUser(config): return config
case let .readUser(_, config): return config
case let .readUserById(_, config): return config
case let .readUserByName(_, config): return config
}
}

Expand All @@ -255,7 +288,9 @@ enum UserRouter: Router {
switch self {
case .readAuthenticatedUser:
return "user"
case let .readUser(username, _):
case let .readUserById(id, _):
return "user/\(id)"
case let .readUserByName(username, _):
return "users/\(username)"
}
}
Expand Down
58 changes: 51 additions & 7 deletions Tests/OctoKitTests/UserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import XCTest
class UserTests: XCTestCase {
// MARK: Actual Request tests

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

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

#if compiler(>=5.5.2) && canImport(_Concurrency)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func testGetUserAsync() async throws {
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/users/mietzmithut", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
let username = "mietzmithut"
let user = try await Octokit(session: session).user(name: username)
XCTAssertEqual(user.login, username)
func testGetUserByNameAsync() async throws {
let expectedUserId = 4672699
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(expectedUserId)", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
let user = try await Octokit(session: session).user(id: expectedUserId)
XCTAssertEqual(user.id, expectedUserId)
XCTAssertNotNil(user.createdAt)
XCTAssertTrue(session.wasCalled)
}
#endif

func testGetUserById() {
let expectedUserId = 4672699
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(expectedUserId)", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
let task = Octokit(session: session).user(id: expectedUserId) { response in
switch response {
case let .success(user):
XCTAssertEqual(user.id, expectedUserId)
XCTAssertNotNil(user.createdAt)
case .failure:
XCTFail("should get a user")
}
}
XCTAssertNotNil(task)
XCTAssertTrue(session.wasCalled)
}

func testFailingToGetUserById() {
let userId = 123456
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(userId)", expectedHTTPMethod: "GET", jsonFile: nil, statusCode: 404)
let task = Octokit(session: session).user(id: userId) { response in
switch response {
case .success:
XCTAssert(false, "should not retrieve user")
case let .failure(error as NSError):
XCTAssertEqual(error.code, 404)
XCTAssertEqual(error.domain, OctoKitErrorDomain)
}
}
XCTAssertNotNil(task)
XCTAssertTrue(session.wasCalled)
}

#if compiler(>=5.5.2) && canImport(_Concurrency)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
func testGetUserByIdAsync() async throws {
let expectedUserId = 4672699
let session = OctoKitURLTestSession(expectedURL: "https://api.github.com/user/\(expectedUserId)", expectedHTTPMethod: "GET", jsonFile: "user_mietzmithut", statusCode: 200)
let user = try await Octokit(session: session).user(id: expectedUserId)
XCTAssertEqual(user.id, expectedUserId)
XCTAssertNotNil(user.createdAt)
XCTAssertTrue(session.wasCalled)
}
Expand Down
Loading