Extract Base16 package
This commit is contained in:
parent
dc3efd51e9
commit
7327d167c3
|
@ -1,5 +0,0 @@
|
||||||
.DS_Store
|
|
||||||
/.build
|
|
||||||
/Packages
|
|
||||||
/*.xcodeproj
|
|
||||||
xcuserdata/
|
|
|
@ -1,22 +0,0 @@
|
||||||
// swift-tools-version:5.3
|
|
||||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
|
||||||
|
|
||||||
import PackageDescription
|
|
||||||
|
|
||||||
let package = Package(
|
|
||||||
name: "Base16",
|
|
||||||
products: [
|
|
||||||
.library(
|
|
||||||
name: "Base16",
|
|
||||||
targets: ["Base16"])
|
|
||||||
],
|
|
||||||
dependencies: [],
|
|
||||||
targets: [
|
|
||||||
.target(
|
|
||||||
name: "Base16",
|
|
||||||
dependencies: []),
|
|
||||||
.testTarget(
|
|
||||||
name: "Base16Tests",
|
|
||||||
dependencies: ["Base16"])
|
|
||||||
]
|
|
||||||
)
|
|
|
@ -1,68 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public enum Base16EncodingError: Error {
|
|
||||||
case invalidLength
|
|
||||||
case invalidByteString(String)
|
|
||||||
case invalidStringEncoding
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension Data {
|
|
||||||
enum Base16EncodingOptions {
|
|
||||||
case uppercase
|
|
||||||
}
|
|
||||||
|
|
||||||
func base16EncodedString(options: [Base16EncodingOptions] = []) -> String {
|
|
||||||
map { String(format: Self.format(options: options), $0) }.joined()
|
|
||||||
}
|
|
||||||
|
|
||||||
func base16EncodedData(options: [Base16EncodingOptions] = []) -> Data {
|
|
||||||
Data(base16EncodedString(options: options).utf8)
|
|
||||||
}
|
|
||||||
|
|
||||||
init(base16Encoded string: String) throws {
|
|
||||||
let stringLength = string.count
|
|
||||||
|
|
||||||
guard stringLength % 2 == 0 else {
|
|
||||||
throw Base16EncodingError.invalidLength
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = [UInt8]()
|
|
||||||
|
|
||||||
data.reserveCapacity(stringLength / 2)
|
|
||||||
|
|
||||||
var i = string.startIndex
|
|
||||||
|
|
||||||
while i != string.endIndex {
|
|
||||||
let j = string.index(i, offsetBy: 2)
|
|
||||||
let byteString = string[i..<j]
|
|
||||||
|
|
||||||
guard let byte = UInt8(byteString, radix: 16) else {
|
|
||||||
throw Base16EncodingError.invalidByteString(String(byteString))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.append(byte)
|
|
||||||
i = j
|
|
||||||
}
|
|
||||||
|
|
||||||
self = Data(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
init(base16Encoded data: Data) throws {
|
|
||||||
guard let string = String(data: data, encoding: .utf8) else {
|
|
||||||
throw Base16EncodingError.invalidStringEncoding
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.init(base16Encoded: string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension Data {
|
|
||||||
static let lowercaseBase16Format = "%02.2hhx"
|
|
||||||
static let uppercaseBase16Format = "%02.2hhX"
|
|
||||||
|
|
||||||
static func format(options: [Base16EncodingOptions]) -> String {
|
|
||||||
options.contains(.uppercase) ? uppercaseBase16Format : lowercaseBase16Format
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
@testable import Base16
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
final class Base16Tests: XCTestCase {
|
|
||||||
let testData = Data([182, 239, 215, 173, 251, 168, 76, 252,
|
|
||||||
140, 7, 39, 163, 56, 255, 171, 35,
|
|
||||||
121, 205, 26, 252, 53, 166, 159, 67,
|
|
||||||
100, 70, 140, 79, 47, 26, 138, 209])
|
|
||||||
let testDataLowercaseString = "b6efd7adfba84cfc8c0727a338ffab2379cd1afc35a69f4364468c4f2f1a8ad1"
|
|
||||||
let testDataLowercaseStringData = Data([98, 54, 101, 102, 100, 55, 97, 100,
|
|
||||||
102, 98, 97, 56, 52, 99, 102, 99,
|
|
||||||
56, 99, 48, 55, 50, 55, 97, 51, 51,
|
|
||||||
56, 102, 102, 97, 98, 50, 51, 55,
|
|
||||||
57, 99, 100, 49, 97, 102, 99, 51,
|
|
||||||
53, 97, 54, 57, 102, 52, 51, 54,
|
|
||||||
52, 52, 54, 56, 99, 52, 102, 50,
|
|
||||||
102, 49, 97, 56, 97, 100, 49])
|
|
||||||
let testDataUppercaseString = "B6EFD7ADFBA84CFC8C0727A338FFAB2379CD1AFC35A69F4364468C4F2F1A8AD1"
|
|
||||||
let testDataUppercaseStringData = Data([66, 54, 69, 70, 68, 55, 65, 68,
|
|
||||||
70, 66, 65, 56, 52, 67, 70, 67,
|
|
||||||
56, 67, 48, 55, 50, 55, 65, 51,
|
|
||||||
51, 56, 70, 70, 65, 66, 50, 51,
|
|
||||||
55, 57, 67, 68, 49, 65, 70, 67,
|
|
||||||
51, 53, 65, 54, 57, 70, 52, 51,
|
|
||||||
54, 52, 52, 54, 56, 67, 52, 70,
|
|
||||||
50, 70, 49, 65, 56, 65, 68, 49])
|
|
||||||
|
|
||||||
func testLowercaseString() {
|
|
||||||
XCTAssertEqual(testData.base16EncodedString(), testDataLowercaseString)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testUppercaseString() {
|
|
||||||
XCTAssertEqual(testData.base16EncodedString(options: [.uppercase]),
|
|
||||||
testDataUppercaseString)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testLowercaseData() {
|
|
||||||
XCTAssertEqual(testData.base16EncodedData(), testDataLowercaseStringData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testUppercaseData() {
|
|
||||||
XCTAssertEqual(testData.base16EncodedData(options: [.uppercase]),
|
|
||||||
testDataUppercaseStringData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInitializationFromLowercaseString() throws {
|
|
||||||
XCTAssertEqual(try Data(base16Encoded: testDataLowercaseString), testData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInitializationFromUppercaseString() throws {
|
|
||||||
XCTAssertEqual(try Data(base16Encoded: testDataUppercaseString), testData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInitializationFromLowercaseData() throws {
|
|
||||||
XCTAssertEqual(try Data(base16Encoded: testDataLowercaseStringData), testData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInitializationFromUppercaseData() throws {
|
|
||||||
XCTAssertEqual(try Data(base16Encoded: testDataUppercaseStringData), testData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInvalidLength() throws {
|
|
||||||
let invalidLength = String(testDataLowercaseString.prefix(testDataLowercaseString.count - 1))
|
|
||||||
|
|
||||||
XCTAssertThrowsError(try Data(base16Encoded: invalidLength)) {
|
|
||||||
guard case Base16EncodingError.invalidLength = $0 else {
|
|
||||||
XCTFail("Expected invalid length error")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInvalidByteString() {
|
|
||||||
let invalidString = testDataLowercaseString.replacingOccurrences(of: "a", with: "z")
|
|
||||||
|
|
||||||
XCTAssertThrowsError(try Data(base16Encoded: invalidString)) {
|
|
||||||
guard case let Base16EncodingError.invalidByteString(invalidByteString) = $0 else {
|
|
||||||
XCTFail("Expected invalid byte string error")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
XCTAssertEqual(invalidByteString, "zd")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInvalidStringEncoding() {
|
|
||||||
let invalidData = testDataLowercaseString.data(using: .utf16)!
|
|
||||||
|
|
||||||
XCTAssertThrowsError(try Data(base16Encoded: invalidData)) {
|
|
||||||
guard case Base16EncodingError.invalidStringEncoding = $0 else {
|
|
||||||
XCTFail("Expected string encoding error")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -350,7 +350,6 @@
|
||||||
D09D972125C65682007E6394 /* SeparatorConfiguredCollectionViewListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorConfiguredCollectionViewListCell.swift; sourceTree = "<group>"; };
|
D09D972125C65682007E6394 /* SeparatorConfiguredCollectionViewListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorConfiguredCollectionViewListCell.swift; sourceTree = "<group>"; };
|
||||||
D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewDataSource.swift; sourceTree = "<group>"; };
|
D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewDataSource.swift; sourceTree = "<group>"; };
|
||||||
D0A7AC7225748BFF00E4E8AB /* ReportStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusView.swift; sourceTree = "<group>"; };
|
D0A7AC7225748BFF00E4E8AB /* ReportStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusView.swift; sourceTree = "<group>"; };
|
||||||
D0AD03552505814D0085A466 /* Base16 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Base16; sourceTree = "<group>"; };
|
|
||||||
D0B32F4F250B373600311912 /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; };
|
D0B32F4F250B373600311912 /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; };
|
||||||
D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileCollection+Extensions.swift"; sourceTree = "<group>"; };
|
D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileCollection+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0B8510B25259E56004E0744 /* LoadMoreTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreTableViewCell.swift; sourceTree = "<group>"; };
|
D0B8510B25259E56004E0744 /* LoadMoreTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
|
@ -635,7 +634,6 @@
|
||||||
children = (
|
children = (
|
||||||
D0477F2A25C6EB90005C5368 /* Activities */,
|
D0477F2A25C6EB90005C5368 /* Activities */,
|
||||||
D0C7D45224F76169001EBDBB /* Assets.xcassets */,
|
D0C7D45224F76169001EBDBB /* Assets.xcassets */,
|
||||||
D0AD03552505814D0085A466 /* Base16 */,
|
|
||||||
D0FE1C9625368A15003EF1EB /* Caches */,
|
D0FE1C9625368A15003EF1EB /* Caches */,
|
||||||
D0D7C013250440610039AD6F /* CodableBloomFilter */,
|
D0D7C013250440610039AD6F /* CodableBloomFilter */,
|
||||||
D0A1F4F5252E7D2A004435BF /* Data Sources */,
|
D0A1F4F5252E7D2A004435BF /* Data Sources */,
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
{
|
{
|
||||||
"object": {
|
"object": {
|
||||||
"pins": [
|
"pins": [
|
||||||
|
{
|
||||||
|
"package": "Base16",
|
||||||
|
"repositoryURL": "https://github.com/metabolist/base16.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "913e1e7ef4a79c5f64e550a40d9a032ad173a21f",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "CombineExpectations",
|
"package": "CombineExpectations",
|
||||||
"repositoryURL": "https://github.com/groue/CombineExpectations.git",
|
"repositoryURL": "https://github.com/groue/CombineExpectations.git",
|
||||||
|
|
|
@ -14,8 +14,8 @@ let package = Package(
|
||||||
targets: ["Secrets"])
|
targets: ["Secrets"])
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(path: "Base16"),
|
.package(path: "Keychain"),
|
||||||
.package(path: "Keychain")
|
.package(name: "Base16", url: "https://github.com/metabolist/base16.git", .upToNextMajor(from: "1.0.0"))
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
|
|
Loading…
Reference in New Issue