OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'dart:convert'; |
| 6 import "dart:typed_data"; |
| 7 import "package:expect/expect.dart"; |
| 8 |
| 9 main() { |
| 10 for (var list in [<int>[], |
| 11 [0x00], |
| 12 [0xff, 0x00], |
| 13 [0xff, 0xaa, 0x55], |
| 14 [0x00, 0x01, 0x02, 0x03], |
| 15 new Iterable<int>.generate(13).toList(), |
| 16 new Iterable<int>.generate(254).toList(), |
| 17 new Iterable<int>.generate(255).toList(), |
| 18 new Iterable<int>.generate(256).toList()]) { |
| 19 testRoundtrip(list, "List#${list.length}"); |
| 20 testRoundtrip(new Uint8List.fromList(list), "Uint8List#${list.length}"); |
| 21 } |
| 22 testErrors(); |
| 23 testIssue25577(); |
| 24 |
| 25 // Decoder is lenienet with mixed styles. |
| 26 Expect.listEquals([0xfb, 0xff, 0xbf, 0x00], BASE64.decode("-_+/AA%3D=")); |
| 27 Expect.listEquals([0xfb, 0xff, 0xbf, 0x00], BASE64.decode("-_+/AA=%3D")); |
| 28 } |
| 29 |
| 30 void testRoundtrip(List<int> list, String name) { |
| 31 // Direct. |
| 32 String encodedNormal = BASE64.encode(list); |
| 33 String encodedPercent = encodedNormal.replaceAll("=", "%3D"); |
| 34 String uriEncoded = BASE64URL.encode(list); |
| 35 String expectedUriEncoded = |
| 36 encodedNormal.replaceAll("+", "-").replaceAll("/", "_"); |
| 37 Expect.equals(expectedUriEncoded, uriEncoded); |
| 38 |
| 39 List result = BASE64.decode(encodedNormal); |
| 40 Expect.listEquals(list, result, name); |
| 41 result = BASE64.decode(encodedPercent); |
| 42 Expect.listEquals(list, result, name); |
| 43 result = BASE64.decode(uriEncoded); |
| 44 Expect.listEquals(list, result, name); |
| 45 |
| 46 int increment = list.length ~/ 7 + 1; |
| 47 // Chunked. |
| 48 for (int i = 0; i < list.length; i += increment) { |
| 49 for (int j = i; j < list.length; j += increment) { |
| 50 // Normal |
| 51 { |
| 52 // Using add/close |
| 53 var results; |
| 54 var sink = new ChunkedConversionSink<String>.withCallback((v) { results
= v; }); |
| 55 var encoder = BASE64.encoder.startChunkedConversion(sink); |
| 56 encoder.add(list.sublist(0, i)); |
| 57 encoder.add(list.sublist(i, j)); |
| 58 encoder.add(list.sublist(j, list.length)); |
| 59 encoder.close(); |
| 60 var name = "0-$i-$j-${list.length}: list"; |
| 61 Expect.equals(encodedNormal, results.join(""), name); |
| 62 } |
| 63 { |
| 64 // Using addSlice |
| 65 var results; |
| 66 var sink = new ChunkedConversionSink<String>.withCallback((v) { results
= v; }); |
| 67 var encoder = BASE64.encoder.startChunkedConversion(sink); |
| 68 encoder.addSlice(list, 0, i, false); |
| 69 encoder.addSlice(list, i, j, false); |
| 70 encoder.addSlice(list, j, list.length, true); |
| 71 var name = "0-$i-$j-${list.length}: $list"; |
| 72 Expect.equals(encodedNormal, results.join(""), name); |
| 73 } |
| 74 // URI |
| 75 { |
| 76 // Using add/close |
| 77 var results; |
| 78 var sink = new ChunkedConversionSink<String>.withCallback((v) { results
= v; }); |
| 79 var encoder = BASE64URL.encoder.startChunkedConversion(sink); |
| 80 encoder.add(list.sublist(0, i)); |
| 81 encoder.add(list.sublist(i, j)); |
| 82 encoder.add(list.sublist(j, list.length)); |
| 83 encoder.close(); |
| 84 var name = "0-$i-$j-${list.length}: list"; |
| 85 Expect.equals(uriEncoded, results.join(""), name); |
| 86 } |
| 87 { |
| 88 // Using addSlice |
| 89 var results; |
| 90 var sink = new ChunkedConversionSink<String>.withCallback((v) { results
= v; }); |
| 91 var encoder = BASE64URL.encoder.startChunkedConversion(sink); |
| 92 encoder.addSlice(list, 0, i, false); |
| 93 encoder.addSlice(list, i, j, false); |
| 94 encoder.addSlice(list, j, list.length, true); |
| 95 var name = "0-$i-$j-${list.length}: $list"; |
| 96 Expect.equals(uriEncoded, results.join(""), name); |
| 97 } |
| 98 } |
| 99 } |
| 100 |
| 101 for (var encoded in [encodedNormal, encodedPercent, uriEncoded]) { |
| 102 increment = encoded.length ~/ 7 + 1; |
| 103 for (int i = 0; i < encoded.length; i += increment) { |
| 104 for (int j = i; j < encoded.length; j += increment) { |
| 105 { |
| 106 // Using add/close |
| 107 List<List<int>> results; |
| 108 var sink = |
| 109 new ChunkedConversionSink<List<int>>.withCallback((v) { results =
v; }); |
| 110 var decoder = BASE64.decoder.startChunkedConversion(sink); |
| 111 decoder.add(encoded.substring(0, i)); |
| 112 decoder.add(encoded.substring(i, j)); |
| 113 decoder.add(encoded.substring(j, encoded.length)); |
| 114 decoder.close(); |
| 115 var name = "0-$i-$j-${encoded.length}: $encoded"; |
| 116 Expect.listEquals(list, results.expand((x)=>x).toList(), name); |
| 117 } |
| 118 { |
| 119 // Using addSlice |
| 120 List<List<int>> results; |
| 121 var sink = |
| 122 new ChunkedConversionSink<List<int>>.withCallback((v) { results =
v; }); |
| 123 var decoder = BASE64.decoder.startChunkedConversion(sink); |
| 124 decoder.addSlice(encoded, 0, i, false); |
| 125 decoder.addSlice(encoded, i, j, false); |
| 126 decoder.addSlice(encoded, j, encoded.length, true); |
| 127 var name = "0-$i-$j-${encoded.length}: $encoded"; |
| 128 Expect.listEquals(list, results.expand((x)=>x).toList(), name); |
| 129 } |
| 130 } |
| 131 } |
| 132 } |
| 133 } |
| 134 |
| 135 bool isFormatException(e) => e is FormatException; |
| 136 bool isArgumentError(e) => e is ArgumentError; |
| 137 |
| 138 void testErrors() { |
| 139 void badChunkDecode(List<String> list) { |
| 140 Expect.throws(() { |
| 141 var sink = new ChunkedConversionSink<List<int>>.withCallback((v) { |
| 142 Expect.fail("Should have thrown: chunk $list"); |
| 143 }); |
| 144 var c = BASE64.decoder.startChunkedConversion(sink); |
| 145 for (String string in list) { |
| 146 c.add(string); |
| 147 } |
| 148 c.close(); |
| 149 }, isFormatException, "chunk $list"); |
| 150 } |
| 151 void badDecode(String string) { |
| 152 Expect.throws(() => BASE64.decode(string), isFormatException, string); |
| 153 Expect.throws(() => BASE64URL.decode(string), isFormatException, string); |
| 154 badChunkDecode([string]); |
| 155 badChunkDecode(["", string]); |
| 156 badChunkDecode([string, ""]); |
| 157 badChunkDecode([string, "", ""]); |
| 158 badChunkDecode(["", string, ""]); |
| 159 } |
| 160 |
| 161 badDecode("A"); |
| 162 badDecode("AA"); |
| 163 badDecode("AAA"); |
| 164 badDecode("AAAAA"); |
| 165 badDecode("AAAAAA"); |
| 166 badDecode("AAAAAAA"); |
| 167 badDecode("AAAA="); |
| 168 badDecode("AAAA=="); |
| 169 badDecode("AAAA==="); |
| 170 badDecode("AAAA===="); |
| 171 badDecode("AAAA%"); |
| 172 badDecode("AAAA%3"); |
| 173 badDecode("AAAA%3D"); |
| 174 badDecode("AAA%3D%"); |
| 175 badDecode("AAA%3D="); |
| 176 badDecode("A="); |
| 177 badDecode("A=A"); |
| 178 badDecode("A=="); |
| 179 badDecode("A==A"); |
| 180 badDecode("A==="); |
| 181 badDecode("===="); |
| 182 badDecode("AA="); |
| 183 badDecode("AA%="); |
| 184 badDecode("AA%3"); |
| 185 badDecode("AA%3D"); |
| 186 badDecode("AA==="); |
| 187 badDecode("AAA=="); |
| 188 badDecode("AAA=AAAA"); |
| 189 badDecode("AAA\x00"); |
| 190 badDecode("AAA=\x00"); |
| 191 badDecode("AAA\x80"); |
| 192 badDecode("AAA\xFF"); |
| 193 badDecode("AAA\u{141}"); |
| 194 badDecode("AAA\u{1041}"); |
| 195 badDecode("AAA\u{10041}"); |
| 196 badDecode("AA\u{141}="); |
| 197 badDecode("AA\u{1041}="); |
| 198 badDecode("AA\u{10041}="); |
| 199 |
| 200 var alphabet = |
| 201 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/-_"; |
| 202 var units = alphabet.codeUnits; |
| 203 for (int i = 0; i < 128; i++) { |
| 204 if (!units.contains(i)) { |
| 205 badDecode(new String.fromCharCode(i) * 4); |
| 206 } |
| 207 } |
| 208 |
| 209 badChunkDecode(["A", "A"]); |
| 210 badChunkDecode(["A", "A", "A"]); |
| 211 badChunkDecode(["A", "A", "="]); |
| 212 badChunkDecode(["A", "A", "=", ""]); |
| 213 badChunkDecode(["A", "A", "=", "=", "="]); |
| 214 badChunkDecode(["AAA", "=="]); |
| 215 badChunkDecode(["A", "A", "A"]); |
| 216 badChunkDecode(["AAA", ""]); |
| 217 badChunkDecode(["AA=", ""]); |
| 218 badChunkDecode(["AB==", ""]); |
| 219 |
| 220 |
| 221 badChunkEncode(List<int> list) { |
| 222 for (int i = 0; i < list.length; i++) { |
| 223 for (int j = 0; j < list.length; j++) { |
| 224 Expect.throws(() { |
| 225 var sink = new ChunkedConversionSink<String>.withCallback((v) { |
| 226 Expect.fail("Should have thrown: chunked $list"); |
| 227 }); |
| 228 var c = BASE64.encoder.startChunkedConversion(sink); |
| 229 c.add(list.sublist(0, i)); |
| 230 c.add(list.sublist(i, j)); |
| 231 c.add(list.sublist(j, list.length)); |
| 232 c.close(); |
| 233 }, isArgumentError, "chunk $list"); |
| 234 } |
| 235 } |
| 236 for (int i = 0; i < list.length; i++) { |
| 237 for (int j = 0; j < list.length; j++) { |
| 238 Expect.throws(() { |
| 239 var sink = new ChunkedConversionSink<String>.withCallback((v) { |
| 240 Expect.fail("Should have thrown: chunked $list"); |
| 241 }); |
| 242 var c = BASE64.encoder.startChunkedConversion(sink); |
| 243 c.addSlice(list, 0, i, false); |
| 244 c.addSlice(list, i, j, false); |
| 245 c.addSlice(list, j, list.length, true); |
| 246 }, isArgumentError, "chunk $list"); |
| 247 } |
| 248 } |
| 249 } |
| 250 |
| 251 void badEncode(int invalid) { |
| 252 Expect.throws(() { |
| 253 BASE64.encode([invalid]); |
| 254 }, isArgumentError, "$invalid"); |
| 255 Expect.throws(() { |
| 256 BASE64.encode([0, invalid, 0]); |
| 257 }, isArgumentError, "$invalid"); |
| 258 badChunkEncode([invalid]); |
| 259 badChunkEncode([0, invalid]); |
| 260 badChunkEncode([0, 0, invalid]); |
| 261 badChunkEncode([0, invalid, 0]); |
| 262 badChunkEncode([invalid, 0, 0]); |
| 263 } |
| 264 |
| 265 badEncode(-1); |
| 266 badEncode(0x100); |
| 267 badEncode(0x1000); |
| 268 badEncode(0x10000); |
| 269 // TODO(rnystrom): These aren't throwing in dev_compiler. Figure out why. |
| 270 |
| 271 |
| 272 } |
| 273 |
| 274 void testIssue25577() { |
| 275 // Regression test for http://dartbug.com/25577 |
| 276 // Should not fail in checked mode. |
| 277 StringConversionSink decodeSink = |
| 278 BASE64.decoder.startChunkedConversion(new TestSink<List<int>>()); |
| 279 ByteConversionSink encodeSink = |
| 280 BASE64.encoder.startChunkedConversion(new TestSink<String>()); |
| 281 } |
| 282 |
| 283 // Implementation of Sink<T> to test type constraints. |
| 284 class TestSink<T> implements Sink<T> { |
| 285 void add(T value) {} |
| 286 void close() {} |
| 287 } |
| 288 // Test created from multitest named /Users/rnystrom/dev/dev_compiler/test/codeg
en/lib/convert/base64_test.dart. |
OLD | NEW |