// 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 { 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. void specialI(int i); } class IntAdapterSink extends MyChunkedIntSink { final _sink; IntAdapterSink(this._sink); add(o) => _sink.add(o); close() => _sink.close(); void specialI(int o) => add(o); } abstract class MyChunkedBoolSink extends ChunkedConversionSink { 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 { 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 { 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); } void 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 { T convert(T x) => x; startChunkedConversion(sink) { return new IdentitySink(sink); } } class IdentitySink extends ChunkedConversionSink { final _sink; IdentitySink(this._sink); void add(T o) => _sink.add(o); close() => _sink.close(); } main() { var intSink, boolSink, sink, sink2; // Test int->bool converter individually. Converter int2boolConverter = new IntBoolConverter1(); Expect.listEquals( [true, false, true], [2, -2, 2].map(int2boolConverter.convert).toList()); var hasExecuted = false; boolSink = new MyChunkedBoolSink.withCallback((value) { hasExecuted = true; Expect.listEquals([true, false, true], value); }); intSink = int2boolConverter.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. Converter bool2intConverter = new BoolIntConverter1(); Expect.listEquals( [1, 0, 1], [true, false, true].map(bool2intConverter.convert).toList()); hasExecuted = false; intSink = new MyChunkedIntSink.withCallback((value) { hasExecuted = true; Expect.listEquals([1, 0, 1], value); }); boolSink = bool2intConverter.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 individually. var identityConverter = new IdentityConverter(); hasExecuted = false; sink = new ChunkedConversionSink.withCallback((value) { hasExecuted = true; Expect.listEquals([1, 2, 3], value); }); sink2 = identityConverter.startChunkedConversion(sink); [1, 2, 3].forEach(sink2.add); sink2.close(); Expect.isTrue(hasExecuted); hasExecuted = false; // Test fused converters. Converter fused = int2boolConverter.fuse(bool2intConverter); Expect.listEquals([1, 0, 1], [2, -2, 2].map(fused.convert).toList()); hasExecuted = false; Sink 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. Converter fused2 = new IdentityConverter().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(new IdentityConverter()); 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 = int2boolConverter.fuse(new IdentityConverter()).fuse(bool2intConverter); 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; }