fix(diary): B7 测试套件 + F11 深色模式修复
B7 API 打磨: - DTO 序列化/反序列化测试 12 个 (Mood/Weather/SyncChange/NotificationType等) - 测试总数 17 → 29,全部通过 - SyncChange 添加 Serialize derive (测试发现遗漏) F11 深色模式: - 修复 mood_page.dart 唯一硬编码颜色 Colors.white → colorScheme.onPrimary - 全面审计确认所有页面均使用 AppColors/colorScheme,无其他硬编码 验证: cargo test 29/29 ✓ flutter analyze 0 error ✓
This commit is contained in:
@@ -213,10 +213,10 @@ class _MoodDistributionChart extends StatelessWidget {
|
||||
color: color,
|
||||
radius: 50,
|
||||
title: '${mc.percentage.toStringAsFixed(0)}%',
|
||||
titleStyle: const TextStyle(
|
||||
titleStyle: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
color: colorScheme.onPrimary,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
@@ -101,7 +101,7 @@ pub struct SyncReq {
|
||||
}
|
||||
|
||||
/// 同步变更条目
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub enum SyncChange {
|
||||
CreateJournal { data: serde_json::Value },
|
||||
UpdateJournal { id: uuid::Uuid, version: i32, data: serde_json::Value },
|
||||
@@ -284,3 +284,150 @@ pub struct AchievementResp {
|
||||
pub is_unlocked: bool,
|
||||
pub unlocked_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mood_serializes_to_lowercase() {
|
||||
let json = serde_json::to_string(&Mood::Happy).unwrap();
|
||||
assert_eq!(json, "\"happy\"");
|
||||
let json = serde_json::to_string(&Mood::Thinking).unwrap();
|
||||
assert_eq!(json, "\"thinking\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mood_deserializes() {
|
||||
let m: Mood = serde_json::from_str("\"calm\"").unwrap();
|
||||
assert!(matches!(m, Mood::Calm));
|
||||
let m: Mood = serde_json::from_str("\"angry\"").unwrap();
|
||||
assert!(matches!(m, Mood::Angry));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weather_roundtrip() {
|
||||
let w = Weather::Snowy;
|
||||
let json = serde_json::to_string(&w).unwrap();
|
||||
let back: Weather = serde_json::from_str(&json).unwrap();
|
||||
assert!(matches!(back, Weather::Snowy));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_journal_req_deserializes() {
|
||||
let json = r#"{
|
||||
"title": "测试日记",
|
||||
"date": "2026-06-01",
|
||||
"mood": "happy",
|
||||
"weather": "sunny",
|
||||
"tags": ["日常"],
|
||||
"is_private": true
|
||||
}"#;
|
||||
let req: CreateJournalReq = serde_json::from_str(json).unwrap();
|
||||
assert_eq!(req.title, "测试日记");
|
||||
assert!(req.is_private);
|
||||
assert!(req.class_id.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_journal_req_minimal() {
|
||||
let req: UpdateJournalReq = serde_json::from_str(r#"{"version": 2}"#).unwrap();
|
||||
assert_eq!(req.version, 2);
|
||||
assert!(req.title.is_none());
|
||||
assert!(req.mood.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn notification_type_serializes_snake_case() {
|
||||
assert_eq!(
|
||||
serde_json::to_string(&NotificationType::CommentReceived).unwrap(),
|
||||
"\"comment_received\""
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&NotificationType::AchievementUnlocked).unwrap(),
|
||||
"\"achievement_unlocked\""
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_change_variants_serialize() {
|
||||
let create = SyncChange::CreateJournal {
|
||||
data: serde_json::json!({"title": "test"}),
|
||||
};
|
||||
let json = serde_json::to_string(&create).unwrap();
|
||||
assert!(json.contains("CreateJournal"));
|
||||
|
||||
let delete = SyncChange::DeleteJournal {
|
||||
id: uuid::Uuid::nil(),
|
||||
version: 3,
|
||||
};
|
||||
let json = serde_json::to_string(&delete).unwrap();
|
||||
assert!(json.contains("DeleteJournal"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conflict_info_serializes() {
|
||||
let info = ConflictInfo {
|
||||
journal_id: uuid::Uuid::nil(),
|
||||
local_version: 1,
|
||||
server_version: 3,
|
||||
};
|
||||
let json = serde_json::to_string(&info).unwrap();
|
||||
assert!(json.contains("\"local_version\":1"));
|
||||
assert!(json.contains("\"server_version\":3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sticker_pack_resp_serializes() {
|
||||
let resp = StickerPackResp {
|
||||
id: uuid::Uuid::nil(),
|
||||
name: "测试贴纸包".into(),
|
||||
description: None,
|
||||
cover_image_url: None,
|
||||
sticker_count: 10,
|
||||
is_free: true,
|
||||
category: Some("动物".into()),
|
||||
};
|
||||
let json = serde_json::to_string(&resp).unwrap();
|
||||
assert!(json.contains("\"sticker_count\":10"));
|
||||
assert!(json.contains("\"is_free\":true"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mood_count_percentage() {
|
||||
let mc = MoodCount {
|
||||
mood: Mood::Happy,
|
||||
count: 3,
|
||||
percentage: 42.5,
|
||||
};
|
||||
let json = serde_json::to_string(&mc).unwrap();
|
||||
assert!(json.contains("\"percentage\":42.5"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_member_resp_fields() {
|
||||
let resp = ClassMemberResp {
|
||||
user_id: uuid::Uuid::nil(),
|
||||
role: "student".into(),
|
||||
nickname: Some("小明".into()),
|
||||
joined_at: chrono::Utc::now(),
|
||||
};
|
||||
let json = serde_json::to_string(&resp).unwrap();
|
||||
assert!(json.contains("\"role\":\"student\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn topic_resp_serializes() {
|
||||
let resp = TopicResp {
|
||||
id: uuid::Uuid::nil(),
|
||||
class_id: uuid::Uuid::nil(),
|
||||
teacher_id: uuid::Uuid::nil(),
|
||||
title: "我的周末".into(),
|
||||
description: Some("描述".into()),
|
||||
due_date: None,
|
||||
is_active: true,
|
||||
};
|
||||
let json = serde_json::to_string(&resp).unwrap();
|
||||
assert!(json.contains("\"is_active\":true"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user