summaryrefslogtreecommitdiff
path: root/internal/store/store_test.go
blob: 02da88311fc7ce75d45fed82660e06f31c3f0f36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package store_test

import (
	"os"
	"path/filepath"
	"testing"

	"codeberg.org/snonux/totalrecall/internal/store"
)

// TestFindCardDirectory verifies that FindCardDirectory locates a directory by
// its word.txt content and returns an empty string when no match exists.
func TestFindCardDirectory(t *testing.T) {
	tmpDir := t.TempDir()

	// Create a card directory with a word file.
	cardDir := filepath.Join(tmpDir, "someCardID")
	if err := os.MkdirAll(cardDir, 0755); err != nil {
		t.Fatalf("setup: %v", err)
	}
	if err := os.WriteFile(filepath.Join(cardDir, "word.txt"), []byte("котка"), 0644); err != nil {
		t.Fatalf("setup: %v", err)
	}

	tests := []struct {
		name    string
		word    string
		wantDir string // empty means expect ""
		wantHit bool
	}{
		{
			name:    "existing word found",
			word:    "котка",
			wantDir: cardDir,
			wantHit: true,
		},
		{
			name:    "unknown word returns empty string",
			word:    "куче",
			wantDir: "",
			wantHit: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := store.FindCardDirectory(tmpDir, tt.word)
			if tt.wantHit && got != tt.wantDir {
				t.Errorf("FindCardDirectory(%q) = %q; want %q", tt.word, got, tt.wantDir)
			}
			if !tt.wantHit && got != "" {
				t.Errorf("FindCardDirectory(%q) = %q; want empty string", tt.word, got)
			}
		})
	}
}

// TestFindCardDirectoryLegacyFallback checks that the legacy _word.txt naming
// convention is still supported for backward compatibility.
func TestFindCardDirectoryLegacyFallback(t *testing.T) {
	tmpDir := t.TempDir()

	// Create a card directory with the old _word.txt naming.
	cardDir := filepath.Join(tmpDir, "legacyCardID")
	if err := os.MkdirAll(cardDir, 0755); err != nil {
		t.Fatalf("setup: %v", err)
	}
	if err := os.WriteFile(filepath.Join(cardDir, "_word.txt"), []byte("ябълка"), 0644); err != nil {
		t.Fatalf("setup: %v", err)
	}

	got := store.FindCardDirectory(tmpDir, "ябълка")
	if got != cardDir {
		t.Errorf("FindCardDirectory (legacy) = %q; want %q", got, cardDir)
	}
}

// TestFindOrCreateCardDirectory verifies that a new directory is created when
// no matching one exists, and that the same directory is returned on a second
// call for the same word.
func TestFindOrCreateCardDirectory(t *testing.T) {
	tmpDir := t.TempDir()

	// First call: directory does not exist yet.
	dir1 := store.FindOrCreateCardDirectory(tmpDir, "хляб")
	if dir1 == "" || dir1 == tmpDir {
		t.Fatalf("expected a new card directory, got %q", dir1)
	}

	// word.txt must have been written.
	data, err := os.ReadFile(filepath.Join(dir1, "word.txt"))
	if err != nil {
		t.Fatalf("word.txt not created: %v", err)
	}
	if string(data) != "хляб" {
		t.Errorf("word.txt content = %q; want %q", string(data), "хляб")
	}

	// Second call: must return the same directory.
	dir2 := store.FindOrCreateCardDirectory(tmpDir, "хляб")
	if dir2 != dir1 {
		t.Errorf("second call returned %q; want %q", dir2, dir1)
	}
}

// TestCardStoreScanWords verifies that ScanWords returns only words from
// directories that pass the predicate and ignores hidden directories.
func TestCardStoreScanWords(t *testing.T) {
	tmpDir := t.TempDir()

	// Helper: create a card directory with word.txt.
	makeCard := func(id, word string) string {
		cardDir := filepath.Join(tmpDir, id)
		_ = os.MkdirAll(cardDir, 0755)
		_ = os.WriteFile(filepath.Join(cardDir, "word.txt"), []byte(word), 0644)
		return cardDir
	}

	dir1 := makeCard("card1", "котка")
	makeCard("card2", "куче")

	// Hidden directory must be skipped.
	makeCard(".hidden", "hidden")

	// ScanWords with a predicate that only passes dir1.
	cs := store.New(tmpDir)
	words := cs.ScanWords(func(wordDir string) bool {
		return wordDir == dir1
	})

	if len(words) != 1 || words[0] != "котка" {
		t.Errorf("ScanWords = %v; want [котка]", words)
	}

	// ScanWords with nil predicate must return all non-hidden words.
	allWords := cs.ScanWords(nil)
	if len(allWords) != 2 {
		t.Errorf("ScanWords(nil) = %v; want 2 words", allWords)
	}
}

func TestCardStoreListCardDirectories(t *testing.T) {
	tmpDir := t.TempDir()

	makeCard := func(id, word string) string {
		cardDir := filepath.Join(tmpDir, id)
		_ = os.MkdirAll(cardDir, 0755)
		_ = os.WriteFile(filepath.Join(cardDir, "word.txt"), []byte(word), 0644)
		return cardDir
	}

	card2 := makeCard("card2", "куче")
	makeCard("card1", "котка")
	makeCard(".hidden", "hidden")

	cs := store.New(tmpDir)
	cards := cs.ListCardDirectories(func(wordDir string) bool {
		return wordDir != card2
	})

	if len(cards) != 1 {
		t.Fatalf("ListCardDirectories() returned %d cards, want 1", len(cards))
	}
	if cards[0].Word != "котка" {
		t.Fatalf("ListCardDirectories()[0].Word = %q, want %q", cards[0].Word, "котка")
	}
	if filepath.Base(cards[0].Path) != "card1" {
		t.Fatalf("ListCardDirectories()[0].Path = %q, want base %q", cards[0].Path, "card1")
	}
}