| Index: test/codegen/lib/convert/chunked_conversion1_test.dart
 | 
| diff --git a/test/codegen/lib/convert/chunked_conversion1_test.dart b/test/codegen/lib/convert/chunked_conversion1_test.dart
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..3c84b3e4d377003dd07e175148fdb0cf9ed3a356
 | 
| --- /dev/null
 | 
| +++ b/test/codegen/lib/convert/chunked_conversion1_test.dart
 | 
| @@ -0,0 +1,256 @@
 | 
| +// 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
 | 
| +    ChunkedConverter<List<int>, List<bool>, int, bool> {
 | 
| +  List<bool> convert(List<int> input) => input.map((x) => x > 0).toList();
 | 
| +
 | 
| +  startChunkedConversion(sink) {
 | 
| +    if (sink is! MyChunkedBoolSink) sink = new MyChunkedBoolSink.from(sink);
 | 
| +    return new IntBoolConverter1Sink(sink);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +class BoolIntConverter1 extends
 | 
| +    ChunkedConverter<List<bool>, List<int>, bool, int> {
 | 
| +  List<int> convert(List<bool> input) => input.map((x) => x ? 1 : 0).toList();
 | 
| +
 | 
| +  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 ChunkedConverter {
 | 
| +  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], converter1.convert([2, -2, 2]));
 | 
| +  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], converter2.convert([true, false, true]));
 | 
| +  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], fused.convert([2, -2, 2]));
 | 
| +  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], fused.convert([2, -2, 2]));
 | 
| +  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;
 | 
| +}
 | 
| 
 |