From c8fe131e278a343f5b67d7b8a58d53f51d4e2c22 Mon Sep 17 00:00:00 2001 From: Matt <85322+mattmassicotte@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:17:54 -0500 Subject: [PATCH] remove unneeded pending state, more tests --- Sources/RangeState/RangeValidator.swift | 8 +--- .../SinglePhaseRangeValidator.swift | 32 +++++++------- .../RangeState/ThreePhaseRangeValidator.swift | 7 +-- .../RangeStateTests/RangeValidatorTests.swift | 43 +++++++++++++++++++ .../SinglePhaseRangeValidatorTests.swift | 5 ++- 5 files changed, 66 insertions(+), 29 deletions(-) create mode 100644 Tests/RangeStateTests/RangeValidatorTests.swift diff --git a/Sources/RangeState/RangeValidator.swift b/Sources/RangeState/RangeValidator.swift index 604e2a0..ffcb305 100644 --- a/Sources/RangeState/RangeValidator.swift +++ b/Sources/RangeState/RangeValidator.swift @@ -13,10 +13,9 @@ public final class RangeValidator { public typealias ContentRange = VersionedRange public typealias ValidationProvider = HybridValueProvider - public enum Action: Sendable { + public enum Action: Sendable, Equatable { case none case needed(ContentRange) - case pending(NSRange) } private var validSet = IndexSet() @@ -58,10 +57,6 @@ public final class RangeValidator { guard let neededRange = nextNeededRange(in: set, prioritizing: range) else { return .none } - if pendingSet.contains(integersIn: neededRange) { - return .pending(neededRange) - } - self.pendingSet.insert(range: neededRange) self.pendingRequests += 1 @@ -175,3 +170,4 @@ extension RangeValidator { } } +extension RangeValidator.Action: Hashable where Content.Version: Hashable {} diff --git a/Sources/RangeState/SinglePhaseRangeValidator.swift b/Sources/RangeState/SinglePhaseRangeValidator.swift index c1f0b93..22ce5ab 100644 --- a/Sources/RangeState/SinglePhaseRangeValidator.swift +++ b/Sources/RangeState/SinglePhaseRangeValidator.swift @@ -5,6 +5,7 @@ import Rearrange @MainActor public final class SinglePhaseRangeValidator { + public typealias ContentRange = RangeValidator.ContentRange public typealias Provider = HybridValueProvider public typealias PriorityRangeProvider = () -> NSRange @@ -68,25 +69,26 @@ public final class SinglePhaseRangeValidator { let action = primaryValidator.beginValidation(of: target, prioritizing: range) - guard case let .needed(contentRange) = action else { - return action - } - - // if we have an outstanding async operation going, force this to be async too - if outstanding { - enqueueValidation(for: contentRange) - return action - } + switch action { + case .none: + return .none + case let .needed(contentRange): + // if we have an outstanding async operation going, force this to be async too + if outstanding { + enqueueValidation(for: contentRange) + return action + } - guard let validation = configuration.provider.sync(contentRange) else { - enqueueValidation(for: contentRange) + guard let validation = configuration.provider.sync(contentRange) else { + enqueueValidation(for: contentRange) - return .pending(contentRange.value) - } + return action + } - completePrimaryValidation(of: contentRange, with: validation) + completePrimaryValidation(of: contentRange, with: validation) - return .none + return .none + } } private func completePrimaryValidation(of contentRange: ContentRange, with validation: Validation) { diff --git a/Sources/RangeState/ThreePhaseRangeValidator.swift b/Sources/RangeState/ThreePhaseRangeValidator.swift index 87449d9..e2a8826 100644 --- a/Sources/RangeState/ThreePhaseRangeValidator.swift +++ b/Sources/RangeState/ThreePhaseRangeValidator.swift @@ -82,10 +82,7 @@ public final class ThreePhaseRangeValidator { switch action { case .none: scheduleSecondaryValidation(of: target, prioritizing: range) - case let .pending(pendingRange): - fallbackValidate(pendingRange, prioritizing: range) case let .needed(contentRange): - // same as above fallbackValidate(contentRange.value, prioritizing: range) } } @@ -98,8 +95,6 @@ public final class ThreePhaseRangeValidator { switch action { case .none: return - case .pending: - preconditionFailure("It makes no sense for this to be pending") case let .needed(contentRange): provider(contentRange.value) @@ -169,7 +164,7 @@ extension ThreePhaseRangeValidator { let action = validator.beginValidation(of: target, prioritizing: range) switch action { - case .none, .pending: + case .none: return case let .needed(contentRange): let validation = await provider(contentRange) diff --git a/Tests/RangeStateTests/RangeValidatorTests.swift b/Tests/RangeStateTests/RangeValidatorTests.swift new file mode 100644 index 0000000..219e0b0 --- /dev/null +++ b/Tests/RangeStateTests/RangeValidatorTests.swift @@ -0,0 +1,43 @@ +import XCTest + +import RangeState + +final class RangeValidatorTests: XCTestCase { + typealias StringValidator = RangeValidator + + @MainActor + func testHandleCompletedValidation() { + let content = StringContent(string: "abc") + let validator = StringValidator(content: content) + + let range = NSRange(0..<3) + let contentRange = StringValidator.ContentRange(range, version: content.currentVersion) + + let val1 = validator.beginValidation(of: .all) + + XCTAssertEqual(val1, .needed(contentRange)) + + validator.completeValidation(of: contentRange, with: .success(range)) + + let val2 = validator.beginValidation(of: .all) + + XCTAssertEqual(val2, .none) + } + + @MainActor + func testHandleDuplicateValidation() { + let content = StringContent(string: "abc") + let validator = StringValidator(content: content) + + let range = NSRange(0..<3) + let contentRange = StringValidator.ContentRange(range, version: content.currentVersion) + + let val1 = validator.beginValidation(of: .all) + + XCTAssertEqual(val1, .needed(contentRange)) + + let val2 = validator.beginValidation(of: .all) + + XCTAssertEqual(val2, .none) + } +} diff --git a/Tests/RangeStateTests/SinglePhaseRangeValidatorTests.swift b/Tests/RangeStateTests/SinglePhaseRangeValidatorTests.swift index cacec82..3c37536 100644 --- a/Tests/RangeStateTests/SinglePhaseRangeValidatorTests.swift +++ b/Tests/RangeStateTests/SinglePhaseRangeValidatorTests.swift @@ -73,12 +73,13 @@ final class SinglePhaseRangeValidatorTests: XCTestCase { let provider = StringValidator.Provider( syncValue: { validationExp.fulfill() - + return .success($0.value) }, asyncValue: { contentRange, _ in return .success(contentRange.value) - }) + } + ) let validator = StringValidator( configuration: .init(