Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s
161 lines
4.1 KiB
Dart
161 lines
4.1 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:qlyra/core/webpush/max_web_protocol.dart';
|
|
|
|
Uint8List _hex(String value) {
|
|
final bytes = Uint8List(value.length ~/ 2);
|
|
for (var i = 0; i < bytes.length; i++) {
|
|
bytes[i] = int.parse(value.substring(i * 2, i * 2 + 2), radix: 16);
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
const _compressedResponseHex =
|
|
'0a010000000601000018f00782a6726567696f6ea25a5aa973796e746865746963c3';
|
|
|
|
void main() {
|
|
test('заголовок кадра совпадает с синтетическим вектором', () {
|
|
final frame = _hex(_compressedResponseHex);
|
|
expect(frame[0], MaxWebFraming.protocolVersion);
|
|
final decoded = MaxWebFraming.decode(frame);
|
|
expect(decoded.cmd, MaxWebCmd.ok);
|
|
expect(decoded.opcode, 6);
|
|
expect(decoded.isOk, isTrue);
|
|
});
|
|
|
|
test('распаковка LZ4 и msgpack из синтетического кадра', () {
|
|
final decoded = MaxWebFraming.decode(_hex(_compressedResponseHex));
|
|
final payload = decoded.payload as Map<Object?, Object?>;
|
|
expect(payload['region'], 'ZZ');
|
|
expect(payload['synthetic'], isTrue);
|
|
expect(payload.length, 2);
|
|
});
|
|
|
|
test('кодирование кадра сохраняет контракт заголовка', () {
|
|
final actual = MaxWebFraming.encode(
|
|
cmd: 0,
|
|
seq: 2,
|
|
opcode: 6,
|
|
payload: <String, Object?>{'synthetic': true},
|
|
);
|
|
expect(
|
|
actual.sublist(0, MaxWebFraming.headerSize),
|
|
_hex('0a00000200060000000c'),
|
|
);
|
|
});
|
|
|
|
test('msgpack переживает круговой рейс', () {
|
|
final source = <String, Object?>{
|
|
'enabled': true,
|
|
'count': 40,
|
|
'offset': -1,
|
|
'nested': <String, Object?>{
|
|
'a': null,
|
|
'b': 3.5,
|
|
'c': <Object?>[1, 'два', false],
|
|
},
|
|
};
|
|
final restored =
|
|
MaxMsgpack.decode(MaxMsgpack.encode(source)) as Map<Object?, Object?>;
|
|
expect(restored['enabled'], true);
|
|
expect(restored['count'], 40);
|
|
expect(restored['offset'], -1);
|
|
final nested = restored['nested'] as Map<Object?, Object?>;
|
|
expect(nested['a'], isNull);
|
|
expect(nested['b'], 3.5);
|
|
expect((nested['c'] as List<Object?>)[1], 'два');
|
|
});
|
|
|
|
test('ext(1) разворачивается во вложенное число', () {
|
|
final pollingInterval =
|
|
MaxMsgpack.decode(
|
|
Uint8List.fromList([
|
|
0x81,
|
|
0xA8,
|
|
0x69,
|
|
0x6E,
|
|
0x74,
|
|
0x65,
|
|
0x72,
|
|
0x76,
|
|
0x61,
|
|
0x6C,
|
|
0xC7,
|
|
0x03,
|
|
0x01,
|
|
0xD1,
|
|
0x13,
|
|
0x88,
|
|
]),
|
|
)
|
|
as Map<Object?, Object?>;
|
|
expect(pollingInterval['interval'], 5000);
|
|
|
|
final expiresAt = MaxMsgpack.decode(
|
|
Uint8List.fromList([
|
|
0xC7,
|
|
0x09,
|
|
0x01,
|
|
0xD3,
|
|
0x00,
|
|
0x00,
|
|
0x01,
|
|
0xA0,
|
|
0x25,
|
|
0x5B,
|
|
0xE9,
|
|
0xD2,
|
|
]),
|
|
);
|
|
expect(expiresAt, 1787333175762);
|
|
});
|
|
|
|
test('LZ4 разворачивает перекрывающиеся совпадения', () {
|
|
final compressed = Uint8List.fromList([
|
|
0x6E,
|
|
0x71,
|
|
0x6C,
|
|
0x79,
|
|
0x72,
|
|
0x61,
|
|
0x20,
|
|
0x06,
|
|
0x00,
|
|
0x46,
|
|
0x70,
|
|
0x75,
|
|
0x73,
|
|
0x68,
|
|
0x05,
|
|
0x00,
|
|
0x50,
|
|
0x20,
|
|
0x70,
|
|
0x75,
|
|
0x73,
|
|
0x68,
|
|
]);
|
|
final result = Lz4Block.decompress(compressed, 256);
|
|
expect(utf8.decode(result), 'qlyra qlyra qlyra qlyra push push push push');
|
|
});
|
|
|
|
test('отклоняет кадр с несовпадающей длиной', () {
|
|
expect(
|
|
() => MaxWebFraming.decode(_hex('0a000002000600000003aa')),
|
|
throwsFormatException,
|
|
);
|
|
});
|
|
|
|
test('ограничивает распаковку LZ4', () {
|
|
expect(
|
|
() => Lz4Block.decompress(
|
|
Uint8List.fromList([0x1f, 0x41, 0x01, 0x00, 0x00]),
|
|
8,
|
|
),
|
|
throwsFormatException,
|
|
);
|
|
});
|
|
}
|