Files
BoostAI/Backend/internal/assignmentgen/personalization_test.go
2026-05-25 17:05:06 +01:00

86 lines
2.8 KiB
Go

package assignmentgen
import (
"fmt"
"testing"
"boostai-backend/internal/sqlc"
"github.com/jackc/pgx/v5/pgtype"
)
func TestBuildWeaknessSummaryAggregatesSignals(t *testing.T) {
rows := []sqlc.ListStudentPlanningPerformanceRow{
{
Topic: sqlc.NullQuestionTopic{QuestionTopic: sqlc.QuestionTopicFractions, Valid: true},
QuestionTags: []string{"fractions", "simplify"},
IsCorrect: pgtype.Bool{Bool: false, Valid: true},
ReviewUnderstandingScore: mustNumeric(t, 0.2),
ReviewNeedsAttention: true,
ReviewIssueReason: pgtype.Text{String: "Missed simplification", Valid: true},
},
{
Topic: sqlc.NullQuestionTopic{QuestionTopic: sqlc.QuestionTopicGeometry, Valid: true},
QuestionTags: []string{"geometry", "angles"},
IsCorrect: pgtype.Bool{Bool: true, Valid: true},
ReviewUnderstandingScore: mustNumeric(t, 0.9),
ReviewIssueReason: pgtype.Text{String: "Explained angle sum well", Valid: true},
},
}
summary := buildWeaknessSummary(rows)
if got := summary.TopicScores[sqlc.QuestionTopicFractions]; got != 10 {
t.Fatalf("expected fractions score 10, got %v", got)
}
if got := summary.TopicScores[sqlc.QuestionTopicGeometry]; got != 95 {
t.Fatalf("expected geometry score 95, got %v", got)
}
if len(summary.WeakTags) == 0 || summary.WeakTags[0] != "fractions" {
t.Fatalf("expected fractions weak tag to rank first, got %#v", summary.WeakTags)
}
if len(summary.RecentIssues) != 2 {
t.Fatalf("expected 2 recent issues, got %d", len(summary.RecentIssues))
}
}
func TestSelectPersonalizedTopicPrefersWeakestNonPrimary(t *testing.T) {
summary := WeaknessSummary{
TopicScores: map[sqlc.QuestionTopic]float64{
sqlc.QuestionTopicFractions: 35,
sqlc.QuestionTopicGeometry: 82,
sqlc.QuestionTopicAlgebra: 61,
},
}
topic, ok := selectPersonalizedTopic(sqlc.QuestionTopicGeometry, summary)
if !ok {
t.Fatal("expected personalized topic to be selected")
}
if topic != sqlc.QuestionTopicFractions {
t.Fatalf("expected fractions, got %q", topic)
}
}
func TestCalculatePersonalizedCountUsesSafeSplit(t *testing.T) {
if got := calculatePersonalizedCount(10, 0.3, true); got != 3 {
t.Fatalf("expected 3 personalized questions, got %d", got)
}
if got := calculatePersonalizedCount(2, 0.3, true); got != 0 {
t.Fatalf("expected 0 personalized questions for tiny set, got %d", got)
}
if got := calculatePersonalizedCount(5, 0.3, false); got != 0 {
t.Fatalf("expected 0 personalized questions without weakness topic, got %d", got)
}
}
func mustNumeric(t *testing.T, value float64) pgtype.Numeric {
t.Helper()
var numeric pgtype.Numeric
if err := numeric.ScanScientific(fmt.Sprintf("%f", value)); err != nil {
t.Fatalf("failed to build numeric: %v", err)
}
return numeric
}