Making the tests & the API nicer.

Signed-off-by: Adam Rocska <adam.rocska@adams.solutions>
This commit is contained in:
Adam Rocska 2020-04-29 16:41:19 +02:00
parent 028b7ae23d
commit e06afd3d7a
5 changed files with 49 additions and 31 deletions

6
.idea/GeoIP2-swift...iml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="." external.linked.project.path="$MODULE_DIR$/." external.root.project.path="$MODULE_DIR$" external.system.id="SPM" type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -4,6 +4,7 @@
<modules>
<module fileurl="file://$PROJECT_DIR$/../../.idea/..iml" filepath="$PROJECT_DIR$/../../.idea/..iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/GeoIP2-swift.iml" filepath="$PROJECT_DIR$/.idea/GeoIP2-swift.iml" />
<module fileurl="file://$PROJECT_DIR$/../.idea/GeoIP2-swift...iml" filepath="$PROJECT_DIR$/../.idea/GeoIP2-swift...iml" />
</modules>
</component>
</project>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -1,22 +1,25 @@
import Foundation
extension Data {
func index(of data: Data) -> Index? {
fileprivate func boyerMoore(data: Data, from: Index) -> Index? {
let patternLength = data.count
precondition(patternLength > 0)
precondition(self.count >= patternLength)
precondition(patternLength > 0, "Pattern can't be empty.")
precondition(self.count >= patternLength, "Pattern can't be >= than the Data to search in.")
precondition(data.indices.contains(from), "Index from which to start the lookup must be contained in the Data.")
var skipTable = [UInt8: Int]()
for (i, byte) in data.enumerated() {
skipTable[byte] = patternLength - i - 1
}
let lastByteIndexOfData = data.index(before: data.endIndex)
let lastByteOfData = data.last
var i = self.index(self.startIndex, offsetBy: patternLength - 1)
let lastIndexOfSelf = self.endIndex
let lastIndexOfData = data.index(before: data.endIndex)
let lastByteOfData = data.last
var i = self.index(from, offsetBy: patternLength - 1, limitedBy: lastIndexOfSelf) ?? lastIndexOfSelf
func reverseMatch() -> Index? {
var dataIndex = lastByteIndexOfData
var dataIndex = lastIndexOfData
var selfIndex = i
while dataIndex > data.startIndex {
selfIndex = self.index(before: selfIndex)
@ -38,10 +41,19 @@ extension Data {
i = self.index(
i,
offsetBy: skipTable[byte] ?? patternLength,
limitedBy: self.endIndex
) ?? self.endIndex
limitedBy: lastIndexOfSelf
) ?? lastIndexOfSelf
}
}
return nil
}
func index(of data: Data) -> Index? {
return boyerMoore(data: data, from: self.startIndex)
}
func index(of data: Data, from: Index) -> Index? {
return boyerMoore(data: data, from: from)
}
}

View File

@ -2,37 +2,32 @@ import Foundation
import XCTest
@testable import MaxMindDBReader
fileprivate extension String {
var asciiData: Data { get { return self.data(using: .ascii) ?? Data() } }
}
class IndexOfData: XCTestCase {
private typealias TestDefinition = (sequence: Data, subsequence: Data, expectedIndex: Data.Index?)
private func testDefinition(sequence: String, subsequence: String, expectedIndex: Int?) -> TestDefinition? {
guard let dataSequence = sequence.data(using: .ascii) else {
XCTFail("Could not represent sequence String as Data using ASCII encoding.")
return nil
}
guard let dataSubsequence = subsequence.data(using: .ascii) else {
XCTFail("Could not represent subsequence String as Data using ASCII encoding.")
return nil
}
return (
sequence: dataSequence,
subsequence: dataSubsequence,
sequence: sequence.asciiData,
subsequence: subsequence.asciiData,
expectedIndex: expectedIndex
)
}
func testIndexOfData() {
func testIndex_ofData() {
let testDefinitions = [
testDefinition(sequence: "Hello World", subsequence: "World", expectedIndex: 6),
testDefinition(sequence: "Hello world", subsequence: "World", expectedIndex: nil),
testDefinition(sequence: "Hello World SOME World", subsequence: "World", expectedIndex: 6),
testDefinition(sequence: "Hello world SOME World", subsequence: "World", expectedIndex: 17),
testDefinition(sequence: "Hello World", subsequence: "Hello", expectedIndex: 0),
testDefinition(sequence: "hello World", subsequence: "hello", expectedIndex: 0),
testDefinition(sequence: "hello world", subsequence: "Hello", expectedIndex: nil),
testDefinition(sequence: "hello World SOME World", subsequence: "Hello", expectedIndex: nil),
testDefinition(sequence: "hello world SOME World", subsequence: "Hello", expectedIndex: nil)
(sequence: "Hello World".asciiData, subsequence: "World".asciiData, expectedIndex: 6),
(sequence: "Hello world".asciiData, subsequence: "World".asciiData, expectedIndex: nil),
(sequence: "Hello World SOME World".asciiData, subsequence: "World".asciiData, expectedIndex: 6),
(sequence: "Hello world SOME World".asciiData, subsequence: "World".asciiData, expectedIndex: 17),
(sequence: "Hello World".asciiData, subsequence: "Hello".asciiData, expectedIndex: 0),
(sequence: "hello World".asciiData, subsequence: "hello".asciiData, expectedIndex: 0),
(sequence: "hello world".asciiData, subsequence: "Hello".asciiData, expectedIndex: nil),
(sequence: "hello World SOME World".asciiData, subsequence: "Hello".asciiData, expectedIndex: nil),
(sequence: "hello world SOME World".asciiData, subsequence: "Hello".asciiData, expectedIndex: nil)
]
for testDefinition in testDefinitions.compactMap({ $0 }) {
@ -42,4 +37,8 @@ class IndexOfData: XCTestCase {
)
}
}
func testIndex_ofData_fromIndex() {
XCTAssertEqual(12, "Hello World Hello World".asciiData.index(of: "Hello World".asciiData, from: 3))
}
}