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 // badEncode(0x100000000); /// 01: ok | |
271 // badEncode(0x10000000000000000); /// 01: continued | |
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 |