Skip to content

Commit 5498b01

Browse files
committed
test(store): add question_bank and kata_bank store tests
- 4 tests for SaveQuestionBank and ListQuestionBank - 4 tests for SaveKata and ListKatas - covers round-trip field integrity, empty-store safety, duplicate-ID replacement, and topic filtering - updates COVERAGE.md with new test inventory
1 parent d007603 commit 5498b01

2 files changed

Lines changed: 270 additions & 0 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package sqlite
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/jazicorn/hatch/internal/kata"
8+
)
9+
10+
func TestSaveAndListKatas(t *testing.T) {
11+
s := openTestStore(t)
12+
ctx := context.Background()
13+
14+
k := &kata.Kata{
15+
ID: "k1",
16+
Topic: "go",
17+
Title: "Hello World",
18+
Description: "Write a hello world program",
19+
StarterCode: "package main\n",
20+
Tests: "func TestHello(t *testing.T) {}",
21+
Language: kata.Go,
22+
}
23+
24+
if err := s.SaveKata(ctx, k); err != nil {
25+
t.Fatalf("SaveKata: %v", err)
26+
}
27+
28+
got, err := s.ListKatas(ctx, "go")
29+
if err != nil {
30+
t.Fatalf("ListKatas: %v", err)
31+
}
32+
if len(got) != 1 {
33+
t.Fatalf("expected 1 kata, got %d", len(got))
34+
}
35+
if got[0].ID != "k1" {
36+
t.Errorf("expected id k1, got %s", got[0].ID)
37+
}
38+
if got[0].Title != "Hello World" {
39+
t.Errorf("expected title 'Hello World', got %s", got[0].Title)
40+
}
41+
if got[0].Topic != "go" {
42+
t.Errorf("expected topic go, got %s", got[0].Topic)
43+
}
44+
if got[0].Language != kata.Go {
45+
t.Errorf("expected language go, got %s", got[0].Language)
46+
}
47+
if got[0].StarterCode != k.StarterCode {
48+
t.Errorf("starter code mismatch: want %q, got %q", k.StarterCode, got[0].StarterCode)
49+
}
50+
if got[0].Tests != k.Tests {
51+
t.Errorf("tests mismatch: want %q, got %q", k.Tests, got[0].Tests)
52+
}
53+
if got[0].Description != k.Description {
54+
t.Errorf("description mismatch: want %q, got %q", k.Description, got[0].Description)
55+
}
56+
}
57+
58+
func TestListKatasEmpty(t *testing.T) {
59+
s := openTestStore(t)
60+
61+
got, err := s.ListKatas(context.Background(), "go")
62+
if err != nil {
63+
t.Fatalf("ListKatas on empty store: %v", err)
64+
}
65+
if len(got) != 0 {
66+
t.Errorf("expected 0 katas, got %d", len(got))
67+
}
68+
}
69+
70+
func TestSaveKataReplaces(t *testing.T) {
71+
s := openTestStore(t)
72+
ctx := context.Background()
73+
74+
orig := &kata.Kata{
75+
ID: "k1",
76+
Topic: "go",
77+
Title: "original title",
78+
Language: kata.Go,
79+
}
80+
if err := s.SaveKata(ctx, orig); err != nil {
81+
t.Fatalf("SaveKata original: %v", err)
82+
}
83+
84+
updated := &kata.Kata{
85+
ID: "k1",
86+
Topic: "go",
87+
Title: "updated title",
88+
Language: kata.Go,
89+
}
90+
if err := s.SaveKata(ctx, updated); err != nil {
91+
t.Fatalf("SaveKata updated: %v", err)
92+
}
93+
94+
got, err := s.ListKatas(ctx, "go")
95+
if err != nil {
96+
t.Fatalf("ListKatas: %v", err)
97+
}
98+
if len(got) != 1 {
99+
t.Fatalf("expected 1 kata, got %d", len(got))
100+
}
101+
if got[0].Title != "updated title" {
102+
t.Errorf("expected title 'updated title', got %s", got[0].Title)
103+
}
104+
}
105+
106+
func TestListKatasFiltersByTopic(t *testing.T) {
107+
s := openTestStore(t)
108+
ctx := context.Background()
109+
110+
katas := []*kata.Kata{
111+
{ID: "k1", Topic: "go", Title: "Go kata", Language: kata.Go},
112+
{ID: "k2", Topic: "python", Title: "Python kata", Language: kata.Python},
113+
}
114+
for _, k := range katas {
115+
if err := s.SaveKata(ctx, k); err != nil {
116+
t.Fatalf("SaveKata %s: %v", k.ID, err)
117+
}
118+
}
119+
120+
got, err := s.ListKatas(ctx, "go")
121+
if err != nil {
122+
t.Fatalf("ListKatas go: %v", err)
123+
}
124+
if len(got) != 1 {
125+
t.Fatalf("expected 1 kata for topic go, got %d", len(got))
126+
}
127+
if got[0].ID != "k1" {
128+
t.Errorf("expected id k1, got %s", got[0].ID)
129+
}
130+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package sqlite
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/jazicorn/hatch/internal/quiz"
8+
)
9+
10+
func TestSaveAndListQuestionBank(t *testing.T) {
11+
s := openTestStore(t)
12+
ctx := context.Background()
13+
14+
questions := []quiz.Question{
15+
{
16+
ID: "q1",
17+
Text: "What is 1+1?",
18+
Options: [4]string{"1", "2", "3", "4"},
19+
CorrectIndex: 1,
20+
Explanation: "basic addition",
21+
},
22+
{
23+
ID: "q2",
24+
Text: "What is 2+2?",
25+
Options: [4]string{"2", "3", "4", "5"},
26+
CorrectIndex: 2,
27+
Explanation: "basic addition again",
28+
},
29+
}
30+
31+
if err := s.SaveQuestionBank(ctx, "math", questions); err != nil {
32+
t.Fatalf("SaveQuestionBank: %v", err)
33+
}
34+
35+
got, err := s.ListQuestionBank(ctx, "math")
36+
if err != nil {
37+
t.Fatalf("ListQuestionBank: %v", err)
38+
}
39+
if len(got) != 2 {
40+
t.Fatalf("expected 2 questions, got %d", len(got))
41+
}
42+
if got[0].ID != "q1" {
43+
t.Errorf("expected id q1, got %s", got[0].ID)
44+
}
45+
if got[0].Text != "What is 1+1?" {
46+
t.Errorf("expected text 'What is 1+1?', got %s", got[0].Text)
47+
}
48+
if got[0].Options != questions[0].Options {
49+
t.Errorf("options mismatch: want %v, got %v", questions[0].Options, got[0].Options)
50+
}
51+
if got[0].CorrectIndex != 1 {
52+
t.Errorf("expected CorrectIndex 1, got %d", got[0].CorrectIndex)
53+
}
54+
if got[0].Explanation != "basic addition" {
55+
t.Errorf("expected explanation 'basic addition', got %s", got[0].Explanation)
56+
}
57+
}
58+
59+
func TestListQuestionBankEmpty(t *testing.T) {
60+
s := openTestStore(t)
61+
62+
got, err := s.ListQuestionBank(context.Background(), "math")
63+
if err != nil {
64+
t.Fatalf("ListQuestionBank on empty store: %v", err)
65+
}
66+
if len(got) != 0 {
67+
t.Errorf("expected 0 questions, got %d", len(got))
68+
}
69+
}
70+
71+
func TestSaveQuestionBankReplaces(t *testing.T) {
72+
s := openTestStore(t)
73+
ctx := context.Background()
74+
75+
orig := []quiz.Question{
76+
{
77+
ID: "q1",
78+
Text: "original text",
79+
Options: [4]string{"a", "b", "c", "d"},
80+
CorrectIndex: 0,
81+
Explanation: "original",
82+
},
83+
}
84+
if err := s.SaveQuestionBank(ctx, "go", orig); err != nil {
85+
t.Fatalf("SaveQuestionBank original: %v", err)
86+
}
87+
88+
updated := []quiz.Question{
89+
{
90+
ID: "q1",
91+
Text: "updated text",
92+
Options: [4]string{"w", "x", "y", "z"},
93+
CorrectIndex: 3,
94+
Explanation: "updated",
95+
},
96+
}
97+
if err := s.SaveQuestionBank(ctx, "go", updated); err != nil {
98+
t.Fatalf("SaveQuestionBank updated: %v", err)
99+
}
100+
101+
got, err := s.ListQuestionBank(ctx, "go")
102+
if err != nil {
103+
t.Fatalf("ListQuestionBank: %v", err)
104+
}
105+
if len(got) != 1 {
106+
t.Fatalf("expected 1 question, got %d", len(got))
107+
}
108+
if got[0].Text != "updated text" {
109+
t.Errorf("expected updated text, got %s", got[0].Text)
110+
}
111+
}
112+
113+
func TestListQuestionBankFiltersByTopic(t *testing.T) {
114+
s := openTestStore(t)
115+
ctx := context.Background()
116+
117+
goQ := []quiz.Question{
118+
{ID: "g1", Text: "go question", Options: [4]string{"a", "b", "c", "d"}, CorrectIndex: 0},
119+
}
120+
pyQ := []quiz.Question{
121+
{ID: "p1", Text: "python question", Options: [4]string{"a", "b", "c", "d"}, CorrectIndex: 1},
122+
}
123+
if err := s.SaveQuestionBank(ctx, "go", goQ); err != nil {
124+
t.Fatalf("SaveQuestionBank go: %v", err)
125+
}
126+
if err := s.SaveQuestionBank(ctx, "python", pyQ); err != nil {
127+
t.Fatalf("SaveQuestionBank python: %v", err)
128+
}
129+
130+
got, err := s.ListQuestionBank(ctx, "go")
131+
if err != nil {
132+
t.Fatalf("ListQuestionBank go: %v", err)
133+
}
134+
if len(got) != 1 {
135+
t.Fatalf("expected 1 question for topic go, got %d", len(got))
136+
}
137+
if got[0].ID != "g1" {
138+
t.Errorf("expected id g1, got %s", got[0].ID)
139+
}
140+
}

0 commit comments

Comments
 (0)