golib/database/csvdb/file_test.go

146 lines
3.4 KiB
Go

package csvdb
import (
"context"
"os"
"testing"
"github.com/therootcompany/golib/database/csvx"
)
func TestFileRoundtrip(t *testing.T) {
root, err := os.OpenRoot(t.TempDir())
if err != nil {
t.Fatal(err)
}
defer func() { _ = root.Close() }()
f := &Store[testRuleRow]{Root: root, Name: "test.tsv", Format: "tsv"}
ctx := context.Background()
if _, err := f.Init(ctx); err != nil {
t.Fatal(err)
}
rows := []testRuleRow{
{Email: "a@example.com"},
{Email: "b@example.com"},
}
if err := f.WriteAll(ctx, rows); err != nil {
t.Fatal(err)
}
got, err := f.Fetch(ctx)
if err != nil {
t.Fatal(err)
}
if len(got) != 2 {
t.Fatalf("got %d rows, want 2", len(got))
}
if got[0].Email != "a@example.com" || got[1].Email != "b@example.com" {
t.Fatalf("unexpected rows: %v", got)
}
}
func TestFileNormalizeHook(t *testing.T) {
root, err := os.OpenRoot(t.TempDir())
if err != nil {
t.Fatal(err)
}
defer func() { _ = root.Close() }()
f := &Store[identityRow]{
Root: root,
Name: "identities.tsv",
Format: "tsv",
Normalize: func(rows []identityRow) {
for i := range rows {
if rows[i].Email.Valid {
rows[i].Email.String = csvx.NormalizeEmail(rows[i].Email.String)
}
if rows[i].Phone.Valid {
rows[i].Phone.String = csvx.NormalizePhone(rows[i].Phone.String)
}
}
},
}
ctx := context.Background()
rows := []identityRow{{
Email: csvx.Text{String: " USER@Example.COM ", Valid: true},
Phone: csvx.Text{String: "+1 (415) 555-0123", Valid: true},
}}
if err := f.WriteAll(ctx, rows); err != nil {
t.Fatal(err)
}
got, err := f.Fetch(ctx)
if err != nil {
t.Fatal(err)
}
if len(got) != 1 || got[0].Email.String != "user@example.com" || got[0].Phone.String != "(415) 555-0123" {
t.Fatalf("contacts = %#v", got)
}
}
func TestFileFetchSkipsComments(t *testing.T) {
root, err := os.OpenRoot(t.TempDir())
if err != nil {
t.Fatal(err)
}
defer func() { _ = root.Close() }()
content := "# beginner note\nemail\trevoked_at\texpires_at\nuser@example.com\t\t\n"
if err := root.WriteFile("comments.tsv", []byte(content), 0600); err != nil {
t.Fatal(err)
}
f := &Store[testRuleRow]{Root: root, Name: "comments.tsv", Format: "tsv"}
got, err := f.Fetch(context.Background())
if err != nil {
t.Fatal(err)
}
if len(got) != 1 || got[0].Email != "user@example.com" {
t.Fatalf("got %#v, want one parsed row", got)
}
}
func TestFileFetchMissing(t *testing.T) {
root, err := os.OpenRoot(t.TempDir())
if err != nil {
t.Fatal(err)
}
defer func() { _ = root.Close() }()
f := &Store[testRuleRow]{Root: root, Name: "missing.tsv", Format: "tsv"}
got, err := f.Fetch(context.Background())
if err != nil {
t.Fatal(err)
}
if len(got) != 0 {
t.Fatalf("got %d rows, want 0", len(got))
}
}
func TestFileAtomicWrite(t *testing.T) {
dir := t.TempDir()
root, err := os.OpenRoot(dir)
if err != nil {
t.Fatal(err)
}
defer func() { _ = root.Close() }()
f := &Store[testRuleRow]{Root: root, Name: "test.tsv", Format: "tsv"}
ctx := context.Background()
if _, err := f.Init(ctx); err != nil {
t.Fatal(err)
}
rows := []testRuleRow{{Email: "x@example.com"}}
for range 5 {
if err := f.WriteAll(ctx, rows); err != nil {
t.Fatal(err)
}
}
info, err := root.Stat("test.tsv")
if err != nil {
t.Fatal(err)
}
if info.Size() == 0 {
t.Fatal("file is empty after writes")
}
entries, _ := os.ReadDir(dir)
if len(entries) != 1 {
t.Fatalf("expected 1 file in dir, got %d (temp files not cleaned up?)", len(entries))
}
}