86 lines
2.8 KiB
Go
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
|
|
}
|