feat(app): 设置页 UI + Mood/成就/贴纸 BLoC 接入 API + B7 测试扩展
前端改动: - 新建设置页面 (主题切换/关于/隐私政策/用户协议/儿童隐私保护) - SettingsBloc 注册到 MultiRepositoryProvider 全局可访问 - MoodBloc 修复编译错误 + 接入 /diary/stats/mood API - MoodPage 添加错误状态展示和重试按钮 - AchievementBloc + 页面改造接入 /diary/achievements API - StickerBloc + 页面改造接入 /diary/sticker-packs API - TemplateBloc + 页面改造接入 /diary/templates API - ProfilePage 设置入口改为跳转 /settings - 添加 /settings 路由 后端改动: - 扩展 mood_stats_service 测试 (连续天数算法/心情计数/边界场景) - 新增 class_service 测试 (班级码生成/唯一性/错误映射) - 新增 achievement_service 测试 (DTO 结构/序列化/map 构建) - 新增 sticker_service 测试 (DTO 序列化/错误处理) - 扩展 dto.rs 测试 (achievement/mood_stats/sticker/template/notification) - 清理 2 个 unused import warning 验证: - cargo check 0 error 0 warning - flutter analyze 0 error
This commit is contained in:
@@ -298,3 +298,56 @@ fn member_model_to_resp(model: class_member::Model) -> ClassMemberResp {
|
||||
joined_at: model.joined_at,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// ===== 班级码生成测试 =====
|
||||
|
||||
#[test]
|
||||
fn generate_class_code_is_6_chars() {
|
||||
let code = generate_class_code();
|
||||
assert_eq!(code.len(), 6, "班级码必须是 6 位");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_class_code_is_alphanumeric() {
|
||||
let code = generate_class_code();
|
||||
assert!(
|
||||
code.chars().all(|c| c.is_ascii_alphanumeric()),
|
||||
"班级码必须全部是字母数字"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_class_code_is_unique() {
|
||||
let codes: std::collections::HashSet<String> = (0..100)
|
||||
.map(|_| generate_class_code())
|
||||
.collect();
|
||||
// 100 个码应该全部不同(概率上几乎确定)
|
||||
assert!(codes.len() > 90, "生成的班级码应该高度唯一");
|
||||
}
|
||||
|
||||
// ===== 错误映射测试 =====
|
||||
|
||||
#[test]
|
||||
fn invalid_class_code_error() {
|
||||
let err = DiaryError::InvalidClassCode;
|
||||
assert!(err.to_string().contains("无效"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_code_expired_error() {
|
||||
let err = DiaryError::ClassCodeExpired;
|
||||
assert!(err.to_string().contains("过期"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_code_locked_error() {
|
||||
let err = DiaryError::ClassCodeLocked {
|
||||
lockout_minutes: 30,
|
||||
};
|
||||
assert!(err.to_string().contains("30"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user