| // Copyright (c) 2013, 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. |
| |
| import 'dart:convert'; |
| |
| import 'package:expect/expect.dart'; |
| |
| // This test implements a new special interface that can be used to |
| // send data more efficiently between two converters. |
| |
| abstract class MyChunkedIntSink extends ChunkedConversionSink<int> { |
| MyChunkedIntSink(); |
| factory MyChunkedIntSink.from(sink) = IntAdapterSink; |
| factory MyChunkedIntSink.withCallback(callback) { |
| var sink = new ChunkedConversionSink.withCallback(callback); |
| return new MyChunkedIntSink.from(sink); |
| } |
| |
| add(int i); |
| close(); |
| |
| // The special method. |
| specialI(i); |
| } |
| |
| class IntAdapterSink extends MyChunkedIntSink { |
| final _sink; |
| IntAdapterSink(this._sink); |
| add(o) => _sink.add(o); |
| close() => _sink.close(); |
| specialI(o) => add(o); |
| } |
| |
| abstract class MyChunkedBoolSink extends ChunkedConversionSink<bool> { |
| MyChunkedBoolSink(); |
| factory MyChunkedBoolSink.from(sink) = BoolAdapterSink; |
| factory MyChunkedBoolSink.withCallback(callback) { |
| var sink = new ChunkedConversionSink.withCallback(callback); |
| return new MyChunkedBoolSink.from(sink); |
| } |
| |
| add(bool b); |
| close(); |
| |
| specialB(bool b); |
| } |
| |
| class BoolAdapterSink extends MyChunkedBoolSink { |
| final _sink; |
| BoolAdapterSink(this._sink); |
| add(o) => _sink.add(o); |
| close() => _sink.close(); |
| specialB(o) => add(o); |
| } |
| |
| class IntBoolConverter1 extends Converter<int, bool> { |
| bool convert(int input) => input > 0; |
| |
| startChunkedConversion(sink) { |
| if (sink is! MyChunkedBoolSink) sink = new MyChunkedBoolSink.from(sink); |
| return new IntBoolConverter1Sink(sink); |
| } |
| } |
| |
| class BoolIntConverter1 extends Converter<bool, int> { |
| int convert(bool input) => input ? 1 : 0; |
| |
| startChunkedConversion(sink) { |
| if (sink is! MyChunkedIntSink) sink = new MyChunkedIntSink.from(sink); |
| return new BoolIntConverter1Sink(sink); |
| } |
| } |
| |
| int specialICounter = 0; |
| int specialBCounter = 0; |
| |
| class IntBoolConverter1Sink extends MyChunkedIntSink { |
| var outSink; |
| IntBoolConverter1Sink(this.outSink); |
| |
| add(int i) { |
| outSink.specialB(i > 0); |
| } |
| |
| specialI(int i) { |
| specialICounter++; |
| add(i); |
| } |
| |
| close() => outSink.close(); |
| } |
| |
| class BoolIntConverter1Sink extends MyChunkedBoolSink { |
| var outSink; |
| BoolIntConverter1Sink(this.outSink); |
| |
| add(bool b) { |
| outSink.specialI(b ? 1 : 0); |
| } |
| |
| specialB(bool b) { |
| specialBCounter++; |
| add(b); |
| } |
| |
| close() => outSink.close(); |
| } |
| |
| class IdentityConverter extends Converter { |
| convert(x) => x; |
| |
| startChunkedConversion(sink) { |
| return new IdentitySink(sink); |
| } |
| } |
| |
| class IdentitySink extends ChunkedConversionSink { |
| final _sink; |
| IdentitySink(this._sink); |
| add(o) => _sink.add(o); |
| close() => _sink.close(); |
| } |
| |
| main() { |
| var converter1, converter2, intSink, intSink2, hasExecuted, boolSink, fused; |
| var converter3, fused2, sink, sink2; |
| |
| // Test int->bool converter individually. |
| converter1 = new IntBoolConverter1(); |
| Expect.listEquals( |
| [true, false, true], [2, -2, 2].map(converter1.convert).toList()); |
| hasExecuted = false; |
| boolSink = new MyChunkedBoolSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([true, false, true], value); |
| }); |
| intSink = converter1.startChunkedConversion(boolSink); |
| intSink.add(3); |
| intSink.specialI(-3); |
| intSink.add(3); |
| intSink.close(); |
| Expect.isTrue(hasExecuted); |
| Expect.equals(1, specialICounter); |
| specialICounter = 0; |
| hasExecuted = false; |
| |
| // Test bool->int converter individually. |
| converter2 = new BoolIntConverter1(); |
| Expect.listEquals( |
| [1, 0, 1], [true, false, true].map(converter2.convert).toList()); |
| hasExecuted = false; |
| intSink = new MyChunkedIntSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([1, 0, 1], value); |
| }); |
| boolSink = converter2.startChunkedConversion(intSink); |
| boolSink.specialB(true); |
| boolSink.add(false); |
| boolSink.add(true); |
| boolSink.close(); |
| Expect.isTrue(hasExecuted); |
| Expect.equals(1, specialBCounter); |
| specialBCounter = 0; |
| hasExecuted = false; |
| |
| // Test identity converter indidivually. |
| converter3 = new IdentityConverter(); |
| hasExecuted = false; |
| sink = new ChunkedConversionSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([1, 2, 3], value); |
| }); |
| sink2 = converter3.startChunkedConversion(sink); |
| [1, 2, 3].forEach(sink2.add); |
| sink2.close(); |
| Expect.isTrue(hasExecuted); |
| hasExecuted = false; |
| |
| // Test fused converters. |
| fused = converter1.fuse(converter2); |
| Expect.listEquals([1, 0, 1], [2, -2, 2].map(fused.convert).toList()); |
| hasExecuted = false; |
| intSink2 = new MyChunkedIntSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([1, 0, 1], value); |
| }); |
| intSink = fused.startChunkedConversion(intSink2); |
| intSink.specialI(3); |
| intSink.add(-3); |
| intSink.add(3); |
| intSink.close(); |
| Expect.isTrue(hasExecuted); |
| Expect.equals(3, specialBCounter); |
| specialBCounter = 0; |
| Expect.equals(1, specialICounter); |
| specialICounter = 0; |
| hasExecuted = false; |
| |
| // With identity in front. |
| fused2 = converter3.fuse(fused); |
| hasExecuted = false; |
| intSink2 = new MyChunkedIntSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([1, 0, 1], value); |
| }); |
| sink = fused2.startChunkedConversion(intSink2); |
| Expect.isFalse(sink is MyChunkedIntSink); |
| sink.add(3); |
| sink.add(-3); |
| sink.add(3); |
| sink.close(); |
| Expect.isTrue(hasExecuted); |
| Expect.equals(3, specialBCounter); |
| specialBCounter = 0; |
| Expect.equals(0, specialICounter); |
| specialICounter = 0; |
| hasExecuted = false; |
| |
| // With identity at the end. |
| fused2 = fused.fuse(converter3); |
| hasExecuted = false; |
| sink = new ChunkedConversionSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([1, 0, 1], value); |
| }); |
| intSink = fused2.startChunkedConversion(sink); |
| Expect.isTrue(intSink is MyChunkedIntSink); |
| intSink.specialI(3); |
| intSink.add(-3); |
| intSink.specialI(3); |
| intSink.close(); |
| Expect.isTrue(hasExecuted); |
| Expect.equals(3, specialBCounter); |
| specialBCounter = 0; |
| Expect.equals(2, specialICounter); |
| specialICounter = 0; |
| hasExecuted = false; |
| |
| // With identity between the two converters. |
| fused = converter1.fuse(converter3).fuse(converter2); |
| Expect.listEquals([1, 0, 1], [2, -2, 2].map(fused.convert).toList()); |
| hasExecuted = false; |
| intSink2 = new MyChunkedIntSink.withCallback((value) { |
| hasExecuted = true; |
| Expect.listEquals([1, 0, 1], value); |
| }); |
| intSink = fused.startChunkedConversion(intSink2); |
| intSink.specialI(3); |
| intSink.add(-3); |
| intSink.add(3); |
| intSink.close(); |
| Expect.isTrue(hasExecuted); |
| Expect.equals(0, specialBCounter); |
| specialBCounter = 0; |
| Expect.equals(1, specialICounter); |
| specialICounter = 0; |
| hasExecuted = false; |
| } |