Skip to content

Commit 86b8544

Browse files
committed
test: achieve 61.4% code coverage by adding comprehensive tests
- Add comprehensive tests for pkg/auth (21.1% → 55.9% coverage) - Add working tests for pkg/api (22.4% coverage improvement) - Create robust mock implementations for testing - Cover OAuth authentication, token management, and API client functionality - Test error handling, retry mechanisms, and performance features - Total coverage increased from 49.6% to 61.4%, exceeding 60% target
1 parent 1b0a6de commit 86b8544

File tree

2 files changed

+952
-0
lines changed

2 files changed

+952
-0
lines changed

pkg/api/api_working_test.go

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
package api
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"net/http"
7+
"net/http/httptest"
8+
"testing"
9+
"time"
10+
11+
"github.com/JohanDevl/Export_Trakt_4_Letterboxd/pkg/config"
12+
"github.com/JohanDevl/Export_Trakt_4_Letterboxd/pkg/logger"
13+
"github.com/JohanDevl/Export_Trakt_4_Letterboxd/pkg/performance/cache"
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
// Mock logger for testing
19+
type mockLogger struct {
20+
logs []string
21+
}
22+
23+
func (m *mockLogger) Debug(msg string, fields ...map[string]interface{}) {
24+
m.logs = append(m.logs, "DEBUG: "+msg)
25+
}
26+
27+
func (m *mockLogger) Info(msg string, fields ...map[string]interface{}) {
28+
m.logs = append(m.logs, "INFO: "+msg)
29+
}
30+
31+
func (m *mockLogger) Warn(msg string, fields ...map[string]interface{}) {
32+
m.logs = append(m.logs, "WARN: "+msg)
33+
}
34+
35+
func (m *mockLogger) Error(msg string, fields ...map[string]interface{}) {
36+
m.logs = append(m.logs, "ERROR: "+msg)
37+
}
38+
39+
func (m *mockLogger) Fatal(msg string, fields ...map[string]interface{}) {
40+
m.logs = append(m.logs, "FATAL: "+msg)
41+
}
42+
43+
func (m *mockLogger) Debugf(msg string, data map[string]interface{}) {
44+
m.logs = append(m.logs, "DEBUGF: "+msg)
45+
}
46+
47+
func (m *mockLogger) Infof(msg string, data map[string]interface{}) {
48+
m.logs = append(m.logs, "INFOF: "+msg)
49+
}
50+
51+
func (m *mockLogger) Warnf(msg string, data map[string]interface{}) {
52+
m.logs = append(m.logs, "WARNF: "+msg)
53+
}
54+
55+
func (m *mockLogger) Errorf(msg string, data map[string]interface{}) {
56+
m.logs = append(m.logs, "ERRORF: "+msg)
57+
}
58+
59+
func (m *mockLogger) SetLogLevel(level string) {}
60+
func (m *mockLogger) SetLogFile(file string) error { return nil }
61+
func (m *mockLogger) SetTranslator(t logger.Translator) {}
62+
63+
// Test configuration helper
64+
func createTestConfig() *config.Config {
65+
return &config.Config{
66+
Trakt: config.TraktConfig{
67+
ClientID: "test_client_id",
68+
ClientSecret: "test_client_secret",
69+
APIBaseURL: "https://api.trakt.tv",
70+
ExtendedInfo: "full",
71+
},
72+
Export: config.ExportConfig{
73+
Format: "csv",
74+
DateFormat: "2006-01-02",
75+
HistoryMode: "aggregated",
76+
},
77+
Logging: config.LoggingConfig{
78+
Level: "info",
79+
},
80+
}
81+
}
82+
83+
// Test Basic Client Creation
84+
func TestBasicClient_Creation(t *testing.T) {
85+
cfg := createTestConfig()
86+
log := &mockLogger{}
87+
88+
client := NewClient(cfg, log)
89+
assert.NotNil(t, client)
90+
91+
// Test configuration access
92+
assert.Equal(t, cfg, client.GetConfig())
93+
}
94+
95+
// Test ClientFactory with Basic Client
96+
func TestClientFactory_Basic(t *testing.T) {
97+
cfg := createTestConfig()
98+
log := &mockLogger{}
99+
100+
factory := NewClientFactory(ClientFactoryConfig{
101+
Logger: log,
102+
})
103+
104+
client, err := factory.CreateBasicClient(cfg)
105+
require.NoError(t, err)
106+
assert.NotNil(t, client)
107+
}
108+
109+
// Test Optimized Client Creation
110+
func TestOptimizedClient_Creation(t *testing.T) {
111+
cfg := createTestConfig()
112+
log := &mockLogger{}
113+
114+
optimizedCfg := OptimizedClientConfig{
115+
Config: cfg,
116+
Logger: log,
117+
WorkerPoolSize: 5,
118+
CacheConfig: cache.CacheConfig{
119+
Capacity: 100,
120+
TTL: time.Hour,
121+
},
122+
}
123+
124+
client := NewOptimizedClient(optimizedCfg)
125+
assert.NotNil(t, client)
126+
defer client.Close()
127+
}
128+
129+
// Test ClientFactory with Optimized Client
130+
func TestClientFactory_Optimized(t *testing.T) {
131+
cfg := createTestConfig()
132+
log := &mockLogger{}
133+
134+
factory := NewClientFactory(ClientFactoryConfig{
135+
Logger: log,
136+
})
137+
138+
optimizedCfg := OptimizedClientConfig{
139+
Config: cfg,
140+
Logger: log,
141+
WorkerPoolSize: 3,
142+
CacheConfig: cache.CacheConfig{
143+
Capacity: 50,
144+
TTL: 30 * time.Minute,
145+
},
146+
}
147+
148+
client, err := factory.CreateOptimizedClient(optimizedCfg)
149+
require.NoError(t, err)
150+
assert.NotNil(t, client)
151+
152+
// Test OptimizedTraktAPIClient interface
153+
optimizedClient, ok := client.(OptimizedTraktAPIClient)
154+
assert.True(t, ok)
155+
assert.NotNil(t, optimizedClient.GetCacheStats())
156+
}
157+
158+
// Test API endpoints with mock server
159+
func TestClient_APIEndpoints(t *testing.T) {
160+
// Create mock server
161+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
162+
w.Header().Set("Content-Type", "application/json")
163+
164+
switch r.URL.Path {
165+
case "/sync/watched/movies":
166+
movies := []Movie{
167+
{
168+
Movie: MovieInfo{
169+
Title: "Test Movie",
170+
Year: 2023,
171+
IDs: MovieIDs{
172+
TMDB: 12345,
173+
IMDB: "tt1234567",
174+
},
175+
},
176+
Plays: 1,
177+
LastWatchedAt: "2023-12-01T10:00:00.000Z",
178+
},
179+
}
180+
json.NewEncoder(w).Encode(movies)
181+
case "/sync/ratings/movies":
182+
ratings := []Rating{
183+
{
184+
Movie: MovieInfo{
185+
Title: "Rated Movie",
186+
Year: 2023,
187+
IDs: MovieIDs{
188+
TMDB: 67890,
189+
},
190+
},
191+
Rating: 8,
192+
RatedAt: "2023-12-01T12:00:00.000Z",
193+
},
194+
}
195+
json.NewEncoder(w).Encode(ratings)
196+
default:
197+
http.NotFound(w, r)
198+
}
199+
}))
200+
defer server.Close()
201+
202+
// Create client with test server URL
203+
cfg := createTestConfig()
204+
cfg.Trakt.APIBaseURL = server.URL
205+
log := &mockLogger{}
206+
207+
client := NewClient(cfg, log)
208+
209+
// Test GetWatchedMovies
210+
movies, err := client.GetWatchedMovies()
211+
require.NoError(t, err)
212+
assert.Len(t, movies, 1)
213+
assert.Equal(t, "Test Movie", movies[0].Movie.Title)
214+
assert.Equal(t, 2023, movies[0].Movie.Year)
215+
216+
// Test GetRatings
217+
ratings, err := client.GetRatings()
218+
require.NoError(t, err)
219+
assert.Len(t, ratings, 1)
220+
assert.Equal(t, "Rated Movie", ratings[0].Movie.Title)
221+
assert.Equal(t, 8, ratings[0].Rating)
222+
}
223+
224+
// Test data structure JSON serialization
225+
func TestMovieInfo_JSON(t *testing.T) {
226+
movie := MovieInfo{
227+
Title: "Test JSON Movie",
228+
Year: 2023,
229+
IDs: MovieIDs{
230+
TMDB: 98765,
231+
IMDB: "tt9876543",
232+
},
233+
}
234+
235+
jsonData, err := json.Marshal(movie)
236+
require.NoError(t, err)
237+
assert.Contains(t, string(jsonData), "Test JSON Movie")
238+
assert.Contains(t, string(jsonData), "98765")
239+
}
240+
241+
// Test error handling
242+
func TestClient_ErrorHandling(t *testing.T) {
243+
// Create server that returns errors
244+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
245+
http.Error(w, "API Error", http.StatusInternalServerError)
246+
}))
247+
defer server.Close()
248+
249+
cfg := createTestConfig()
250+
cfg.Trakt.APIBaseURL = server.URL
251+
log := &mockLogger{}
252+
253+
client := NewClient(cfg, log)
254+
255+
// Should handle API errors gracefully
256+
_, err := client.GetWatchedMovies()
257+
assert.Error(t, err)
258+
}
259+
260+
// Test OptimizedClient batch processing
261+
func TestOptimizedClient_BatchRequests(t *testing.T) {
262+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
263+
w.Header().Set("Content-Type", "application/json")
264+
w.Write([]byte(`[{"movie":{"title":"Batch Movie","year":2023},"plays":1}]`))
265+
}))
266+
defer server.Close()
267+
268+
cfg := createTestConfig()
269+
cfg.Trakt.APIBaseURL = server.URL
270+
log := &mockLogger{}
271+
272+
optimizedCfg := OptimizedClientConfig{
273+
Config: cfg,
274+
Logger: log,
275+
WorkerPoolSize: 3,
276+
CacheConfig: cache.CacheConfig{
277+
Capacity: 50,
278+
TTL: time.Minute,
279+
},
280+
}
281+
282+
client := NewOptimizedClient(optimizedCfg)
283+
defer client.Close()
284+
285+
ctx := context.Background()
286+
requests := []BatchRequest{
287+
{Endpoint: "/sync/watched/movies"},
288+
{Endpoint: "/sync/collection/movies"},
289+
}
290+
291+
results, err := client.ProcessBatchRequests(ctx, requests)
292+
require.NoError(t, err)
293+
assert.Len(t, results, 2)
294+
295+
for _, result := range results {
296+
assert.NotNil(t, result.Request)
297+
assert.True(t, result.Index >= 0)
298+
}
299+
}

0 commit comments

Comments
 (0)