Files
sqlite3/conn_test.go

343 lines
6.3 KiB
Go
Raw Permalink Normal View History

2023-01-26 11:12:00 +00:00
package sqlite3
import (
"bytes"
2023-02-16 13:58:53 +00:00
"context"
2023-02-10 16:42:49 +00:00
"errors"
2023-01-26 11:12:00 +00:00
"math"
"testing"
)
2023-02-10 16:42:49 +00:00
func TestConn_Close(t *testing.T) {
var conn *Conn
conn.Close()
}
func TestConn_Close_BUSY(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-02-10 16:42:49 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
2023-02-14 18:21:18 +00:00
stmt, _, err := db.Prepare(`BEGIN`)
2023-02-10 16:42:49 +00:00
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
err = db.Close()
if err == nil {
t.Fatal("want error")
}
var serr *Error
if !errors.As(err, &serr) {
t.Fatalf("got %T, want sqlite3.Error", err)
}
if rc := serr.Code(); rc != BUSY {
t.Errorf("got %d, want sqlite3.BUSY", rc)
}
if got := err.Error(); got != `sqlite3: database is locked: unable to close due to unfinalized statements or unfinished backups` {
t.Error("got message: ", got)
}
}
2023-02-16 13:30:31 +00:00
func TestConn_SetInterrupt(t *testing.T) {
2023-02-14 18:21:18 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
2023-02-16 13:58:53 +00:00
ctx, cancel := context.WithCancel(context.TODO())
db.SetInterrupt(ctx.Done())
// Interrupt doesn't interrupt this.
err = db.Exec(`SELECT 1`)
if err != nil {
t.Fatal(err)
}
db.SetInterrupt(nil)
2023-02-14 18:21:18 +00:00
stmt, _, err := db.Prepare(`
WITH RECURSIVE
fibonacci (curr, next)
AS (
SELECT 0, 1
UNION ALL
SELECT next, curr + next FROM fibonacci
2023-02-16 13:30:31 +00:00
LIMIT 1e6
2023-02-14 18:21:18 +00:00
)
SELECT min(curr) FROM fibonacci
`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
2023-02-16 13:58:53 +00:00
cancel()
db.SetInterrupt(ctx.Done())
2023-02-14 18:21:18 +00:00
var serr *Error
2023-02-16 13:30:31 +00:00
// Interrupting works.
err = stmt.Exec()
if err != nil {
if !errors.As(err, &serr) {
t.Fatalf("got %T, want sqlite3.Error", err)
}
if rc := serr.Code(); rc != INTERRUPT {
t.Errorf("got %d, want sqlite3.INTERRUPT", rc)
}
if got := err.Error(); got != `sqlite3: interrupted` {
t.Error("got message: ", got)
}
2023-02-14 18:21:18 +00:00
}
2023-02-16 13:30:31 +00:00
// Interrupting sticks.
err = db.Exec(`SELECT 1`)
if err != nil {
if !errors.As(err, &serr) {
t.Fatalf("got %T, want sqlite3.Error", err)
}
if rc := serr.Code(); rc != INTERRUPT {
t.Errorf("got %d, want sqlite3.INTERRUPT", rc)
}
if got := err.Error(); got != `sqlite3: interrupted` {
t.Error("got message: ", got)
}
2023-02-14 18:21:18 +00:00
}
db.SetInterrupt(nil)
2023-02-16 13:30:31 +00:00
// Interrupting can be cleared.
err = db.Exec(`SELECT 1`)
if err != nil {
t.Fatal(err)
}
2023-02-14 18:21:18 +00:00
}
2023-02-10 16:42:49 +00:00
func TestConn_Prepare_Empty(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-02-10 16:42:49 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
2023-02-14 18:21:18 +00:00
stmt, _, err := db.Prepare(``)
2023-02-10 16:42:49 +00:00
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
if stmt != nil {
t.Error("want nil")
}
}
func TestConn_Prepare_Invalid(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-02-10 16:42:49 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
var serr *Error
2023-02-14 18:21:18 +00:00
_, _, err = db.Prepare(`SELECT`)
2023-02-10 16:42:49 +00:00
if err == nil {
t.Fatal("want error")
}
if !errors.As(err, &serr) {
t.Fatalf("got %T, want sqlite3.Error", err)
}
if rc := serr.Code(); rc != ERROR {
t.Errorf("got %d, want sqlite3.ERROR", rc)
}
if got := err.Error(); got != `sqlite3: SQL logic error: incomplete input` {
t.Error("got message: ", got)
}
2023-02-14 18:21:18 +00:00
_, _, err = db.Prepare(`SELECT * FRM sqlite_schema`)
2023-02-10 16:42:49 +00:00
if err == nil {
t.Fatal("want error")
}
if !errors.As(err, &serr) {
t.Fatalf("got %T, want sqlite3.ERROR", err)
}
if rc := serr.Code(); rc != ERROR {
t.Errorf("got %d, want sqlite3.ERROR", rc)
}
if got := serr.SQL(); got != `FRM sqlite_schema` {
t.Error("got SQL: ", got)
}
if got := serr.Error(); got != `sqlite3: SQL logic error: near "FRM": syntax error` {
t.Error("got message: ", got)
}
}
2023-01-26 11:12:00 +00:00
func TestConn_new(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-01-26 11:12:00 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
defer func() { _ = recover() }()
db.new(math.MaxUint32)
2023-02-10 16:42:49 +00:00
t.Error("want panic")
2023-01-26 11:12:00 +00:00
}
2023-02-14 11:34:24 +00:00
func TestConn_newArena(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-02-14 11:34:24 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
arena := db.newArena(16)
defer arena.reset()
const title = "Lorem ipsum"
ptr := arena.string(title)
if ptr == 0 {
t.Fatalf("got nullptr")
}
if got := db.mem.readString(ptr, math.MaxUint32); got != title {
t.Errorf("got %q, want %q", got, title)
}
const body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
ptr = arena.string(body)
if ptr == 0 {
t.Fatalf("got nullptr")
}
if got := db.mem.readString(ptr, math.MaxUint32); got != body {
t.Errorf("got %q, want %q", got, body)
}
}
2023-01-26 11:12:00 +00:00
func TestConn_newBytes(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-01-26 11:12:00 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
ptr := db.newBytes(nil)
if ptr != 0 {
2023-02-10 16:42:49 +00:00
t.Errorf("got %#x, want nullptr", ptr)
2023-01-26 11:12:00 +00:00
}
buf := []byte("sqlite3")
ptr = db.newBytes(buf)
if ptr == 0 {
2023-01-26 12:15:34 +00:00
t.Fatal("got nullptr, want a pointer")
2023-01-26 11:12:00 +00:00
}
want := buf
2023-01-29 02:11:41 +00:00
if got := db.mem.view(ptr, uint32(len(want))); !bytes.Equal(got, want) {
2023-01-26 12:15:34 +00:00
t.Errorf("got %q, want %q", got, want)
2023-01-26 11:12:00 +00:00
}
}
func TestConn_newString(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-01-26 11:12:00 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
ptr := db.newString("")
if ptr == 0 {
2023-01-26 12:15:34 +00:00
t.Error("got nullptr, want a pointer")
2023-01-26 11:12:00 +00:00
}
str := "sqlite3\000sqlite3"
ptr = db.newString(str)
if ptr == 0 {
2023-01-26 12:15:34 +00:00
t.Fatal("got nullptr, want a pointer")
2023-01-26 11:12:00 +00:00
}
want := str + "\000"
2023-01-29 02:11:41 +00:00
if got := db.mem.view(ptr, uint32(len(want))); string(got) != want {
2023-01-26 12:15:34 +00:00
t.Errorf("got %q, want %q", got, want)
2023-01-26 11:12:00 +00:00
}
}
func TestConn_getString(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-01-26 11:12:00 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
ptr := db.newString("")
if ptr == 0 {
2023-01-26 12:15:34 +00:00
t.Error("got nullptr, want a pointer")
2023-01-26 11:12:00 +00:00
}
str := "sqlite3" + "\000 drop this"
ptr = db.newString(str)
if ptr == 0 {
2023-01-26 12:15:34 +00:00
t.Fatal("got nullptr, want a pointer")
2023-01-26 11:12:00 +00:00
}
want := "sqlite3"
2023-01-28 12:47:39 +00:00
if got := db.mem.readString(ptr, math.MaxUint32); got != want {
2023-01-26 12:15:34 +00:00
t.Errorf("got %q, want %q", got, want)
2023-01-26 11:12:00 +00:00
}
2023-01-28 12:47:39 +00:00
if got := db.mem.readString(ptr, 0); got != "" {
2023-01-26 12:15:34 +00:00
t.Errorf("got %q, want empty", got)
2023-01-26 11:12:00 +00:00
}
func() {
defer func() { _ = recover() }()
2023-01-28 12:47:39 +00:00
db.mem.readString(ptr, uint32(len(want)/2))
2023-02-10 16:42:49 +00:00
t.Error("want panic")
2023-01-26 11:12:00 +00:00
}()
func() {
defer func() { _ = recover() }()
2023-01-28 12:47:39 +00:00
db.mem.readString(0, math.MaxUint32)
2023-02-10 16:42:49 +00:00
t.Error("want panic")
2023-01-26 11:12:00 +00:00
}()
}
func TestConn_free(t *testing.T) {
2023-02-15 16:24:34 +00:00
t.Parallel()
2023-01-26 11:12:00 +00:00
db, err := Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
db.free(0)
2023-02-06 01:29:54 +00:00
ptr := db.new(1)
2023-01-26 11:12:00 +00:00
if ptr == 0 {
2023-01-26 12:15:34 +00:00
t.Error("got nullptr, want a pointer")
2023-01-26 11:12:00 +00:00
}
db.free(ptr)
}