diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/SaplingParamsActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/SaplingParamsActionTests.swift index ee431750..48d28513 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/SaplingParamsActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/SaplingParamsActionTests.swift @@ -14,6 +14,9 @@ final class SaplingParamsActionTests: ZcashTestCase { let loggerMock = LoggerMock() let saplingParametersHandlerMock = SaplingParametersHandlerMock() + loggerMock.debugFileFunctionLineClosure = { _, _, _, _ in } + saplingParametersHandlerMock.handleIfNeededClosure = { } + mockContainer.mock(type: Logger.self, isSingleton: true) { _ in loggerMock } mockContainer.mock(type: SaplingParametersHandler.self, isSingleton: true) { _ in saplingParametersHandlerMock } @@ -21,6 +24,8 @@ final class SaplingParamsActionTests: ZcashTestCase { do { let nextContext = try await saplingParamsActionAction.run(with: .init(state: .handleSaplingParams)) { _ in } + XCTAssertTrue(loggerMock.debugFileFunctionLineCalled, "logger.debug(...) is expected to be called.") + XCTAssertTrue(saplingParametersHandlerMock.handleIfNeededCalled, "saplingParametersHandler.handleIfNeeded() is expected to be called.") let nextState = await nextContext.state XCTAssertTrue( nextState == .scanDownloaded, diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift index 0b4f8dcf..620782f5 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/ScanActionTests.swift @@ -14,22 +14,27 @@ final class ScanActionTests: ZcashTestCase { let blockScannerMock = BlockScannerMock() let transactionRepositoryMock = TransactionRepositoryMock() let loggerMock = LoggerMock() + + transactionRepositoryMock.lastScannedHeightReturnValue = 1500 + loggerMock.debugFileFunctionLineClosure = { _, _, _, _ in } + blockScannerMock.scanBlocksAtTotalProgressRangeDidScanClosure = { _, _, _ in 2 } - mockContainer.mock(type: BlockScanner.self, isSingleton: true) { _ in blockScannerMock } - mockContainer.mock(type: TransactionRepository.self, isSingleton: true) { _ in transactionRepositoryMock } - mockContainer.mock(type: Logger.self, isSingleton: true) { _ in loggerMock } - - let config: CompactBlockProcessor.Configuration = .standard( - for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: 0 - ) - - let scanAction = ScanAction( - container: mockContainer, - config: config - ) + let scanAction = setupAction(blockScannerMock, transactionRepositoryMock, loggerMock) + let syncContext = await setupActionContext() do { - let nextContext = try await scanAction.run(with: .init(state: .scan)) { _ in } + let nextContext = try await scanAction.run(with: syncContext) { event in + guard case .progressPartialUpdate(.syncing(let progress)) = event else { + XCTFail("event is expected to be .progressPartialUpdate(.syncing()) but received \(event)") + return + } + XCTAssertEqual(progress.startHeight, BlockHeight(1000)) + XCTAssertEqual(progress.targetHeight, BlockHeight(2000)) + XCTAssertEqual(progress.progressHeight, BlockHeight(1500)) + } + XCTAssertTrue(transactionRepositoryMock.lastScannedHeightCalled, "transactionRepository.lastScannedHeight() is expected to be called.") + XCTAssertTrue(loggerMock.debugFileFunctionLineCalled, "logger.debug(...) is expected to be called.") + XCTAssertTrue(blockScannerMock.scanBlocksAtTotalProgressRangeDidScanCalled, "blockScanner.scanBlocks(...) is expected to be called.") let nextState = await nextContext.state XCTAssertTrue( nextState == .clearAlreadyScannedBlocks, @@ -39,4 +44,80 @@ final class ScanActionTests: ZcashTestCase { XCTFail("testScanAction_NextAction is not expected to fail. \(error)") } } + + func testScanAction_EarlyOutForNoDownloadAndScanRangeSet() async throws { + let blockScannerMock = BlockScannerMock() + let transactionRepositoryMock = TransactionRepositoryMock() + let loggerMock = LoggerMock() + + let scanAction = setupAction(blockScannerMock, transactionRepositoryMock, loggerMock) + let syncContext: ActionContext = .init(state: .scan) + + do { + let _ = try await scanAction.run(with: syncContext) { _ in } + XCTAssertFalse(transactionRepositoryMock.lastScannedHeightCalled, "transactionRepository.lastScannedHeight() is expected to be called.") + XCTAssertFalse(loggerMock.debugFileFunctionLineCalled, "logger.debug(...) is expected to be called.") + XCTAssertFalse(blockScannerMock.scanBlocksAtTotalProgressRangeDidScanCalled, "blockScanner.scanBlocks(...) is expected to be called.") + } catch { + XCTFail("testScanAction_NextAction is not expected to fail. \(error)") + } + } + + func testScanAction_StartRangeHigherThanEndRange() async throws { + let blockScannerMock = BlockScannerMock() + let transactionRepositoryMock = TransactionRepositoryMock() + let loggerMock = LoggerMock() + + transactionRepositoryMock.lastScannedHeightReturnValue = 2001 + + let scanAction = setupAction(blockScannerMock, transactionRepositoryMock, loggerMock) + let syncContext = await setupActionContext() + + do { + let _ = try await scanAction.run(with: syncContext) { _ in } + XCTAssertTrue(transactionRepositoryMock.lastScannedHeightCalled, "transactionRepository.lastScannedHeight() is expected to be called.") + XCTAssertFalse(loggerMock.debugFileFunctionLineCalled, "logger.debug(...) is expected to be called.") + XCTAssertFalse(blockScannerMock.scanBlocksAtTotalProgressRangeDidScanCalled, "blockScanner.scanBlocks(...) is expected to be called.") + } catch { + XCTFail("testScanAction_NextAction is not expected to fail. \(error)") + } + } + + func setupAction( + _ blockScannerMock: BlockScannerMock, + _ transactionRepositoryMock: TransactionRepositoryMock, + _ loggerMock: LoggerMock + ) -> ScanAction { + mockContainer.mock(type: BlockScanner.self, isSingleton: true) { _ in blockScannerMock } + mockContainer.mock(type: TransactionRepository.self, isSingleton: true) { _ in transactionRepositoryMock } + mockContainer.mock(type: Logger.self, isSingleton: true) { _ in loggerMock } + + let config: CompactBlockProcessor.Configuration = .standard( + for: ZcashNetworkBuilder.network(for: .testnet), walletBirthday: 0 + ) + + return ScanAction( + container: mockContainer, + config: config + ) + } + + func setupActionContext() async -> ActionContext { + let syncContext: ActionContext = .init(state: .scan) + + let syncRanges = SyncRanges( + latestBlockHeight: 0, + downloadedButUnscannedRange: nil, + downloadAndScanRange: CompactBlockRange(uncheckedBounds: (1000, 2000)), + enhanceRange: nil, + fetchUTXORange: nil, + latestScannedHeight: nil, + latestDownloadedBlockHeight: nil + ) + + await syncContext.update(syncRanges: syncRanges) + await syncContext.update(totalProgressRange: CompactBlockRange(uncheckedBounds: (1000, 2000))) + + return syncContext + } } diff --git a/Tests/OfflineTests/CompactBlockProcessorActions/ValidateActionTests.swift b/Tests/OfflineTests/CompactBlockProcessorActions/ValidateActionTests.swift index 46cb9e0f..9f3ba023 100644 --- a/Tests/OfflineTests/CompactBlockProcessorActions/ValidateActionTests.swift +++ b/Tests/OfflineTests/CompactBlockProcessorActions/ValidateActionTests.swift @@ -13,6 +13,8 @@ final class ValidateActionTests: ZcashTestCase { func testValidateAction_NextAction() async throws { let blockValidatorMock = BlockValidatorMock() + blockValidatorMock.validateClosure = { } + mockContainer.mock(type: BlockValidator.self, isSingleton: true) { _ in blockValidatorMock } let validateAction = ValidateAction( @@ -21,6 +23,7 @@ final class ValidateActionTests: ZcashTestCase { do { let nextContext = try await validateAction.run(with: .init(state: .validate)) { _ in } + XCTAssertTrue(blockValidatorMock.validateCalled, "validator.validate() is expected to be called.") let nextState = await nextContext.state XCTAssertTrue( nextState == .scan, diff --git a/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift b/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift index a174e2f5..b4e0db64 100644 --- a/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift +++ b/Tests/TestUtils/Sourcery/GeneratedMocks/AutoMockable.generated.swift @@ -448,32 +448,7 @@ class SaplingParametersHandlerMock: SaplingParametersHandler { throw error } handleIfNeededCallsCount += 1 - try await handleIfNeededClosure?() - } - -} -class SaplingParametersHandlerMock: SaplingParametersHandler { - - - init( - ) { - } - - // MARK: - handleIfNeeded - - var handleIfNeededThrowableError: Error? - var handleIfNeededCallsCount = 0 - var handleIfNeededCalled: Bool { - return handleIfNeededCallsCount > 0 - } - var handleIfNeededClosure: (() async throws -> Void)? - - func handleIfNeeded() async throws { - if let error = handleIfNeededThrowableError { - throw error - } - handleIfNeededCallsCount += 1 - try await handleIfNeededClosure?() + try await handleIfNeededClosure!() } }