package index
import (
"sort"
"strings"
"testing"
)
// #263: a tip move rewrites only the files that changed. Whatever it
// skips, the rows and the full-text index read exactly as if the tree
// had been written from scratch: an unchanged file is found at the new
// tip, a changed one by its new words and not its old, a new one is
// found, a removed one is not, and the FTS index is consistent.
func TestATreeMoveRewritesOnlyWhatChanged(t *testing.T) {
ix := openIndex(t)
if err := ix.ReplaceTree("v1", []TreeText{
{Path: "keep.go", Body: "steady alpaca"},
{Path: "edit.go", Body: "old wombat"},
{Path: "gone.go", Body: "doomed narwhal"},
{Path: "README.md", Body: "intro", Doc: true},
}); err != nil {
t.Fatal(err)
}
if err := ix.ReplaceTree("v2", []TreeText{
{Path: "keep.go", Body: "steady alpaca"},
{Path: "edit.go", Body: "new quokka"},
{Path: "added.go", Body: "fresh okapi"},
{Path: "README.md", Body: "intro", Doc: true},
}); err != nil {
t.Fatal(err)
}
refs := func(q string) []string {
t.Helper()
rs, err := ix.Search(q, "", 20)
if err != nil {
t.Fatal(err)
}
var out []string
for _, r := range rs {
out = append(out, r.Ref)
}
sort.Strings(out)
return out
}
for q, want := range map[string]string{
"alpaca": "v2/keep.go", "quokka": "v2/edit.go", "okapi": "v2/added.go", "intro": "v2/README.md",
"wombat": "", "narwhal": "",
} {
got := strings.Join(refs(q), " ")
if got != want {
t.Errorf("FAIL: %q finds %q, want %q", q, got, want)
}
}
if _, err := ix.db.Exec(`INSERT INTO search_fts (search_fts) VALUES ('integrity-check')`); err != nil {
t.Errorf("FAIL: the full-text index disagrees with its rows: %v", err)
}
var trig string
ix.db.QueryRow(`SELECT sql FROM sqlite_master WHERE name = 'search_doc_au'`).Scan(&trig)
if !strings.Contains(trig, "UPDATE OF text") {
t.Errorf("FAIL: the update trigger still fires on any column: %s", trig)
}
}
// An index made before the narrowed trigger has it replaced on open.
func TestAnOldSearchUpdateTriggerIsReplacedOnOpen(t *testing.T) {
path := t.TempDir() + "/index.db"
ix, err := Open(path)
if err != nil {
t.Fatal(err)
}
if _, err := ix.w.Exec(`DROP TRIGGER search_doc_au;
CREATE TRIGGER search_doc_au AFTER UPDATE ON search_doc BEGIN
INSERT INTO search_fts (search_fts, rowid, text) VALUES ('delete', old.rowid, old.text);
INSERT INTO search_fts (rowid, text) VALUES (new.rowid, new.text);
END;`); err != nil {
t.Fatal(err)
}
ix.Close()
ix, err = Open(path)
if err != nil {
t.Fatal(err)
}
defer ix.Close()
var trig string
ix.db.QueryRow(`SELECT sql FROM sqlite_master WHERE name = 'search_doc_au'`).Scan(&trig)
if !strings.Contains(trig, "UPDATE OF text") {
t.Errorf("FAIL: reopening kept the old trigger: %s", trig)
}
}