package learning import ( "context" "encoding/json" "testing" "github.com/gooseek/backend/internal/db" "github.com/gooseek/backend/internal/llm" ) func TestBuildPersonalPlanAppliesDefaults(t *testing.T) { course := &db.LearningCourse{ Title: "Go Backend", ShortDescription: "Курс по backend-разработке на Go", Difficulty: "intermediate", DurationHours: 24, BaseOutline: json.RawMessage(`{"modules":[{"index":0,"title":"base","description":"base","skills":["go"],"estimated_hours":4,"practice_focus":"api"}]}`), } client := &mockLLMClient{ generateFunc: func(ctx context.Context, req llm.StreamRequest) (string, error) { return `{ "modules": [ {"index": 999, "title": "API design", "description": "design REST", "skills": ["http"], "estimated_hours": 6, "practice_focus": "build handlers", "task_count": 0}, {"index": 999, "title": "DB layer", "description": "storage", "skills": ["sql"], "estimated_hours": 8, "practice_focus": "repository pattern", "task_count": 3} ], "total_hours": 0, "difficulty_adjusted": "intermediate", "personalization_notes": "adapted" }`, nil }, } planJSON, err := BuildPersonalPlan(context.Background(), client, course, `{"level":"junior"}`) if err != nil { t.Fatalf("BuildPersonalPlan error: %v", err) } var plan PersonalPlan if err := json.Unmarshal(planJSON, &plan); err != nil { t.Fatalf("unmarshal plan: %v", err) } if len(plan.Modules) != 2 { t.Fatalf("expected 2 modules, got %d", len(plan.Modules)) } if plan.Modules[0].Index != 0 || plan.Modules[1].Index != 1 { t.Fatalf("module indexes were not normalized: %+v", plan.Modules) } if plan.Modules[0].TaskCount != 2 { t.Fatalf("expected default task_count=2, got %d", plan.Modules[0].TaskCount) } if plan.TotalHours != 14 { t.Fatalf("expected total_hours=14, got %d", plan.TotalHours) } } func TestTruncateStr(t *testing.T) { if got := truncateStr("abc", 5); got != "abc" { t.Fatalf("truncateStr should keep short string, got %q", got) } if got := truncateStr("abcdef", 3); got != "abc..." { t.Fatalf("truncateStr should truncate with ellipsis, got %q", got) } }