246050a1ef
The new formatter supports opting a region of code out from being formatted. I'm applying this marker to all of the multitests since those tests are often very sensitive to formatting and easily broken. This way, anyone touching a multitest (including me when I reformat the tests) doesn't have to remember to not run the formatter on it. Change-Id: I34831719cd35e669b49e02a0d00c32b44068a34e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396103 Commit-Queue: Lasse Nielsen <lrn@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Auto-Submit: Bob Nystrom <rnystrom@google.com>
302 lines
9.8 KiB
Dart
302 lines
9.8 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// Formatting can break multitests, so don't format them.
|
|
// dart format off
|
|
|
|
import 'dart:convert';
|
|
import "dart:typed_data";
|
|
import "package:expect/expect.dart";
|
|
|
|
main() {
|
|
for (var list in [
|
|
<int>[],
|
|
[0x00],
|
|
[0xff, 0x00],
|
|
[0xff, 0xaa, 0x55],
|
|
[0x00, 0x01, 0x02, 0x03],
|
|
new Iterable<int>.generate(13).toList(),
|
|
new Iterable<int>.generate(254).toList(),
|
|
new Iterable<int>.generate(255).toList(),
|
|
new Iterable<int>.generate(256).toList()
|
|
]) {
|
|
testRoundtrip(list, "List#${list.length}");
|
|
testRoundtrip(new Uint8List.fromList(list), "Uint8List#${list.length}");
|
|
}
|
|
testErrors();
|
|
testIssue25577();
|
|
|
|
// Decoder is lenient with mixed styles.
|
|
Expect.listEquals([0xfb, 0xff, 0xbf, 0x00], base64.decode("-_+/AA%3D="));
|
|
Expect.listEquals([0xfb, 0xff, 0xbf, 0x00], base64.decode("-_+/AA=%3D"));
|
|
}
|
|
|
|
void testRoundtrip(List<int> list, String name) {
|
|
// Direct.
|
|
String encodedNormal = base64.encode(list);
|
|
String encodedPercent = encodedNormal.replaceAll("=", "%3D");
|
|
String uriEncoded = base64Url.encode(list);
|
|
String expectedUriEncoded =
|
|
encodedNormal.replaceAll("+", "-").replaceAll("/", "_");
|
|
Expect.equals(expectedUriEncoded, uriEncoded);
|
|
|
|
List result = base64.decode(encodedNormal);
|
|
Expect.listEquals(list, result, name);
|
|
result = base64.decode(encodedPercent);
|
|
Expect.listEquals(list, result, name);
|
|
result = base64.decode(uriEncoded);
|
|
Expect.listEquals(list, result, name);
|
|
|
|
int increment = list.length ~/ 7 + 1;
|
|
// Chunked.
|
|
for (int i = 0; i < list.length; i += increment) {
|
|
for (int j = i; j < list.length; j += increment) {
|
|
// Normal
|
|
{
|
|
// Using add/close
|
|
var results;
|
|
var sink = new ChunkedConversionSink<String>.withCallback((v) {
|
|
results = v;
|
|
});
|
|
var encoder = base64.encoder.startChunkedConversion(sink);
|
|
encoder.add(list.sublist(0, i));
|
|
encoder.add(list.sublist(i, j));
|
|
encoder.add(list.sublist(j, list.length));
|
|
encoder.close();
|
|
var name = "0-$i-$j-${list.length}: list";
|
|
Expect.equals(encodedNormal, results.join(""), name);
|
|
}
|
|
{
|
|
// Using addSlice
|
|
var results;
|
|
var sink = new ChunkedConversionSink<String>.withCallback((v) {
|
|
results = v;
|
|
});
|
|
var encoder = base64.encoder.startChunkedConversion(sink);
|
|
encoder.addSlice(list, 0, i, false);
|
|
encoder.addSlice(list, i, j, false);
|
|
encoder.addSlice(list, j, list.length, true);
|
|
var name = "0-$i-$j-${list.length}: $list";
|
|
Expect.equals(encodedNormal, results.join(""), name);
|
|
}
|
|
// URI
|
|
{
|
|
// Using add/close
|
|
var results;
|
|
var sink = new ChunkedConversionSink<String>.withCallback((v) {
|
|
results = v;
|
|
});
|
|
var encoder = base64Url.encoder.startChunkedConversion(sink);
|
|
encoder.add(list.sublist(0, i));
|
|
encoder.add(list.sublist(i, j));
|
|
encoder.add(list.sublist(j, list.length));
|
|
encoder.close();
|
|
var name = "0-$i-$j-${list.length}: list";
|
|
Expect.equals(uriEncoded, results.join(""), name);
|
|
}
|
|
{
|
|
// Using addSlice
|
|
var results;
|
|
var sink = new ChunkedConversionSink<String>.withCallback((v) {
|
|
results = v;
|
|
});
|
|
var encoder = base64Url.encoder.startChunkedConversion(sink);
|
|
encoder.addSlice(list, 0, i, false);
|
|
encoder.addSlice(list, i, j, false);
|
|
encoder.addSlice(list, j, list.length, true);
|
|
var name = "0-$i-$j-${list.length}: $list";
|
|
Expect.equals(uriEncoded, results.join(""), name);
|
|
}
|
|
}
|
|
}
|
|
// Using .encode
|
|
Expect.equals(uriEncoded, base64Url.encode(list), ".encode($list)");
|
|
// Using base64UrlEncode
|
|
Expect.equals(uriEncoded, base64UrlEncode(list), ".encode($list)");
|
|
|
|
for (var encoded in [encodedNormal, encodedPercent, uriEncoded]) {
|
|
increment = encoded.length ~/ 7 + 1;
|
|
for (int i = 0; i < encoded.length; i += increment) {
|
|
for (int j = i; j < encoded.length; j += increment) {
|
|
{
|
|
// Using add/close
|
|
late List<List<int>> results;
|
|
var sink = new ChunkedConversionSink<List<int>>.withCallback((v) {
|
|
results = v;
|
|
});
|
|
var decoder = base64.decoder.startChunkedConversion(sink);
|
|
decoder.add(encoded.substring(0, i));
|
|
decoder.add(encoded.substring(i, j));
|
|
decoder.add(encoded.substring(j, encoded.length));
|
|
decoder.close();
|
|
var name = "0-$i-$j-${encoded.length}: $encoded";
|
|
Expect.listEquals(list, results.expand((x) => x).toList(), name);
|
|
}
|
|
{
|
|
// Using addSlice
|
|
late List<List<int>> results;
|
|
var sink = new ChunkedConversionSink<List<int>>.withCallback((v) {
|
|
results = v;
|
|
});
|
|
var decoder = base64.decoder.startChunkedConversion(sink);
|
|
decoder.addSlice(encoded, 0, i, false);
|
|
decoder.addSlice(encoded, i, j, false);
|
|
decoder.addSlice(encoded, j, encoded.length, true);
|
|
var name = "0-$i-$j-${encoded.length}: $encoded";
|
|
Expect.listEquals(list, results.expand((x) => x).toList(), name);
|
|
}
|
|
}
|
|
}
|
|
Expect.listEquals(list, base64.decode(encoded), ".decode($encoded)");
|
|
Expect.listEquals(list, base64Url.decode(encoded), "url.decode($encoded)");
|
|
Expect.listEquals(list, base64Decode(encoded), "base64Decode($encoded)");
|
|
}
|
|
}
|
|
|
|
void testErrors() {
|
|
void badChunkDecode(List<String> list) {
|
|
Expect.throwsFormatException(() {
|
|
var sink = new ChunkedConversionSink<List<int>>.withCallback((v) {
|
|
Expect.fail("Should have thrown: chunk $list");
|
|
});
|
|
var c = base64.decoder.startChunkedConversion(sink);
|
|
for (String string in list) {
|
|
c.add(string);
|
|
}
|
|
c.close();
|
|
}, "chunk $list");
|
|
}
|
|
|
|
void badDecode(String string) {
|
|
Expect.throwsFormatException(() => base64.decode(string), string);
|
|
Expect.throwsFormatException(() => base64Url.decode(string), string);
|
|
badChunkDecode([string]);
|
|
badChunkDecode(["", string]);
|
|
badChunkDecode([string, ""]);
|
|
badChunkDecode([string, "", ""]);
|
|
badChunkDecode(["", string, ""]);
|
|
}
|
|
|
|
badDecode("A");
|
|
badDecode("AA");
|
|
badDecode("AAA");
|
|
badDecode("AAAAA");
|
|
badDecode("AAAAAA");
|
|
badDecode("AAAAAAA");
|
|
badDecode("AAAA=");
|
|
badDecode("AAAA==");
|
|
badDecode("AAAA===");
|
|
badDecode("AAAA====");
|
|
badDecode("AAAA%");
|
|
badDecode("AAAA%3");
|
|
badDecode("AAAA%3D");
|
|
badDecode("AAA%3D%");
|
|
badDecode("AAA%3D=");
|
|
badDecode("A=");
|
|
badDecode("A=A");
|
|
badDecode("A==");
|
|
badDecode("A==A");
|
|
badDecode("A===");
|
|
badDecode("====");
|
|
badDecode("AA=");
|
|
badDecode("AA%=");
|
|
badDecode("AA%3");
|
|
badDecode("AA%3D");
|
|
badDecode("AA===");
|
|
badDecode("AAA==");
|
|
badDecode("AAA=AAAA");
|
|
badDecode("AAA\x00");
|
|
badDecode("AAA=\x00");
|
|
badDecode("AAA\x80");
|
|
badDecode("AAA\xFF");
|
|
badDecode("AAA\u{141}");
|
|
badDecode("AAA\u{1041}");
|
|
badDecode("AAA\u{10041}");
|
|
badDecode("AA\u{141}=");
|
|
badDecode("AA\u{1041}=");
|
|
badDecode("AA\u{10041}=");
|
|
|
|
var alphabet =
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/-_";
|
|
var units = alphabet.codeUnits;
|
|
for (int i = 0; i < 128; i++) {
|
|
if (!units.contains(i)) {
|
|
badDecode(new String.fromCharCode(i) * 4);
|
|
}
|
|
}
|
|
|
|
badChunkDecode(["A", "A"]);
|
|
badChunkDecode(["A", "A", "A"]);
|
|
badChunkDecode(["A", "A", "="]);
|
|
badChunkDecode(["A", "A", "=", ""]);
|
|
badChunkDecode(["A", "A", "=", "=", "="]);
|
|
badChunkDecode(["AAA", "=="]);
|
|
badChunkDecode(["A", "A", "A"]);
|
|
badChunkDecode(["AAA", ""]);
|
|
badChunkDecode(["AA=", ""]);
|
|
badChunkDecode(["AB==", ""]);
|
|
|
|
badChunkEncode(List<int> list) {
|
|
for (int i = 0; i < list.length; i++) {
|
|
for (int j = 0; j < list.length; j++) {
|
|
Expect.throwsArgumentError(() {
|
|
var sink = new ChunkedConversionSink<String>.withCallback((v) {
|
|
Expect.fail("Should have thrown: chunked $list");
|
|
});
|
|
var c = base64.encoder.startChunkedConversion(sink);
|
|
c.add(list.sublist(0, i));
|
|
c.add(list.sublist(i, j));
|
|
c.add(list.sublist(j, list.length));
|
|
c.close();
|
|
}, "chunk $list");
|
|
}
|
|
}
|
|
for (int i = 0; i < list.length; i++) {
|
|
for (int j = 0; j < list.length; j++) {
|
|
Expect.throwsArgumentError(() {
|
|
var sink = new ChunkedConversionSink<String>.withCallback((v) {
|
|
Expect.fail("Should have thrown: chunked $list");
|
|
});
|
|
var c = base64.encoder.startChunkedConversion(sink);
|
|
c.addSlice(list, 0, i, false);
|
|
c.addSlice(list, i, j, false);
|
|
c.addSlice(list, j, list.length, true);
|
|
}, "chunk $list");
|
|
}
|
|
}
|
|
}
|
|
|
|
void badEncode(int invalid) {
|
|
Expect.throwsArgumentError(() => base64.encode([invalid]), "$invalid");
|
|
Expect.throwsArgumentError(
|
|
() => base64.encode([0, invalid, 0]), "$invalid");
|
|
badChunkEncode([invalid]);
|
|
badChunkEncode([0, invalid]);
|
|
badChunkEncode([0, 0, invalid]);
|
|
badChunkEncode([0, invalid, 0]);
|
|
badChunkEncode([invalid, 0, 0]);
|
|
}
|
|
|
|
badEncode(-1);
|
|
badEncode(0x100);
|
|
badEncode(0x1000);
|
|
badEncode(0x10000);
|
|
badEncode(0x100000000); // //# 01: ok
|
|
badEncode(0x7000000000000000); // //# 01: continued
|
|
}
|
|
|
|
void testIssue25577() {
|
|
// Regression test for http://dartbug.com/25577.
|
|
StringConversionSink decodeSink =
|
|
base64.decoder.startChunkedConversion(new TestSink<List<int>>());
|
|
ByteConversionSink encodeSink =
|
|
base64.encoder.startChunkedConversion(new TestSink<String>());
|
|
}
|
|
|
|
// Implementation of Sink<T> to test type constraints.
|
|
class TestSink<T> implements Sink<T> {
|
|
void add(T value) {}
|
|
void close() {}
|
|
}
|