package oltp
import "testing"
// Chat read-state advances only forward — a re-read at the same seq
// (or an older one arriving out of order) must not move the pointer
// backward or generate a write.
func TestChatReadAdvancesForwardOnly(t *testing.T) {
db := testDB(t)
if got := db.ChatReadSeq("r", "alice"); got != 0 {
t.Fatalf("unread channel read seq = %d, want 0", got)
}
if err := db.MarkChatRead("r", "alice", 10); err != nil {
t.Fatal(err)
}
if got := db.ChatReadSeq("r", "alice"); got != 10 {
t.Fatalf("read seq = %d, want 10", got)
}
// A revisit with nothing new (or older) does not move the pointer.
if err := db.MarkChatRead("r", "alice", 5); err != nil {
t.Fatal(err)
}
if got := db.ChatReadSeq("r", "alice"); got != 10 {
t.Fatalf("read seq regressed to %d after an older mark, want 10", got)
}
if err := db.MarkChatRead("r", "alice", 10); err != nil {
t.Fatal(err)
}
if got := db.ChatReadSeq("r", "alice"); got != 10 {
t.Fatalf("read seq = %d after a same-seq revisit, want 10", got)
}
// A new message arrives; the pointer only advances on an explicit mark.
if err := db.MarkChatRead("r", "alice", 42); err != nil {
t.Fatal(err)
}
if got := db.ChatReadSeq("r", "alice"); got != 42 {
t.Fatalf("read seq = %d, want 42", got)
}
}
// Read-state is per account and per repo, same isolation as forum_read.
func TestChatReadIsPerAccountAndRepo(t *testing.T) {
db := testDB(t)
if err := db.MarkChatRead("r", "alice", 10); err != nil {
t.Fatal(err)
}
if got := db.ChatReadSeq("r", "bob"); got != 0 {
t.Fatalf("alice's mark leaked to bob: seq = %d, want 0", got)
}
if got := db.ChatReadSeq("other", "alice"); got != 0 {
t.Fatalf("alice's mark leaked across repos: seq = %d, want 0", got)
}
if got := db.ChatReadSeq("r", ""); got != 0 {
t.Fatalf("anonymous read seq = %d, want 0", got)
}
if err := db.MarkChatRead("r", "", 99); err != nil {
t.Fatal(err)
}
if got := db.ChatReadSeq("r", ""); got != 0 {
t.Fatalf("anonymous mark must be a no-op, got seq = %d", got)
}
}
// ChatReadAll answers every repo's pointer for one account in one call.
func TestChatReadAll(t *testing.T) {
db := testDB(t)
if err := db.MarkChatRead("r1", "alice", 5); err != nil {
t.Fatal(err)
}
if err := db.MarkChatRead("r2", "alice", 20); err != nil {
t.Fatal(err)
}
if err := db.MarkChatRead("r1", "bob", 100); err != nil {
t.Fatal(err)
}
all, err := db.ChatReadAll("alice")
if err != nil {
t.Fatal(err)
}
if all["r1"] != 5 || all["r2"] != 20 {
t.Fatalf("ChatReadAll(alice) = %v, want {r1:5, r2:20}", all)
}
if len(all) != 2 {
t.Fatalf("ChatReadAll(alice) leaked another account's repo: %v", all)
}
all, err = db.ChatReadAll("")
if err != nil {
t.Fatal(err)
}
if len(all) != 0 {
t.Fatalf("ChatReadAll(anonymous) = %v, want empty", all)
}
}