feat: 完成云同步、语音控制与多平台扩展基础架构搭建
本次提交完成了项目核心基础架构升级: 1. 新增动态API中间件与权限控制系统,支持匿名/鉴权接口分离 2. 搭建云同步服务体系,包含认证、任务同步、安全策略等核心模块 3. 实现语音控制全链路,从STT/意图解析到命令执行 4. 新增任务类型、附件实体与相关仓储接口 5. 重构前端配置与代理规则,统一后端端口为5057 6. 新增多平台测试项目与CI脚本优化 7. 完善项目文档与代码注释规范 移除了旧版迁移文件与冗余代理配置,调整项目结构适配跨平台部署需求。
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
using System.Reflection;
|
||||
using Hua.Todo.Application.Services.Meeting;
|
||||
using Hua.Todo.Application.Services.Meeting.Models;
|
||||
using Hua.Todo.Core.Entities;
|
||||
using Xunit;
|
||||
|
||||
namespace Hua.Todo.Host.Tests.Meeting;
|
||||
|
||||
/// <summary>
|
||||
/// 工单 03-03 AI 任务拆分服务测试。
|
||||
/// </summary>
|
||||
public class MeetingAiBreakdownTests
|
||||
{
|
||||
[Fact]
|
||||
public void MeetingTaskSuggestion_DefaultProperties()
|
||||
{
|
||||
var suggestion = new MeetingTaskSuggestion
|
||||
{
|
||||
Title = "整理需求文档",
|
||||
Priority = TaskPriority.High,
|
||||
Reason = "会议中提及需要在周五前完成"
|
||||
};
|
||||
|
||||
Assert.Equal("整理需求文档", suggestion.Title);
|
||||
Assert.Equal(TaskPriority.High, suggestion.Priority);
|
||||
Assert.Equal("会议中提及需要在周五前完成", suggestion.Reason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeetingTaskSuggestion_DefaultValues()
|
||||
{
|
||||
var suggestion = new MeetingTaskSuggestion();
|
||||
|
||||
Assert.Equal(string.Empty, suggestion.Title);
|
||||
Assert.Equal(TaskPriority.Medium, suggestion.Priority);
|
||||
Assert.Equal(string.Empty, suggestion.Reason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreakdownRequest_CanBeCreated()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var request = new BreakdownRequest
|
||||
{
|
||||
TaskId = taskId,
|
||||
Notes = "会议讨论了三个议题"
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, request.TaskId);
|
||||
Assert.Equal("会议讨论了三个议题", request.Notes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreakdownRequest_NotesCanBeNull()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var request = new BreakdownRequest
|
||||
{
|
||||
TaskId = taskId,
|
||||
Notes = null
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, request.TaskId);
|
||||
Assert.Null(request.Notes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreakdownResponse_ContainsCorrectData()
|
||||
{
|
||||
var suggestions = new List<MeetingTaskSuggestion>
|
||||
{
|
||||
new() { Title = "任务A", Priority = TaskPriority.High, Reason = "原因A" },
|
||||
new() { Title = "任务B", Priority = TaskPriority.Low, Reason = "原因B" }
|
||||
};
|
||||
|
||||
var taskId = Guid.NewGuid();
|
||||
var response = new BreakdownResponse
|
||||
{
|
||||
TaskId = taskId,
|
||||
Suggestions = suggestions
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, response.TaskId);
|
||||
Assert.Equal(2, response.Suggestions.Count);
|
||||
Assert.Equal("任务A", response.Suggestions[0].Title);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreakdownResponse_DefaultSuggestionsIsEmpty()
|
||||
{
|
||||
var response = new BreakdownResponse();
|
||||
|
||||
Assert.NotNull(response.Suggestions);
|
||||
Assert.Empty(response.Suggestions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubTaskCreateItem_CanBeCreated()
|
||||
{
|
||||
var item = new SubTaskCreateItem
|
||||
{
|
||||
Title = "子任务标题",
|
||||
Priority = TaskPriority.High
|
||||
};
|
||||
|
||||
Assert.Equal("子任务标题", item.Title);
|
||||
Assert.Equal(TaskPriority.High, item.Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubTaskCreateItem_DefaultPriorityIsMedium()
|
||||
{
|
||||
var item = new SubTaskCreateItem();
|
||||
|
||||
Assert.Equal(TaskPriority.Medium, item.Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConfirmBreakdownRequest_CanBeCreated()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var request = new ConfirmBreakdownRequest
|
||||
{
|
||||
TaskId = taskId,
|
||||
SubTasks = new List<SubTaskCreateItem>
|
||||
{
|
||||
new() { Title = "任务1" },
|
||||
new() { Title = "任务2", Priority = TaskPriority.High }
|
||||
}
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, request.TaskId);
|
||||
Assert.Equal(2, request.SubTasks.Count);
|
||||
Assert.Equal("任务1", request.SubTasks[0].Title);
|
||||
Assert.Equal(TaskPriority.High, request.SubTasks[1].Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConfirmBreakdownRequest_DefaultSubTasksIsEmpty()
|
||||
{
|
||||
var request = new ConfirmBreakdownRequest();
|
||||
|
||||
Assert.NotNull(request.SubTasks);
|
||||
Assert.Empty(request.SubTasks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BatchCreateResult_CanBeCreated()
|
||||
{
|
||||
var result = new BatchCreateResult
|
||||
{
|
||||
CreatedCount = 3,
|
||||
SubTasks = new List<Application.Models.TaskDto>
|
||||
{
|
||||
new() { Id = Guid.NewGuid(), Title = "任务1" },
|
||||
new() { Id = Guid.NewGuid(), Title = "任务2" },
|
||||
new() { Id = Guid.NewGuid(), Title = "任务3" }
|
||||
}
|
||||
};
|
||||
|
||||
Assert.Equal(3, result.CreatedCount);
|
||||
Assert.Equal(3, result.SubTasks.Count);
|
||||
Assert.Equal("任务1", result.SubTasks[0].Title);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BatchCreateResult_DefaultSubTasksIsEmpty()
|
||||
{
|
||||
var result = new BatchCreateResult();
|
||||
|
||||
Assert.Equal(0, result.CreatedCount);
|
||||
Assert.NotNull(result.SubTasks);
|
||||
Assert.Empty(result.SubTasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 解析有效的 LLM JSON 响应。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_ValidJson_ReturnsSuggestions()
|
||||
{
|
||||
string json = """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"title": "整理需求文档",
|
||||
"priority": 1,
|
||||
"reason": "会议中决定需要整理"
|
||||
},
|
||||
{
|
||||
"title": "安排评审会议",
|
||||
"priority": 2,
|
||||
"reason": "下周前需要完成评审"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Equal("整理需求文档", result[0].Title);
|
||||
Assert.Equal(TaskPriority.Medium, result[0].Priority);
|
||||
Assert.Equal("会议中决定需要整理", result[0].Reason);
|
||||
Assert.Equal("安排评审会议", result[1].Title);
|
||||
Assert.Equal(TaskPriority.High, result[1].Priority);
|
||||
Assert.Equal("下周前需要完成评审", result[1].Reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 解析被 markdown 代码块包裹的 LLM 响应。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_MarkdownWrapped_StripsMarkdown()
|
||||
{
|
||||
string json = """
|
||||
```json
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"title": "更新项目计划",
|
||||
"priority": 1,
|
||||
"reason": "里程碑已调整"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("更新项目计划", result[0].Title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 处理空建议列表。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_EmptySuggestions_ReturnsEmptyList()
|
||||
{
|
||||
string json = """{"suggestions":[]}""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 过滤标题为空的条目。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_FiltersEmptyTitle()
|
||||
{
|
||||
string json = """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"title": "",
|
||||
"priority": 1,
|
||||
"reason": "空标题"
|
||||
},
|
||||
{
|
||||
"title": "有效任务",
|
||||
"priority": 0,
|
||||
"reason": "有标题"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("有效任务", result[0].Title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 过滤空白标题的条目。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_FiltersWhitespaceTitle()
|
||||
{
|
||||
string json = """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"title": " ",
|
||||
"priority": 1,
|
||||
"reason": "空白标题"
|
||||
},
|
||||
{
|
||||
"title": "有效任务",
|
||||
"priority": 0,
|
||||
"reason": "有标题"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("有效任务", result[0].Title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 处理无效 JSON。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_InvalidJson_ReturnsEmptyList()
|
||||
{
|
||||
string json = "这不是有效的 JSON";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 处理空字符串。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_EmptyString_ReturnsEmptyList()
|
||||
{
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson("");
|
||||
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 返回的条目标题已 Trim。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_TrimsTitleWhitespace()
|
||||
{
|
||||
string json = """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"title": " 前后空格 ",
|
||||
"priority": 1,
|
||||
"reason": "测试"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("前后空格", result[0].Title);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ParseBreakdownJson 处理 Reason 为 null 的条目。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseBreakdownJson_NullReason_ReturnsEmptyReason()
|
||||
{
|
||||
string json = """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"title": "测试任务",
|
||||
"priority": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
var result = MeetingAiBreakdownService.ParseBreakdownJson(json);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("测试任务", result[0].Title);
|
||||
Assert.Equal(string.Empty, result[0].Reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 IMeetingService 接口包含 RequestBreakdownAsync 方法。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IMeetingService_HasRequestBreakdownAsyncMethod()
|
||||
{
|
||||
var method = typeof(IMeetingService).GetMethod("RequestBreakdownAsync");
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal(typeof(Task<BreakdownResponse>), method!.ReturnType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 IMeetingService 接口包含 ConfirmBreakdownAsync 方法。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IMeetingService_HasConfirmBreakdownAsyncMethod()
|
||||
{
|
||||
var method = typeof(IMeetingService).GetMethod("ConfirmBreakdownAsync");
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal(typeof(Task<BatchCreateResult>), method!.ReturnType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 MeetingAiBreakdownService 类型存在并具有所需方法。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void MeetingAiBreakdownService_HasAnalyzeAsyncMethod()
|
||||
{
|
||||
var method = typeof(MeetingAiBreakdownService).GetMethod("AnalyzeAsync");
|
||||
Assert.NotNull(method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 MeetingAiBreakdownService 类型存在并具有 ConfirmAndCreateAsync 方法。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void MeetingAiBreakdownService_HasConfirmAndCreateAsyncMethod()
|
||||
{
|
||||
var method = typeof(MeetingAiBreakdownService).GetMethod("ConfirmAndCreateAsync");
|
||||
Assert.NotNull(method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 MeetingAiBreakdownService 类型存在并具有 ParseBreakdownJson 公开静态方法。
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void MeetingAiBreakdownService_HasParseBreakdownJsonMethod()
|
||||
{
|
||||
var method = typeof(MeetingAiBreakdownService).GetMethod("ParseBreakdownJson",
|
||||
BindingFlags.Public | BindingFlags.Static);
|
||||
Assert.NotNull(method);
|
||||
Assert.True(method!.IsStatic);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using Hua.Todo.Application.Services.Meeting.Models;
|
||||
using Hua.Todo.Core.Entities;
|
||||
using Xunit;
|
||||
|
||||
namespace Hua.Todo.Host.Tests.Meeting;
|
||||
|
||||
/// <summary>
|
||||
/// 工单 03-01 会议数据模型与 API 测试。
|
||||
/// </summary>
|
||||
public class MeetingModelTests
|
||||
{
|
||||
[Fact]
|
||||
public void TaskType_Normal_IsZero()
|
||||
{
|
||||
Assert.Equal(0, (int)TaskType.Normal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskType_Meeting_IsOne()
|
||||
{
|
||||
Assert.Equal(1, (int)TaskType.Meeting);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskEntity_DefaultTaskType_IsNormal()
|
||||
{
|
||||
var entity = new TaskEntity();
|
||||
Assert.Equal(TaskType.Normal, entity.TaskType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskEntity_DefaultMeetingNotes_IsNull()
|
||||
{
|
||||
var entity = new TaskEntity();
|
||||
Assert.Null(entity.MeetingNotes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskEntity_DefaultAudioDuration_IsNull()
|
||||
{
|
||||
var entity = new TaskEntity();
|
||||
Assert.Null(entity.AudioDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskEntity_MeetingFields_CanBeSet()
|
||||
{
|
||||
var entity = new TaskEntity
|
||||
{
|
||||
TaskType = TaskType.Meeting,
|
||||
MeetingNotes = "会议讨论了三个议题",
|
||||
AudioDuration = 1830.5
|
||||
};
|
||||
|
||||
Assert.Equal(TaskType.Meeting, entity.TaskType);
|
||||
Assert.Equal("会议讨论了三个议题", entity.MeetingNotes);
|
||||
Assert.Equal(1830.5, entity.AudioDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SaveNotesRequest_CanBeCreated()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var request = new SaveNotesRequest
|
||||
{
|
||||
TaskId = taskId,
|
||||
Notes = "会议纪要内容"
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, request.TaskId);
|
||||
Assert.Equal("会议纪要内容", request.Notes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SaveNotesResponse_ContainsCorrectData()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var response = new SaveNotesResponse
|
||||
{
|
||||
TaskId = taskId,
|
||||
MeetingNotes = "已保存的纪要"
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, response.TaskId);
|
||||
Assert.Equal("已保存的纪要", response.MeetingNotes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeetingDetailResponse_ContainsCorrectData()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var response = new MeetingDetailResponse
|
||||
{
|
||||
TaskId = taskId,
|
||||
Title = "周一产品评审会",
|
||||
MeetingNotes = "纪要内容",
|
||||
AudioDuration = 900.0,
|
||||
IsCompleted = false
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, response.TaskId);
|
||||
Assert.Equal("周一产品评审会", response.Title);
|
||||
Assert.Equal("纪要内容", response.MeetingNotes);
|
||||
Assert.Equal(900.0, response.AudioDuration);
|
||||
Assert.False(response.IsCompleted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskEntity_MeetingType_CanBeChildTask()
|
||||
{
|
||||
var parentId = Guid.NewGuid();
|
||||
var parent = new TaskEntity
|
||||
{
|
||||
Id = parentId,
|
||||
Title = "周一例会",
|
||||
TaskType = TaskType.Meeting
|
||||
};
|
||||
|
||||
var child = new TaskEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Title = "准备PPT",
|
||||
ParentTaskId = parentId,
|
||||
ParentTask = parent
|
||||
};
|
||||
|
||||
parent.SubTasks.Add(child);
|
||||
|
||||
Assert.Single(parent.SubTasks);
|
||||
Assert.Equal(TaskType.Meeting, parent.TaskType);
|
||||
Assert.Equal(parentId, child.ParentTaskId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskType_IsDefinedOnEntity()
|
||||
{
|
||||
// 验证 TaskType 是 TaskEntity 的有效属性
|
||||
var property = typeof(TaskEntity).GetProperty("TaskType");
|
||||
Assert.NotNull(property);
|
||||
Assert.Equal(typeof(TaskType), property.PropertyType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeetingNotes_IsDefinedOnEntity()
|
||||
{
|
||||
var property = typeof(TaskEntity).GetProperty("MeetingNotes");
|
||||
Assert.NotNull(property);
|
||||
Assert.Equal(typeof(string), property.PropertyType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioDuration_IsDefinedOnEntity()
|
||||
{
|
||||
var property = typeof(TaskEntity).GetProperty("AudioDuration");
|
||||
Assert.NotNull(property);
|
||||
Assert.Equal(typeof(double?), property.PropertyType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using Hua.Todo.Application.Services.Meeting;
|
||||
using Hua.Todo.Application.Services.Meeting.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace Hua.Todo.Host.Tests.Meeting;
|
||||
|
||||
/// <summary>
|
||||
/// 工单 03-02 音频录制与转写测试。
|
||||
/// </summary>
|
||||
public class MeetingTranscriptionTests
|
||||
{
|
||||
[Fact]
|
||||
public void TranscribeRequest_CanBeCreated()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var request = new TranscribeRequest
|
||||
{
|
||||
TaskId = taskId,
|
||||
AudioBase64 = "dGVzdA==",
|
||||
Format = "webm",
|
||||
AudioDuration = 90.0
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, request.TaskId);
|
||||
Assert.Equal("dGVzdA==", request.AudioBase64);
|
||||
Assert.Equal("webm", request.Format);
|
||||
Assert.Equal(90.0, request.AudioDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TranscribeResponse_CanBeCreated()
|
||||
{
|
||||
var taskId = Guid.NewGuid();
|
||||
var response = new TranscribeResponse
|
||||
{
|
||||
TaskId = taskId,
|
||||
Transcript = "这是转写后的文字内容",
|
||||
AudioDuration = 90.0
|
||||
};
|
||||
|
||||
Assert.Equal(taskId, response.TaskId);
|
||||
Assert.Equal("这是转写后的文字内容", response.Transcript);
|
||||
Assert.Equal(90.0, response.AudioDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TranscribeResponse_DefaultValues()
|
||||
{
|
||||
var response = new TranscribeResponse();
|
||||
|
||||
Assert.Equal(Guid.Empty, response.TaskId);
|
||||
Assert.Equal(string.Empty, response.Transcript);
|
||||
Assert.Equal(0.0, response.AudioDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TranscribeRequest_DefaultValues()
|
||||
{
|
||||
var request = new TranscribeRequest();
|
||||
|
||||
Assert.Equal(Guid.Empty, request.TaskId);
|
||||
Assert.Equal(string.Empty, request.AudioBase64);
|
||||
Assert.Equal(string.Empty, request.Format);
|
||||
Assert.Equal(0.0, request.AudioDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ISttService_InterfaceExists()
|
||||
{
|
||||
var type = typeof(ISttService);
|
||||
Assert.True(type.IsInterface);
|
||||
Assert.Contains("Hua.Todo.Application.Services.Meeting", type.Namespace);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SttService_ImplementsISttService()
|
||||
{
|
||||
var type = typeof(SttService);
|
||||
Assert.True(typeof(ISttService).IsAssignableFrom(type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ISttService_HasTranscribeAsyncMethod()
|
||||
{
|
||||
var method = typeof(ISttService).GetMethod("TranscribeAsync");
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal(typeof(Task<string>), method.ReturnType);
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
Assert.Equal(3, parameters.Length);
|
||||
Assert.Equal(typeof(Stream), parameters[0].ParameterType);
|
||||
Assert.Equal(typeof(string), parameters[1].ParameterType);
|
||||
Assert.Equal(typeof(CancellationToken), parameters[2].ParameterType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IMeetingService_HasTranscribeAudioAsyncMethod()
|
||||
{
|
||||
var method = typeof(IMeetingService).GetMethod("TranscribeAudioAsync");
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal(typeof(Task<TranscribeResponse>), method.ReturnType);
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
Assert.Single(parameters);
|
||||
Assert.Equal(typeof(TranscribeRequest), parameters[0].ParameterType);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user