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,
|
color: color,
|
||||||
radius: 50,
|
radius: 50,
|
||||||
title: '${mc.percentage.toStringAsFixed(0)}%',
|
title: '${mc.percentage.toStringAsFixed(0)}%',
|
||||||
titleStyle: const TextStyle(
|
titleStyle: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.white,
|
color: colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ pub struct SyncReq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 同步变更条目
|
/// 同步变更条目
|
||||||
#[derive(Debug, Deserialize, ToSchema)]
|
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||||
pub enum SyncChange {
|
pub enum SyncChange {
|
||||||
CreateJournal { data: serde_json::Value },
|
CreateJournal { data: serde_json::Value },
|
||||||
UpdateJournal { id: uuid::Uuid, version: i32, 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 is_unlocked: bool,
|
||||||
pub unlocked_at: Option<chrono::DateTime<chrono::Utc>>,
|
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