DataRaft swift package
This commit is contained in:
194
Tests/DataRaftTests/Classes/DatabaseServiceTests.swift
Normal file
194
Tests/DataRaftTests/Classes/DatabaseServiceTests.swift
Normal file
@@ -0,0 +1,194 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
import DataLiteC
|
||||
import DataLiteCore
|
||||
import DataRaft
|
||||
|
||||
class DatabaseServiceTests: DatabaseServiceKeyProvider {
|
||||
private let keyOne = Connection.Key.rawKey(Data([
|
||||
0xe8, 0xd7, 0x92, 0xa2, 0xa1, 0x35, 0x56, 0xc0,
|
||||
0xfd, 0xbb, 0x2f, 0x91, 0xe8, 0x0b, 0x4b, 0x2a,
|
||||
0xa2, 0xd7, 0x78, 0xe9, 0xe5, 0x87, 0x05, 0xb4,
|
||||
0xe2, 0x1a, 0x42, 0x74, 0xee, 0xbc, 0x4c, 0x06
|
||||
]))
|
||||
|
||||
private let keyTwo = Connection.Key.rawKey(Data([
|
||||
0x9f, 0x45, 0x23, 0xbf, 0xfe, 0x11, 0x3e, 0x79,
|
||||
0x42, 0x21, 0x48, 0x7c, 0xb6, 0xb1, 0xd5, 0x09,
|
||||
0x34, 0x5f, 0xcb, 0x53, 0xa3, 0xdd, 0x8e, 0x41,
|
||||
0x95, 0x27, 0xbb, 0x4e, 0x6e, 0xd8, 0xa7, 0x05
|
||||
]))
|
||||
|
||||
private let fileURL: URL
|
||||
private let service: DatabaseService
|
||||
|
||||
private lazy var currentKey = keyOne
|
||||
|
||||
init() throws {
|
||||
let fileURL = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathExtension("sqlite")
|
||||
|
||||
let service = try DatabaseService(provider: {
|
||||
try Connection(
|
||||
path: fileURL.path,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
})
|
||||
|
||||
self.fileURL = fileURL
|
||||
self.service = service
|
||||
self.service.keyProvider = self
|
||||
|
||||
try self.service.perform { connection in
|
||||
try connection.execute(sql: """
|
||||
CREATE TABLE IF NOT EXISTS Item (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
try? FileManager.default.removeItem(at: fileURL)
|
||||
}
|
||||
|
||||
func databaseServiceKey(_ service: DatabaseService) throws -> Connection.Key {
|
||||
currentKey
|
||||
}
|
||||
}
|
||||
|
||||
extension DatabaseServiceTests {
|
||||
@Test func testSuccessPerformTransaction() throws {
|
||||
try service.perform(in: .deferred) { connection in
|
||||
#expect(connection.isAutocommit == false)
|
||||
let stmt = try connection.prepare(
|
||||
sql: "INSERT INTO Item (name) VALUES (?)",
|
||||
options: []
|
||||
)
|
||||
try stmt.bind("Book", at: 1)
|
||||
try stmt.step()
|
||||
}
|
||||
try service.perform { connection in
|
||||
let stmt = try connection.prepare(
|
||||
sql: "SELECT COUNT(*) FROM Item",
|
||||
options: []
|
||||
)
|
||||
try stmt.step()
|
||||
#expect(connection.isAutocommit)
|
||||
#expect(stmt.columnValue(at: 0) == 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testNestedPerformTransaction() throws {
|
||||
try service.perform(in: .deferred) { _ in
|
||||
try service.perform(in: .deferred) { connection in
|
||||
#expect(connection.isAutocommit == false)
|
||||
let stmt = try connection.prepare(
|
||||
sql: "INSERT INTO Item (name) VALUES (?)",
|
||||
options: []
|
||||
)
|
||||
try stmt.bind("Book", at: 1)
|
||||
try stmt.step()
|
||||
}
|
||||
}
|
||||
try service.perform { connection in
|
||||
let stmt = try connection.prepare(
|
||||
sql: "SELECT COUNT(*) FROM Item",
|
||||
options: []
|
||||
)
|
||||
try stmt.step()
|
||||
#expect(connection.isAutocommit)
|
||||
#expect(stmt.columnValue(at: 0) == 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testRollbackPerformTransaction() throws {
|
||||
struct DummyError: Error, Equatable {}
|
||||
#expect(throws: DummyError(), performing: {
|
||||
try self.service.perform(in: .deferred) { connection in
|
||||
#expect(connection.isAutocommit == false)
|
||||
let stmt = try connection.prepare(
|
||||
sql: "INSERT INTO Item (name) VALUES (?)",
|
||||
options: []
|
||||
)
|
||||
try stmt.bind("Book", at: 1)
|
||||
try stmt.step()
|
||||
throw DummyError()
|
||||
}
|
||||
})
|
||||
try service.perform { connection in
|
||||
let stmt = try connection.prepare(
|
||||
sql: "SELECT COUNT(*) FROM Item",
|
||||
options: []
|
||||
)
|
||||
try stmt.step()
|
||||
#expect(connection.isAutocommit)
|
||||
#expect(stmt.columnValue(at: 0) == 0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testSuccessReconnectPerformTransaction() throws {
|
||||
let connection = try Connection(
|
||||
path: fileURL.path,
|
||||
options: [.readwrite]
|
||||
)
|
||||
try connection.apply(currentKey)
|
||||
try connection.rekey(keyTwo)
|
||||
currentKey = keyTwo
|
||||
|
||||
try service.perform(in: .deferred) { connection in
|
||||
#expect(connection.isAutocommit == false)
|
||||
let stmt = try connection.prepare(
|
||||
sql: "INSERT INTO Item (name) VALUES (?)",
|
||||
options: []
|
||||
)
|
||||
try stmt.bind("Book", at: 1)
|
||||
try stmt.step()
|
||||
}
|
||||
try service.perform { connection in
|
||||
let stmt = try connection.prepare(
|
||||
sql: "SELECT COUNT(*) FROM Item",
|
||||
options: []
|
||||
)
|
||||
try stmt.step()
|
||||
#expect(stmt.columnValue(at: 0) == 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testFailReconnectPerformTransaction() throws {
|
||||
let connection = try Connection(
|
||||
path: fileURL.path,
|
||||
options: [.readwrite]
|
||||
)
|
||||
try connection.apply(currentKey)
|
||||
try connection.rekey(keyTwo)
|
||||
let error = Connection.Error(
|
||||
code: SQLITE_NOTADB,
|
||||
message: "file is not a database"
|
||||
)
|
||||
#expect(throws: error, performing: {
|
||||
try self.service.perform(in: .deferred) { connection in
|
||||
#expect(connection.isAutocommit == false)
|
||||
let stmt = try connection.prepare(
|
||||
sql: "INSERT INTO Item (name) VALUES (?)",
|
||||
options: []
|
||||
)
|
||||
try stmt.bind("Book", at: 1)
|
||||
try stmt.step()
|
||||
}
|
||||
})
|
||||
currentKey = keyTwo
|
||||
try service.reconnect()
|
||||
try service.perform { connection in
|
||||
let stmt = try connection.prepare(
|
||||
sql: "SELECT COUNT(*) FROM Item",
|
||||
options: []
|
||||
)
|
||||
try stmt.step()
|
||||
#expect(connection.isAutocommit)
|
||||
#expect(stmt.columnValue(at: 0) == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
101
Tests/DataRaftTests/Classes/MigrationServiceTests.swift
Normal file
101
Tests/DataRaftTests/Classes/MigrationServiceTests.swift
Normal file
@@ -0,0 +1,101 @@
|
||||
import Testing
|
||||
import DataLiteCore
|
||||
@testable import DataRaft
|
||||
|
||||
@Suite struct MigrationServiceTests {
|
||||
private typealias MigrationService = DataRaft.MigrationService<DatabaseService, VersionStorage>
|
||||
|
||||
private var connection: Connection!
|
||||
private var migrationService: MigrationService!
|
||||
|
||||
init() throws {
|
||||
let connection = try Connection(location: .inMemory, options: .readwrite)
|
||||
self.connection = connection
|
||||
self.migrationService = .init(service: .init(connection: connection), storage: .init())
|
||||
}
|
||||
|
||||
@Test func addMigration() throws {
|
||||
let migration1 = Migration<Int32>(version: 1, byResource: "migration_1", extension: "sql", in: .module)!
|
||||
let migration2 = Migration<Int32>(version: 2, byResource: "migration_2", extension: "sql", in: .module)!
|
||||
let migration3 = Migration<Int32>(version: 3, byResource: "migration_2", extension: "sql", in: .module)!
|
||||
|
||||
#expect(try migrationService.add(migration1) == ())
|
||||
#expect(try migrationService.add(migration2) == ())
|
||||
|
||||
do {
|
||||
try migrationService.add(migration3)
|
||||
Issue.record("Expected duplicateMigration error for version \(migration3.version)")
|
||||
} catch MigrationService.Error.duplicateMigration(let migration) {
|
||||
#expect(migration == migration3)
|
||||
} catch {
|
||||
Issue.record("Unexpected error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test func migrate() throws {
|
||||
let migration1 = Migration<Int32>(version: 1, byResource: "migration_1", extension: "sql", in: .module)!
|
||||
let migration2 = Migration<Int32>(version: 2, byResource: "migration_2", extension: "sql", in: .module)!
|
||||
|
||||
try migrationService.add(migration1)
|
||||
try migrationService.add(migration2)
|
||||
try migrationService.migrate()
|
||||
|
||||
#expect(connection.userVersion == 2)
|
||||
}
|
||||
|
||||
@Test func migrateWithError() throws {
|
||||
let migration1 = Migration<Int32>(version: 1, byResource: "migration_1", extension: "sql", in: .module)!
|
||||
let migration2 = Migration<Int32>(version: 2, byResource: "migration_2", extension: "sql", in: .module)!
|
||||
let migration3 = Migration<Int32>(version: 3, byResource: "migration_3", extension: "sql", in: .module)!
|
||||
|
||||
try migrationService.add(migration1)
|
||||
try migrationService.add(migration2)
|
||||
try migrationService.add(migration3)
|
||||
|
||||
do {
|
||||
try migrationService.migrate()
|
||||
Issue.record("Expected migrationFailed error for version \(migration3.version)")
|
||||
} catch MigrationService.Error.migrationFailed(let migration, _) {
|
||||
#expect(migration == migration3)
|
||||
} catch {
|
||||
Issue.record("Unexpected error: \(error)")
|
||||
}
|
||||
|
||||
#expect(connection.userVersion == 0)
|
||||
}
|
||||
|
||||
@Test func migrateWithEmptyMigration() throws {
|
||||
let migration1 = Migration<Int32>(version: 1, byResource: "migration_1", extension: "sql", in: .module)!
|
||||
let migration2 = Migration<Int32>(version: 2, byResource: "migration_2", extension: "sql", in: .module)!
|
||||
let migration4 = Migration<Int32>(version: 4, byResource: "migration_4", extension: "sql", in: .module)!
|
||||
|
||||
try migrationService.add(migration1)
|
||||
try migrationService.add(migration2)
|
||||
try migrationService.add(migration4)
|
||||
|
||||
do {
|
||||
try migrationService.migrate()
|
||||
Issue.record("Expected migrationFailed error for version \(migration4.version)")
|
||||
} catch MigrationService.Error.emptyMigrationScript(let migration) {
|
||||
#expect(migration == migration4)
|
||||
} catch {
|
||||
Issue.record("Unexpected error: \(error)")
|
||||
}
|
||||
|
||||
#expect(connection.userVersion == 0)
|
||||
}
|
||||
}
|
||||
|
||||
private extension MigrationServiceTests {
|
||||
struct VersionStorage: DataRaft.VersionStorage {
|
||||
typealias Version = Int32
|
||||
|
||||
func getVersion(_ connection: Connection) throws -> Version {
|
||||
connection.userVersion
|
||||
}
|
||||
|
||||
func setVersion(_ connection: Connection, _ version: Version) throws {
|
||||
connection.userVersion = version
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Tests/DataRaftTests/Classes/UserVersionStorage.swift
Normal file
64
Tests/DataRaftTests/Classes/UserVersionStorage.swift
Normal file
@@ -0,0 +1,64 @@
|
||||
import Testing
|
||||
import DataLiteCore
|
||||
@testable import DataRaft
|
||||
|
||||
@Suite struct UserVersionStorageTests {
|
||||
private var connection: Connection!
|
||||
|
||||
init() throws {
|
||||
connection = try .init(location: .inMemory, options: .readwrite)
|
||||
}
|
||||
|
||||
@Test func getVersion() throws {
|
||||
connection.userVersion = 123
|
||||
let storage = UserVersionStorage<Version>()
|
||||
let version = try storage.getVersion(connection)
|
||||
#expect(version == Version(rawValue: 123))
|
||||
}
|
||||
|
||||
@Test func getVersionWithError() {
|
||||
connection.userVersion = 123
|
||||
let storage = UserVersionStorage<NilVersion>()
|
||||
do {
|
||||
_ = try storage.getVersion(connection)
|
||||
Issue.record("Expected failure for invalid stored version")
|
||||
} catch UserVersionStorage<NilVersion>.Error.invalidStoredVersion(let version) {
|
||||
#expect(version == UInt32(bitPattern: connection.userVersion))
|
||||
} catch {
|
||||
Issue.record("Unexpected error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test func setVersion() throws {
|
||||
let storage = UserVersionStorage<Version>()
|
||||
let version = Version(rawValue: 456)
|
||||
try storage.setVersion(connection, version)
|
||||
#expect(connection.userVersion == 456)
|
||||
}
|
||||
}
|
||||
|
||||
private extension UserVersionStorageTests {
|
||||
struct Version: RawRepresentable, VersionRepresentable, Equatable {
|
||||
let rawValue: UInt32
|
||||
|
||||
init(rawValue: UInt32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.rawValue < rhs.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
struct NilVersion: RawRepresentable, VersionRepresentable {
|
||||
let rawValue: UInt32
|
||||
|
||||
init?(rawValue: UInt32) {
|
||||
return nil
|
||||
}
|
||||
|
||||
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.rawValue < rhs.rawValue
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Tests/DataRaftTests/Resources/migration_1.sql
Normal file
12
Tests/DataRaftTests/Resources/migration_1.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- Create table User
|
||||
CREATE TABLE User (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Insert values into User
|
||||
INSERT INTO User (id, name, email)
|
||||
VALUES
|
||||
(1, 'john_doe', 'john@example.com'), -- Inserting John Doe
|
||||
(2, 'jane_doe', 'jane@example.com'); -- Inserting Jane Doe
|
||||
11
Tests/DataRaftTests/Resources/migration_2.sql
Normal file
11
Tests/DataRaftTests/Resources/migration_2.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Create table Device
|
||||
CREATE TABLE Device (
|
||||
id INTEGER PRIMARY KEY,
|
||||
model TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Insert values into Device
|
||||
INSERT INTO Device (id, model)
|
||||
VALUES
|
||||
(1, 'iPhone 14'), -- Inserting iPhone 14
|
||||
(2, 'iPhone 15'); -- Inserting iPhone 15
|
||||
2
Tests/DataRaftTests/Resources/migration_3.sql
Normal file
2
Tests/DataRaftTests/Resources/migration_3.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- Wrong sql statement
|
||||
WRONG SQL STATEMENT;
|
||||
1
Tests/DataRaftTests/Resources/migration_4.sql
Normal file
1
Tests/DataRaftTests/Resources/migration_4.sql
Normal file
@@ -0,0 +1 @@
|
||||
-- Empty Script
|
||||
182
Tests/DataRaftTests/Structures/BitPackVersionTests.swift
Normal file
182
Tests/DataRaftTests/Structures/BitPackVersionTests.swift
Normal file
@@ -0,0 +1,182 @@
|
||||
import Testing
|
||||
import DataRaft
|
||||
|
||||
@Suite struct BitPackVersionTests {
|
||||
@Test(arguments: [
|
||||
(0, 0, 0, 0, "0.0.0"),
|
||||
(0, 0, 1, 1, "0.0.1"),
|
||||
(0, 1, 0, 256, "0.1.0"),
|
||||
(1, 0, 0, 1048576, "1.0.0"),
|
||||
(15, 15, 15, 15732495, "15.15.15"),
|
||||
(123, 456, 78, 129091662, "123.456.78"),
|
||||
(255, 255, 255, 267452415, "255.255.255"),
|
||||
(4095, 4095, 255, 4294967295, "4095.4095.255")
|
||||
])
|
||||
func versionComponents(
|
||||
_ major: UInt32,
|
||||
_ minor: UInt32,
|
||||
_ patch: UInt32,
|
||||
_ rawValue: UInt32,
|
||||
_ description: String
|
||||
) throws {
|
||||
let version = try BitPackVersion(
|
||||
major: major,
|
||||
minor: minor,
|
||||
patch: patch
|
||||
)
|
||||
|
||||
#expect(version.major == major)
|
||||
#expect(version.minor == minor)
|
||||
#expect(version.patch == patch)
|
||||
#expect(version.rawValue == rawValue)
|
||||
#expect(version.description == description)
|
||||
}
|
||||
|
||||
@Test func majorOverflow() {
|
||||
do {
|
||||
_ = try BitPackVersion(major: 4096, minor: 0)
|
||||
Issue.record("Expected BitPackVersion.Error.majorOverflow, but succeeded")
|
||||
} catch BitPackVersion.Error.majorOverflow(let value) {
|
||||
let error = BitPackVersion.Error.majorOverflow(value)
|
||||
let description = "Major version overflow: \(value). Allowed range: 0...4095."
|
||||
#expect(value == 4096)
|
||||
#expect(error.localizedDescription == description)
|
||||
} catch {
|
||||
Issue.record("Unexpected error type: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test func minorOverflow() {
|
||||
do {
|
||||
_ = try BitPackVersion(major: 0, minor: 4096)
|
||||
Issue.record("Expected BitPackVersion.Error.minorOverflow, but succeeded")
|
||||
} catch BitPackVersion.Error.minorOverflow(let value) {
|
||||
let error = BitPackVersion.Error.minorOverflow(value)
|
||||
let description = "Minor version overflow: \(value). Allowed range: 0...4095."
|
||||
#expect(value == 4096)
|
||||
#expect(error.localizedDescription == description)
|
||||
} catch {
|
||||
Issue.record("Unexpected error type: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test func patchOverflow() {
|
||||
do {
|
||||
_ = try BitPackVersion(major: 0, minor: 0, patch: 256)
|
||||
Issue.record("Expected BitPackVersion.Error.patchOverflow, but succeeded")
|
||||
} catch BitPackVersion.Error.patchOverflow(let value) {
|
||||
let error = BitPackVersion.Error.patchOverflow(value)
|
||||
let description = "Patch version overflow: \(value). Allowed range: 0...255."
|
||||
#expect(value == 256)
|
||||
#expect(error.localizedDescription == description)
|
||||
} catch {
|
||||
Issue.record("Unexpected error type: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test(arguments: try [
|
||||
(
|
||||
BitPackVersion(major: 0, minor: 0, patch: 0),
|
||||
BitPackVersion(major: 0, minor: 0, patch: 1)
|
||||
),
|
||||
(
|
||||
BitPackVersion(major: 0, minor: 1, patch: 0),
|
||||
BitPackVersion(major: 1, minor: 0, patch: 0)
|
||||
),
|
||||
(
|
||||
BitPackVersion(major: 1, minor: 1, patch: 1),
|
||||
BitPackVersion(major: 1, minor: 1, patch: 2)
|
||||
),
|
||||
(
|
||||
BitPackVersion(major: 5, minor: 0, patch: 255),
|
||||
BitPackVersion(major: 5, minor: 1, patch: 0)
|
||||
),
|
||||
(
|
||||
BitPackVersion(major: 10, minor: 100, patch: 100),
|
||||
BitPackVersion(major: 11, minor: 0, patch: 0)
|
||||
),
|
||||
(
|
||||
BitPackVersion(major: 4094, minor: 4095, patch: 255),
|
||||
BitPackVersion(major: 4095, minor: 0, patch: 0)
|
||||
)
|
||||
])
|
||||
func compare(
|
||||
_ versionOne: BitPackVersion,
|
||||
_ versionTwo: BitPackVersion
|
||||
) throws {
|
||||
#expect(versionOne < versionTwo)
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
@available(macOS 13.0, *)
|
||||
@Test(arguments: [
|
||||
("0.0.0", 0, 0, 0, 0, "0.0.0"),
|
||||
("0.0.1", 0, 0, 1, 1, "0.0.1"),
|
||||
("0.1.0", 0, 1, 0, 256, "0.1.0"),
|
||||
("1.0.0", 1, 0, 0, 1048576, "1.0.0"),
|
||||
("1.2.3", 1, 2, 3, 1049091, "1.2.3"),
|
||||
("123.456.78", 123, 456, 78, 129091662, "123.456.78"),
|
||||
("4095.4095.255", 4095, 4095, 255, 4294967295, "4095.4095.255"),
|
||||
("10.20", 10, 20, 0, 10490880, "10.20.0"),
|
||||
("42.0.13", 42, 0, 13, 44040205, "42.0.13")
|
||||
])
|
||||
func fromString(
|
||||
_ string: String,
|
||||
_ major: UInt32,
|
||||
_ minor: UInt32,
|
||||
_ patch: UInt32,
|
||||
_ rawValue: UInt32,
|
||||
_ description: String
|
||||
) throws {
|
||||
let version = try BitPackVersion(version: string)
|
||||
|
||||
#expect(version.major == major)
|
||||
#expect(version.minor == minor)
|
||||
#expect(version.patch == patch)
|
||||
#expect(version.rawValue == rawValue)
|
||||
#expect(version.description == description)
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
@available(macOS 13.0, *)
|
||||
@Test(arguments: [
|
||||
"",
|
||||
"1",
|
||||
"1.",
|
||||
".1",
|
||||
"1.2.3.4",
|
||||
"1.2.",
|
||||
"1..2",
|
||||
"a.b.c",
|
||||
"1.2.c",
|
||||
"01.2.3",
|
||||
"1.02.3",
|
||||
"1.2.03",
|
||||
" 1.2.3",
|
||||
"1.2.3 ",
|
||||
" 1.2 ",
|
||||
"1,2,3",
|
||||
])
|
||||
func fromInvalidStrings(_ input: String) {
|
||||
do {
|
||||
_ = try BitPackVersion(version: input)
|
||||
Issue.record("Expected failure for: \(input)")
|
||||
} catch BitPackVersion.ParseError.invalidFormat(let str) {
|
||||
let error = BitPackVersion.ParseError.invalidFormat(str)
|
||||
let description = "Invalid version format: \(str). Expected something like '1.2' or '1.2.3'."
|
||||
#expect(str == input)
|
||||
#expect(error.localizedDescription == description)
|
||||
} catch {
|
||||
Issue.record("Unexpected error for: \(input) — \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
@available(macOS 13.0, *)
|
||||
@Test func stringLiteralInit() {
|
||||
let version: BitPackVersion = "1.2.3"
|
||||
#expect(version.major == 1)
|
||||
#expect(version.minor == 2)
|
||||
#expect(version.patch == 3)
|
||||
}
|
||||
}
|
||||
69
Tests/DataRaftTests/Structures/MigrationTests.swift
Normal file
69
Tests/DataRaftTests/Structures/MigrationTests.swift
Normal file
@@ -0,0 +1,69 @@
|
||||
import Testing
|
||||
import Foundation
|
||||
|
||||
@testable import DataRaft
|
||||
|
||||
@Suite struct MigrationTests {
|
||||
@Test func initWithURL() {
|
||||
let version = DummyVersion(rawValue: 1)
|
||||
let url = URL(fileURLWithPath: "/tmp/migration.sql")
|
||||
let migration = Migration(version: version, scriptURL: url)
|
||||
|
||||
#expect(migration.version == version)
|
||||
#expect(migration.scriptURL == url)
|
||||
}
|
||||
|
||||
@Test func initFromBundle_success() throws {
|
||||
let bundle = Bundle.module // или другой, если тестовая ресурсная цель другая
|
||||
let version = DummyVersion(rawValue: 2)
|
||||
|
||||
let migration = Migration(
|
||||
version: version,
|
||||
byResource: "migration_1",
|
||||
extension: "sql",
|
||||
in: bundle
|
||||
)
|
||||
|
||||
#expect(migration != nil)
|
||||
#expect(migration?.version == version)
|
||||
#expect(migration?.scriptURL.lastPathComponent == "migration_1.sql")
|
||||
}
|
||||
|
||||
@Test func initFromBundle_failure() {
|
||||
let version = DummyVersion(rawValue: 3)
|
||||
|
||||
let migration = Migration(
|
||||
version: version,
|
||||
byResource: "NonexistentFile",
|
||||
extension: "sql",
|
||||
in: .main
|
||||
)
|
||||
|
||||
#expect(migration == nil)
|
||||
}
|
||||
|
||||
@Test func hashableEquatable() {
|
||||
let version = DummyVersion(rawValue: 5)
|
||||
let url = URL(fileURLWithPath: "/tmp/migration.sql")
|
||||
|
||||
let migration1 = Migration(version: version, scriptURL: url)
|
||||
let migration2 = Migration(version: version, scriptURL: url)
|
||||
|
||||
#expect(migration1 == migration2)
|
||||
#expect(migration1.hashValue == migration2.hashValue)
|
||||
}
|
||||
}
|
||||
|
||||
private extension MigrationTests {
|
||||
struct DummyVersion: VersionRepresentable {
|
||||
let rawValue: UInt32
|
||||
|
||||
init(rawValue: UInt32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
static func < (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.rawValue < rhs.rawValue
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user