diff --git a/Sources/Carlos/CacheLevels/Composed.swift b/Sources/Carlos/CacheLevels/Composed.swift index 359e22b..4ef8c1c 100644 --- a/Sources/Carlos/CacheLevels/Composed.swift +++ b/Sources/Carlos/CacheLevels/Composed.swift @@ -11,17 +11,17 @@ extension CacheLevel { */ public func compose(_ cache: A) -> BasicCache where A.KeyType == KeyType, A.OutputType == OutputType { BasicCache( - getClosure: { [weak self] key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return self.get(key) + getClosure: { key in + self.get(key) .catch { _ -> AnyPublisher in Logger.log("Composed| error on getting value for key \(key) on cache \(String(describing: self)).", .info) return cache.get(key) - .flatMap { value -> AnyPublisher<(OutputType, Void), Error> in + .flatMap { [weak self] value -> AnyPublisher<(OutputType, Void), Error> in + guard let self = self else { + return Empty(completeImmediately: true).eraseToAnyPublisher() + } + let get = Just(value).setFailureType(to: Error.self) let set = self.set(value, forKey: key) return Publishers.Zip(get, set) @@ -31,33 +31,25 @@ extension CacheLevel { .eraseToAnyPublisher() }.eraseToAnyPublisher() }, - setClosure: { [weak self] value, key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return Publishers.Zip( + setClosure: { value, key in + Publishers.Zip( self.set(value, forKey: key), cache.set(value, forKey: key) ) .map { _ in () } .eraseToAnyPublisher() }, - removeClosure: { [weak self] key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return Publishers.Zip(self.remove(key), cache.remove(key)) + removeClosure: { key in + Publishers.Zip(self.remove(key), cache.remove(key)) .map { _ in () } .eraseToAnyPublisher() }, - clearClosure: { [weak self] in - self?.clear() + clearClosure: { + self.clear() cache.clear() }, - memoryClosure: { [weak self] in - self?.onMemoryWarning() + memoryClosure: { + self.onMemoryWarning() cache.onMemoryWarning() } ) diff --git a/Sources/Carlos/Core/FetcherValueTransformation.swift b/Sources/Carlos/Core/FetcherValueTransformation.swift index f0a9d3d..c1f7562 100644 --- a/Sources/Carlos/Core/FetcherValueTransformation.swift +++ b/Sources/Carlos/Core/FetcherValueTransformation.swift @@ -13,12 +13,8 @@ extension Fetcher { */ public func transformValues(_ transformer: A) -> BasicFetcher where OutputType == A.TypeIn { BasicFetcher( - getClosure: { [weak self] key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return self.get(key) + getClosure: { key in + self.get(key) .flatMap(transformer.transform) .eraseToAnyPublisher() } diff --git a/Sources/Carlos/Operations/KeyTransformation.swift b/Sources/Carlos/Operations/KeyTransformation.swift index 7bd665a..0b9d0ff 100644 --- a/Sources/Carlos/Operations/KeyTransformation.swift +++ b/Sources/Carlos/Operations/KeyTransformation.swift @@ -13,32 +13,20 @@ extension CacheLevel { */ public func transformKeys(_ transformer: A) -> BasicCache where KeyType == A.TypeOut { BasicCache( - getClosure: { [weak self] key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return transformer.transform(key) + getClosure: { key in + transformer.transform(key) .flatMap(self.get) .eraseToAnyPublisher() }, - setClosure: { [weak self] value, key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return transformer.transform(key) + setClosure: { value, key in + transformer.transform(key) .flatMap { transformedKey in self.set(value, forKey: transformedKey) } .eraseToAnyPublisher() }, - removeClosure: { [weak self] in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return transformer.transform($0) + removeClosure: { + transformer.transform($0) .flatMap(self.remove) .eraseToAnyPublisher() }, diff --git a/Sources/Carlos/Operations/ValueTransformation.swift b/Sources/Carlos/Operations/ValueTransformation.swift index 23065a9..3cdf463 100644 --- a/Sources/Carlos/Operations/ValueTransformation.swift +++ b/Sources/Carlos/Operations/ValueTransformation.swift @@ -13,21 +13,13 @@ extension CacheLevel { */ public func transformValues(_ transformer: A) -> BasicCache where OutputType == A.TypeIn { BasicCache( - getClosure: { [weak self] key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return self.get(key) + getClosure: { key in + self.get(key) .flatMap(transformer.transform) .eraseToAnyPublisher() }, - setClosure: { [weak self] value, key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return transformer.inverseTransform(value) + setClosure: { value, key in + transformer.inverseTransform(value) .flatMap { transformedValue in self.set(transformedValue, forKey: key) } diff --git a/Sources/Carlos/Transformers/ConditionedValueTransformation.swift b/Sources/Carlos/Transformers/ConditionedValueTransformation.swift index adc681b..881a62f 100644 --- a/Sources/Carlos/Transformers/ConditionedValueTransformation.swift +++ b/Sources/Carlos/Transformers/ConditionedValueTransformation.swift @@ -15,20 +15,12 @@ extension CacheLevel { */ public func conditionedValueTransformation(transformer: A) -> BasicCache where OutputType == A.TypeIn, A.KeyType == KeyType { BasicCache( - getClosure: { [weak self] key -> AnyPublisher in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - - return self.get(key) + getClosure: { key -> AnyPublisher in + self.get(key) .flatMap { transformer.conditionalTransform(key: key, value: $0) } .eraseToAnyPublisher() }, - setClosure: { [weak self] value, key in - guard let self = self else { - return Empty(completeImmediately: true).eraseToAnyPublisher() - } - + setClosure: { value, key in return transformer.conditionalInverseTransform(key: key, value: value) .flatMap { transformedValue in self.set(transformedValue, forKey: key) diff --git a/Tests/CarlosTests/CompositionTests.swift b/Tests/CarlosTests/CompositionTests.swift index fbf0b64..c7faa73 100644 --- a/Tests/CarlosTests/CompositionTests.swift +++ b/Tests/CarlosTests/CompositionTests.swift @@ -1,4 +1,5 @@ import Foundation +import XCTest import Nimble import Quick @@ -752,3 +753,67 @@ final class CacheLevelCompositionTests: QuickSpec { } } } + +final class ComposedCacheTests: XCTestCase { + var cancellables: Set! + var cache: BasicCache! + + override func setUp() { + super.setUp() + + cancellables = Set() + cache = MemoryCacheLevel().compose(DiskCacheLevel()) + } + + override func tearDown() { + cache.clear() + + super.tearDown() + } + + func testGet_whenKeyDoesNotExistInCache_shallCompleteWithError() { + let expectation = self.expectation(description: #function) + + cache.get("does_not_exist") + .sink(receiveCompletion: { completion in + switch completion { + case let .failure(error): + XCTAssertEqual(error as! FetchError, FetchError.valueNotInCache) + + expectation.fulfill() + case .finished: + XCTFail("Shall not finish") + } + }, receiveValue: { _ in + XCTFail("Shall not receive any value") + }) + .store(in: &cancellables) + + wait(for: [expectation], timeout: 1.0) + } + + func testGet_whenKeyDoesExistInCache_shallReturnCachedValue() { + let expectation = self.expectation(description: #function) + let key = "does_exist" + let expectedValue = "value" + + cache.set(expectedValue.data(using: .utf8)! as NSData, forKey: key) + .flatMap { + self.cache.get(key) + } + .sink(receiveCompletion: { completion in + switch completion { + case let .failure(error): + XCTFail("Shall not fail with error \(error)") + case .finished: + expectation.fulfill() + } + }, receiveValue: { value in + let resultValue = String(data: value as Data, encoding: .utf8) + XCTAssertEqual(resultValue, expectedValue) + }) + .store(in: &cancellables) + + wait(for: [expectation], timeout: 1.0) + } +}