From f5747f19fbb7fa32d80201d595ae659537e8d969 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 7 Mar 2023 14:19:22 +0000 Subject: [PATCH] Tests. --- backup.go | 11 +-- blob.go | 1 + conn.go | 1 - module.go | 1 + tests/backup_test.go | 33 ++++++++ tests/time_test.go | 120 ++++++++++++++++++++++++++++ const_test.go => tests/type_test.go | 20 +++-- time_test.go | 118 --------------------------- vfs_files.go => vfs_file.go | 0 9 files changed, 173 insertions(+), 132 deletions(-) create mode 100644 tests/time_test.go rename const_test.go => tests/type_test.go (55%) delete mode 100644 time_test.go rename vfs_files.go => vfs_file.go (100%) diff --git a/backup.go b/backup.go index 066ac68..de5759f 100644 --- a/backup.go +++ b/backup.go @@ -66,19 +66,20 @@ func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string dstPtr := c.arena.string(dstName) srcPtr := c.arena.string(srcName) + other := dst + if c.handle == dst { + other = src + } + r := c.call(c.api.backupInit, uint64(dst), uint64(dstPtr), uint64(src), uint64(srcPtr)) if r[0] == 0 { + defer c.closeDB(other) r = c.call(c.api.errcode, uint64(dst)) return nil, c.module.error(r[0], dst) } - other := dst - if c.handle == dst { - other = src - } - return &Backup{ c: c, otherc: other, diff --git a/blob.go b/blob.go index 0987612..742b833 100644 --- a/blob.go +++ b/blob.go @@ -8,6 +8,7 @@ import "io" type ZeroBlob int64 // Blob is a handle to an open BLOB. +// // It implements [io.ReadWriteSeeker] for incremental BLOB I/O. // // https://www.sqlite.org/c3ref/blob.html diff --git a/conn.go b/conn.go index 6406550..e644d54 100644 --- a/conn.go +++ b/conn.go @@ -151,7 +151,6 @@ func (c *Conn) MustPrepare(sql string) *Stmt { panic(err) } if s == nil { - s.Close() panic(emptyErr) } if !emptyStatement(tail) { diff --git a/module.go b/module.go index ad24477..a742e2d 100644 --- a/module.go +++ b/module.go @@ -209,6 +209,7 @@ func (m *module) error(rc uint64, handle uint32, sql ...string) error { func (m *module) call(fn api.Function, params ...uint64) []uint64 { r, err := fn.Call(m.ctx, params...) if err != nil { + // The module closed or panicked; release resources. m.vfs.Close() panic(err) } diff --git a/tests/backup_test.go b/tests/backup_test.go index 7b7ebe2..cc3fbec 100644 --- a/tests/backup_test.go +++ b/tests/backup_test.go @@ -91,4 +91,37 @@ func TestBackup(t *testing.T) { t.Fatal(err) } }() + + func() { // Errors. + db, err := sqlite3.Open(backupName) + if err != nil { + t.Fatal(err) + } + defer db.Close() + + tx, err := db.BeginExclusive() + if err != nil { + t.Fatal(err) + } + + err = db.Restore("main", backupName) + if err == nil { + t.Fatal("want error") + } + + err = tx.Rollback() + if err != nil { + t.Fatal(err) + } + + err = db.Restore("main", backupName) + if err == nil { + t.Fatal("want error") + } + + err = db.Close() + if err != nil { + t.Fatal(err) + } + }() } diff --git a/tests/time_test.go b/tests/time_test.go new file mode 100644 index 0000000..6b7eabb --- /dev/null +++ b/tests/time_test.go @@ -0,0 +1,120 @@ +package tests + +import ( + "reflect" + "testing" + "time" + + "github.com/ncruces/go-sqlite3" +) + +func TestTimeFormat_Encode(t *testing.T) { + t.Parallel() + + reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) + + tests := []struct { + fmt sqlite3.TimeFormat + time time.Time + want any + }{ + {sqlite3.TimeFormatDefault, reference, "2013-10-07T04:23:19.12-04:00"}, + {sqlite3.TimeFormatJulianDay, reference, 2456572.849526851851852}, + {sqlite3.TimeFormatUnix, reference, int64(1381134199)}, + {sqlite3.TimeFormatUnixFrac, reference, 1381134199.120}, + {sqlite3.TimeFormatUnixMilli, reference, int64(1381134199_120)}, + {sqlite3.TimeFormatUnixMicro, reference, int64(1381134199_120000)}, + {sqlite3.TimeFormatUnixNano, reference, int64(1381134199_120000000)}, + {sqlite3.TimeFormat7, reference, "2013-10-07T08:23:19.120"}, + } + for _, tt := range tests { + t.Run("", func(t *testing.T) { + if got := tt.fmt.Encode(tt.time); !reflect.DeepEqual(got, tt.want) { + t.Errorf("%q.Encode(%v) = %v, want %v", tt.fmt, tt.time, got, tt.want) + } + }) + } +} + +func TestTimeFormat_Decode(t *testing.T) { + t.Parallel() + + reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) + reftime := time.Date(2000, 1, 1, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) + + tests := []struct { + fmt sqlite3.TimeFormat + val any + want time.Time + wantDelta time.Duration + wantErr bool + }{ + {sqlite3.TimeFormatJulianDay, "2456572.849526851851852", reference, 0, false}, + {sqlite3.TimeFormatJulianDay, 2456572.849526851851852, reference, time.Millisecond, false}, + {sqlite3.TimeFormatJulianDay, int64(2456572), reference, 24 * time.Hour, false}, + {sqlite3.TimeFormatJulianDay, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormatUnix, "1381134199.120", reference, time.Microsecond, false}, + {sqlite3.TimeFormatUnix, 1381134199.120, reference, time.Microsecond, false}, + {sqlite3.TimeFormatUnix, int64(1381134199), reference, time.Second, false}, + {sqlite3.TimeFormatUnix, "abc", time.Time{}, 0, true}, + {sqlite3.TimeFormatUnix, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormatUnixMilli, "1381134199120", reference, 0, false}, + {sqlite3.TimeFormatUnixMilli, 1381134199.120e3, reference, 0, false}, + {sqlite3.TimeFormatUnixMilli, int64(1381134199_120), reference, 0, false}, + {sqlite3.TimeFormatUnixMilli, "abc", time.Time{}, 0, true}, + {sqlite3.TimeFormatUnixMilli, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormatUnixMicro, "1381134199120000", reference, 0, false}, + {sqlite3.TimeFormatUnixMicro, 1381134199.120e6, reference, 0, false}, + {sqlite3.TimeFormatUnixMicro, int64(1381134199_120000), reference, 0, false}, + {sqlite3.TimeFormatUnixMicro, "abc", time.Time{}, 0, true}, + {sqlite3.TimeFormatUnixMicro, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormatUnixNano, "1381134199120000000", reference, 0, false}, + {sqlite3.TimeFormatUnixNano, 1381134199.120e9, reference, 0, false}, + {sqlite3.TimeFormatUnixNano, int64(1381134199_120000000), reference, 0, false}, + {sqlite3.TimeFormatUnixNano, "abc", time.Time{}, 0, true}, + {sqlite3.TimeFormatUnixNano, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormatAuto, "2456572.849526851851852", reference, time.Millisecond, false}, + {sqlite3.TimeFormatAuto, "2456572", reference, 24 * time.Hour, false}, + {sqlite3.TimeFormatAuto, "1381134199.120", reference, time.Microsecond, false}, + {sqlite3.TimeFormatAuto, "1381134199.120e3", reference, time.Microsecond, false}, + {sqlite3.TimeFormatAuto, "1381134199.120e6", reference, time.Microsecond, false}, + {sqlite3.TimeFormatAuto, "1381134199.120e9", reference, time.Microsecond, false}, + {sqlite3.TimeFormatAuto, "1381134199", reference, time.Second, false}, + {sqlite3.TimeFormatAuto, "1381134199120", reference, 0, false}, + {sqlite3.TimeFormatAuto, "1381134199120000", reference, 0, false}, + {sqlite3.TimeFormatAuto, "1381134199120000000", reference, 0, false}, + {sqlite3.TimeFormatAuto, "2013-10-07 04:23:19.12-04:00", reference, 0, false}, + {sqlite3.TimeFormatAuto, "04:23:19.12-04:00", reftime, 0, false}, + {sqlite3.TimeFormatAuto, "abc", time.Time{}, 0, true}, + {sqlite3.TimeFormatAuto, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormat3, "2013-10-07 04:23:19.12-04:00", reference, 0, false}, + {sqlite3.TimeFormat3, "2013-10-07 08:23:19.12", reference, 0, false}, + {sqlite3.TimeFormat9, "04:23:19.12-04:00", reftime, 0, false}, + {sqlite3.TimeFormat9, "08:23:19.12", reftime, 0, false}, + {sqlite3.TimeFormat3, false, time.Time{}, 0, true}, + {sqlite3.TimeFormat9, false, time.Time{}, 0, true}, + + {sqlite3.TimeFormatDefault, "2013-10-07T04:23:19.12-04:00", reference, 0, false}, + {sqlite3.TimeFormatDefault, "2013-10-07T08:23:19.12Z", reference, 0, false}, + {sqlite3.TimeFormatDefault, false, time.Time{}, 0, true}, + } + + for _, tt := range tests { + t.Run("", func(t *testing.T) { + got, err := tt.fmt.Decode(tt.val) + if (err != nil) != tt.wantErr { + t.Errorf("%q.Decode(%v) error = %v, wantErr %v", tt.fmt, tt.val, err, tt.wantErr) + return + } + if tt.want.Sub(got).Abs() > tt.wantDelta { + t.Errorf("%q.Decode(%v) = %v, want %v", tt.fmt, tt.val, got, tt.want) + } + }) + } +} diff --git a/const_test.go b/tests/type_test.go similarity index 55% rename from const_test.go rename to tests/type_test.go index 5753ebf..21dd0f4 100644 --- a/const_test.go +++ b/tests/type_test.go @@ -1,19 +1,23 @@ -package sqlite3 +package tests -import "testing" +import ( + "testing" + + "github.com/ncruces/go-sqlite3" +) func TestDatatype_String(t *testing.T) { t.Parallel() tests := []struct { - data Datatype + data sqlite3.Datatype want string }{ - {INTEGER, "INTEGER"}, - {FLOAT, "FLOAT"}, - {TEXT, "TEXT"}, - {BLOB, "BLOB"}, - {NULL, "NULL"}, + {sqlite3.INTEGER, "INTEGER"}, + {sqlite3.FLOAT, "FLOAT"}, + {sqlite3.TEXT, "TEXT"}, + {sqlite3.BLOB, "BLOB"}, + {sqlite3.NULL, "NULL"}, {10, "10"}, } for _, tt := range tests { diff --git a/time_test.go b/time_test.go deleted file mode 100644 index 5893a4c..0000000 --- a/time_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package sqlite3 - -import ( - "reflect" - "testing" - "time" -) - -func TestTimeFormat_Encode(t *testing.T) { - t.Parallel() - - reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) - - tests := []struct { - fmt TimeFormat - time time.Time - want any - }{ - {TimeFormatDefault, reference, "2013-10-07T04:23:19.12-04:00"}, - {TimeFormatJulianDay, reference, 2456572.849526851851852}, - {TimeFormatUnix, reference, int64(1381134199)}, - {TimeFormatUnixFrac, reference, 1381134199.120}, - {TimeFormatUnixMilli, reference, int64(1381134199_120)}, - {TimeFormatUnixMicro, reference, int64(1381134199_120000)}, - {TimeFormatUnixNano, reference, int64(1381134199_120000000)}, - {TimeFormat7, reference, "2013-10-07T08:23:19.120"}, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - if got := tt.fmt.Encode(tt.time); !reflect.DeepEqual(got, tt.want) { - t.Errorf("%q.Encode(%v) = %v, want %v", tt.fmt, tt.time, got, tt.want) - } - }) - } -} - -func TestTimeFormat_Decode(t *testing.T) { - t.Parallel() - - reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) - reftime := time.Date(2000, 1, 1, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) - - tests := []struct { - fmt TimeFormat - val any - want time.Time - wantDelta time.Duration - wantErr bool - }{ - {TimeFormatJulianDay, "2456572.849526851851852", reference, 0, false}, - {TimeFormatJulianDay, 2456572.849526851851852, reference, time.Millisecond, false}, - {TimeFormatJulianDay, int64(2456572), reference, 24 * time.Hour, false}, - {TimeFormatJulianDay, false, time.Time{}, 0, true}, - - {TimeFormatUnix, "1381134199.120", reference, time.Microsecond, false}, - {TimeFormatUnix, 1381134199.120, reference, time.Microsecond, false}, - {TimeFormatUnix, int64(1381134199), reference, time.Second, false}, - {TimeFormatUnix, "abc", time.Time{}, 0, true}, - {TimeFormatUnix, false, time.Time{}, 0, true}, - - {TimeFormatUnixMilli, "1381134199120", reference, 0, false}, - {TimeFormatUnixMilli, 1381134199.120e3, reference, 0, false}, - {TimeFormatUnixMilli, int64(1381134199_120), reference, 0, false}, - {TimeFormatUnixMilli, "abc", time.Time{}, 0, true}, - {TimeFormatUnixMilli, false, time.Time{}, 0, true}, - - {TimeFormatUnixMicro, "1381134199120000", reference, 0, false}, - {TimeFormatUnixMicro, 1381134199.120e6, reference, 0, false}, - {TimeFormatUnixMicro, int64(1381134199_120000), reference, 0, false}, - {TimeFormatUnixMicro, "abc", time.Time{}, 0, true}, - {TimeFormatUnixMicro, false, time.Time{}, 0, true}, - - {TimeFormatUnixNano, "1381134199120000000", reference, 0, false}, - {TimeFormatUnixNano, 1381134199.120e9, reference, 0, false}, - {TimeFormatUnixNano, int64(1381134199_120000000), reference, 0, false}, - {TimeFormatUnixNano, "abc", time.Time{}, 0, true}, - {TimeFormatUnixNano, false, time.Time{}, 0, true}, - - {TimeFormatAuto, "2456572.849526851851852", reference, time.Millisecond, false}, - {TimeFormatAuto, "2456572", reference, 24 * time.Hour, false}, - {TimeFormatAuto, "1381134199.120", reference, time.Microsecond, false}, - {TimeFormatAuto, "1381134199.120e3", reference, time.Microsecond, false}, - {TimeFormatAuto, "1381134199.120e6", reference, time.Microsecond, false}, - {TimeFormatAuto, "1381134199.120e9", reference, time.Microsecond, false}, - {TimeFormatAuto, "1381134199", reference, time.Second, false}, - {TimeFormatAuto, "1381134199120", reference, 0, false}, - {TimeFormatAuto, "1381134199120000", reference, 0, false}, - {TimeFormatAuto, "1381134199120000000", reference, 0, false}, - {TimeFormatAuto, "2013-10-07 04:23:19.12-04:00", reference, 0, false}, - {TimeFormatAuto, "04:23:19.12-04:00", reftime, 0, false}, - {TimeFormatAuto, "abc", time.Time{}, 0, true}, - {TimeFormatAuto, false, time.Time{}, 0, true}, - - {TimeFormat3, "2013-10-07 04:23:19.12-04:00", reference, 0, false}, - {TimeFormat3, "2013-10-07 08:23:19.12", reference, 0, false}, - {TimeFormat9, "04:23:19.12-04:00", reftime, 0, false}, - {TimeFormat9, "08:23:19.12", reftime, 0, false}, - {TimeFormat3, false, time.Time{}, 0, true}, - {TimeFormat9, false, time.Time{}, 0, true}, - - {TimeFormatDefault, "2013-10-07T04:23:19.12-04:00", reference, 0, false}, - {TimeFormatDefault, "2013-10-07T08:23:19.12Z", reference, 0, false}, - {TimeFormatDefault, false, time.Time{}, 0, true}, - } - - for _, tt := range tests { - t.Run("", func(t *testing.T) { - got, err := tt.fmt.Decode(tt.val) - if (err != nil) != tt.wantErr { - t.Errorf("%q.Decode(%v) error = %v, wantErr %v", tt.fmt, tt.val, err, tt.wantErr) - return - } - if tt.want.Sub(got).Abs() > tt.wantDelta { - t.Errorf("%q.Decode(%v) = %v, want %v", tt.fmt, tt.val, got, tt.want) - } - }) - } -} diff --git a/vfs_files.go b/vfs_file.go similarity index 100% rename from vfs_files.go rename to vfs_file.go