This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | func test_givenUnlockedSecureStorage_whenSavingValue_itCanBeLaterRead() { | |
| let storage = SecureStorage<String>() | |
| let unlockExpectation = self.expectation(description: "secure storage is unlocked") | |
| let saveExpectation = self.expectation(description: "value is saved") | |
| let readExpectation = self.expectation(description: "value is read") | |
| storage.unlock { (unlocked) in | |
| XCTAssertTrue(unlocked) | |
| unlockExpectation.fulfill() | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | class LevelSelectionViewModelTests: XCTestCase { | |
| private var viewModel: LevelSelectionViewModel! | |
| private var mockDelegate: MockLevelSelectionViewModelDelegate! | |
| override func setUp() { | |
| super.setUp() | |
| let levels = [ | |
| Level(status: .unlocked, identifier: "abc"), | |
| Level(status: .locked, identifier: "def") | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | private final class MockTaskStatusDelegate: TaskStatusDelegate { | |
| var didCall_taskDidChangeStatus: ((Task, Task.Status) -> Void)? | |
| func taskDidChangeStatus(task: Task, status: Task.Status) { | |
| didCall_taskDidChangeStatus?(task, status) | |
| } | |
| } | |
| class TaskTests: XCTestCase { | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | enum ToggleValue { | |
| case initial(Bool) | |
| case updated(Bool) | |
| case fallback(Bool) | |
| case unknown(Error) | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | func test_givenStorageThatSucceedsOnSave_whenChangingToggleValue_itEmitsUpdatedValue() { | |
| let mockStorage = MockToggleStorage(readValue: true, saveShouldFail: false) | |
| let simulatedValueSubject = PublishSubject<Bool>() // simulated user input | |
| let toggle = Toggle(storage: mockStorage) | |
| let initialValueExpectation = self.expectation(description: "will emit initial value") | |
| let updatedValueExpectation = self.expectation(description: "will emit 2 updated values") | |
| updatedValueExpectation.expectedFulfillmentCount = 2 | |
| let (value, _) = toggle.manage(change: simulatedValueSubject.asObservable()) | |
| var recordedValues: [ToggleValue] = [] | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | extension UISwitch { | |
| func shake() { | |
| transform = CGAffineTransform(translationX: 15, y: 0) | |
| UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 1, options: .curveEaseInOut, animations: { | |
| self.transform = CGAffineTransform.identity | |
| }, completion: nil) | |
| } | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | private func setUp(settingSwitch: UISwitch, with toggle: Toggle) { | |
| let (value, isBusy) = toggle.manage(change: settingSwitch.rx.isOn.changed.asObservable()) | |
| // ... | |
| let fallbackValue = value | |
| .filter { $0.isFallback } | |
| .map { $0.value } | |
| .flatMap { $0.map(Driver.just) ?? Driver.empty() } // .unwrap() if using `RxSwiftExt` | |
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | private func setUp(settingSwitch: UISwitch, with toggle: Toggle) { | |
| let (value, isBusy) = toggle.manage(change: settingSwitch.rx.isOn.changed.asObservable()) | |
| // ... | |
| let isSwitchDisabled = isBusy | |
| .map { !$0 } | |
| isSwitchDisabled | |
| .drive(settingSwitch.rx.isEnabled) | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | extension ToggleValue { | |
| var value: Bool? { | |
| switch self { | |
| case .initial(let value), .updated(let value), .fallback(let value): | |
| return value | |
| case .unknown: | |
| return nil | |
| } | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | private func setUp(settingSwitch: UISwitch, with toggle: Toggle) { | |
| let (value, isBusy) = toggle.manage(change: settingSwitch.rx.isOn.changed.asObservable()) | |
| let initialValue = value | |
| .filter { $0.isInitial } | |
| .map { $0.value } | |
| .flatMap { $0.map(Driver.just) ?? Driver.empty() } // .unwrap() if using `RxSwiftExt` | |
| let fallbackValue = value | |
| .filter { $0.isFallback } |