// Copyright 2026 tamakyi. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package db import ( "context" "testing" "time" "github.com/stretchr/testify/require" ) // TestBoxTrendAnswerByAnsweredDate 验证「每日回答数」按 answered_at 分组, // 而不是按 created_at。 // // 背景:BoxTrend 一度两条 SQL 都复用 created_at 的日期表达式,导致「40 天前创建、 // 昨天才回答」的提问被排除在窗口外(created_at < from),昨天/今天的回答数里 // 根本不出现;「今天创建、明天回答」的又会被记到今天。本测试构造一条 // 「创建日远早于窗口、回答日落在窗口内」的提问,断言它出现在回答日那天。 func TestBoxTrendAnswerByAnsweredDate(t *testing.T) { db, cleanup := newTestDB(t) ctx := context.Background() store := NewBoxAnalyticsStore(db) t.Cleanup(func() { _ = cleanup("questions") }) now := time.Now() // 窗口 = 最近 7 天 from := now.AddDate(0, 0, -6) to := now // 一条 40 天前创建、昨天才回答的提问 answeredAt := now.AddDate(0, 0, -1) createdAt := now.AddDate(0, 0, -40) q := &Question{ UserID: 9, Content: "很久以前问的,昨天才回答", Answer: "这是回答", AnsweredAt: &answeredAt, } // 直接写 created_at / answered_at,绕过 Create 的自动时间戳 require.NoError(t, db.Model(&Question{}).Create(q).Error) require.NoError(t, db.Model(&Question{}).Where("id = ?", q.ID). Updates(map[string]interface{}{ "created_at": createdAt, "answered_at": answeredAt, "updated_at": answeredAt, }).Error) trend, err := store.BoxTrend(ctx, 9, from, to) require.NoError(t, err) // 找到回答日那天(昨天)的计数,答案数应 >= 1 var found bool for _, d := range trend { if d.Day.Year() == answeredAt.Year() && d.Day.Month() == answeredAt.Month() && d.Day.Day() == answeredAt.Day() { require.GreaterOrEqual(t, d.Answers, int64(1), "回答应计入 answered_at 那一天,而不是按 created_at 被排除") found = true } // 创建日(40 天前)不应出现在窗口内 if d.Day.Year() == createdAt.Year() && d.Day.Month() == createdAt.Month() && d.Day.Day() == createdAt.Day() { t.Errorf("创建日在窗口外,不应出现在趋势里") } } require.True(t, found, "回答日应出现在趋势结果里") }