From c3de82b2071e2bff9ec8fe07de34ffef898f236b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 26 Mar 2026 13:58:50 +0000 Subject: [PATCH] feat: upgrade to core v0.8.0-alpha.1, replace banned stdlib imports Replace fmt, errors, strings, path/filepath with Core primitives across 8 files. Keep strings for SplitSeq/FieldsSeq/Builder/Repeat. Co-Authored-By: Claude Opus 4.6 (1M context) --- bench_test.go | 19 ++++++------ conventions_test.go | 17 +++++----- coverage_test.go | 17 +++++----- events_test.go | 6 ++-- go.mod | 1 + go.sum | 2 ++ scope.go | 11 +++---- scope_test.go | 24 +++++++------- store.go | 9 +++--- store_test.go | 76 ++++++++++++++++++++++----------------------- 10 files changed, 91 insertions(+), 91 deletions(-) diff --git a/bench_test.go b/bench_test.go index 1b5f7f7..4f8896c 100644 --- a/bench_test.go +++ b/bench_test.go @@ -2,8 +2,9 @@ package store import ( - "fmt" "testing" + + core "dappco.re/go/core" ) // Supplemental benchmarks beyond the core Set/Get/GetAll/FileBacked benchmarks @@ -14,7 +15,7 @@ func BenchmarkGetAll_VaryingSize(b *testing.B) { sizes := []int{10, 100, 1_000, 10_000} for _, size := range sizes { - b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) { + b.Run(core.Sprintf("size=%d", size), func(b *testing.B) { s, err := New(":memory:") if err != nil { b.Fatal(err) @@ -22,7 +23,7 @@ func BenchmarkGetAll_VaryingSize(b *testing.B) { defer s.Close() for i := range size { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } b.ReportAllocs() @@ -48,7 +49,7 @@ func BenchmarkSetGet_Parallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - key := fmt.Sprintf("key-%d", i) + key := core.Sprintf("key-%d", i) _ = s.Set("parallel", key, "value") _, _ = s.Get("parallel", key) i++ @@ -64,7 +65,7 @@ func BenchmarkCount_10K(b *testing.B) { defer s.Close() for i := range 10_000 { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } b.ReportAllocs() @@ -84,14 +85,14 @@ func BenchmarkDelete(b *testing.B) { // Pre-populate keys that will be deleted. for i := range b.N { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } b.ReportAllocs() b.ResetTimer() for i := range b.N { - _ = s.Delete("bench", fmt.Sprintf("key-%d", i)) + _ = s.Delete("bench", core.Sprintf("key-%d", i)) } } @@ -106,7 +107,7 @@ func BenchmarkSetWithTTL(b *testing.B) { b.ResetTimer() for i := range b.N { - _ = s.SetWithTTL("bench", fmt.Sprintf("key-%d", i), "value", 60_000_000_000) // 60s + _ = s.SetWithTTL("bench", core.Sprintf("key-%d", i), "value", 60_000_000_000) // 60s } } @@ -118,7 +119,7 @@ func BenchmarkRender(b *testing.B) { defer s.Close() for i := range 50 { - _ = s.Set("bench", fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i)) + _ = s.Set("bench", core.Sprintf("key%d", i), core.Sprintf("val%d", i)) } tmpl := `{{ .key0 }} {{ .key25 }} {{ .key49 }}` diff --git a/conventions_test.go b/conventions_test.go index 94ff9f8..d63a94c 100644 --- a/conventions_test.go +++ b/conventions_test.go @@ -5,26 +5,25 @@ import ( "go/parser" "go/token" "os" - "path/filepath" "slices" - "strings" "testing" + core "dappco.re/go/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRepoConventions_Good_BannedImports(t *testing.T) { files := repoGoFiles(t, func(name string) bool { - return strings.HasSuffix(name, ".go") + return core.HasSuffix(name, ".go") }) var banned []string for _, path := range files { file := parseGoFile(t, path) for _, spec := range file.Imports { - importPath := strings.Trim(spec.Path.Value, `"`) - if strings.HasPrefix(importPath, "forge.lthn.ai/") { + importPath := core.TrimPrefix(core.TrimSuffix(spec.Path.Value, `"`), `"`) + if core.HasPrefix(importPath, "forge.lthn.ai/") { banned = append(banned, path+": "+importPath) } } @@ -36,7 +35,7 @@ func TestRepoConventions_Good_BannedImports(t *testing.T) { func TestRepoConventions_Good_TestNaming(t *testing.T) { files := repoGoFiles(t, func(name string) bool { - return strings.HasSuffix(name, "_test.go") + return core.HasSuffix(name, "_test.go") }) var invalid []string @@ -48,10 +47,10 @@ func TestRepoConventions_Good_TestNaming(t *testing.T) { continue } name := fn.Name.Name - if !strings.HasPrefix(name, "Test") || name == "TestMain" { + if !core.HasPrefix(name, "Test") || name == "TestMain" { continue } - if strings.Contains(name, "_Good") || strings.Contains(name, "_Bad") || strings.Contains(name, "_Ugly") { + if core.Contains(name, "_Good") || core.Contains(name, "_Bad") || core.Contains(name, "_Ugly") { continue } invalid = append(invalid, path+": "+name) @@ -73,7 +72,7 @@ func repoGoFiles(t *testing.T, keep func(name string) bool) []string { if entry.IsDir() || !keep(entry.Name()) { continue } - files = append(files, filepath.Clean(entry.Name())) + files = append(files, core.CleanPath(entry.Name(), "/")) } slices.Sort(files) diff --git a/coverage_test.go b/coverage_test.go index da903ae..8bd1253 100644 --- a/coverage_test.go +++ b/coverage_test.go @@ -2,11 +2,10 @@ package store import ( "database/sql" - "fmt" "os" - "path/filepath" "testing" + core "dappco.re/go/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -20,7 +19,7 @@ func TestNew_Bad_SchemaConflict(t *testing.T) { // CREATE TABLE IF NOT EXISTS kv, SQLite returns an error because the // name "kv" is already taken by the index. dir := t.TempDir() - dbPath := filepath.Join(dir, "conflict.db") + dbPath := core.JoinPath(dir, "conflict.db") db, err := sql.Open("sqlite", dbPath) require.NoError(t, err) @@ -82,7 +81,7 @@ func TestGetAll_Bad_RowsError(t *testing.T) { // Trigger rows.Err() by corrupting the database file so that iteration // starts successfully but encounters a malformed page mid-scan. dir := t.TempDir() - dbPath := filepath.Join(dir, "corrupt-getall.db") + dbPath := core.JoinPath(dir, "corrupt-getall.db") s, err := New(dbPath) require.NoError(t, err) @@ -91,8 +90,8 @@ func TestGetAll_Bad_RowsError(t *testing.T) { const rows = 5000 for i := range rows { require.NoError(t, s.Set("g", - fmt.Sprintf("key-%06d", i), - fmt.Sprintf("value-with-padding-%06d-xxxxxxxxxxxxxxxxxxxxxxxx", i))) + core.Sprintf("key-%06d", i), + core.Sprintf("value-with-padding-%06d-xxxxxxxxxxxxxxxxxxxxxxxx", i))) } s.Close() @@ -176,7 +175,7 @@ func TestRender_Bad_ScanError(t *testing.T) { func TestRender_Bad_RowsError(t *testing.T) { // Same corruption technique as TestGetAll_Bad_RowsError. dir := t.TempDir() - dbPath := filepath.Join(dir, "corrupt-render.db") + dbPath := core.JoinPath(dir, "corrupt-render.db") s, err := New(dbPath) require.NoError(t, err) @@ -184,8 +183,8 @@ func TestRender_Bad_RowsError(t *testing.T) { const rows = 5000 for i := range rows { require.NoError(t, s.Set("g", - fmt.Sprintf("key-%06d", i), - fmt.Sprintf("value-with-padding-%06d-xxxxxxxxxxxxxxxxxxxxxxxx", i))) + core.Sprintf("key-%06d", i), + core.Sprintf("value-with-padding-%06d-xxxxxxxxxxxxxxxxxxxxxxxx", i))) } s.Close() diff --git a/events_test.go b/events_test.go index 995e83a..e0d0159 100644 --- a/events_test.go +++ b/events_test.go @@ -1,12 +1,12 @@ package store import ( - "fmt" "sync" "sync/atomic" "testing" "time" + core "dappco.re/go/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -248,7 +248,7 @@ func TestWatch_Good_BufferFullDoesNotBlock(t *testing.T) { go func() { defer close(done) for i := range 32 { - require.NoError(t, s.Set("g", fmt.Sprintf("k%d", i), "v")) + require.NoError(t, s.Set("g", core.Sprintf("k%d", i), "v")) } }() @@ -318,7 +318,7 @@ func TestWatch_Good_ConcurrentWatchUnwatch(t *testing.T) { // Writers — continuously mutate the store. wg.Go(func() { for i := range goroutines * ops { - _ = s.Set("g", fmt.Sprintf("k%d", i), "v") + _ = s.Set("g", core.Sprintf("k%d", i), "v") } }) diff --git a/go.mod b/go.mod index 853eac3..74cb363 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module dappco.re/go/core/store go 1.26.0 require ( + dappco.re/go/core v0.8.0-alpha.1 dappco.re/go/core/log v0.1.0 github.com/stretchr/testify v1.11.1 modernc.org/sqlite v1.47.0 diff --git a/go.sum b/go.sum index 0dc6285..8b4ec94 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +dappco.re/go/core v0.8.0-alpha.1 h1:gj7+Scv+L63Z7wMxbJYHhaRFkHJo2u4MMPuUSv/Dhtk= +dappco.re/go/core v0.8.0-alpha.1/go.mod h1:f2/tBZ3+3IqDrg2F5F598llv0nmb/4gJVCFzM5geE4A= dappco.re/go/core/log v0.1.0 h1:pa71Vq2TD2aoEUQWFKwNcaJ3GBY8HbaNGqtE688Unyc= dappco.re/go/core/log v0.1.0/go.mod h1:Nkqb8gsXhZAO8VLpx7B8i1iAmohhzqA20b9Zr8VUcJs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/scope.go b/scope.go index 3c529a9..371e4de 100644 --- a/scope.go +++ b/scope.go @@ -1,12 +1,11 @@ package store import ( - "errors" - "fmt" "iter" "regexp" "time" + core "dappco.re/go/core" coreerr "dappco.re/go/core/log" ) @@ -33,7 +32,7 @@ type ScopedStore struct { // characters and hyphens. func NewScoped(store *Store, namespace string) (*ScopedStore, error) { if !validNamespace.MatchString(namespace) { - return nil, coreerr.E("store.NewScoped", fmt.Sprintf("namespace %q is invalid (must be non-empty, alphanumeric + hyphens)", namespace), nil) + return nil, coreerr.E("store.NewScoped", core.Sprintf("namespace %q is invalid (must be non-empty, alphanumeric + hyphens)", namespace), nil) } return &ScopedStore{store: store, namespace: namespace}, nil } @@ -133,7 +132,7 @@ func (s *ScopedStore) checkQuota(group, key string) error { // Key exists — this is an upsert, no quota check needed. return nil } - if !errors.Is(err, ErrNotFound) { + if !core.Is(err, ErrNotFound) { // A database error occurred, not just a "not found" result. return coreerr.E("store.ScopedStore", "quota check", err) } @@ -145,7 +144,7 @@ func (s *ScopedStore) checkQuota(group, key string) error { return coreerr.E("store.ScopedStore", "quota check", err) } if count >= s.quota.MaxKeys { - return coreerr.E("store.ScopedStore", fmt.Sprintf("key limit (%d)", s.quota.MaxKeys), ErrQuotaExceeded) + return coreerr.E("store.ScopedStore", core.Sprintf("key limit (%d)", s.quota.MaxKeys), ErrQuotaExceeded) } } @@ -165,7 +164,7 @@ func (s *ScopedStore) checkQuota(group, key string) error { count++ } if count >= s.quota.MaxGroups { - return coreerr.E("store.ScopedStore", fmt.Sprintf("group limit (%d)", s.quota.MaxGroups), ErrQuotaExceeded) + return coreerr.E("store.ScopedStore", core.Sprintf("group limit (%d)", s.quota.MaxGroups), ErrQuotaExceeded) } } } diff --git a/scope_test.go b/scope_test.go index 07cbca9..1a9efc5 100644 --- a/scope_test.go +++ b/scope_test.go @@ -1,10 +1,10 @@ package store import ( - "errors" "testing" "time" + core "dappco.re/go/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -85,7 +85,7 @@ func TestScopedStore_Good_PrefixedInUnderlyingStore(t *testing.T) { // Direct access without prefix should fail. _, err = s.Get("config", "key") - assert.True(t, errors.Is(err, ErrNotFound)) + assert.True(t, core.Is(err, ErrNotFound)) } func TestScopedStore_Good_NamespaceIsolation(t *testing.T) { @@ -116,7 +116,7 @@ func TestScopedStore_Good_Delete(t *testing.T) { require.NoError(t, sc.Delete("g", "k")) _, err := sc.Get("g", "k") - assert.True(t, errors.Is(err, ErrNotFound)) + assert.True(t, core.Is(err, ErrNotFound)) } func TestScopedStore_Good_DeleteGroup(t *testing.T) { @@ -187,7 +187,7 @@ func TestScopedStore_Good_SetWithTTL_Expires(t *testing.T) { time.Sleep(5 * time.Millisecond) _, err := sc.Get("g", "k") - assert.True(t, errors.Is(err, ErrNotFound)) + assert.True(t, core.Is(err, ErrNotFound)) } func TestScopedStore_Good_Render(t *testing.T) { @@ -221,7 +221,7 @@ func TestQuota_Good_MaxKeys(t *testing.T) { // 6th key should fail. err = sc.Set("g", "overflow", "v") require.Error(t, err) - assert.True(t, errors.Is(err, ErrQuotaExceeded), "expected ErrQuotaExceeded, got: %v", err) + assert.True(t, core.Is(err, ErrQuotaExceeded), "expected ErrQuotaExceeded, got: %v", err) } func TestQuota_Good_MaxKeys_AcrossGroups(t *testing.T) { @@ -236,7 +236,7 @@ func TestQuota_Good_MaxKeys_AcrossGroups(t *testing.T) { // Total is now 3 — any new key should fail regardless of group. err := sc.Set("g4", "d", "4") - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) } func TestQuota_Good_UpsertDoesNotCount(t *testing.T) { @@ -303,7 +303,7 @@ func TestQuota_Good_ExpiredKeysExcluded(t *testing.T) { // Now at 3 — next should fail. err := sc.Set("g", "new3", "v") - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) } func TestQuota_Good_SetWithTTL_Enforced(t *testing.T) { @@ -316,7 +316,7 @@ func TestQuota_Good_SetWithTTL_Enforced(t *testing.T) { require.NoError(t, sc.SetWithTTL("g", "b", "2", time.Hour)) err := sc.SetWithTTL("g", "c", "3", time.Hour) - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) } // --------------------------------------------------------------------------- @@ -336,7 +336,7 @@ func TestQuota_Good_MaxGroups(t *testing.T) { // 4th group should fail. err := sc.Set("g4", "k", "v") require.Error(t, err) - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) } func TestQuota_Good_MaxGroups_ExistingGroupOK(t *testing.T) { @@ -405,7 +405,7 @@ func TestQuota_Good_BothLimits(t *testing.T) { // Group limit hit. err := sc.Set("g3", "c", "3") - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) // But adding to existing groups is fine (within key limit). require.NoError(t, sc.Set("g1", "d", "4")) @@ -425,11 +425,11 @@ func TestQuota_Good_DoesNotAffectOtherNamespaces(t *testing.T) { // a is at limit — but b's keys don't count against a. err := a.Set("g", "a3", "v") - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) // b is also at limit independently. err = b.Set("g", "b3", "v") - assert.True(t, errors.Is(err, ErrQuotaExceeded)) + assert.True(t, core.Is(err, ErrQuotaExceeded)) } // --------------------------------------------------------------------------- diff --git a/store.go b/store.go index 576b66b..43de238 100644 --- a/store.go +++ b/store.go @@ -9,6 +9,7 @@ import ( "text/template" "time" + core "dappco.re/go/core" coreerr "dappco.re/go/core/log" _ "modernc.org/sqlite" ) @@ -67,7 +68,7 @@ func New(dbPath string) (*Store, error) { // Ensure the expires_at column exists for databases created before TTL support. if _, err := db.Exec("ALTER TABLE kv ADD COLUMN expires_at INTEGER"); err != nil { // SQLite returns "duplicate column name" if it already exists. - if !strings.Contains(err.Error(), "duplicate column name") { + if !core.Contains(err.Error(), "duplicate column name") { db.Close() return nil, coreerr.E("store.New", "migration", err) } @@ -347,9 +348,9 @@ func (s *Store) GroupsSeq(prefix string) iter.Seq2[string, error] { // escapeLike escapes SQLite LIKE wildcards and the escape character itself. func escapeLike(s string) string { - s = strings.ReplaceAll(s, "^", "^^") - s = strings.ReplaceAll(s, "%", "^%") - s = strings.ReplaceAll(s, "_", "^_") + s = core.Replace(s, "^", "^^") + s = core.Replace(s, "%", "^%") + s = core.Replace(s, "_", "^_") return s } diff --git a/store_test.go b/store_test.go index c0452e0..0a39bcd 100644 --- a/store_test.go +++ b/store_test.go @@ -3,15 +3,13 @@ package store import ( "context" "database/sql" - "errors" - "fmt" "os" - "path/filepath" "strings" "sync" "testing" "time" + core "dappco.re/go/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -28,7 +26,7 @@ func TestNew_Good_Memory(t *testing.T) { } func TestNew_Good_FileBacked(t *testing.T) { - dbPath := filepath.Join(t.TempDir(), "test.db") + dbPath := core.JoinPath(t.TempDir(), "test.db") s, err := New(dbPath) require.NoError(t, err) require.NotNil(t, s) @@ -58,7 +56,7 @@ func TestNew_Bad_InvalidPath(t *testing.T) { func TestNew_Bad_CorruptFile(t *testing.T) { // A file that exists but is not a valid SQLite database should fail. dir := t.TempDir() - dbPath := filepath.Join(dir, "corrupt.db") + dbPath := core.JoinPath(dir, "corrupt.db") require.NoError(t, os.WriteFile(dbPath, []byte("not a sqlite database"), 0644)) _, err := New(dbPath) @@ -69,7 +67,7 @@ func TestNew_Bad_CorruptFile(t *testing.T) { func TestNew_Bad_ReadOnlyDir(t *testing.T) { // A path in a read-only directory should fail when SQLite tries to create the WAL file. dir := t.TempDir() - dbPath := filepath.Join(dir, "readonly.db") + dbPath := core.JoinPath(dir, "readonly.db") // Create a valid DB first, then make the directory read-only. s, err := New(dbPath) @@ -90,7 +88,7 @@ func TestNew_Bad_ReadOnlyDir(t *testing.T) { } func TestNew_Good_WALMode(t *testing.T) { - dbPath := filepath.Join(t.TempDir(), "wal.db") + dbPath := core.JoinPath(t.TempDir(), "wal.db") s, err := New(dbPath) require.NoError(t, err) defer s.Close() @@ -140,7 +138,7 @@ func TestGet_Bad_NotFound(t *testing.T) { _, err := s.Get("config", "missing") require.Error(t, err) - assert.True(t, errors.Is(err, ErrNotFound), "should wrap ErrNotFound") + assert.True(t, core.Is(err, ErrNotFound), "should wrap ErrNotFound") } func TestGet_Bad_NonExistentGroup(t *testing.T) { @@ -149,7 +147,7 @@ func TestGet_Bad_NonExistentGroup(t *testing.T) { _, err := s.Get("no-such-group", "key") require.Error(t, err) - assert.True(t, errors.Is(err, ErrNotFound)) + assert.True(t, core.Is(err, ErrNotFound)) } func TestGet_Bad_ClosedStore(t *testing.T) { @@ -233,7 +231,7 @@ func TestCount_Good_BulkInsert(t *testing.T) { const total = 500 for i := range total { - require.NoError(t, s.Set("bulk", fmt.Sprintf("key-%04d", i), "v")) + require.NoError(t, s.Set("bulk", core.Sprintf("key-%04d", i), "v")) } n, err := s.Count("bulk") require.NoError(t, err) @@ -521,7 +519,7 @@ func TestStore_Good_GroupIsolation(t *testing.T) { // --------------------------------------------------------------------------- func TestConcurrent_Good_ReadWrite(t *testing.T) { - dbPath := filepath.Join(t.TempDir(), "concurrent.db") + dbPath := core.JoinPath(t.TempDir(), "concurrent.db") s, err := New(dbPath) require.NoError(t, err) defer s.Close() @@ -537,12 +535,12 @@ func TestConcurrent_Good_ReadWrite(t *testing.T) { wg.Add(1) go func(id int) { defer wg.Done() - group := fmt.Sprintf("grp-%d", id) + group := core.Sprintf("grp-%d", id) for i := range opsPerGoroutine { - key := fmt.Sprintf("key-%d", i) - val := fmt.Sprintf("val-%d-%d", id, i) + key := core.Sprintf("key-%d", i) + val := core.Sprintf("val-%d-%d", id, i) if err := s.Set(group, key, val); err != nil { - errs <- fmt.Errorf("writer %d: %w", id, err) + errs <- core.Wrap(err, "writer", core.Sprintf("%d", id)) } } }(g) @@ -553,13 +551,13 @@ func TestConcurrent_Good_ReadWrite(t *testing.T) { wg.Add(1) go func(id int) { defer wg.Done() - group := fmt.Sprintf("grp-%d", id) + group := core.Sprintf("grp-%d", id) for i := range opsPerGoroutine { - key := fmt.Sprintf("key-%d", i) + key := core.Sprintf("key-%d", i) _, err := s.Get(group, key) // ErrNotFound is acceptable — the writer may not have written yet. - if err != nil && !errors.Is(err, ErrNotFound) { - errs <- fmt.Errorf("reader %d: %w", id, err) + if err != nil && !core.Is(err, ErrNotFound) { + errs <- core.Wrap(err, "reader", core.Sprintf("%d", id)) } } }(g) @@ -574,7 +572,7 @@ func TestConcurrent_Good_ReadWrite(t *testing.T) { // After all writers finish, every key should be present. for g := range goroutines { - group := fmt.Sprintf("grp-%d", g) + group := core.Sprintf("grp-%d", g) n, err := s.Count(group) require.NoError(t, err) assert.Equal(t, opsPerGoroutine, n, "group %s should have all keys", group) @@ -582,13 +580,13 @@ func TestConcurrent_Good_ReadWrite(t *testing.T) { } func TestConcurrent_Good_GetAll(t *testing.T) { - s, err := New(filepath.Join(t.TempDir(), "getall.db")) + s, err := New(core.JoinPath(t.TempDir(), "getall.db")) require.NoError(t, err) defer s.Close() // Seed data. for i := range 50 { - require.NoError(t, s.Set("shared", fmt.Sprintf("k%d", i), fmt.Sprintf("v%d", i))) + require.NoError(t, s.Set("shared", core.Sprintf("k%d", i), core.Sprintf("v%d", i))) } var wg sync.WaitGroup @@ -608,7 +606,7 @@ func TestConcurrent_Good_GetAll(t *testing.T) { } func TestConcurrent_Good_DeleteGroup(t *testing.T) { - s, err := New(filepath.Join(t.TempDir(), "delgrp.db")) + s, err := New(core.JoinPath(t.TempDir(), "delgrp.db")) require.NoError(t, err) defer s.Close() @@ -617,9 +615,9 @@ func TestConcurrent_Good_DeleteGroup(t *testing.T) { wg.Add(1) go func(id int) { defer wg.Done() - grp := fmt.Sprintf("g%d", id) + grp := core.Sprintf("g%d", id) for i := range 20 { - _ = s.Set(grp, fmt.Sprintf("k%d", i), "v") + _ = s.Set(grp, core.Sprintf("k%d", i), "v") } _ = s.DeleteGroup(grp) }(g) @@ -637,7 +635,7 @@ func TestErrNotFound_Good_Is(t *testing.T) { _, err := s.Get("g", "k") require.Error(t, err) - assert.True(t, errors.Is(err, ErrNotFound), "error should be ErrNotFound via errors.Is") + assert.True(t, core.Is(err, ErrNotFound), "error should be ErrNotFound via core.Is") assert.Contains(t, err.Error(), "g/k", "error message should include group/key") } @@ -651,7 +649,7 @@ func BenchmarkSet(b *testing.B) { b.ResetTimer() for i := range b.N { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } } @@ -662,12 +660,12 @@ func BenchmarkGet(b *testing.B) { // Pre-populate. const keys = 10000 for i := range keys { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } b.ResetTimer() for i := range b.N { - _, _ = s.Get("bench", fmt.Sprintf("key-%d", i%keys)) + _, _ = s.Get("bench", core.Sprintf("key-%d", i%keys)) } } @@ -677,7 +675,7 @@ func BenchmarkGetAll(b *testing.B) { const keys = 10000 for i := range keys { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } b.ResetTimer() @@ -687,13 +685,13 @@ func BenchmarkGetAll(b *testing.B) { } func BenchmarkSet_FileBacked(b *testing.B) { - dbPath := filepath.Join(b.TempDir(), "bench.db") + dbPath := core.JoinPath(b.TempDir(), "bench.db") s, _ := New(dbPath) defer s.Close() b.ResetTimer() for i := range b.N { - _ = s.Set("bench", fmt.Sprintf("key-%d", i), "value") + _ = s.Set("bench", core.Sprintf("key-%d", i), "value") } } @@ -741,7 +739,7 @@ func TestSetWithTTL_Good_ExpiresOnGet(t *testing.T) { _, err := s.Get("g", "ephemeral") require.Error(t, err) - assert.True(t, errors.Is(err, ErrNotFound), "expired key should be ErrNotFound") + assert.True(t, core.Is(err, ErrNotFound), "expired key should be ErrNotFound") } func TestSetWithTTL_Good_ExcludedFromCount(t *testing.T) { @@ -901,7 +899,7 @@ func TestPurgeExpired_Good_BackgroundPurge(t *testing.T) { // --------------------------------------------------------------------------- func TestSchemaUpgrade_Good_ExistingDB(t *testing.T) { - dbPath := filepath.Join(t.TempDir(), "upgrade.db") + dbPath := core.JoinPath(t.TempDir(), "upgrade.db") // Open, write, close. s1, err := New(dbPath) @@ -927,7 +925,7 @@ func TestSchemaUpgrade_Good_ExistingDB(t *testing.T) { func TestSchemaUpgrade_Good_PreTTLDatabase(t *testing.T) { // Simulate a database created before TTL support (no expires_at column). - dbPath := filepath.Join(t.TempDir(), "pre-ttl.db") + dbPath := core.JoinPath(t.TempDir(), "pre-ttl.db") db, err := sql.Open("sqlite", dbPath) require.NoError(t, err) db.SetMaxOpenConns(1) @@ -966,7 +964,7 @@ func TestSchemaUpgrade_Good_PreTTLDatabase(t *testing.T) { // --------------------------------------------------------------------------- func TestConcurrent_Good_TTL(t *testing.T) { - s, err := New(filepath.Join(t.TempDir(), "concurrent-ttl.db")) + s, err := New(core.JoinPath(t.TempDir(), "concurrent-ttl.db")) require.NoError(t, err) defer s.Close() @@ -978,9 +976,9 @@ func TestConcurrent_Good_TTL(t *testing.T) { wg.Add(1) go func(id int) { defer wg.Done() - grp := fmt.Sprintf("ttl-%d", id) + grp := core.Sprintf("ttl-%d", id) for i := range ops { - key := fmt.Sprintf("k%d", i) + key := core.Sprintf("k%d", i) if i%2 == 0 { _ = s.SetWithTTL(grp, key, "v", 50*time.Millisecond) } else { @@ -995,7 +993,7 @@ func TestConcurrent_Good_TTL(t *testing.T) { time.Sleep(60 * time.Millisecond) for g := range goroutines { - grp := fmt.Sprintf("ttl-%d", g) + grp := core.Sprintf("ttl-%d", g) n, err := s.Count(grp) require.NoError(t, err) assert.Equal(t, ops/2, n, "only non-TTL keys should remain in %s", grp)