package browse
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// tableHash is a helper for the common "the table must exist here" case.
func tableHash(t *testing.T, db *DB, ctx context.Context, refStr, table string) string {
t.Helper()
h, ok, err := db.TableHash(ctx, refStr, table)
require.NoError(t, err)
require.True(t, ok, "table %q must exist at %q", table, refStr)
require.NotEmpty(t, h)
return h
}
func TestTableHashStable(t *testing.T) {
db := openFixture(t)
ctx := context.Background()
first := tableHash(t, db, ctx, "main", "users")
second := tableHash(t, db, ctx, "main", "users")
assert.Equal(t, first, second, "the same table at the same ref must hash the same")
// A branch and the commit hash it points at are the same root, so they must
// produce the same table hash. dev's head is C2.
byBranch := tableHash(t, db, ctx, "dev", "users")
byCommit := tableHash(t, db, ctx, commitHash(t, msgInsert), "users")
assert.Equal(t, byBranch, byCommit, "branch and its head commit must agree")
}
// TestTableHashDetectsChange is the property the whole history walk rests on:
// the hash changes exactly when the table does.
func TestTableHashDetectsChange(t *testing.T) {
db := openFixture(t)
ctx := context.Background()
atInsert := tableHash(t, db, ctx, commitHash(t, msgInsert), "users") // C2
atModify := tableHash(t, db, ctx, commitHash(t, msgModify), "users") // C3: rows changed
atAddItem := tableHash(t, db, ctx, commitHash(t, msgAddItem), "users")
assert.NotEqual(t, atInsert, atModify, "C3 changed users rows, hash must differ")
// C4 created items and docs and left users alone: a walk must be able to
// skip it without reading a row.
assert.Equal(t, atAddItem, atModify, "C4 did not touch users, hash must be unchanged")
}
func TestTableHashMissingTable(t *testing.T) {
db := openFixture(t)
ctx := context.Background()
// items is created by C4, so it does not exist at C2 — an ordinary answer
// for a backwards walk, not an error.
h, ok, err := db.TableHash(ctx, commitHash(t, msgInsert), "items")
require.NoError(t, err)
assert.False(t, ok)
assert.Empty(t, h)
// A table that never existed behaves the same way.
h, ok, err = db.TableHash(ctx, "main", "no-such-table")
require.NoError(t, err)
assert.False(t, ok)
assert.Empty(t, h)
}
func TestTableHashRefNotFound(t *testing.T) {
db := openFixture(t)
ctx := context.Background()
_, ok, err := db.TableHash(ctx, "no-such-ref", "users")
require.ErrorIs(t, err, ErrRefNotFound)
assert.False(t, ok)
}
func TestTableHashDistinctTables(t *testing.T) {
db := openFixture(t)
ctx := context.Background()
users := tableHash(t, db, ctx, "main", "users")
items := tableHash(t, db, ctx, "main", "items")
docs := tableHash(t, db, ctx, "main", "docs")
assert.NotEqual(t, users, items)
assert.NotEqual(t, users, docs)
assert.NotEqual(t, items, docs, "an empty table must not collide with another table")
}