// 功能描述:验证 multipart 文件上传鉴权、会话过期与资源路径解析。 // 版本:1.0.0。 import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:user_app/data/repositories/client_repository.dart'; import 'package:user_app/data/services/api_client.dart'; void main() { test('上传携带鉴权和文件内容,不使用 JSON 包装二进制', () async { final api = ApiClient( () => 'test-token', baseUrl: 'https://api.example.com', client: MockClient((request) async { expect(request.headers['authorization'], 'test-token'); expect(request.url.path, '/upload/avatar'); expect(request.headers['content-type'], startsWith('multipart/form-data; boundary=')); expect(request.body, contains('name="file"; filename="avatar.png"')); return http.Response('{"code":0,"details":{"uri":"/uploads/avatars/test.png"}}', 200); }), ); expect( await ClientRepository(api).uploadAvatar(Uint8List.fromList([1, 2, 3]), 'avatar.png'), '/uploads/avatars/test.png', ); }); test('超过大小限制不会发起请求;上传过期使会话失效', () async { var requests = 0; final rejected = []; final api = ApiClient( () => 'expired', onUnauthorized: rejected.add, client: MockClient((request) async { requests++; return http.Response('', 401); }), ); await expectLater( api.uploadAvatar(Uint8List(2 * 1024 * 1024 + 1), 'x.png'), throwsA(isA()), ); expect(requests, 0); await expectLater( api.uploadAvatar(Uint8List.fromList([1]), 'x.png'), throwsA(isA()), ); expect(rejected, ['expired']); }); test('图片相对路径使用配置的 API 域名,拒绝非网络协议', () { final repo = ClientRepository(ApiClient(() => '', baseUrl: 'https://api.example.com')); expect( repo.resolveImageUrl('/uploads/product.png'), 'https://api.example.com/uploads/product.png', ); expect(repo.resolveImageUrl('https://cdn.example.com/a.png'), 'https://cdn.example.com/a.png'); for (final value in ['//other.example.com/a', 'javascript:x', 'file:///secret']) { expect(repo.resolveImageUrl(value), ''); } }); }