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:
iven
2026-06-01 10:07:44 +08:00
parent c4a317c90f
commit 05317d50d5
2 changed files with 150 additions and 3 deletions

View File

@@ -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(),

View File

@@ -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"));
}
}