feat: 添加自动化任务(automation_jobs)功能模块
This commit is contained in:
@@ -1,173 +0,0 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:social_app/features/chat/data/ai/ai_decision_engine.dart';
|
||||
|
||||
void main() {
|
||||
late AiDecisionEngine engine;
|
||||
|
||||
setUp(() {
|
||||
engine = AiDecisionEngine();
|
||||
});
|
||||
|
||||
group('matchIntent', () {
|
||||
test('returns searchEvent for "今天有什么日程"', () {
|
||||
expect(engine.matchIntent('今天有什么日程'), Intent.searchEvent);
|
||||
});
|
||||
|
||||
test('returns searchEvent for "查看日程"', () {
|
||||
expect(engine.matchIntent('查看日程'), Intent.searchEvent);
|
||||
});
|
||||
|
||||
test('returns searchEvent for "查询安排"', () {
|
||||
expect(engine.matchIntent('查询安排'), Intent.searchEvent);
|
||||
});
|
||||
|
||||
test('returns createEvent for "提醒我明天开会"', () {
|
||||
expect(engine.matchIntent('提醒我明天开会'), Intent.createEvent);
|
||||
});
|
||||
|
||||
test('returns createEvent for "安排时间"', () {
|
||||
expect(engine.matchIntent('安排时间'), Intent.createEvent);
|
||||
});
|
||||
|
||||
test('returns createEvent for time pattern "明天10点"', () {
|
||||
expect(engine.matchIntent('明天10点'), Intent.createEvent);
|
||||
});
|
||||
|
||||
test('returns unknown for "你好"', () {
|
||||
expect(engine.matchIntent('你好'), Intent.unknown);
|
||||
});
|
||||
|
||||
test('returns unknown for random text', () {
|
||||
expect(engine.matchIntent('随便说点什么'), Intent.unknown);
|
||||
});
|
||||
});
|
||||
|
||||
group('shouldTriggerToolCall', () {
|
||||
test('returns false for "你好"', () {
|
||||
expect(engine.shouldTriggerToolCall('你好'), false);
|
||||
});
|
||||
|
||||
test('returns false for search intent', () {
|
||||
expect(engine.shouldTriggerToolCall('今天有什么日程'), false);
|
||||
});
|
||||
|
||||
test('returns true for create event intent', () {
|
||||
expect(engine.shouldTriggerToolCall('提醒我明天开会'), true);
|
||||
});
|
||||
|
||||
test('returns true for time pattern', () {
|
||||
expect(engine.shouldTriggerToolCall('明天10点开会'), true);
|
||||
});
|
||||
});
|
||||
|
||||
group('tryExtractEventArgs', () {
|
||||
test('returns map with title and startAt for "提醒我明天10点开会"', () {
|
||||
final result = engine.tryExtractEventArgs('提醒我明天10点开会');
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['title'], isNotNull);
|
||||
expect(result['startAt'], isNotNull);
|
||||
expect(result['timezone'], 'Asia/Shanghai');
|
||||
});
|
||||
|
||||
test('returns null for "你好"', () {
|
||||
expect(engine.tryExtractEventArgs('你好'), isNull);
|
||||
});
|
||||
|
||||
test('returns null for search intent', () {
|
||||
expect(engine.tryExtractEventArgs('今天有什么日程'), isNull);
|
||||
});
|
||||
|
||||
test('extracts title correctly', () {
|
||||
final result = engine.tryExtractEventArgs('提醒我开会明天10点');
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['title'], contains('开会'));
|
||||
});
|
||||
|
||||
test('parses today time correctly', () {
|
||||
final result = engine.tryExtractEventArgs('开会今天14:30');
|
||||
final now = DateTime.now();
|
||||
|
||||
expect(result, isNotNull);
|
||||
final startAt = DateTime.parse(result!['startAt'] as String);
|
||||
expect(startAt.year, now.year);
|
||||
expect(startAt.month, now.month);
|
||||
expect(startAt.day, now.day);
|
||||
expect(startAt.hour, 14);
|
||||
expect(startAt.minute, 30);
|
||||
});
|
||||
|
||||
test('parses tomorrow time correctly', () {
|
||||
final result = engine.tryExtractEventArgs('开会明天9点');
|
||||
final now = DateTime.now();
|
||||
final expectedTomorrow = DateTime(now.year, now.month, now.day + 1);
|
||||
|
||||
expect(result, isNotNull);
|
||||
final startAt = DateTime.parse(result!['startAt'] as String);
|
||||
expect(startAt.day, equals(expectedTomorrow.day));
|
||||
expect(startAt.hour, 9);
|
||||
expect(startAt.minute, 0);
|
||||
});
|
||||
});
|
||||
|
||||
group('tryForceTrigger', () {
|
||||
test(
|
||||
'returns ForceTriggerResult for "#tool:front.navigate_to_route {}"',
|
||||
() {
|
||||
final result = engine.tryForceTrigger(
|
||||
'#tool:front.navigate_to_route {}',
|
||||
);
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!.toolName, 'front.navigate_to_route');
|
||||
expect(result.args, isEmpty);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'returns ForceTriggerResult with args for "#tool:custom {"key": "value"}"',
|
||||
() {
|
||||
final result = engine.tryForceTrigger('#tool:custom {"key": "value"}');
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!.toolName, 'custom');
|
||||
expect(result.args['key'], 'value');
|
||||
},
|
||||
);
|
||||
|
||||
test('returns null for normal text', () {
|
||||
expect(engine.tryForceTrigger('普通文本'), isNull);
|
||||
});
|
||||
|
||||
test('returns null for empty string', () {
|
||||
expect(engine.tryForceTrigger(''), isNull);
|
||||
});
|
||||
|
||||
test('handles invalid JSON gracefully', () {
|
||||
final result = engine.tryForceTrigger('#tool:test {invalid json}');
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!.toolName, 'test');
|
||||
expect(result.args, isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
group('getToolCallArgs', () {
|
||||
test('returns args for create event intent', () {
|
||||
final result = engine.getToolCallArgs('提醒我明天10点开会');
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['title'], isNotNull);
|
||||
expect(result['startAt'], isNotNull);
|
||||
});
|
||||
|
||||
test('returns null for non-create intent', () {
|
||||
expect(engine.getToolCallArgs('你好'), isNull);
|
||||
});
|
||||
|
||||
test('returns null for search intent', () {
|
||||
expect(engine.getToolCallArgs('今天有什么日程'), isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:social_app/features/chat/data/tools/route_navigation_tool.dart';
|
||||
import 'package:social_app/features/chat/data/tools/tool_registry.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
ToolRegistry.initialize();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
RouteNavigationTool.instance.clearNavigator();
|
||||
});
|
||||
|
||||
group('getTool', () {
|
||||
test('returns tool definition for front.navigate_to_route', () {
|
||||
final tool = ToolRegistry.getTool('front.navigate_to_route');
|
||||
|
||||
expect(tool, isNotNull);
|
||||
expect(tool!.name, 'front.navigate_to_route');
|
||||
expect(tool.description, isNotEmpty);
|
||||
});
|
||||
|
||||
test('returns null for unknown tool', () {
|
||||
expect(ToolRegistry.getTool('unknown_tool'), isNull);
|
||||
});
|
||||
});
|
||||
|
||||
group('validateArgs', () {
|
||||
test('returns error for empty args (missing target)', () {
|
||||
final result = ToolRegistry.validateArgs('front.navigate_to_route', {});
|
||||
|
||||
expect(result.ok, false);
|
||||
expect(result.error, contains('target'));
|
||||
});
|
||||
|
||||
test('returns ok: true for valid args', () {
|
||||
final result = ToolRegistry.validateArgs('front.navigate_to_route', {
|
||||
'target': '/settings',
|
||||
});
|
||||
|
||||
expect(result.ok, true);
|
||||
expect(result.error, isNull);
|
||||
});
|
||||
|
||||
test('returns error for unknown tool', () {
|
||||
final result = ToolRegistry.validateArgs('unknown_tool', {});
|
||||
|
||||
expect(result.ok, false);
|
||||
expect(result.error, contains('Tool not found'));
|
||||
});
|
||||
});
|
||||
|
||||
group('execute', () {
|
||||
test('throws ToolNotFoundException for unknown tool', () async {
|
||||
expect(
|
||||
() => ToolRegistry.execute('unknown_tool', {}),
|
||||
throwsA(isA<ToolNotFoundException>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('front.navigate_to_route rejects disallowed target', () async {
|
||||
final result = await ToolRegistry.execute('front.navigate_to_route', {
|
||||
'target': '/admin',
|
||||
});
|
||||
|
||||
expect(result['ok'], false);
|
||||
expect(result['error'], contains('not allowed'));
|
||||
});
|
||||
|
||||
test(
|
||||
'front.navigate_to_route executes allowed target when navigator is bound',
|
||||
() async {
|
||||
String? navigatedTo;
|
||||
bool replaced = false;
|
||||
RouteNavigationTool.instance.bindNavigator((target, {replace = false}) {
|
||||
navigatedTo = target;
|
||||
replaced = replace;
|
||||
});
|
||||
|
||||
final result = await ToolRegistry.execute('front.navigate_to_route', {
|
||||
'target': '/settings',
|
||||
'replace': true,
|
||||
});
|
||||
|
||||
expect(result['ok'], true);
|
||||
expect(navigatedTo, '/settings');
|
||||
expect(replaced, true);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('getAllTools', () {
|
||||
test('returns list of tool definitions', () {
|
||||
final tools = ToolRegistry.getAllTools();
|
||||
|
||||
expect(tools, isNotEmpty);
|
||||
expect(tools.any((t) => t.name == 'front.navigate_to_route'), true);
|
||||
expect(tools.any((t) => t.name == 'create_calendar_event'), false);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user