summaryrefslogtreecommitdiff
path: root/internal/testutil/mocks.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-20 21:20:40 +0300
committerPaul Buetow <paul@buetow.org>2025-07-20 21:20:40 +0300
commit9e3328a6aaefe4bd1aa0ec3e8bf6e93d6033180b (patch)
treef70a6b53facc81a8bddbe5eeee76708e474e3298 /internal/testutil/mocks.go
parent1afd19206720af695625dd46ff0ded0dedeef329 (diff)
test: add comprehensive test suite for audio and anki packages
- Add tests for audio package (62.8% coverage) - OpenAI provider tests with mocking - Provider interface and fallback mechanism tests - Bulgarian text validation tests - Audio caching functionality tests - Add tests for anki package (84.8% coverage) - CSV generation tests - APKG package generation tests - Card management and formatting tests - Directory scanning and media handling tests - Add test utilities and mocks - Mock implementations for external dependencies - Test helpers for common operations - Utilities for creating test directories and files - Update Taskfile.yaml with comprehensive test targets - test: Run all tests - test-verbose: Run with verbose output - test-coverage: Run with coverage report - test-coverage-html: Generate HTML coverage report - test-race: Run with race detector - test-short: Run only short tests - test-all: Comprehensive suite with coverage and race detection - clean: Remove build artifacts and test files - Fix existing image package tests - Remove tests for non-existent methods - Update tests to match actual implementation - Skip tests requiring live OpenAI API This provides a solid foundation for ensuring code quality and catching regressions. πŸ€– Generated with [opencode](https://opencode.ai) Co-Authored-By: opencode <noreply@opencode.ai>
Diffstat (limited to 'internal/testutil/mocks.go')
-rw-r--r--internal/testutil/mocks.go187
1 files changed, 187 insertions, 0 deletions
diff --git a/internal/testutil/mocks.go b/internal/testutil/mocks.go
new file mode 100644
index 0000000..811b840
--- /dev/null
+++ b/internal/testutil/mocks.go
@@ -0,0 +1,187 @@
+package testutil
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// MockHTTPClient mocks HTTP client for testing
+type MockHTTPClient struct {
+ Responses map[string]*MockResponse
+ Errors map[string]error
+ Calls []string
+}
+
+// MockResponse represents a mocked HTTP response
+type MockResponse struct {
+ StatusCode int
+ Body string
+ Headers map[string]string
+}
+
+// Get mocks an HTTP GET request
+func (m *MockHTTPClient) Get(url string) (*MockResponse, error) {
+ m.Calls = append(m.Calls, fmt.Sprintf("GET %s", url))
+
+ if err, ok := m.Errors[url]; ok {
+ return nil, err
+ }
+
+ if resp, ok := m.Responses[url]; ok {
+ return resp, nil
+ }
+
+ return &MockResponse{
+ StatusCode: 404,
+ Body: "Not Found",
+ }, nil
+}
+
+// Post mocks an HTTP POST request
+func (m *MockHTTPClient) Post(url string, body interface{}) (*MockResponse, error) {
+ m.Calls = append(m.Calls, fmt.Sprintf("POST %s", url))
+
+ if err, ok := m.Errors[url]; ok {
+ return nil, err
+ }
+
+ if resp, ok := m.Responses[url]; ok {
+ return resp, nil
+ }
+
+ return &MockResponse{
+ StatusCode: 404,
+ Body: "Not Found",
+ }, nil
+}
+
+// MockOpenAIClient mocks OpenAI API client
+type MockOpenAIClient struct {
+ TTSResponses map[string][]byte
+ ImageResponses map[string]string
+ Errors map[string]error
+ Calls []string
+}
+
+// CreateSpeech mocks OpenAI TTS API
+func (m *MockOpenAIClient) CreateSpeech(ctx context.Context, text, voice, model string) (io.ReadCloser, error) {
+ call := fmt.Sprintf("TTS: %s (voice=%s, model=%s)", text, voice, model)
+ m.Calls = append(m.Calls, call)
+
+ key := fmt.Sprintf("%s-%s-%s", text, voice, model)
+ if err, ok := m.Errors[key]; ok {
+ return nil, err
+ }
+
+ if data, ok := m.TTSResponses[key]; ok {
+ return io.NopCloser(strings.NewReader(string(data))), nil
+ }
+
+ // Default response
+ return io.NopCloser(strings.NewReader("mock audio data")), nil
+}
+
+// CreateImage mocks OpenAI DALL-E API
+func (m *MockOpenAIClient) CreateImage(ctx context.Context, prompt string) (string, error) {
+ call := fmt.Sprintf("Image: %s", prompt)
+ m.Calls = append(m.Calls, call)
+
+ if err, ok := m.Errors[prompt]; ok {
+ return "", err
+ }
+
+ if url, ok := m.ImageResponses[prompt]; ok {
+ return url, nil
+ }
+
+ // Default response
+ return "https://example.com/mock-image.jpg", nil
+}
+
+// MockFileSystem mocks file system operations
+type MockFileSystem struct {
+ Files map[string][]byte
+ Errors map[string]error
+ Calls []string
+}
+
+// ReadFile mocks reading a file
+func (m *MockFileSystem) ReadFile(path string) ([]byte, error) {
+ m.Calls = append(m.Calls, fmt.Sprintf("READ %s", path))
+
+ if err, ok := m.Errors[path]; ok {
+ return nil, err
+ }
+
+ if data, ok := m.Files[path]; ok {
+ return data, nil
+ }
+
+ return nil, fmt.Errorf("file not found: %s", path)
+}
+
+// WriteFile mocks writing a file
+func (m *MockFileSystem) WriteFile(path string, data []byte) error {
+ m.Calls = append(m.Calls, fmt.Sprintf("WRITE %s (%d bytes)", path, len(data)))
+
+ if err, ok := m.Errors[path]; ok {
+ return err
+ }
+
+ m.Files[path] = data
+ return nil
+}
+
+// Exists mocks checking if a file exists
+func (m *MockFileSystem) Exists(path string) bool {
+ m.Calls = append(m.Calls, fmt.Sprintf("EXISTS %s", path))
+ _, exists := m.Files[path]
+ return exists
+}
+
+// MockTranslator mocks translation service
+type MockTranslator struct {
+ Translations map[string]string
+ Errors map[string]error
+ Calls []string
+}
+
+// Translate mocks translating text
+func (m *MockTranslator) Translate(ctx context.Context, text, fromLang, toLang string) (string, error) {
+ call := fmt.Sprintf("Translate: %s (%s->%s)", text, fromLang, toLang)
+ m.Calls = append(m.Calls, call)
+
+ if err, ok := m.Errors[text]; ok {
+ return "", err
+ }
+
+ if translation, ok := m.Translations[text]; ok {
+ return translation, nil
+ }
+
+ // Default mock translation
+ return fmt.Sprintf("mock translation of %s", text), nil
+}
+
+// TestDataGenerator generates test data
+type TestDataGenerator struct{}
+
+// GenerateBulgarianWord generates a test Bulgarian word
+func (g *TestDataGenerator) GenerateBulgarianWord() string {
+ words := []string{"ябълка", "ΠΊΠΎΡ‚ΠΊΠ°", "ΠΊΡƒΡ‡Π΅", "хляб", "Π²ΠΎΠ΄Π°", "ΠΊΠ½ΠΈΠ³Π°", "стол", "ΠΏΡ€ΠΎΠ·ΠΎΡ€Π΅Ρ†"}
+ return words[0] // Simple implementation, could be randomized
+}
+
+// GenerateAudioData generates mock audio data
+func (g *TestDataGenerator) GenerateAudioData() []byte {
+ // Simple mock MP3 header
+ return []byte{0xFF, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00}
+}
+
+// GenerateImageData generates mock image data
+func (g *TestDataGenerator) GenerateImageData() []byte {
+ // Simple mock JPEG header
+ return []byte{0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46}
+}