Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

View trupin's full-sized avatar

Theophane RUPIN trupin

View GitHub Profile
final class MovieManager {
/// Fetches popular movies from the server, then stores them.
func getPopularMovies(_ completion: @escaping (Result<[Movie], MovieManagerError>) -> Void) {
HTTPClient.shared.get(path: "/movies/popular") { httpResponse, data, error in
// handles error if any
do {
// parses data from the server
protocol MovieManaging {
/// Fetches popular movies from the server, then stores them.
func getPopularMovies(_ completion: @escaping (Result<[Movie], MovieManagerError>) -> Void)
/// Fetches a movie from the store if it exists, from the server otherwise.
func getMovie(id movieID: String, completion: @escaping (Result<Movie, MovieManagerError>) -> Void)
}
protocol KeyValueStoring {
/// Fetches a movie based on its key
func getValue<Value>(for key: String, completion: @escaping (Result<Value?, KeyValueStoreError>) -> Void)
/// Insert or update a movie
func set<Value>(value: Value, for key: String)
}
protocol ClientProtocol {
/// Performs a request and retrieves a response from the server.
func get(path: String, completion: @escaping (Result<Any, ClientError>) -> Void)
}
protocol ClientProtocol {
/// Performs a request, retrieves a response from the server and convert it to `Model`
func get<Model>(path: String, completion: @escaping (Result<Model, ClientError>) -> Void)
}
extension ClientProtocol {
func get<Model>(path: String, completion: @escaping (Result<Model, ClientError>) -> Void) where Model: Decodable {
get(path: path) { (result: Result<Data, ClientError>) in
switch result {
case .success(let data):
do {
let model = try JSONDecoder().decode(Model.self, from: data)
completion(.success(model))
} catch {
final class MovieManager: MovieManaging {
let client: ClientProtocol
let store: KeyValueStoring
init(client: ClientProtocol, store: KeyValueStoring) {
self.client = client
self.store = store
}
final class MovieManagerTests: XCTestCase {
private var storeSpy: KeyValueStoreSpy!
private var clientSpy: ClientSpy!
private var movieManager: MovieManaging!
override func setUp() {
super.setUp()
final class KeyValueStoreSpy: KeyValueStoring {
// MARK: - Records
private(set) var keyRecords = [String]()
private(set) var valueRecords = [StoreValueRepresentable]()
// MARK: - Stubs
final class MoviesViewController: UIViewController {
private let dependencies: MoviesViewControllerDependencyResolver
// weaver: movieManager <- MovieManaging
required init(injecting dependencies: MoviesViewControllerDependencyResolver) {
self.dependencies = dependencies
super.init(nibName: nil, bundle: nil)
}