OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // Library tag to allow the test to run on Dartium. | 5 // Library tag to allow the test to run on Dartium. |
6 library base64_test; | 6 library base64_test; |
7 | 7 |
8 import 'dart:math'; | 8 import 'dart:math'; |
| 9 import 'dart:async'; |
9 | 10 |
10 import "package:crypto/crypto.dart"; | 11 import "package:crypto/crypto.dart"; |
11 import "package:test/test.dart"; | 12 import "package:test/test.dart"; |
12 | 13 |
13 void main() { | 14 void main() { |
14 test('encoder', _testEncoder); | 15 test('encoder', _testEncoder); |
15 test('decoder', _testDecoder); | 16 test('decoder', _testDecoder); |
16 test('decoder for malformed input', _testDecoderForMalformedInput); | 17 test('decoder for malformed input', _testDecoderForMalformedInput); |
17 test('encode decode lists', _testEncodeDecodeLists); | 18 test('encode decode lists', _testEncodeDecodeLists); |
18 test('url safe encode-decode', _testUrlSafeEncodeDecode); | 19 test('url safe encode-decode', _testUrlSafeEncodeDecode); |
| 20 test('consistent safe/unsafe character decoding', |
| 21 _testConsistentSafeUnsafeDecode); |
| 22 test('percent-encoded padding character encode-decode', |
| 23 _testPaddingCharacter); |
| 24 test('streaming encoder', _testStreamingEncoder); |
| 25 test('streaming decoder', _testStreamingDecoder); |
| 26 test('streaming decoder for malformed input', |
| 27 _testStreamingDecoderForMalformedInput); |
| 28 test('streaming encoder for different decompositions of a list of bytes', |
| 29 _testStreamingEncoderForDecompositions); |
| 30 test('streaming decoder for different decompositions of a string', |
| 31 _testStreamingDecoderForDecompositions); |
| 32 test('consistent safe/unsafe character streaming decoding', |
| 33 _testConsistentSafeUnsafeStreamDecode); |
| 34 test('streaming for encoded padding character', |
| 35 _testStreamingForEncodedPadding); |
| 36 test('old api', _testOldApi); |
| 37 test('url safe streaming encoder/decoder', _testUrlSafeStreaming); |
19 test('performance', _testPerformance); | 38 test('performance', _testPerformance); |
| 39 |
| 40 |
20 } | 41 } |
21 | 42 |
22 // Data from http://tools.ietf.org/html/rfc4648. | 43 // Data from http://tools.ietf.org/html/rfc4648. |
23 const _INPUTS = | 44 const _INPUTS = |
24 const [ '', 'f', 'fo', 'foo', 'foob', 'fooba', 'foobar']; | 45 const [ '', 'f', 'fo', 'foo', 'foob', 'fooba', 'foobar']; |
25 const _RESULTS = | 46 const _RESULTS = |
26 const [ '', 'Zg==', 'Zm8=', 'Zm9v', 'Zm9vYg==', 'Zm9vYmE=', 'Zm9vYmFy']; | 47 const [ '', 'Zg==', 'Zm8=', 'Zm9v', 'Zm9vYg==', 'Zm9vYmE=', 'Zm9vYmFy']; |
27 | 48 |
| 49 const _PADDING_INPUT = const [2, 8]; |
| 50 |
| 51 var _STREAMING_ENCODER_INPUT = |
| 52 [[102, 102], [111, 102], |
| 53 [111, 111, 102, 111, 111, 98, 102, 111, |
| 54 111, 98, 97, 102, 111, 111, 98, 97, 114]]; |
| 55 |
| 56 const _STREAMING_ENCODED = 'ZmZvZm9vZm9vYmZvb2JhZm9vYmFy'; |
| 57 const _STREAMING_DECODER_INPUT = |
| 58 const ['YmFz', 'ZTY', '0I', 'GRlY29kZXI=']; |
| 59 const _STREAMING_DECODED = |
| 60 const [98, 97, 115, 101, 54, 52, 32, 100, 101, 99, 111, 100, 101, 114]; |
| 61 const _STREAMING_DECODER_INPUT_FOR_ZEROES = |
| 62 const ['AAAA', 'AAA=', 'AA==', '']; |
| 63 var _STREAMING_DECODED_ZEROES = [0, 0, 0, 0, 0, 0]; |
| 64 |
| 65 var _DECOMPOSITIONS_FOR_DECODING = [ |
| 66 ["A", "", "BCD"], ["A", "BCD", "", ""], ["A", "B", "", "", "CD", ""], |
| 67 ["", "A", "BC", "", "D"], ["", "AB", "C", "", "", "D"], ["AB", "CD", ""], |
| 68 ["", "ABC", "", "D"], ["", "ABC", "D", ""], ["", "", "ABCD", ""], |
| 69 ["A", "B", "C", "D"], ["", "A", "B", "C", "D", ""], |
| 70 ["", "A", "B", "", "", "C", "", "D", ""]]; |
| 71 |
| 72 const _DECOMPOSITION_DECODED = const [0, 16, 131]; |
| 73 |
| 74 var _DECOMPOSITIONS_FOR_ENCODING = [ |
| 75 [[196, 16], [], [158], [196]], |
| 76 [[196, 16], [158, 196], [], []], |
| 77 [[196], [], [16], [], [], [158], [], [196]], |
| 78 [[196], [], [16], [158, 196], [], []], |
| 79 [[], [196], [], [], [16, 158], [], [196]], |
| 80 [[], [196], [16, 158, 196], []], |
| 81 [[196, 16, 158], [], [], [196]], |
| 82 [[196, 16, 158], [], [196], []], |
| 83 [[196, 16, 158, 196], [], [], []]]; |
| 84 |
| 85 const _DECOMPOSITION_ENCODED = 'xBCexA=='; |
| 86 |
| 87 const _INCONSISTENT_SAFE_RESULT = 'A+_x'; |
| 88 |
| 89 const _INCONSISTENT_SAFE_STREAMING_RESULT = const ['A+AAA', '_x=']; |
| 90 |
28 // Test data with only zeroes. | 91 // Test data with only zeroes. |
29 var inputsWithZeroes = [[0, 0, 0], [0, 0], [0], []]; | 92 var inputsWithZeroes = [[0, 0, 0], [0, 0], [0], []]; |
30 const _RESULTS_WITH_ZEROS = const ['AAAA', 'AAA=', 'AA==', '']; | 93 const _RESULTS_WITH_ZEROS = const ['AAAA', 'AAA=', 'AA==', '']; |
31 | 94 |
32 const _LONG_LINE = | 95 const _LONG_LINE = |
33 "Man is distinguished, not only by his reason, but by this singular " | 96 "Man is distinguished, not only by his reason, but by this singular " |
34 "passion from other animals, which is a lust of the mind, that by a " | 97 "passion from other animals, which is a lust of the mind, that by a " |
35 "perseverance of delight in the continued and indefatigable generation " | 98 "perseverance of delight in the continued and indefatigable generation " |
36 "of knowledge, exceeds the short vehemence of any carnal pleasure."; | 99 "of knowledge, exceeds the short vehemence of any carnal pleasure."; |
37 | 100 |
(...skipping 16 matching lines...) Expand all Loading... |
54 "BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg" | 117 "BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg" |
55 "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcm" | 118 "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcm" |
56 "FuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu" | 119 "FuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu" |
57 "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYX" | 120 "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYX" |
58 "Rpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo" | 121 "Rpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo" |
59 "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm" | 122 "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm" |
60 "5hbCBwbGVhc3VyZS4="; | 123 "5hbCBwbGVhc3VyZS4="; |
61 | 124 |
62 void _testEncoder() { | 125 void _testEncoder() { |
63 for (var i = 0; i < _INPUTS.length; i++) { | 126 for (var i = 0; i < _INPUTS.length; i++) { |
64 expect(CryptoUtils.bytesToBase64(_INPUTS[i].codeUnits), _RESULTS[i]); | 127 expect(BASE64.encode(_INPUTS[i].codeUnits), _RESULTS[i]); |
65 } | 128 } |
66 for (var i = 0; i < inputsWithZeroes.length; i++) { | 129 for (var i = 0; i < inputsWithZeroes.length; i++) { |
67 expect(CryptoUtils.bytesToBase64(inputsWithZeroes[i]), | 130 expect(BASE64.encode(inputsWithZeroes[i]), |
68 _RESULTS_WITH_ZEROS[i]); | 131 _RESULTS_WITH_ZEROS[i]); |
69 } | 132 } |
70 expect( | 133 expect(BASE64.encode(_LONG_LINE.codeUnits, addLineSeparator : true), |
71 CryptoUtils.bytesToBase64(_LONG_LINE.codeUnits, addLineSeparator : true), | 134 _LONG_LINE_RESULT); |
72 _LONG_LINE_RESULT); | 135 expect(BASE64.encode(_LONG_LINE.codeUnits), |
73 expect(CryptoUtils.bytesToBase64(_LONG_LINE.codeUnits), | 136 _LONG_LINE_RESULT_NO_BREAK); |
74 _LONG_LINE_RESULT_NO_BREAK); | |
75 } | 137 } |
76 | 138 |
77 void _testDecoder() { | 139 void _testDecoder() { |
78 for (var i = 0; i < _RESULTS.length; i++) { | 140 for (var i = 0; i < _RESULTS.length; i++) { |
79 expect( | 141 expect( |
80 new String.fromCharCodes(CryptoUtils.base64StringToBytes(_RESULTS[i])), | 142 new String.fromCharCodes(BASE64.decode(_RESULTS[i])), |
81 _INPUTS[i]); | 143 _INPUTS[i]); |
82 } | 144 } |
| 145 |
83 for (var i = 0; i < _RESULTS_WITH_ZEROS.length; i++) { | 146 for (var i = 0; i < _RESULTS_WITH_ZEROS.length; i++) { |
84 expect(CryptoUtils.base64StringToBytes(_RESULTS_WITH_ZEROS[i]), | 147 expect(BASE64.decode(_RESULTS_WITH_ZEROS[i]), |
85 inputsWithZeroes[i]); | 148 inputsWithZeroes[i]); |
86 } | 149 } |
87 var longLineDecoded = CryptoUtils.base64StringToBytes(_LONG_LINE_RESULT); | 150 |
| 151 var longLineDecoded = BASE64.decode(_LONG_LINE_RESULT); |
88 expect(new String.fromCharCodes(longLineDecoded), _LONG_LINE); | 152 expect(new String.fromCharCodes(longLineDecoded), _LONG_LINE); |
89 var longLineResultNoBreak = | 153 |
90 CryptoUtils.base64StringToBytes(_LONG_LINE_RESULT); | 154 var longLineResultNoBreak = BASE64.decode(_LONG_LINE_RESULT); |
91 expect(new String.fromCharCodes(longLineResultNoBreak), _LONG_LINE); | 155 expect(new String.fromCharCodes(longLineResultNoBreak), _LONG_LINE); |
92 } | 156 } |
93 | 157 |
| 158 void _testPaddingCharacter() { |
| 159 var encoded = BASE64.encode(_PADDING_INPUT, encodePaddingCharacter: true); |
| 160 expect(encoded, 'Agg%3D'); |
| 161 expect(BASE64.decode(encoded), _PADDING_INPUT); |
| 162 } |
| 163 |
| 164 Future _testStreamingEncoder() async { |
| 165 expect( |
| 166 await new Stream.fromIterable(_STREAMING_ENCODER_INPUT) |
| 167 .transform(BASE64.encoder) |
| 168 .join(), |
| 169 _STREAMING_ENCODED); |
| 170 } |
| 171 |
| 172 Future _testStreamingDecoder() async { |
| 173 expect( |
| 174 await new Stream.fromIterable(_STREAMING_DECODER_INPUT) |
| 175 .transform(BASE64.decoder) |
| 176 .expand((l) => l) |
| 177 .toList(), |
| 178 _STREAMING_DECODED); |
| 179 |
| 180 expect( |
| 181 await new Stream.fromIterable(_STREAMING_DECODER_INPUT_FOR_ZEROES) |
| 182 .transform(BASE64.decoder) |
| 183 .expand((l) => l) |
| 184 .toList(), |
| 185 _STREAMING_DECODED_ZEROES); |
| 186 } |
| 187 |
| 188 Future _testStreamingDecoderForMalformedInput() async { |
| 189 expect(new Stream.fromIterable(['ABz']) |
| 190 .transform(BASE64.decoder) |
| 191 .toList(), |
| 192 throwsFormatException); |
| 193 |
| 194 expect(new Stream.fromIterable(['AB', 'Lx', 'z', 'xx']) |
| 195 .transform(BASE64.decoder) |
| 196 .toList(), |
| 197 throwsFormatException); |
| 198 } |
| 199 |
| 200 Future _testStreamingEncoderForDecompositions() async { |
| 201 for(var decomposition in _DECOMPOSITIONS_FOR_ENCODING) { |
| 202 expect( |
| 203 await new Stream.fromIterable(decomposition) |
| 204 .transform(BASE64.encoder) |
| 205 .join(), |
| 206 _DECOMPOSITION_ENCODED); |
| 207 } |
| 208 } |
| 209 |
| 210 Future _testStreamingDecoderForDecompositions() async { |
| 211 for(var decomposition in _DECOMPOSITIONS_FOR_DECODING) { |
| 212 expect( |
| 213 await new Stream.fromIterable(decomposition) |
| 214 .transform(BASE64.decoder) |
| 215 .expand((x) => x) |
| 216 .toList(), |
| 217 _DECOMPOSITION_DECODED); |
| 218 } |
| 219 } |
| 220 |
94 void _testDecoderForMalformedInput() { | 221 void _testDecoderForMalformedInput() { |
95 expect(() { | 222 expect(() { |
96 CryptoUtils.base64StringToBytes('AB~'); | 223 BASE64.decode('AB~'); |
97 }, throwsFormatException); | 224 }, throwsFormatException); |
98 | 225 |
99 expect(() { | 226 expect(() { |
100 CryptoUtils.base64StringToBytes('A'); | 227 BASE64.decode('A'); |
101 }, throwsFormatException); | 228 }, throwsFormatException); |
102 } | 229 } |
103 | 230 |
| 231 Future _testUrlSafeStreaming() async { |
| 232 String encUrlSafe = '-_A='; |
| 233 List<List<int>> dec = [BASE64.decode('+/A=')]; |
| 234 var streamedResult = await new Stream.fromIterable(dec) |
| 235 .transform(new Base64Encoder(urlSafe: true)).join(); |
| 236 |
| 237 expect(streamedResult, encUrlSafe); |
| 238 } |
| 239 |
| 240 void _testConsistentSafeUnsafeDecode() { |
| 241 expect(() { |
| 242 BASE64.decode(_INCONSISTENT_SAFE_RESULT); |
| 243 }, throwsFormatException); |
| 244 } |
| 245 |
| 246 Future _testConsistentSafeUnsafeStreamDecode() { |
| 247 expect(new Stream.fromIterable(_INCONSISTENT_SAFE_STREAMING_RESULT) |
| 248 .transform(BASE64.decoder) |
| 249 .toList(), |
| 250 throwsFormatException); |
| 251 } |
| 252 |
| 253 Future _testStreamingForEncodedPadding() async { |
| 254 List<String> withEncodedPadding = ['AA%', '3D', '%', '3', 'DEFGZ']; |
| 255 List<int> decoded = BASE64.decode('AA==EFGZ'); |
| 256 var streamedResult = await new Stream.fromIterable(withEncodedPadding) |
| 257 .transform(BASE64.decoder).expand((x) => x).toList(); |
| 258 |
| 259 expect(streamedResult, decoded); |
| 260 } |
| 261 |
104 void _testUrlSafeEncodeDecode() { | 262 void _testUrlSafeEncodeDecode() { |
105 List<int> decUrlSafe = CryptoUtils.base64StringToBytes('-_A='); | 263 List<int> decUrlSafe = BASE64.decode('-_A='); |
106 List<int> dec = CryptoUtils.base64StringToBytes('+/A='); | 264 List<int> dec = BASE64.decode('+/A='); |
107 expect(decUrlSafe, orderedEquals(dec)); | 265 expect(decUrlSafe, orderedEquals(dec)); |
108 expect(CryptoUtils.bytesToBase64(dec, urlSafe: true), '-_A='); | 266 expect(BASE64.encode(dec, urlSafe: true), '-_A='); |
109 expect(CryptoUtils.bytesToBase64(dec), '+/A='); | 267 expect(BASE64.encode(dec), '+/A='); |
110 } | 268 } |
111 | 269 |
112 void _testEncodeDecodeLists() { | 270 void _testEncodeDecodeLists() { |
113 for (int i = 0; i < 10; i++) { | 271 for (int i = 0; i < 10; i++) { |
114 for (int j = 0; j < 256 - i; j++) { | 272 for (int j = 0; j < 256 - i; j++) { |
115 List<int> x = new List<int>(i); | 273 List<int> x = new List<int>(i); |
116 for (int k = 0; k < i; k++) { | 274 for (int k = 0; k < i; k++) { |
117 x[k] = j; | 275 x[k] = j; |
118 } | 276 } |
119 var enc = CryptoUtils.bytesToBase64(x); | 277 var enc = BASE64.encode(x); |
120 var dec = CryptoUtils.base64StringToBytes(enc); | 278 var dec = BASE64.decode(enc); |
121 expect(dec, orderedEquals(x)); | 279 expect(dec, orderedEquals(x)); |
122 } | 280 } |
123 } | 281 } |
124 } | 282 } |
125 | 283 |
126 void _fillRandom(List<int> l) { | 284 void _fillRandom(List<int> l) { |
127 var random = new Random(0xBABE); | 285 var random = new Random(0xBABE); |
128 for (int j = 0; j < l.length; j++) { | 286 for (int j = 0; j < l.length; j++) { |
129 l[j] = random.nextInt(255); | 287 l[j] = random.nextInt(255); |
130 } | 288 } |
131 } | 289 } |
132 | 290 |
| 291 void _testOldApi() { |
| 292 for (int i = 0; i < _INPUTS.length; i++) { |
| 293 expect(CryptoUtils.bytesToBase64(_INPUTS[i].codeUnits), _RESULTS[i]); |
| 294 expect(CryptoUtils.base64StringToBytes(_RESULTS[i]), _INPUTS[i].codeUnits); |
| 295 } |
| 296 } |
| 297 |
133 void _testPerformance() { | 298 void _testPerformance() { |
134 var l = new List<int>(1024); | 299 var l = new List<int>(1024); |
135 var iters = 5000; | 300 var iters = 5000; |
136 _fillRandom(l); | 301 _fillRandom(l); |
137 String enc; | 302 String enc; |
138 var w = new Stopwatch()..start(); | 303 var w = new Stopwatch()..start(); |
139 for( int i = 0; i < iters; ++i ) { | 304 for( int i = 0; i < iters; ++i ) { |
140 enc = CryptoUtils.bytesToBase64(l); | 305 enc = BASE64.encode(l); |
141 } | 306 } |
142 int ms = w.elapsedMilliseconds; | 307 int ms = w.elapsedMilliseconds; |
143 int perSec = (iters * l.length) * 1000 ~/ ms; | 308 int perSec = (iters * l.length) * 1000 ~/ ms; |
144 // print("Encode 1024 bytes for $iters times: $ms msec. $perSec b/s"); | 309 // print("Encode 1024 bytes for $iters times: $ms msec. $perSec b/s"); |
145 w..reset(); | 310 w..reset(); |
146 for( int i = 0; i < iters; ++i ) { | 311 for( int i = 0; i < iters; ++i ) { |
147 CryptoUtils.base64StringToBytes(enc); | 312 BASE64.decode(enc); |
148 } | 313 } |
149 ms = w.elapsedMilliseconds; | 314 ms = w.elapsedMilliseconds; |
150 perSec = (iters * l.length) * 1000 ~/ ms; | 315 perSec = (iters * l.length) * 1000 ~/ ms; |
151 // print('''Decode into ${l.length} bytes for $iters | 316 // ('''Decode into ${l.length} bytes for $iters |
152 // times: $ms msec. $perSec b/s'''); | 317 // times: $ms msec. $perSec b/s'''); |
153 } | 318 } |
OLD | NEW |