Skip to content

Commit

Permalink
PR improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
bgoncal committed Feb 22, 2024
1 parent f682702 commit c56d6b7
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 22 deletions.
33 changes: 30 additions & 3 deletions Source/Caches/HACache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ public class HACache<ValueType> {
/// - subscribe: The info (one or more) for what subscriptions to start for updates or triggers for populating
public init(
connection: HAConnection,
subscribe: HACacheSubscribeInfo<ValueType>
subscribe: HACacheSubscribeInfo<ValueType?>
) {
self.connection = connection
self.populateInfo = nil
self.subscribeInfo = [subscribe]
self.subscribeInfo = nil

self.start = { connection, cache, state in
state.isWaitingForPopulate = false
Expand Down Expand Up @@ -368,7 +368,7 @@ public class HACache<ValueType> {
subscription.start(connection, { [weak cache, weak connection] handler in
guard let cache, let connection else { return }
cache.state.mutate { state in
switch handler(state.current) {
switch handler(state.current!) {
case .ignore: break
case .reissuePopulate:
if let populate {
Expand All @@ -383,6 +383,33 @@ public class HACache<ValueType> {
})
}

private static func startSubscribe<ValueType>(
to subscription: HACacheSubscribeInfo<ValueType?>,
on connection: HAConnection,
populate: HACachePopulateInfo<ValueType>?,
cache: HACache<ValueType>
) -> HACancellable {
subscription.start(connection, { [weak cache, weak connection] handler in
guard let cache, let connection else { return }
cache.state.mutate { state in
switch handler(state.current) {
case .ignore: break
case .reissuePopulate:
if let populate {
let populateToken = startPopulate(for: populate, on: connection, cache: cache)
state.appendRequestToken(populateToken)

Check warning on line 400 in Source/Caches/HACache.swift

View check run for this annotation

Codecov / codecov/patch

Source/Caches/HACache.swift#L398-L400

Added lines #L398 - L400 were not covered by tests
}
case let .replace(value):
state.current = value

if let value {
cache.notify(subscribers: state.subscribers, for: value)
}
}
}
})
}

/// Create a cancellable which removes this subscription
/// - Parameter info: The subscription info that would be removed
/// - Returns: A cancellable for the subscription info, which strongly retains this cache
Expand Down
10 changes: 5 additions & 5 deletions Source/Caches/HACacheSubscribeInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public struct HACacheSubscribeInfo<OutgoingType> {
/// - transform: The handler to convert the subscription's handler type into the cache's value
public init<IncomingType: HADataDecodable>(
subscription: HATypedSubscription<IncomingType>,
transform: @escaping (HACacheTransformInfo<IncomingType, OutgoingType?>) -> Response
transform: @escaping (HACacheTransformInfo<IncomingType, OutgoingType>) -> Response
) {
let nonRetrySubscription: HATypedSubscription<IncomingType> = {
var updated = subscription
Expand All @@ -27,7 +27,7 @@ public struct HACacheSubscribeInfo<OutgoingType> {
self.init(
request: subscription.request,
anyTransform: { possibleValue in
guard let value = possibleValue as? HACacheTransformInfo<IncomingType, OutgoingType?> else {
guard let value = possibleValue as? HACacheTransformInfo<IncomingType, OutgoingType> else {
throw TransformError.incorrectType(
have: String(describing: possibleValue),
expected: String(describing: IncomingType.self)
Expand Down Expand Up @@ -65,12 +65,12 @@ public struct HACacheSubscribeInfo<OutgoingType> {
/// - current: The current value part of the transform info
/// - Throws: If the type of incoming does not match the original IncomingType
/// - Returns: The response from the transform block
public func transform<IncomingType>(incoming: IncomingType, current: OutgoingType?) throws -> Response {
try anyTransform(HACacheTransformInfo<IncomingType, OutgoingType?>(incoming: incoming, current: current))
public func transform<IncomingType>(incoming: IncomingType, current: OutgoingType) throws -> Response {
try anyTransform(HACacheTransformInfo<IncomingType, OutgoingType>(incoming: incoming, current: current))
}

/// The start handler
typealias StartHandler = (HAConnection, @escaping ((OutgoingType?) -> Response) -> Void) -> HACancellable
typealias StartHandler = (HAConnection, @escaping ((OutgoingType) -> Response) -> Void) -> HACancellable

/// Type-erasing block to perform the subscription and its transform
internal let start: StartHandler
Expand Down
2 changes: 1 addition & 1 deletion Source/Caches/HACacheTransformInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public struct HACacheTransformInfo<IncomingType, OutgoingType> {

/// The current value of the cache
/// For populate transforms, this is nil if an initial request hasn't been sent yet and the cache not reset.
/// For subscribe transforms, this is non-optional.
/// For subscribe transforms, this is nil if the populate did not produce results (or does not exist).
public var current: OutgoingType
}
13 changes: 5 additions & 8 deletions Source/Caches/HACachedStates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@ private struct HACacheKeyStates: HACacheKey {
.init(
connection: connection,
populate: .init(request: .getStates(), transform: { .init(entities: $0.incoming) }),
subscribe: .init(
subscription: .stateChanged(),
transform: { (info: HACacheTransformInfo<HAResponseEventStateChanged, HACachedStates?>) in
guard var updated = info.current else { return .ignore }
updated[info.incoming.entityId] = info.incoming.newState
return .replace(updated)
}
)
subscribe: .init(subscription: .stateChanged(), transform: { info in
var updated = info.current
updated[info.incoming.entityId] = info.incoming.newState
return .replace(updated)
})
)
}
}
Expand Down
87 changes: 83 additions & 4 deletions Tests/HACache.test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ internal class HACacheTests: XCTestCase {
private var connection: HAMockConnection!

private var populateInfo: HACachePopulateInfo<CacheItem>!
private var subscribeInfoNoPopulate: HACacheSubscribeInfo<CacheItem?>!
private var populateCount: Int!
private var populateCancellableInvoked: Bool = false
private var populatePerform: (((CacheItem?) throws -> CacheItem) -> Void)?

private var subscribeInfo: HACacheSubscribeInfo<CacheItem>!
private var subscribeCancellableInvoked: Bool = false
private var subscribePerform: (((CacheItem?) -> HACacheSubscribeInfo<CacheItem>.Response) -> Void)?
private var subscribePerformNoPopulate: (((CacheItem?) -> HACacheSubscribeInfo<CacheItem?>.Response) -> Void)?
private var subscribeInfo2: HACacheSubscribeInfo<CacheItem>!
private var subscribeCancellableInvoked2: Bool = false
private var subscribePerform2: (((CacheItem?) -> HACacheSubscribeInfo<CacheItem>.Response) -> Void)?
Expand Down Expand Up @@ -49,6 +51,14 @@ internal class HACacheTests: XCTestCase {
value(block)
}

private func subscribeNoPopulate(_ block: (CacheItem?) -> HACacheSubscribeInfo<CacheItem?>.Response) throws {
if subscribePerform == nil {
waitForCallback()
}
let value = try XCTUnwrap(subscribePerformNoPopulate)
value(block)
}

private func subscribe2(_ block: (CacheItem?) -> HACacheSubscribeInfo<CacheItem>.Response) throws {
if subscribePerform2 == nil {
waitForCallback()
Expand Down Expand Up @@ -91,6 +101,17 @@ internal class HACacheTests: XCTestCase {
}
}
)
subscribeInfoNoPopulate = HACacheSubscribeInfo<CacheItem?>(
request: .init(type: "none", data: [:]),
anyTransform: { _ in
fatalError()
}, start: { [weak self] _, subscribe in
self?.subscribePerformNoPopulate = subscribe
return HAMockCancellable { [weak self] in
self?.subscribeCancellableInvoked = true
}
}
)
subscribeInfo2 = .init(
request: .init(type: "none", data: [:]),
anyTransform: { _ in
Expand Down Expand Up @@ -674,14 +695,72 @@ internal class HACacheTests: XCTestCase {
XCTAssertEqual(populateCount, 1)
}

func testInitSubscribingWithoutPopulate() {
let cache = HACache(connection: connection, subscribe: subscribeInfo)
func testInitSubscribingWithoutPopulate() throws {
let cache = HACache(connection: connection, subscribe: subscribeInfoNoPopulate)
let result = cache.subscribe { _, _ in }
XCTAssertEqual(cache.subscribeInfo?.count, 1)
let expectedValue = CacheItem()

try subscribeNoPopulate { current in
XCTAssertNil(current)
return .replace(expectedValue)
}

XCTAssertNil(cache.subscribeInfo)
XCTAssertNil(cache.populateInfo)
XCTAssertNotNil(cache.connection)
XCTAssertNotNil(subscribePerformNoPopulate)
XCTAssertNotNil(result)
}

func testSubscriptionWithNilPopulateInfo() {
let cache = HACache(connection: connection, subscribe: subscribeInfoNoPopulate)

var receivedUpdates = [CacheItem?]()
let expectation = self.expectation(description: "SubscriptionUpdate")
expectation.expectedFulfillmentCount = 2

let token = cache.subscribe { _, item in
receivedUpdates.append(item)
expectation.fulfill()
}

try? subscribeNoPopulate { _ in
.replace(CacheItem())
}

try? subscribeNoPopulate { _ in
.replace(CacheItem())
}

waitForExpectations(timeout: 10.0)
token.cancel()

XCTAssertNotNil(receivedUpdates[0], "First update should not be nil")
XCTAssertNotNil(receivedUpdates[1], "Second update should not be nil")
}

func testSubscriptionWithConnectionStateChanges() {
let cache = HACache(connection: connection, subscribe: subscribeInfoNoPopulate)

var receivedUpdates = [CacheItem?]()
let expectation = self.expectation(description: "ConnectionStateChange")
expectation.expectedFulfillmentCount = 1

_ = cache.subscribe { _, item in
receivedUpdates.append(item)
expectation.fulfill()
}

connection.setState(.disconnected(reason: .disconnected))
connection.setState(.ready(version: "testVersion"))

try? subscribeNoPopulate { _ in
.replace(CacheItem())
}

waitForExpectations(timeout: 10.0)

XCTAssertNotNil(receivedUpdates.first, "Should have received an update after connection state changes")
}
}

private struct CacheItem: Equatable {
Expand Down
2 changes: 1 addition & 1 deletion Tests/HACacheSubscribeInfo.test.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal class HACacheSubscribeInfoTests: XCTestCase {

let subscribeInfo = HACacheSubscribeInfo<SubscribeWrapper>(subscription: subscription, transform: { info in
XCTAssertEqual(info.incoming, updated)
XCTAssertEqual(info.current?.subscribeItem, existing)
XCTAssertEqual(info.current.subscribeItem, existing)
return result
})

Expand Down

0 comments on commit c56d6b7

Please sign in to comment.