Skip to content

Commit 8468d2f

Browse files
unhappychoiceclaude
andcommitted
test: add unit tests for domain services
Added comprehensive unit tests for: - AnalyticsService: 6 tests covering analytics data loading, repository stats, language stats, and daily sessions - SessionService: 8 tests covering session retrieval, filtering by repository/date, and sorting - RepositoryService: 9 tests covering repository retrieval, cache status, and languages All 296 tests pass successfully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 04e7ead commit 8468d2f

File tree

4 files changed

+740
-0
lines changed

4 files changed

+740
-0
lines changed
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
use gittype::domain::models::{Challenge, GitRepository, SessionResult};
2+
use gittype::domain::repositories::SessionRepository;
3+
use gittype::domain::services::analytics_service::AnalyticsService;
4+
use gittype::domain::services::scoring::{StageInput, StageTracker};
5+
use gittype::infrastructure::database::database::Database;
6+
use std::sync::Arc;
7+
8+
#[test]
9+
fn test_analytics_service_new() {
10+
let session_repository = Arc::new(SessionRepository::new().unwrap());
11+
let db = Arc::new(Database::new().unwrap());
12+
let _service = AnalyticsService::new(session_repository, db);
13+
14+
// Service creation should succeed
15+
assert!(true);
16+
}
17+
18+
#[test]
19+
fn test_load_analytics_data_empty() {
20+
let session_repository = Arc::new(SessionRepository::new().unwrap());
21+
let db = Arc::new(Database::new().unwrap());
22+
let service = AnalyticsService::new(session_repository, db);
23+
24+
let result = service.load_analytics_data();
25+
assert!(result.is_ok());
26+
27+
let data = result.unwrap();
28+
assert_eq!(data.total_sessions, 0);
29+
assert_eq!(data.avg_cpm, 0.0);
30+
assert_eq!(data.avg_accuracy, 0.0);
31+
assert!(data.top_repositories.is_empty());
32+
assert!(data.top_languages.is_empty());
33+
assert!(data.cpm_trend.is_empty());
34+
assert!(data.accuracy_trend.is_empty());
35+
}
36+
37+
#[test]
38+
fn test_load_analytics_data_with_session() {
39+
let session_repository = Arc::new(SessionRepository::new().unwrap());
40+
let db = Arc::new(Database::new().unwrap());
41+
42+
// Record a test session
43+
let mut session_result = SessionResult::new();
44+
session_result.session_score = 150.0;
45+
session_result.overall_wpm = 60.0;
46+
session_result.overall_cpm = 300.0;
47+
session_result.overall_accuracy = 95.0;
48+
49+
let git_repo = GitRepository {
50+
user_name: "analyticsuser".to_string(),
51+
repository_name: "analyticsrepo".to_string(),
52+
remote_url: "https://github.com/analyticsuser/analyticsrepo".to_string(),
53+
branch: Some("main".to_string()),
54+
commit_hash: Some("abc123".to_string()),
55+
is_dirty: false,
56+
root_path: None,
57+
};
58+
59+
let challenge = Challenge::new("test-id".to_string(), "test code".to_string())
60+
.with_language("rust".to_string());
61+
62+
let mut tracker = StageTracker::new("test code".to_string());
63+
tracker.record(StageInput::Start);
64+
tracker.record(StageInput::Keystroke {
65+
ch: 't',
66+
position: 0,
67+
});
68+
tracker.record(StageInput::Finish);
69+
70+
session_repository
71+
.record_session(
72+
&session_result,
73+
Some(&git_repo),
74+
"normal",
75+
None,
76+
&[("stage1".to_string(), tracker)],
77+
&[challenge],
78+
)
79+
.unwrap();
80+
81+
// Load analytics data
82+
let service = AnalyticsService::new(session_repository, db);
83+
let result = service.load_analytics_data();
84+
assert!(result.is_ok());
85+
86+
let data = result.unwrap();
87+
assert!(data.total_sessions > 0);
88+
assert!(data.avg_cpm > 0.0);
89+
assert!(data.avg_accuracy > 0.0);
90+
}
91+
92+
#[test]
93+
fn test_load_analytics_data_repository_stats() {
94+
let session_repository = Arc::new(SessionRepository::new().unwrap());
95+
let db = Arc::new(Database::new().unwrap());
96+
97+
// Record sessions for the same repository
98+
for i in 0..3 {
99+
let mut session_result = SessionResult::new();
100+
session_result.session_score = 100.0 + (i as f64 * 10.0);
101+
session_result.overall_wpm = 50.0 + (i as f64 * 5.0);
102+
session_result.overall_cpm = 250.0 + (i as f64 * 25.0);
103+
session_result.overall_accuracy = 90.0 + (i as f64);
104+
105+
let git_repo = GitRepository {
106+
user_name: "repouser".to_string(),
107+
repository_name: "reporepo".to_string(),
108+
remote_url: "https://github.com/repouser/reporepo".to_string(),
109+
branch: Some("main".to_string()),
110+
commit_hash: Some(format!("hash{}", i)),
111+
is_dirty: false,
112+
root_path: None,
113+
};
114+
115+
let challenge = Challenge::new(format!("test-{}", i), "test code".to_string());
116+
let mut tracker = StageTracker::new("test code".to_string());
117+
tracker.record(StageInput::Start);
118+
tracker.record(StageInput::Finish);
119+
120+
session_repository
121+
.record_session(
122+
&session_result,
123+
Some(&git_repo),
124+
"normal",
125+
None,
126+
&[("stage1".to_string(), tracker)],
127+
&[challenge],
128+
)
129+
.unwrap();
130+
}
131+
132+
// Load analytics data
133+
let service = AnalyticsService::new(session_repository, db);
134+
let result = service.load_analytics_data();
135+
assert!(result.is_ok());
136+
137+
let data = result.unwrap();
138+
139+
// Sessions should be recorded
140+
assert!(data.total_sessions >= 3);
141+
142+
// Check that repository stats are calculated if data exists
143+
let repo_name = "repouser/reporepo";
144+
if data.repository_stats.contains_key(repo_name) {
145+
let stats = &data.repository_stats[repo_name];
146+
assert!(stats.total_sessions >= 3);
147+
assert!(stats.avg_cpm > 0.0);
148+
assert!(stats.best_cpm > 0.0);
149+
}
150+
}
151+
152+
#[test]
153+
fn test_load_analytics_data_language_stats() {
154+
let session_repository = Arc::new(SessionRepository::new().unwrap());
155+
let db = Arc::new(Database::new().unwrap());
156+
157+
// Record a session with language
158+
let mut session_result = SessionResult::new();
159+
session_result.session_score = 120.0;
160+
session_result.overall_wpm = 55.0;
161+
session_result.overall_cpm = 275.0;
162+
session_result.overall_accuracy = 93.0;
163+
164+
let git_repo = GitRepository {
165+
user_name: "languser".to_string(),
166+
repository_name: "langrepo".to_string(),
167+
remote_url: "https://github.com/languser/langrepo".to_string(),
168+
branch: Some("main".to_string()),
169+
commit_hash: Some("langhash".to_string()),
170+
is_dirty: false,
171+
root_path: None,
172+
};
173+
174+
let challenge = Challenge::new("lang-test".to_string(), "fn main() {}".to_string())
175+
.with_language("rust".to_string());
176+
177+
let mut tracker = StageTracker::new("fn main() {}".to_string());
178+
tracker.record(StageInput::Start);
179+
tracker.record(StageInput::Keystroke {
180+
ch: 'f',
181+
position: 0,
182+
});
183+
tracker.record(StageInput::Finish);
184+
185+
session_repository
186+
.record_session(
187+
&session_result,
188+
Some(&git_repo),
189+
"normal",
190+
None,
191+
&[("stage1".to_string(), tracker)],
192+
&[challenge],
193+
)
194+
.unwrap();
195+
196+
// Load analytics data
197+
let service = AnalyticsService::new(session_repository, db);
198+
let result = service.load_analytics_data();
199+
assert!(result.is_ok());
200+
201+
let data = result.unwrap();
202+
203+
// Check language stats
204+
if data.language_stats.contains_key("rust") {
205+
let stats = &data.language_stats["rust"];
206+
assert!(stats.total_sessions > 0);
207+
assert!(stats.avg_cpm > 0.0);
208+
}
209+
}
210+
211+
#[test]
212+
fn test_load_analytics_data_daily_sessions() {
213+
let session_repository = Arc::new(SessionRepository::new().unwrap());
214+
let db = Arc::new(Database::new().unwrap());
215+
216+
// Record a session
217+
let mut session_result = SessionResult::new();
218+
session_result.session_score = 100.0;
219+
220+
let git_repo = GitRepository {
221+
user_name: "dailyuser".to_string(),
222+
repository_name: "dailyrepo".to_string(),
223+
remote_url: "https://github.com/dailyuser/dailyrepo".to_string(),
224+
branch: Some("main".to_string()),
225+
commit_hash: Some("daily123".to_string()),
226+
is_dirty: false,
227+
root_path: None,
228+
};
229+
230+
let challenge = Challenge::new("daily-test".to_string(), "test".to_string());
231+
let mut tracker = StageTracker::new("test".to_string());
232+
tracker.record(StageInput::Start);
233+
tracker.record(StageInput::Finish);
234+
235+
session_repository
236+
.record_session(
237+
&session_result,
238+
Some(&git_repo),
239+
"normal",
240+
None,
241+
&[("stage1".to_string(), tracker)],
242+
&[challenge],
243+
)
244+
.unwrap();
245+
246+
// Load analytics data
247+
let service = AnalyticsService::new(session_repository, db);
248+
let result = service.load_analytics_data();
249+
assert!(result.is_ok());
250+
251+
let data = result.unwrap();
252+
assert!(!data.daily_sessions.is_empty(), "Should have daily session counts");
253+
}

tests/unit/domain/services/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
mod analytics_service_tests;
12
mod challenge_generator;
23
mod config_service_tests;
4+
mod repository_service_tests;
35
pub mod scoring;
6+
mod session_service_tests;
47
mod source_code_parser;
58
mod source_file_extractor;
69
mod theme_manager_tests;

0 commit comments

Comments
 (0)