Files
Qlyra/test/max_web_protocol_test.dart
sevenhill f74057ce9b
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
Rebrand application as Qlyra
2026-08-30 13:16:17 +03:00

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,
);
});
}