yx_tracking_flutter/test/system_dim_info_test.dart

253 lines
8.6 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:yx_tracking_flutter/src/model/system_dim_info.dart';
SystemDimInfo _emptyInfo({SdkStrategy? strategy}) {
return SystemDimInfo(
systemInfo: const SystemInfo(raw: <String, Object?>{'k': 'v'}),
eventDefinitions: const <EventDefinition>[],
tagDefinitions: const <TagDefinition>[],
sdkStrategy: strategy,
lastFetchedAt: DateTime.fromMillisecondsSinceEpoch(1),
version: 'v1',
);
}
String _eventCodeOf(EventDefinition event) => event.eventCode;
String _tagNameOf(TagDefinition tag) => tag.tagName;
void main() {
group('SystemDimInfo helpers', () {
test('hasEvent/requiredTags/strategy helpers', () {
final info = SystemDimInfo(
systemInfo: const SystemInfo(raw: <String, Object?>{'k': 'v'}),
eventDefinitions: const <EventDefinition>[
EventDefinition(eventCode: 'A', eventName: 'A1'),
],
tagDefinitions: const <TagDefinition>[
TagDefinition(tagName: 't1', tagType: 'string', isRequired: true),
TagDefinition(tagName: 't2', tagType: 'int', isRequired: false),
],
sdkStrategy: const SdkStrategy(
enabled: true,
defaultSampleRate: 0.5,
eventSettings: <String, EventStrategy>{
'A': EventStrategy(enabled: false, sampleRate: 0.1),
},
),
lastFetchedAt: DateTime.fromMillisecondsSinceEpoch(2),
);
expect(info.hasEvent('A'), isTrue);
expect(info.hasEvent('B'), isFalse);
expect(info.requiredTags.map((e) => e.tagName), <String>['t1']);
expect(info.isStrategyEnabled, isTrue);
expect(info.strategyFor('A')?.enabled, isFalse);
expect(info.strategyFor('B'), isNull);
expect(info.sampleRateFor('A'), 0.1);
expect(info.sampleRateFor('B'), 0.5);
expect(info.isEventEnabledByStrategy('A'), isFalse);
expect(info.isEventEnabledByStrategy('B'), isTrue);
});
test('无策略时走默认值', () {
final info = _emptyInfo();
expect(info.isStrategyEnabled, isTrue);
expect(info.strategyFor('X'), isNull);
expect(info.sampleRateFor('X'), 1);
expect(info.isEventEnabledByStrategy('X'), isTrue);
});
});
group('SystemDimInfo cache/response 解析', () {
test('toCacheJson/fromCacheJson 往返', () {
final original = SystemDimInfo(
systemInfo: const SystemInfo(raw: <String, Object?>{'a': 1}),
eventDefinitions: const <EventDefinition>[
EventDefinition(eventCode: 'E', eventName: 'Event'),
],
tagDefinitions: const <TagDefinition>[
TagDefinition(tagName: 'tag', tagType: 'string', isRequired: true),
],
sdkStrategy: const SdkStrategy(
enabled: false,
defaultSampleRate: 0.3,
eventSettings: <String, EventStrategy>{
'E': EventStrategy(enabled: true, sampleRate: 1),
},
),
lastFetchedAt: DateTime.fromMillisecondsSinceEpoch(10),
version: 'ver',
);
final cached = original.toCacheJson();
final parsed = SystemDimInfo.fromCacheJson(cached);
expect(parsed.systemInfo?.raw['a'], 1);
expect(parsed.eventDefinitions.single.eventCode, 'E');
expect(parsed.tagDefinitions.single.tagName, 'tag');
expect(parsed.sdkStrategy?.enabled, isFalse);
expect(parsed.sdkStrategy?.eventSettings['E']?.sampleRate, 1);
expect(parsed.version, 'ver');
expect(parsed.lastFetchedAt.millisecondsSinceEpoch, 10);
});
test('fromResponse 兼容字段差异与异常输入', () {
final fetchedAt = DateTime.fromMillisecondsSinceEpoch(99);
final info = SystemDimInfo.fromResponse(
<String, Object?>{
'systemInfo': <String, Object?>{'sys': true},
'systemEventTypes': <Object?>[
<String, Object?>{'event_code': 'E1', 'event_name': 'Name'},
<String, Object?>{'eventType': 'E2'},
<String, Object?>{'eventCode': ''},
123,
],
// 使用拼写错误字段名
'systemCustonTas': <Object?>[
<String, Object?>{
'tag_name': 'req',
'tag_type': 'int',
'is_required': '1',
'desc': 'd',
},
<String, Object?>{'name': 'opt', 'type': 'string'},
<String, Object?>{'tagName': ''},
'bad',
],
// 使用 sdk_strategy 字段名
'sdk_strategy': <String, Object?>{
'enabled': 'false',
'defaultSampleRate': 2,
'eventSettings': <String, Object?>{
'E1': <String, Object?>{'enabled': 0, 'sampleRate': -1},
'E2': <String, Object?>{
'enabled': true,
'sampleRate': double.infinity,
},
'bad': 1,
},
},
},
fetchedAt: fetchedAt,
version: 'v2',
);
expect(info.systemInfo?.raw['sys'], isTrue);
expect(
info.eventDefinitions.map(_eventCodeOf).toList(growable: false),
containsAll(<String>['E1', 'E2']),
);
expect(
info.tagDefinitions.map(_tagNameOf).toList(growable: false),
containsAll(<String>['req', 'opt']),
);
expect(info.tagDefinitions.first.isRequired, isTrue);
// defaultSampleRate=2 会被 clamp 为 1
expect(info.sdkStrategy?.defaultSampleRate, 1);
// -1 会被 clamp 为 0
expect(info.sdkStrategy?.eventSettings['E1']?.sampleRate, 0);
// infinity 会被 clamp 为 1
expect(info.sdkStrategy?.eventSettings['E2']?.sampleRate, 1);
expect(info.isStrategyEnabled, isFalse);
expect(info.lastFetchedAt, fetchedAt);
expect(info.version, 'v2');
});
test('异常类型输入会返回空集合/空策略', () {
final info = SystemDimInfo.fromResponse(
<String, Object?>{
'systemEventTypes': 'not-list',
'systemCustomTags': 123,
'sdkStrategy': 'bad',
},
fetchedAt: DateTime.fromMillisecondsSinceEpoch(1),
);
expect(info.eventDefinitions, isEmpty);
expect(info.tagDefinitions, isEmpty);
expect(info.sdkStrategy, isNull);
});
test('fromCacheJson 支持 num 与 string 数值', () {
final info = SystemDimInfo.fromCacheJson(
<String, Object?>{
'systemInfo': <String, Object?>{'k': 'v'},
'eventDefinitions': const <Object?>[],
'tagDefinitions': const <Object?>[],
'sdkStrategy': <String, Object?>{
'enabled': true,
'defaultSampleRate': '0.25',
'eventSettings': <String, Object?>{
'E': <String, Object?>{'enabled': true, 'sampleRate': '0.75'},
},
},
'lastFetchedAt': 1.5,
},
);
expect(info.lastFetchedAt.millisecondsSinceEpoch, 1);
expect(info.sdkStrategy?.defaultSampleRate, 0.25);
expect(info.sdkStrategy?.eventSettings['E']?.sampleRate, 0.75);
});
test('fromCacheJson 的 lastFetchedAt 支持字符串整数', () {
final info = SystemDimInfo.fromCacheJson(
<String, Object?>{
'systemInfo': const <String, Object?>{},
'eventDefinitions': const <Object?>[],
'tagDefinitions': const <Object?>[],
'lastFetchedAt': '2',
},
);
expect(info.lastFetchedAt.millisecondsSinceEpoch, 2);
});
});
group('Model toJson', () {
test('SystemInfo/EventDefinition/TagDefinition/SdkStrategy/EventStrategy', () {
const system = SystemInfo(raw: <String, Object?>{'k': 'v'});
const event = EventDefinition(eventCode: 'E', eventName: 'N');
const tag = TagDefinition(
tagName: 't',
tagType: 'string',
isRequired: true,
);
const strategy = SdkStrategy(
enabled: true,
defaultSampleRate: 0.7,
eventSettings: <String, EventStrategy>{
'E': EventStrategy(enabled: true, sampleRate: 0.7),
},
);
expect(SystemInfo.fromJson(system.toJson()).raw['k'], 'v');
expect(event.toJson()['eventCode'], 'E');
expect(tag.toJson()['isRequired'], isTrue);
expect(strategy.toJson()['eventSettings'], contains('E'));
});
test('defaultSampleRate 为 NaN 时会回落到 1', () {
final info = SystemDimInfo.fromResponse(
<String, Object?>{
'sdkStrategy': <String, Object?>{
'enabled': true,
'defaultSampleRate': double.nan,
'eventSettings': const <String, Object?>{},
},
},
fetchedAt: DateTime.fromMillisecondsSinceEpoch(1),
);
expect(info.sdkStrategy?.defaultSampleRate, 1);
});
});
}