HKHealthStoreMock.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. //
  2. // HKHealthStoreMock.swift
  3. // LoopKitTests
  4. //
  5. // Copyright © 2018 LoopKit Authors. All rights reserved.
  6. //
  7. import HealthKit
  8. import XCTest
  9. import Foundation
  10. @testable import LoopKit
  11. class MockHKObserverQuery: HKObserverQuery {
  12. var updateHandler: ((HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void)?
  13. override init(sampleType: HKSampleType, predicate: NSPredicate?, updateHandler: @escaping (HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void)
  14. {
  15. super.init(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
  16. self.updateHandler = updateHandler
  17. }
  18. override init(queryDescriptors: [HKQueryDescriptor], updateHandler: @escaping (HKObserverQuery, Set<HKSampleType>?, @escaping HKObserverQueryCompletionHandler, Error?) -> Void) {
  19. super.init(queryDescriptors: queryDescriptors, updateHandler: updateHandler)
  20. }
  21. }
  22. class MockHKAnchoredObjectQuery: HKAnchoredObjectQuery {
  23. var resultsHandler: ((HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void)?
  24. var anchor: HKQueryAnchor?
  25. override init(type: HKSampleType, predicate: NSPredicate?, anchor: HKQueryAnchor?, limit: Int, resultsHandler handler: @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void)
  26. {
  27. super.init(type: type, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: handler)
  28. self.resultsHandler = handler
  29. self.anchor = anchor
  30. }
  31. override init(queryDescriptors: [HKQueryDescriptor], anchor: HKQueryAnchor?, limit: Int, resultsHandler handler: @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) {
  32. super.init(queryDescriptors: queryDescriptors, anchor: anchor, limit: limit, resultsHandler: handler)
  33. }
  34. }
  35. class HKHealthStoreMock: HKHealthStoreProtocol {
  36. func stop(_ query: HKQuery) {
  37. }
  38. func enableBackgroundDelivery(for type: HKObjectType, frequency: HKUpdateFrequency) async throws {
  39. didEnableBackgroundDelivery = true
  40. }
  41. func cachedPreferredUnits(for quantityTypeIdentifier: HKQuantityTypeIdentifier) async -> HKUnit? {
  42. return unitsCache[quantityTypeIdentifier]
  43. }
  44. var unitsCache: [HKQuantityTypeIdentifier: HKUnit] = [
  45. .bloodGlucose : .milligramsPerDeciliter,
  46. .insulinDelivery : .internationalUnit(),
  47. .dietaryCarbohydrates : .gram()
  48. ]
  49. var saveError: Error?
  50. var didEnableBackgroundDelivery: Bool = false
  51. var deleteError: Error?
  52. var queryResults: (samples: [HKSample]?, error: Error?)?
  53. var observerQuery: HKObserverQuery?
  54. var anchoredObjectQuery: HKAnchoredObjectQuery?
  55. var authorizationStatus: HKAuthorizationStatus?
  56. let authorizationRequestUserResponse: Result<Bool, Error> = .success(true)
  57. var observerQueryStartedExpectation: XCTestExpectation?
  58. var anchorQueryStartedExpectation: XCTestExpectation?
  59. private var saveHandler: ((_ objects: [HKObject], _ success: Bool, _ error: Error?) -> Void)?
  60. private var deleteObjectsHandler: ((_ objectType: HKObjectType, _ predicate: NSPredicate, _ success: Bool, _ count: Int, _ error: Error?) -> Void)?
  61. let queue = DispatchQueue(label: "HKHealthStoreMock")
  62. func execute(_ query: HKQuery) {
  63. switch query {
  64. case let q as HKObserverQuery:
  65. observerQuery = q
  66. observerQueryStartedExpectation?.fulfill()
  67. case let q as HKAnchoredObjectQuery:
  68. anchoredObjectQuery = q
  69. anchorQueryStartedExpectation?.fulfill()
  70. default:
  71. print("Unhandled query: \(query)")
  72. }
  73. }
  74. func save(_ object: HKObject, withCompletion completion: @escaping (Bool, Error?) -> Void) {
  75. queue.async {
  76. self.saveHandler?([object], self.saveError == nil, self.saveError)
  77. completion(self.saveError == nil, self.saveError)
  78. }
  79. }
  80. func save(_ objects: [HKObject], withCompletion completion: @escaping (Bool, Error?) -> Void) {
  81. queue.async {
  82. self.saveHandler?(objects, self.saveError == nil, self.saveError)
  83. completion(self.saveError == nil, self.saveError)
  84. }
  85. }
  86. func delete(_ objects: [HKObject], withCompletion completion: @escaping (Bool, Error?) -> Void) {
  87. queue.async {
  88. completion(self.deleteError == nil, self.deleteError)
  89. }
  90. }
  91. func deleteObjects(of objectType: HKObjectType, predicate: NSPredicate, withCompletion completion: @escaping (Bool, Int, Error?) -> Void) {
  92. queue.async {
  93. self.deleteObjectsHandler?(objectType, predicate, self.deleteError == nil, 0, self.deleteError)
  94. completion(self.deleteError == nil, 0, self.deleteError)
  95. }
  96. }
  97. func setSaveHandler(_ saveHandler: ((_ objects: [HKObject], _ success: Bool, _ error: Error?) -> Void)?) {
  98. queue.sync {
  99. self.saveHandler = saveHandler
  100. }
  101. }
  102. func requestAuthorization(toShare typesToShare: Set<HKSampleType>?, read typesToRead: Set<HKObjectType>?, completion: @escaping (Bool, Error?) -> Void) {
  103. switch authorizationRequestUserResponse {
  104. case .success(let authorized):
  105. authorizationStatus = authorized ? .sharingAuthorized : .sharingDenied
  106. DispatchQueue.main.async {
  107. completion(true, nil)
  108. }
  109. case .failure(let error):
  110. DispatchQueue.main.async {
  111. completion(false, error)
  112. }
  113. }
  114. }
  115. func authorizationStatus(for type: HKObjectType) -> HKAuthorizationStatus {
  116. return authorizationStatus ?? .notDetermined
  117. }
  118. func setDeletedObjectsHandler(_ deleteObjectsHandler: ((_ objectType: HKObjectType, _ predicate: NSPredicate, _ success: Bool, _ count: Int, _ error: Error?) -> Void)?) {
  119. queue.sync {
  120. self.deleteObjectsHandler = deleteObjectsHandler
  121. }
  122. }
  123. }
  124. extension HKHealthStoreMock: HKSampleQueryTestable {
  125. func executeSampleQuery(
  126. for type: HKSampleType,
  127. matching predicate: NSPredicate,
  128. limit: Int,
  129. sortDescriptors: [NSSortDescriptor]?,
  130. resultsHandler: @escaping (_ query: HKSampleQuery, _ results: [HKSample]?, _ error: Error?) -> Void
  131. ) {
  132. let query = HKSampleQuery(sampleType: type, predicate: predicate, limit: limit, sortDescriptors: sortDescriptors, resultsHandler: resultsHandler)
  133. guard let results = queryResults else {
  134. execute(query)
  135. return
  136. }
  137. queue.async {
  138. resultsHandler(query, results.samples, results.error)
  139. }
  140. }
  141. }