Unverified Commit ecd89fb7 authored by Yegor's avatar Yegor Committed by GitHub

fix message codecs for the Web (#36549)

parent 5ecda9e1
......@@ -338,6 +338,14 @@ class StandardMessageCodec implements MessageCodec<dynamic> {
buffer.putUint8(_valueNull);
} else if (value is bool) {
buffer.putUint8(value ? _valueTrue : _valueFalse);
} else if (value is double) { // Double precedes int because in JS everything is a double.
// Therefore in JS, both `is int` and `is double` always
// return `true`. If we check int first, we'll end up treating
// all numbers as ints and attempt the int32/int64 conversion,
// which is wrong. This precedence rule is irrelevant when
// decoding because we use tags to detect the type of value.
buffer.putUint8(_valueFloat64);
buffer.putFloat64(value);
} else if (value is int) {
if (-0x7fffffff - 1 <= value && value <= 0x7fffffff) {
buffer.putUint8(_valueInt32);
......@@ -346,9 +354,6 @@ class StandardMessageCodec implements MessageCodec<dynamic> {
buffer.putUint8(_valueInt64);
buffer.putInt64(value);
}
} else if (value is double) {
buffer.putUint8(_valueFloat64);
buffer.putFloat64(value);
} else if (value is String) {
buffer.putUint8(_valueString);
final List<int> bytes = utf8.encoder.convert(value);
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:flutter/services.dart';
import '../flutter_test_alternative.dart';
void checkEncoding<T>(MessageCodec<T> codec, T message, List<int> expectedBytes) {
final ByteData encoded = codec.encodeMessage(message);
expect(
encoded.buffer.asUint8List(0, encoded.lengthInBytes),
orderedEquals(expectedBytes),
);
}
void checkEncodeDecode<T>(MessageCodec<T> codec, T message) {
final ByteData encoded = codec.encodeMessage(message);
final T decoded = codec.decodeMessage(encoded);
if (message == null) {
expect(encoded, isNull);
expect(decoded, isNull);
} else {
expect(deepEquals(message, decoded), isTrue);
final ByteData encodedAgain = codec.encodeMessage(decoded);
expect(
encodedAgain.buffer.asUint8List(),
orderedEquals(encoded.buffer.asUint8List()),
);
}
}
bool deepEquals(dynamic valueA, dynamic valueB) {
if (valueA is TypedData)
return valueB is TypedData && deepEqualsTypedData(valueA, valueB);
if (valueA is List)
return valueB is List && deepEqualsList(valueA, valueB);
if (valueA is Map)
return valueB is Map && deepEqualsMap(valueA, valueB);
if (valueA is double && valueA.isNaN)
return valueB is double && valueB.isNaN;
return valueA == valueB;
}
bool deepEqualsTypedData(TypedData valueA, TypedData valueB) {
if (valueA is ByteData) {
return valueB is ByteData
&& deepEqualsList(
valueA.buffer.asUint8List(), valueB.buffer.asUint8List());
}
if (valueA is Uint8List)
return valueB is Uint8List && deepEqualsList(valueA, valueB);
if (valueA is Int32List)
return valueB is Int32List && deepEqualsList(valueA, valueB);
if (valueA is Int64List)
return valueB is Int64List && deepEqualsList(valueA, valueB);
if (valueA is Float64List)
return valueB is Float64List && deepEqualsList(valueA, valueB);
throw 'Unexpected typed data: $valueA';
}
bool deepEqualsList(List<dynamic> valueA, List<dynamic> valueB) {
if (valueA.length != valueB.length)
return false;
for (int i = 0; i < valueA.length; i++) {
if (!deepEquals(valueA[i], valueB[i]))
return false;
}
return true;
}
bool deepEqualsMap(Map<dynamic, dynamic> valueA, Map<dynamic, dynamic> valueB) {
if (valueA.length != valueB.length)
return false;
for (final dynamic key in valueA.keys) {
if (!valueB.containsKey(key) || !deepEquals(valueA[key], valueB[key]))
return false;
}
return true;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains tests that are only supported by the Dart VM. For
// example, on the Web there's no way to express large integers.
@TestOn('!chrome')
import 'dart:typed_data';
import 'package:flutter/services.dart';
import '../flutter_test_alternative.dart';
import 'message_codecs_testing.dart';
void main() {
group('JSON message codec', () {
const MessageCodec<dynamic> json = JSONMessageCodec();
test('should encode and decode big numbers', () {
checkEncodeDecode<dynamic>(json, 9223372036854775807);
checkEncodeDecode<dynamic>(json, -9223372036854775807);
});
test('should encode and decode list with a big number', () {
final List<dynamic> message = <dynamic>[-7000000000000000007];
checkEncodeDecode<dynamic>(json, message);
});
});
group('Standard message codec', () {
const MessageCodec<dynamic> standard = StandardMessageCodec();
test('should encode integers correctly at boundary cases', () {
checkEncoding<dynamic>(
standard,
-0x7fffffff - 1,
<int>[3, 0x00, 0x00, 0x00, 0x80],
);
checkEncoding<dynamic>(
standard,
-0x7fffffff - 2,
<int>[4, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff],
);
checkEncoding<dynamic>(
standard,
0x7fffffff,
<int>[3, 0xff, 0xff, 0xff, 0x7f],
);
checkEncoding<dynamic>(
standard,
0x7fffffff + 1,
<int>[4, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00],
);
checkEncoding<dynamic>(
standard,
-0x7fffffffffffffff - 1,
<int>[4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80],
);
checkEncoding<dynamic>(
standard,
-0x7fffffffffffffff - 2,
<int>[4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f],
);
checkEncoding<dynamic>(
standard,
0x7fffffffffffffff,
<int>[4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f],
);
checkEncoding<dynamic>(
standard,
0x7fffffffffffffff + 1,
<int>[4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80],
);
});
test('should encode and decode big numbers', () {
checkEncodeDecode<dynamic>(standard, 9223372036854775807);
checkEncodeDecode<dynamic>(standard, -9223372036854775807);
});
test('should encode and decode a list containing big numbers', () {
final List<dynamic> message = <dynamic>[
-7000000000000000007,
Int64List.fromList(
<int>[-0x7fffffffffffffff - 1, 0, 0x7fffffffffffffff]),
];
checkEncodeDecode<dynamic>(standard, message);
});
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment