commit
48e3da2922
|
@ -3,6 +3,11 @@
|
|||
All notable changes to this project will be documented in this file. `Scout` adheres to [Semantic Versioning](http://semver.org).
|
||||
|
||||
---
|
||||
## [4.0.3]( https://github.com/ABridoux/scout/tree/4.0.3) (06/06/2021)
|
||||
### Fixed
|
||||
- Jaro-Winkler crash when comparing two strings of single characters. [#253]
|
||||
- `computeIndex(from:arrayCount:)` fixed empty arrays and 0 index [#254]
|
||||
|
||||
## [4.0.2](https://github.com/ABridoux/scout/tree/4.0.2) (08/05/2021)
|
||||
### Changed
|
||||
- Removed useless `indirect` attribute on `ExplorerValue` enum.
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
// MIT license, see LICENSE file for details
|
||||
|
||||
public enum ScoutVersion {
|
||||
public static let current = "4.0.2"
|
||||
public static let current = "4.0.3"
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ extension ExplorerValue {
|
|||
return try addCount(value: value, tail: tail)
|
||||
}
|
||||
|
||||
let index = try computeIndex(from: index, arrayCount: array.count)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: array.count)
|
||||
let newValue = try array[index]._add(path: tail, value: value)
|
||||
|
||||
if tail.isEmpty {
|
||||
|
|
|
@ -57,7 +57,7 @@ extension ExplorerValue {
|
|||
|
||||
private mutating func delete(index: Int, tail: SlicePath, deleteIfEmpty: Bool) throws {
|
||||
var array = try self.array.unwrapOrThrow(.subscriptIndexNoArray)
|
||||
let index = try computeIndex(from: index, arrayCount: array.count)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: array.count)
|
||||
var value = array[index]
|
||||
let shouldDelete = try value._delete(path: tail, deleteIfEmpty: deleteIfEmpty)
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ extension ExplorerValue {
|
|||
|
||||
private func get(index: Int, tail: SlicePath) throws -> Self {
|
||||
let array = try self.array.unwrapOrThrow(.subscriptIndexNoArray)
|
||||
let index = try computeIndex(from: index, arrayCount: array.count)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: array.count)
|
||||
return try array[index]._get(path: tail)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,9 @@ extension PathExplorer {
|
|||
/// - Parameters:
|
||||
/// - index: Index to compute
|
||||
/// - arrayCount: Array count
|
||||
func computeIndex(from index: Int, arrayCount: Int) throws -> Int {
|
||||
static func computeIndex(from index: Int, arrayCount: Int) throws -> Int {
|
||||
let computedIndex = index < 0 ? arrayCount + index : index
|
||||
|
||||
if computedIndex == 0 && arrayCount == 0 { return 0 }
|
||||
|
||||
guard 0 <= computedIndex, computedIndex < arrayCount else {
|
||||
throw ExplorerError.wrong(index: index, arrayCount: arrayCount)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ extension ExplorerValue {
|
|||
|
||||
private mutating func set(index: Int, to newValue: Self, tail: SlicePath) throws {
|
||||
var array = try self.array.unwrapOrThrow(.subscriptIndexNoArray)
|
||||
let index = try computeIndex(from: index, arrayCount: array.count)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: array.count)
|
||||
var element = array[index]
|
||||
try element._set(path: tail, to: newValue)
|
||||
array[index] = element
|
||||
|
@ -110,7 +110,7 @@ extension ExplorerValue {
|
|||
|
||||
private mutating func set(index: Int, keyName: String, tail: SlicePath) throws {
|
||||
var array = try self.array.unwrapOrThrow(.subscriptIndexNoArray)
|
||||
let index = try computeIndex(from: index, arrayCount: array.count)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: array.count)
|
||||
var element = array[index]
|
||||
try element._set(path: tail, keyName: keyName)
|
||||
array[index] = element
|
||||
|
|
|
@ -82,7 +82,7 @@ extension ExplorerXML {
|
|||
return try addCount(value: value, tail: tail)
|
||||
}
|
||||
|
||||
let index = try computeIndex(from: index, arrayCount: childrenCount)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: childrenCount)
|
||||
|
||||
guard tail.isEmpty else {
|
||||
try children[index]._add(value: value, at: tail)
|
||||
|
|
|
@ -48,7 +48,7 @@ extension ExplorerXML {
|
|||
}
|
||||
|
||||
private func delete(index: Int, deleteIfEmpty: Bool, tail: SlicePath) throws {
|
||||
let index = try computeIndex(from: index, arrayCount: childrenCount)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: childrenCount)
|
||||
let next = children[index]
|
||||
try delete(tail: tail, on: next, deleteIfEmpty: deleteIfEmpty)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ extension ExplorerXML {
|
|||
}
|
||||
|
||||
private func get(index: Int, tail: SlicePath) throws -> Self {
|
||||
let index = try computeIndex(from: index, arrayCount: children.count)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: children.count)
|
||||
return try children[index]._get(path: tail)
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ extension ExplorerXML {
|
|||
try getJaroWinkler(key: key)._set(path: tail, to: newValue)
|
||||
|
||||
case .index(let index):
|
||||
let index = try computeIndex(from: index, arrayCount: childrenCount)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: childrenCount)
|
||||
try children[index]._set(path: tail, to: newValue)
|
||||
|
||||
default: throw ExplorerError.wrongUsage(of: head)
|
||||
|
@ -95,7 +95,7 @@ extension ExplorerXML {
|
|||
try getJaroWinkler(key: key).set(path: tail, keyNameTo: newKeyName)
|
||||
|
||||
case .index(let index):
|
||||
let index = try computeIndex(from: index, arrayCount: childrenCount)
|
||||
let index = try Self.computeIndex(from: index, arrayCount: childrenCount)
|
||||
try children[index].set(path: tail, keyNameTo: newKeyName)
|
||||
|
||||
default: throw ExplorerError.wrongUsage(of: element)
|
||||
|
|
|
@ -38,7 +38,7 @@ private struct JaroWinklerDistance {
|
|||
self.string1 = string1
|
||||
self.string2 = string2
|
||||
|
||||
maxSpacing = max(string1.count, string2.count) / 2 - 1
|
||||
maxSpacing = max(0, max(string1.count, string2.count) / 2 - 1)
|
||||
}
|
||||
|
||||
func computeMatches() -> [Int] {
|
||||
|
|
|
@ -6,9 +6,17 @@
|
|||
import XCTest
|
||||
@testable import Scout
|
||||
|
||||
final class ArrayExtensionsTests: XCTestCase {
|
||||
final class ArrayExtensionsTests: XCTestCase {}
|
||||
|
||||
let stubArray = ["Riri", "Fifi", "Loulou", "Scrooge", "Donald", "Daisy"]
|
||||
// MARK: - Delete range
|
||||
|
||||
extension ArrayExtensionsTests {
|
||||
|
||||
// MARK: Stubs
|
||||
|
||||
var stubArray: [String] { ["Riri", "Fifi", "Loulou", "Scrooge", "Donald", "Daisy"] }
|
||||
|
||||
// MARK: Tests
|
||||
|
||||
func testDeleteRange1() throws {
|
||||
let range = 2...4
|
||||
|
@ -28,3 +36,4 @@ final class ArrayExtensionsTests: XCTestCase {
|
|||
XCTAssertEqual(stubArray.remove(in: range), ["Donald", "Daisy"])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Scout
|
||||
// Copyright (c) 2020-present Alexis Bridoux
|
||||
// MIT license, see LICENSE file for details
|
||||
|
||||
@testable import Scout
|
||||
import XCTest
|
||||
|
||||
final class PathExplorerHelpersTest: XCTestCase {
|
||||
|
||||
func testComputeIndex_PositiveIndex() throws {
|
||||
let result = try PathExplorers.Json.computeIndex(from: 5, arrayCount: 10)
|
||||
|
||||
XCTAssertEqual(result, 5)
|
||||
}
|
||||
|
||||
func testComputeIndex_NegativeIndex() throws {
|
||||
let result = try PathExplorers.Json.computeIndex(from: -3, arrayCount: 10)
|
||||
|
||||
XCTAssertEqual(result, 7)
|
||||
}
|
||||
|
||||
func testComputeIndex_EmptyArray_PositiveIndexThrows() throws {
|
||||
XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 1, arrayCount: 0),
|
||||
.wrong(index: 1, arrayCount: 0))
|
||||
}
|
||||
|
||||
func testComputeIndex_EmptyArray_NegativeIndexThrows() throws {
|
||||
XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: -1, arrayCount: 0),
|
||||
.wrong(index: -1, arrayCount: 0))
|
||||
}
|
||||
|
||||
func testComputeIndex_EmptyArray_ZeroIndexThrows() throws {
|
||||
XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 0, arrayCount: 0),
|
||||
.wrong(index: 0, arrayCount: 0))
|
||||
}
|
||||
|
||||
func testComputeIndex_SingleElementArray_PositiveIndexThrows() throws {
|
||||
XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 1, arrayCount: 1),
|
||||
.wrong(index: 1, arrayCount: 1))
|
||||
}
|
||||
|
||||
func testComputeIndex_SingleElementArray_NegativeIndex() throws {
|
||||
let result = try PathExplorers.Json.computeIndex(from: -1, arrayCount: 1)
|
||||
|
||||
XCTAssertEqual(result, 0)
|
||||
}
|
||||
|
||||
func testComputeIndex_OutOfBounds_PositiveIndexThrows() throws {
|
||||
XCTAssertErrorsEqual(try PathExplorers.Json.computeIndex(from: 5, arrayCount: 4),
|
||||
.wrong(index: 5, arrayCount: 4))
|
||||
}
|
||||
|
||||
}
|
|
@ -33,4 +33,9 @@ final class String_JaroWinklerTests: XCTestCase {
|
|||
let result = target.bestJaroWinklerMatchIn(propositions: propositions)
|
||||
XCTAssertEqual(result, "version")
|
||||
}
|
||||
|
||||
func testMatchSingleCharacters_Equals0() {
|
||||
let result = "b".jaroWinklerDistance(from: "a")
|
||||
XCTAssertEqual(result, 0)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue