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:async'; | |
6 import 'dart:convert'; | |
7 import 'dart:math'; | |
8 | |
9 import "package:charcode/ascii.dart"; | |
10 import "package:crypto/crypto.dart"; | |
11 import "package:test/test.dart"; | |
12 | |
13 void main() { | |
14 group("encoder", () { | |
15 test("for simple inputs", () { | |
16 expect(BASE64.encode([]), equals('')); | |
17 expect(BASE64.encode([$f]), equals('Zg==')); | |
18 expect(BASE64.encode([$f, $o]), equals('Zm8=')); | |
19 expect(BASE64.encode([$f, $o, $o]), equals('Zm9v')); | |
20 expect(BASE64.encode([$f, $o, $o, $b]), equals('Zm9vYg==')); | |
21 expect(BASE64.encode([$f, $o, $o, $b, $a]), equals('Zm9vYmE=')); | |
22 expect(BASE64.encode([$f, $o, $o, $b, $a, $r]), equals('Zm9vYmFy')); | |
23 }); | |
24 | |
25 test("for inputs with zeroes", () { | |
26 expect(BASE64.encode([0]), equals('AA==')); | |
27 expect(BASE64.encode([0, 0]), equals('AAA=')); | |
28 expect(BASE64.encode([0, 0, 0]), equals('AAAA')); | |
29 expect(BASE64.encode([0, 0, 0, 0]), equals('AAAAAA==')); | |
30 }); | |
31 | |
32 test("for a large input with line separators", () { | |
33 expect( | |
34 BASE64.encode( | |
35 UTF8.encode( | |
36 "Man is distinguished, not only by his reason, but by this " | |
37 "singular passion from other animals, which is a lust of the " | |
38 "mind, that by a perseverance of delight in the continued " | |
39 "and indefatigable generation of knowledge, exceeds the " | |
40 "short vehemence of any carnal pleasure."), | |
41 addLineSeparator: true), | |
42 equals( | |
43 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1" | |
44 "dCBieSB0aGlz\r\n" | |
45 "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBh" | |
46 "IGx1c3Qgb2Yg\r\n" | |
47 "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0" | |
48 "aGUgY29udGlu\r\n" | |
49 "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBl" | |
50 "eGNlZWRzIHRo\r\n" | |
51 "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=")); | |
52 }); | |
53 | |
54 test("for a large input without line separators", () { | |
55 expect( | |
56 BASE64.encode( | |
57 UTF8.encode( | |
58 "Man is distinguished, not only by his reason, but by this " | |
59 "singular passion from other animals, which is a lust of the " | |
60 "mind, that by a perseverance of delight in the continued " | |
61 "and indefatigable generation of knowledge, exceeds the " | |
62 "short vehemence of any carnal pleasure.")), | |
63 equals( | |
64 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1" | |
65 "dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3" | |
66 "aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFu" | |
67 "Y2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxl" | |
68 "IGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhl" | |
69 "bWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=")); | |
70 }); | |
71 | |
72 test("for chunked input", () { | |
73 expect(_encodeChunked([ | |
74 [102, 102], | |
75 [111, 102], | |
76 [ | |
77 111, 111, 102, 111, 111, 98, 102, 111, 111, 98, 97, 102, 111, 111, | |
78 98, 97, 114 | |
79 ] | |
80 ]), equals("ZmZvZm9vZm9vYmZvb2JhZm9vYmFy")); | |
81 | |
82 expect(_encodeChunked([[196, 16], [], [158], [196]]), equals("xBCexA==")); | |
83 expect(_encodeChunked([[196, 16], [158, 196], [], []]), | |
84 equals("xBCexA==")); | |
85 expect(_encodeChunked([[196], [], [16], [], [], [158], [], [196]]), | |
86 equals("xBCexA==")); | |
87 expect(_encodeChunked([[196], [], [16], [158, 196], [], []]), | |
88 equals("xBCexA==")); | |
89 expect(_encodeChunked([[], [196], [], [], [16, 158], [], [196]]), | |
90 equals("xBCexA==")); | |
91 expect(_encodeChunked([[], [196], [16, 158, 196], []]), | |
92 equals("xBCexA==")); | |
93 expect(_encodeChunked([[196, 16, 158], [], [], [196]]), | |
94 equals("xBCexA==")); | |
95 expect(_encodeChunked([[196, 16, 158], [], [196], []]), | |
96 equals("xBCexA==")); | |
97 expect(_encodeChunked([[196, 16, 158, 196], [], [], []]), | |
98 equals("xBCexA==")); | |
99 }); | |
100 | |
101 test('with a URL-safe alphabet', () { | |
102 expect(BASE64.encode(BASE64.decode('+/A='), urlSafe: true), | |
103 equals('-_A=')); | |
104 }); | |
105 | |
106 test('with a percent-encoded padding character', () { | |
107 expect(BASE64.encode([2, 8], encodePaddingCharacter: true), | |
108 equals('Agg%3D')); | |
109 }); | |
110 | |
111 test('with the old API', () { | |
112 expect(CryptoUtils.bytesToBase64([]), equals('')); | |
113 expect(CryptoUtils.bytesToBase64([$f]), equals('Zg==')); | |
114 expect(CryptoUtils.bytesToBase64([$f, $o]), equals('Zm8=')); | |
115 expect(CryptoUtils.bytesToBase64([$f, $o, $o]), equals('Zm9v')); | |
116 expect(CryptoUtils.bytesToBase64([$f, $o, $o, $b]), equals('Zm9vYg==')); | |
117 expect(CryptoUtils.bytesToBase64([$f, $o, $o, $b, $a]), | |
118 equals('Zm9vYmE=')); | |
119 expect(CryptoUtils.bytesToBase64([$f, $o, $o, $b, $a, $r]), | |
120 equals('Zm9vYmFy')); | |
121 }); | |
122 }); | |
123 | |
124 group("decoder", () { | |
125 test("for simple inputs", () { | |
126 expect(BASE64.decode(''), equals([])); | |
127 expect(BASE64.decode('Zg=='), equals([$f])); | |
128 expect(BASE64.decode('Zm8='), equals([$f, $o])); | |
129 expect(BASE64.decode('Zm9v'), equals([$f, $o, $o])); | |
130 expect(BASE64.decode('Zm9vYg=='), equals([$f, $o, $o, $b])); | |
131 expect(BASE64.decode('Zm9vYmE='), equals([$f, $o, $o, $b, $a])); | |
132 expect(BASE64.decode('Zm9vYmFy'), equals([$f, $o, $o, $b, $a, $r])); | |
133 }); | |
134 | |
135 test("for inputs with zeroes", () { | |
136 expect(BASE64.decode('AA=='), equals([0])); | |
137 expect(BASE64.decode('AAA='), equals([0, 0])); | |
138 expect(BASE64.decode('AAAA'), equals([0, 0, 0])); | |
139 expect(BASE64.decode('AAAAAA=='), equals([0, 0, 0, 0])); | |
140 }); | |
141 | |
142 test("for a large input with line separators", () { | |
143 expect( | |
144 BASE64.decode( | |
145 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1" | |
146 "dCBieSB0aGlz\r\n" | |
147 "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBh" | |
148 "IGx1c3Qgb2Yg\r\n" | |
149 "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0" | |
150 "aGUgY29udGlu\r\n" | |
151 "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBl" | |
152 "eGNlZWRzIHRo\r\n" | |
153 "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="), | |
154 equals(UTF8.encode( | |
155 "Man is distinguished, not only by his reason, but by this " | |
156 "singular passion from other animals, which is a lust of the " | |
157 "mind, that by a perseverance of delight in the continued and " | |
158 "indefatigable generation of knowledge, exceeds the short " | |
159 "vehemence of any carnal pleasure."))); | |
160 }); | |
161 | |
162 test("for a large input without line separators", () { | |
163 expect( | |
164 BASE64.decode( | |
165 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1" | |
166 "dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3" | |
167 "aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFu" | |
168 "Y2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxl" | |
169 "IGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhl" | |
170 "bWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="), | |
171 equals(UTF8.encode( | |
172 "Man is distinguished, not only by his reason, but by this " | |
173 "singular passion from other animals, which is a lust of the " | |
174 "mind, that by a perseverance of delight in the continued and " | |
175 "indefatigable generation of knowledge, exceeds the short " | |
176 "vehemence of any carnal pleasure."))); | |
177 }); | |
178 | |
179 test("for chunked input", () { | |
180 expect(_decodeChunked(['YmFz', 'ZTY', '0I', 'GRlY29kZXI=']), equals([ | |
181 98, 97, 115, 101, 54, 52, 32, 100, 101, 99, 111, 100, 101, 114 | |
182 ])); | |
183 }); | |
184 | |
185 test("for chunked input containing zeroes", () { | |
186 expect(_decodeChunked(['AAAA', 'AAA=', 'AA==', '']), | |
187 equals([0, 0, 0, 0, 0, 0])); | |
188 | |
189 expect(_decodeChunked(["A", "", "BCD"]), equals([0, 16, 131])); | |
190 expect(_decodeChunked(["A", "BCD", "", ""]), equals([0, 16, 131])); | |
191 expect(_decodeChunked(["A", "B", "", "", "CD", ""]), | |
192 equals([0, 16, 131])); | |
193 expect(_decodeChunked(["", "A", "BC", "", "D"]), equals([0, 16, 131])); | |
194 expect(_decodeChunked(["", "AB", "C", "", "", "D"]), | |
195 equals([0, 16, 131])); | |
196 expect(_decodeChunked(["AB", "CD", ""]), equals([0, 16, 131])); | |
197 expect(_decodeChunked(["", "ABC", "", "D"]), equals([0, 16, 131])); | |
198 expect(_decodeChunked(["", "ABC", "D", ""]), equals([0, 16, 131])); | |
199 expect(_decodeChunked(["", "", "ABCD", ""]), equals([0, 16, 131])); | |
200 expect(_decodeChunked(["A", "B", "C", "D"]), equals([0, 16, 131])); | |
201 expect(_decodeChunked(["", "A", "B", "C", "D", ""]), | |
202 equals([0, 16, 131])); | |
203 expect(_decodeChunked(["", "A", "B", "", "", "C", "", "D", ""]), | |
204 equals([0, 16, 131])); | |
205 }); | |
206 | |
207 test("for chunked input with encoded padding", () { | |
208 expect(_decodeChunked(['AA%', '3D', '%', '3', 'DEFGZ']), | |
209 equals(BASE64.decode('AA==EFGZ'))); | |
210 }); | |
211 | |
212 test('with a URL-safe alphabet', () { | |
213 expect(BASE64.decode('-_A='), equals(BASE64.decode('+/A='))); | |
214 }); | |
215 | |
216 test('with a percent-encoded padding character', () { | |
217 expect(BASE64.decode('Agg%3D'), equals([2, 8])); | |
218 }); | |
219 | |
220 test("with the old API", () { | |
221 expect(CryptoUtils.base64StringToBytes(''), equals([])); | |
222 expect(CryptoUtils.base64StringToBytes('Zg=='), equals([$f])); | |
223 expect(CryptoUtils.base64StringToBytes('Zm8='), equals([$f, $o])); | |
224 expect(CryptoUtils.base64StringToBytes('Zm9v'), equals([$f, $o, $o])); | |
225 expect(CryptoUtils.base64StringToBytes('Zm9vYg=='), | |
226 equals([$f, $o, $o, $b])); | |
227 expect(CryptoUtils.base64StringToBytes('Zm9vYmE='), | |
228 equals([$f, $o, $o, $b, $a])); | |
229 expect(CryptoUtils.base64StringToBytes('Zm9vYmFy'), | |
230 equals([$f, $o, $o, $b, $a, $r])); | |
231 }); | |
232 | |
233 group("rejects", () { | |
234 test("input of the wrong length", () { | |
235 expect(() => BASE64.decode('A'), throwsFormatException); | |
236 expect(() => BASE64.decode('AB'), throwsFormatException); | |
237 expect(() => BASE64.decode('ABz'), throwsFormatException); | |
238 expect(() => BASE64.decode('ABzdE'), throwsFormatException); | |
239 expect(() => BASE64.decode('ABzdEf'), throwsFormatException); | |
240 expect(() => BASE64.decode('ABzdEfg'), throwsFormatException); | |
241 }); | |
242 | |
243 test("input with invalid characters", () { | |
244 expect(() => BASE64.decode('AB~'), throwsFormatException); | |
245 }); | |
246 | |
247 test("chunked input of the wrong length", () { | |
248 expect(() => _decodeChunked(['ABz']), throwsFormatException); | |
249 expect(() => _decodeChunked(['AB', 'Lx', 'z', 'xx']), | |
250 throwsFormatException); | |
251 }); | |
252 | |
253 test("input with the wrong padding", () { | |
254 expect(() => BASE64.decode('A=='), throwsFormatException); | |
255 expect(() => BASE64.decode('AB='), throwsFormatException); | |
256 expect(() => BASE64.decode('ABz=='), throwsFormatException); | |
257 expect(() => BASE64.decode('ABzdE='), throwsFormatException); | |
258 }); | |
259 | |
260 test("input with the wrong encoded padding", () { | |
261 expect(() => BASE64.decode('A%3D%3D'), throwsFormatException); | |
262 expect(() => BASE64.decode('AB%3D'), throwsFormatException); | |
263 expect(() => BASE64.decode('ABz%3D%3D'), throwsFormatException); | |
264 expect(() => BASE64.decode('ABzdE%3D'), throwsFormatException); | |
265 }); | |
266 }); | |
267 }); | |
268 | |
269 test('successfully round-trips data', () { | |
270 for (var i = 0; i < 10; i++) { | |
271 for (var j = 0; j < 256 - i; j++) { | |
272 var data = new List.filled(i, j); | |
273 expect(BASE64.decode(BASE64.encode(data)), equals(data)); | |
274 } | |
275 } | |
276 }); | |
277 } | |
278 | |
279 /// Performs chunked Base64 decoding of [chunks] and returns the result as a | |
280 /// byte array. | |
281 List<int> _decodeChunked(Iterable<String> chunks) { | |
282 var bytes; | |
283 var innerSink = new ByteConversionSink.withCallback( | |
284 (result) => bytes = result); | |
285 var sink = BASE64.decoder.startChunkedConversion(innerSink); | |
286 | |
287 for (var chunk in chunks) { | |
288 sink.add(chunk); | |
289 } | |
290 sink.close(); | |
291 | |
292 return bytes; | |
293 } | |
294 | |
295 /// Performs chunked Base64 encoding of [chunks] and returns the result. | |
296 String _encodeChunked(Iterable<List<int>> chunks) { | |
297 var string; | |
298 var innerSink = new StringConversionSink.withCallback( | |
299 (result) => string = result); | |
300 var sink = BASE64.encoder.startChunkedConversion(innerSink); | |
301 | |
302 for (var chunk in chunks) { | |
303 sink.add(chunk); | |
304 } | |
305 sink.close(); | |
306 | |
307 return string; | |
308 } | |
OLD | NEW |