水印优化+ORC优化

This commit is contained in:
2026-09-28 11:39:19 +08:00
parent c5b3d81d07
commit 6176c49964
19 changed files with 1701 additions and 171 deletions
+159
View File
@@ -0,0 +1,159 @@
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:qiangbao_accounting/api/geo_api.dart';
import 'package:qiangbao_accounting/core/network/api_exception.dart';
/// 用一个假的 HTTP 适配器接管请求,按 URL 分发不同的响应。
/// 这样不用真的联网,也能把「百度失败 → Nominatim 兜底」整条链路跑通。
class _FakeAdapter implements HttpClientAdapter {
_FakeAdapter(this.handler);
final Future<ResponseBody> Function(RequestOptions options) handler;
/// 记录每次请求,用来断言请求头和参数
final List<RequestOptions> requests = [];
@override
Future<ResponseBody> fetch(
RequestOptions options,
Stream<Uint8List>? requestStream,
Future<void>? cancelFuture,
) {
requests.add(options);
return handler(options);
}
@override
void close({bool force = false}) {}
}
ResponseBody _json(String body) => ResponseBody.fromString(
body,
200,
headers: {
Headers.contentTypeHeader: ['application/json'],
},
);
bool _isBaidu(RequestOptions o) => o.uri.host.contains('baidu');
bool _isNominatim(RequestOptions o) => o.uri.host.contains('nominatim');
void main() {
GeoApi apiWith(_FakeAdapter adapter) => GeoApi(dio: Dio()..httpClientAdapter = adapter);
group('地址解析:百度优先、Nominatim 兜底', () {
test('百度正常时用百度的结果(国内数据最准)', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) {
return _json(
'{"status":0,"result":{"formatted_address":"云南省昆明市五华区护国街道南屏街112"}}',
);
}
fail('百度成功了就不该再去打 Nominatim');
});
final address = await apiWith(adapter)
.reverseAddress(latitude: 25.041234, longitude: 102.712345);
expect(address, '云南省昆明市五华区护国街道南屏街112');
expect(adapter.requests.length, 1);
});
test('★ 百度配额用完时自动降级到 Nominatim(用户实际撞到的情况)', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) {
return _json('{"status":4,"msg":"AK 配额校验失败"}');
}
return _json(
'{"display_name":"庆云街, 护国街道, 五华区, 昆明市, 云南省, 650011, 中国",'
'"address":{"road":"庆云街","suburb":"护国街道","district":"五华区",'
'"city":"昆明市","state":"云南省","postcode":"650011","country":"中国"}}',
);
});
final address = await apiWith(adapter)
.reverseAddress(latitude: 25.041234, longitude: 102.712345);
// 拼成中文习惯的「大 → 小」,而不是 Nominatim 原生的「小 → 大」
expect(address, '云南省昆明市五华区护国街道庆云街');
expect(adapter.requests.length, 2);
});
test('百度网络异常也会降级(不只是配额问题)', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) {
throw DioException(requestOptions: o, message: 'connection timeout');
}
return _json('{"address":{"state":"云南省","city":"昆明市","district":"五华区"}}');
});
final address = await apiWith(adapter)
.reverseAddress(latitude: 25.0, longitude: 102.7);
expect(address, '云南省昆明市五华区');
});
test('两个都挂时,把百度的原因带出来(而不是一句笼统的失败)', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) return _json('{"status":4,"msg":"AK 配额校验失败"}');
throw DioException(requestOptions: o, message: 'timeout');
});
expect(
() => apiWith(adapter).reverseAddress(latitude: 25.0, longitude: 102.7),
throwsA(
isA<ApiException>().having(
(e) => e.message,
'message',
contains('配额'),
),
),
);
});
test('Nominatim 只给 display_name 时也能拼出地址,且滤掉邮编和国家', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) return _json('{"status":1,"msg":"失败"}');
return _json(
'{"display_name":"庆云街, 护国街道, 五华区, 昆明市, 云南省, 650011, 中国"}',
);
});
final address = await apiWith(adapter)
.reverseAddress(latitude: 25.0, longitude: 102.7);
expect(address, '云南省昆明市五华区护国街道庆云街');
});
test('Nominatim 请求必须带 User-Agent(它的使用政策要求,不带会被拒)', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) return _json('{"status":1,"msg":"失败"}');
return _json('{"address":{"state":"云南省"}}');
});
await apiWith(adapter).reverseAddress(latitude: 25.0, longitude: 102.7);
final nominatim = adapter.requests.firstWhere(_isNominatim);
expect(nominatim.headers['User-Agent'], isNotNull);
expect(nominatim.headers['User-Agent'], contains('Qiangbao'));
});
test('百度请求带 coordtype=wgs84ll(geolocator 给的是 WGS84)', () async {
final adapter = _FakeAdapter((o) async {
if (_isBaidu(o)) {
return _json('{"status":0,"result":{"formatted_address":"昆明"}}');
}
return _json('{}');
});
await apiWith(adapter).reverseAddress(latitude: 25.0, longitude: 102.7);
final baidu = adapter.requests.firstWhere(_isBaidu);
expect(baidu.uri.queryParameters['coordtype'], 'wgs84ll');
expect(baidu.uri.queryParameters['location'], '25.0,102.7');
});
});
}