package oltp
import "testing"
func TestModerationGate(t *testing.T) {
db := testDB(t)
if db.ModerationEnabled("r") {
t.Fatal("moderation on by default")
}
if err := db.SetModeration("r", true); err != nil {
t.Fatal(err)
}
if !db.ModerationEnabled("r") || db.ModerationEnabled("other") {
t.Fatal("gate scope wrong")
}
id, err := db.StagePost("r", "post", "", "Hi", "body", "text/x-markdown", "eve")
if err != nil {
t.Fatal(err)
}
pending, err := db.StagedPending("r")
if err != nil || len(pending) != 1 || pending[0].Author != "eve" {
t.Fatalf("pending = %v err=%v", pending, err)
}
// Two moderators race: exactly one resolution wins.
if err := db.ResolveStaged("r", id, "approved"); err != nil {
t.Fatal(err)
}
if err := db.ResolveStaged("r", id, "rejected"); err == nil {
t.Fatal("double resolution accepted")
}
if pending, _ := db.StagedPending("r"); len(pending) != 0 {
t.Fatalf("resolved entry still pending: %v", pending)
}
// The hook verdict is advisory data on the row.
id2, _ := db.StagePost("r", "reply", "roothash", "", "spam?", "", "mallory")
if err := db.SetStagedAI("r", id2, "reject", 0.97, "link farm"); err != nil {
t.Fatal(err)
}
if s, ok, _ := db.StagedByID("r", id2); !ok || s.AIAction != "reject" || s.AIScore != 0.97 {
t.Fatalf("verdict lost: %+v", s)
}
}
func TestModLogAppendsAndHiddenPosts(t *testing.T) {
db := testDB(t)
must := func(err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
must(db.AppendModLog("r", "dan", "reject", "staged:4", "spam", "jan"))
must(db.AppendModLog("r", "hook", "ai-hold", "staged:5", "uncertain", "jan"))
log, err := db.ModLog("r", 10)
if err != nil || len(log) != 2 {
t.Fatalf("log = %v err=%v", log, err)
}
if log[0].Actor != "hook" || log[1].Action != "reject" {
t.Fatalf("order/content: %v", log)
}
must(db.HidePost("r", "posthash", "flamebait", "dan"))
if h, _ := db.HiddenPosts("r"); h["posthash"] != "flamebait" {
t.Fatalf("hidden = %v", h)
}
must(db.UnhidePost("r", "posthash"))
if h, _ := db.HiddenPosts("r"); len(h) != 0 {
t.Fatalf("unhide left state: %v", h)
}
}
func TestPurgeRepoSweepsModeration(t *testing.T) {
db := testDB(t)
db.SetModeration("gone", true)
db.StagePost("gone", "post", "", "t", "b", "", "eve")
db.AppendModLog("gone", "dan", "approve", "staged:1", "", "jan")
db.HidePost("gone", "p", "r", "dan")
if err := db.PurgeRepo("gone"); err != nil {
t.Fatal(err)
}
if db.ModerationEnabled("gone") {
t.Fatal("gate survived purge")
}
if p, _ := db.StagedPending("gone"); len(p) != 0 {
t.Fatal("staged survived purge")
}
if l, _ := db.ModLog("gone", 10); len(l) != 0 {
t.Fatal("log survived purge")
}
if h, _ := db.HiddenPosts("gone"); len(h) != 0 {
t.Fatal("hidden survived purge")
}
}
func TestForumSubscriptions(t *testing.T) {
db := testDB(t)
must := func(err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
// Authoring auto-subscribes...
must(db.AutoSubscribe("r", "alice", "t1"))
if subs, _ := db.ForumSubscribers("r", "t1"); len(subs) != 1 || subs[0] != "alice" {
t.Fatalf("subs = %v", subs)
}
// ...but an explicit unsubscribe outranks every later auto-sub.
must(db.SetForumSub("r", "alice", "t1", "unsub"))
must(db.AutoSubscribe("r", "alice", "t1"))
if subs, _ := db.ForumSubscribers("r", "t1"); len(subs) != 0 {
t.Fatalf("auto-sub overrode explicit unsub: %v", subs)
}
if db.ForumSubState("r", "alice", "t1") != "unsub" {
t.Fatal("state lost")
}
// An explicit re-subscribe works, of course.
must(db.SetForumSub("r", "alice", "t1", "sub"))
if subs, _ := db.ForumSubscribers("r", "t1"); len(subs) != 1 {
t.Fatalf("resubscribe failed: %v", subs)
}
if db.ForumSubState("r", "", "t1") != "" {
t.Fatal("anonymous has sub state")
}
}
func TestPurgeRepoSweepsSubs(t *testing.T) {
db := testDB(t)
db.AutoSubscribe("gone", "alice", "t1")
if err := db.PurgeRepo("gone"); err != nil {
t.Fatal(err)
}
if subs, _ := db.ForumSubscribers("gone", "t1"); len(subs) != 0 {
t.Fatal("subs survived purge")
}
}