Skip to content

Commit 278f068

Browse files
committed
Add tests for Connection.Location, URIQueryParameter, and TypeAffinity
1 parent 6e68248 commit 278f068

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//
2+
// LocationAndAffinityTests.swift
3+
// SQLite
4+
//
5+
// Created by Alsey Coleman Miller on 7/17/26.
6+
//
7+
8+
import Foundation
9+
import Testing
10+
@testable import SQLite
11+
12+
@Suite struct LocationAndAffinityTests {
13+
14+
// MARK: - Connection.Location
15+
16+
@Test func locationDescriptions() {
17+
#expect(Connection.Location.inMemory.description == ":memory:")
18+
#expect(Connection.Location.temporary.description == "")
19+
#expect(Connection.Location.uri("/tmp/db.sqlite").description == "/tmp/db.sqlite")
20+
#expect(Connection.Location.uri("/tmp/db.sqlite", parameters: []).description == "/tmp/db.sqlite")
21+
}
22+
23+
@Test func locationURIWithParameters() {
24+
let description = Connection.Location.uri(
25+
"/tmp/db.sqlite",
26+
parameters: [.mode(.readOnly), .cache(.shared)]
27+
).description
28+
// a scheme-less URI gains the file: scheme when parameters are appended
29+
#expect(description.hasPrefix("file:"))
30+
#expect(description.contains("mode=ro"))
31+
#expect(description.contains("cache=shared"))
32+
// existing query items are preserved
33+
let merged = Connection.Location.uri(
34+
"file:/tmp/db.sqlite?foo=1",
35+
parameters: [.immutable(true)]
36+
).description
37+
#expect(merged.contains("foo=1"))
38+
#expect(merged.contains("immutable=1"))
39+
}
40+
41+
@Test func locationEquality() {
42+
#expect(Connection.Location.inMemory == .inMemory)
43+
#expect(Connection.Location.inMemory != .temporary)
44+
#expect(Connection.Location.uri("/a") == .uri("/a", parameters: []))
45+
let locations: Set<Connection.Location> = [.inMemory, .temporary, .uri("/a"), .uri("/a")]
46+
#expect(locations.count == 3)
47+
}
48+
49+
@Test func openInMemoryLocation() throws {
50+
let connection = try Connection(path: .inMemory)
51+
try connection.run("CREATE TABLE t (value INTEGER)")
52+
try connection.run("INSERT INTO t (value) VALUES (?)", [42.binding])
53+
#expect(try connection.scalar("SELECT value FROM t")?.integer == 42)
54+
}
55+
56+
@Test func openTemporaryLocation() throws {
57+
let connection = try Connection(path: .temporary)
58+
try connection.run("CREATE TABLE t (value INTEGER)")
59+
#expect(try connection.scalar("SELECT COUNT(*) FROM t")?.integer == 0)
60+
}
61+
62+
// MARK: - URIQueryParameter
63+
64+
@Test func uriQueryParameterItems() {
65+
#expect(URIQueryParameter.cache(.shared).queryItem == URLQueryItem(name: "cache", value: "shared"))
66+
#expect(URIQueryParameter.cache(.private).queryItem == URLQueryItem(name: "cache", value: "private"))
67+
#expect(URIQueryParameter.immutable(true).queryItem == URLQueryItem(name: "immutable", value: "1"))
68+
#expect(URIQueryParameter.immutable(false).queryItem == URLQueryItem(name: "immutable", value: "0"))
69+
#expect(URIQueryParameter.modeOf("/tmp/base.sqlite").queryItem == URLQueryItem(name: "modeOf", value: "/tmp/base.sqlite"))
70+
#expect(URIQueryParameter.mode(.memory).queryItem == URLQueryItem(name: "mode", value: "memory"))
71+
#expect(URIQueryParameter.nolock(true).queryItem == URLQueryItem(name: "nolock", value: "1"))
72+
#expect(URIQueryParameter.nolock(false).queryItem == URLQueryItem(name: "nolock", value: "0"))
73+
#expect(URIQueryParameter.powersafeOverwrite(true).queryItem == URLQueryItem(name: "psow", value: "1"))
74+
#expect(URIQueryParameter.powersafeOverwrite(false).queryItem == URLQueryItem(name: "psow", value: "0"))
75+
#expect(URIQueryParameter.vfs("unix-none").queryItem == URLQueryItem(name: "vfs", value: "unix-none"))
76+
}
77+
78+
@Test func uriQueryParameterDescription() {
79+
#expect(URIQueryParameter.mode(.readWriteCreate).description == URLQueryItem(name: "mode", value: "rwc").description)
80+
}
81+
82+
@Test func fileModeRawValues() {
83+
#expect(URIQueryParameter.FileMode.readOnly.rawValue == "ro")
84+
#expect(URIQueryParameter.FileMode.readWrite.rawValue == "rw")
85+
#expect(URIQueryParameter.FileMode.readWriteCreate.rawValue == "rwc")
86+
#expect(URIQueryParameter.FileMode.memory.rawValue == "memory")
87+
#expect(URIQueryParameter.FileMode.allCases.count == 4)
88+
#expect(URIQueryParameter.CacheMode.allCases.map(\.rawValue) == ["shared", "private"])
89+
}
90+
91+
// MARK: - TypeAffinity
92+
93+
@Test func typeAffinityFromDeclaredType() throws {
94+
guard #available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) else { return }
95+
// Rule 1: INT anywhere in the declared type
96+
#expect(TypeAffinity("INTEGER") == .integer)
97+
#expect(TypeAffinity("TINYINT") == .integer)
98+
#expect(TypeAffinity("int") == .integer)
99+
// rule order: CHARINT matches rules 1 and 2, rule 1 wins
100+
#expect(TypeAffinity("CHARINT") == .integer)
101+
// Rule 2: CHAR, CLOB, or TEXT
102+
#expect(TypeAffinity("VARCHAR(255)") == .text)
103+
#expect(TypeAffinity("CLOB") == .text)
104+
#expect(TypeAffinity("text") == .text)
105+
// Rule 3: BLOB
106+
#expect(TypeAffinity("BLOB") == .blob)
107+
// Rule 4: REAL, FLOA, or DOUB
108+
#expect(TypeAffinity("REAL") == .real)
109+
#expect(TypeAffinity("FLOAT") == .real)
110+
#expect(TypeAffinity("DOUBLE PRECISION") == .real)
111+
// Rule 5: everything else
112+
#expect(TypeAffinity("DECIMAL(10,5)") == .numeric)
113+
#expect(TypeAffinity("DATETIME") == .numeric)
114+
#expect(TypeAffinity("") == .numeric)
115+
}
116+
117+
@Test func typeAffinityRules() {
118+
#expect(TypeAffinity.integer.rule == 1)
119+
#expect(TypeAffinity.text.rule == 2)
120+
#expect(TypeAffinity.blob.rule == 3)
121+
#expect(TypeAffinity.real.rule == 4)
122+
#expect(TypeAffinity.numeric.rule == 5)
123+
}
124+
125+
@Test func typeAffinityDescription() {
126+
for affinity in TypeAffinity.allCases {
127+
#expect(affinity.description == affinity.rawValue)
128+
}
129+
}
130+
}

0 commit comments

Comments
 (0)