222 lines
6.9 KiB
Dart
222 lines
6.9 KiB
Dart
import 'dart:convert';
|
||
import 'dart:io';
|
||
import 'package:test/test.dart';
|
||
|
||
void main() {
|
||
group('Encoding Support', () {
|
||
test('handles UTF-8 encoding', () {
|
||
const testString = 'Hello, 世界! 🌍';
|
||
final encoded = utf8.encode(testString);
|
||
final decoded = utf8.decode(encoded);
|
||
|
||
expect(decoded, testString);
|
||
expect(
|
||
encoded.length,
|
||
greaterThan(
|
||
testString.length,
|
||
),
|
||
); // UTF-8 uses multiple bytes for non-ASCII
|
||
});
|
||
|
||
test('handles ASCII encoding', () {
|
||
const testString = 'Hello, World!';
|
||
final encoded = ascii.encode(testString);
|
||
final decoded = ascii.decode(encoded);
|
||
|
||
expect(decoded, testString);
|
||
expect(
|
||
encoded.length,
|
||
testString.length,
|
||
); // ASCII is 1 byte per character
|
||
});
|
||
|
||
test('handles Latin1 encoding', () {
|
||
const testString = 'Café';
|
||
final encoded = latin1.encode(testString);
|
||
final decoded = latin1.decode(encoded);
|
||
|
||
expect(decoded, testString);
|
||
});
|
||
|
||
test('handles Base64 encoding and decoding', () {
|
||
const testString = 'Hello, World!';
|
||
final bytes = utf8.encode(testString);
|
||
final encoded = base64Encode(bytes);
|
||
final decoded = base64Decode(encoded);
|
||
final result = utf8.decode(decoded);
|
||
|
||
expect(result, testString);
|
||
expect(encoded, 'SGVsbG8sIFdvcmxkIQ==');
|
||
});
|
||
|
||
test('handles URL encoding and decoding', () {
|
||
const testString = r'Hello World & Special Characters!@#$%^&*()';
|
||
final encoded = Uri.encodeComponent(testString);
|
||
final decoded = Uri.decodeComponent(encoded);
|
||
|
||
expect(decoded, testString);
|
||
expect(encoded, contains('%20')); // Space should be encoded as %20
|
||
expect(encoded, contains('%26')); // & should be encoded as %26
|
||
});
|
||
|
||
test('detects BOM for UTF-8', () {
|
||
final utf8Bom = [0xEF, 0xBB, 0xBF];
|
||
final testBytes = utf8Bom + utf8.encode('Hello');
|
||
|
||
// 检测 BOM
|
||
final hasUtf8Bom = testBytes.length >= 3 &&
|
||
testBytes[0] == 0xEF &&
|
||
testBytes[1] == 0xBB &&
|
||
testBytes[2] == 0xBF;
|
||
|
||
expect(hasUtf8Bom, true);
|
||
});
|
||
|
||
test('detects BOM for UTF-16LE', () {
|
||
final utf16leBom = [0xFF, 0xFE];
|
||
|
||
final hasUtf16LeBom = utf16leBom.length >= 2 &&
|
||
utf16leBom[0] == 0xFF &&
|
||
utf16leBom[1] == 0xFE;
|
||
|
||
expect(hasUtf16LeBom, true);
|
||
});
|
||
|
||
test('detects BOM for UTF-16BE', () {
|
||
final utf16beBom = [0xFE, 0xFF];
|
||
|
||
final hasUtf16BeBom = utf16beBom.length >= 2 &&
|
||
utf16beBom[0] == 0xFE &&
|
||
utf16beBom[1] == 0xFF;
|
||
|
||
expect(hasUtf16BeBom, true);
|
||
});
|
||
|
||
test('handles chunked transfer encoding format', () {
|
||
// 模拟分块传输编码的数据格式
|
||
const chunkData = '5\r\nHello\r\n5\r\nWorld\r\n0\r\n\r\n';
|
||
final bytes = ascii.encode(chunkData);
|
||
|
||
// 简单的分块解码逻辑测试
|
||
final result = <int>[];
|
||
var offset = 0;
|
||
|
||
while (offset < bytes.length) {
|
||
// 查找块大小行的结束
|
||
var lineEnd = offset;
|
||
while (lineEnd < bytes.length - 1) {
|
||
if (bytes[lineEnd] == 13 && bytes[lineEnd + 1] == 10) break; // \r\n
|
||
lineEnd++;
|
||
}
|
||
if (lineEnd >= bytes.length - 1) break;
|
||
|
||
// 解析块大小
|
||
final sizeHex = String.fromCharCodes(bytes.sublist(offset, lineEnd));
|
||
final chunkSize = int.tryParse(sizeHex, radix: 16) ?? 0;
|
||
if (chunkSize == 0) break; // 最后一个块
|
||
|
||
// 跳过 \r\n
|
||
offset = lineEnd + 2;
|
||
|
||
// 读取块数据
|
||
if (offset + chunkSize <= bytes.length) {
|
||
result.addAll(bytes.sublist(offset, offset + chunkSize));
|
||
offset += chunkSize + 2; // 跳过块数据后的 \r\n
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
final decodedString = ascii.decode(result);
|
||
expect(decodedString, 'HelloWorld');
|
||
});
|
||
|
||
test('validates encoding compatibility', () {
|
||
const testString = 'Hello, World!';
|
||
|
||
// UTF-8 应该能处理任何字符串
|
||
expect(() => utf8.encode(testString), returnsNormally);
|
||
|
||
// ASCII 只能处理 ASCII 字符
|
||
expect(() => ascii.encode(testString), returnsNormally);
|
||
|
||
// 测试非 ASCII 字符
|
||
const nonAsciiString = 'Hello, 世界!';
|
||
expect(() => utf8.encode(nonAsciiString), returnsNormally);
|
||
expect(() => ascii.encode(nonAsciiString), throwsA(isA<ArgumentError>()));
|
||
});
|
||
|
||
test('handles different content encodings', () {
|
||
const testData = 'Hello, World!';
|
||
final originalBytes = utf8.encode(testData);
|
||
|
||
// 测试 gzip 压缩和解压
|
||
final gzipCompressed = gzip.encode(originalBytes);
|
||
final gzipDecompressed = gzip.decode(gzipCompressed);
|
||
expect(utf8.decode(gzipDecompressed), testData);
|
||
|
||
// 测试 zlib 压缩和解压
|
||
final zlibCompressed = zlib.encode(originalBytes);
|
||
final zlibDecompressed = zlib.decode(zlibCompressed);
|
||
expect(utf8.decode(zlibDecompressed), testData);
|
||
});
|
||
|
||
test('handles form URL encoding', () {
|
||
final formData = {
|
||
'name': 'John Doe',
|
||
'email': 'john@example.com',
|
||
'message': 'Hello & welcome!',
|
||
};
|
||
|
||
final encodedPairs = <String>[];
|
||
formData.forEach((key, value) {
|
||
final encodedKey = Uri.encodeComponent(key);
|
||
final encodedValue = Uri.encodeComponent(value);
|
||
encodedPairs.add('$encodedKey=$encodedValue');
|
||
});
|
||
|
||
final encoded = encodedPairs.join('&');
|
||
expect(encoded, contains('name=John%20Doe'));
|
||
expect(encoded, contains('email=john%40example.com'));
|
||
expect(encoded, contains('message=Hello%20%26%20welcome!'));
|
||
});
|
||
|
||
test('handles binary data encoding', () {
|
||
// 创建一些二进制数据
|
||
final binaryData = List.generate(256, (i) => i);
|
||
|
||
// Base64 编码
|
||
final base64Encoded = base64Encode(binaryData);
|
||
final base64Decoded = base64Decode(base64Encoded);
|
||
expect(base64Decoded, binaryData);
|
||
|
||
// 验证 Base64 编码的特征
|
||
expect(base64Encoded.length % 4, 0); // Base64 长度应该是 4 的倍数
|
||
expect(RegExp(r'^[A-Za-z0-9+/]*={0,2}$').hasMatch(base64Encoded), true);
|
||
});
|
||
|
||
test('handles mixed encoding scenarios', () {
|
||
// 模拟真实场景:JSON 数据包含多种字符
|
||
final jsonData = {
|
||
'name': 'José María',
|
||
'description': 'Café & Restaurant 🍽️',
|
||
'price': 29.99,
|
||
'tags': ['food', 'café', '美食'],
|
||
};
|
||
|
||
final jsonString = jsonEncode(jsonData);
|
||
final utf8Bytes = utf8.encode(jsonString);
|
||
final base64Encoded = base64Encode(utf8Bytes);
|
||
|
||
// 解码过程
|
||
final decodedBytes = base64Decode(base64Encoded);
|
||
final decodedString = utf8.decode(decodedBytes);
|
||
final decodedJson = jsonDecode(decodedString) as Map<String, dynamic>;
|
||
|
||
expect(decodedJson['name'], 'José María');
|
||
expect(decodedJson['description'], 'Café & Restaurant 🍽️');
|
||
expect(decodedJson['tags'], ['food', 'café', '美食']);
|
||
});
|
||
});
|
||
}
|