| // Copyright (c) 2014, 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 "package:expect/expect.dart"; | 
 | import 'dart:collection'; | 
 | import 'dart:typed_data'; | 
 |  | 
 | class MyList extends ListBase { | 
 |   List list; | 
 |   MyList(this.list); | 
 |  | 
 |   get length => list.length; | 
 |   set length(val) { | 
 |     list.length = val; | 
 |   } | 
 |  | 
 |   operator [](index) => list[index]; | 
 |   operator []=(index, val) => list[index] = val; | 
 | } | 
 |  | 
 | Iterable id(Iterable x) => x; | 
 |  | 
 | main() { | 
 |   // Test functionality. | 
 |   for (dynamic iterable in [ | 
 |     const [1, 2, 3], | 
 |     [1, 2, 3], | 
 |     new List<int?>.filled(3, null) | 
 |       ..[0] = 1 | 
 |       ..[1] = 2 | 
 |       ..[2] = 3, | 
 |     {1: 1, 2: 2, 3: 3}.keys, | 
 |     {1: 1, 2: 2, 3: 3}.values, | 
 |     new Iterable.generate(3, (x) => x + 1), | 
 |     new List.generate(3, (x) => x + 1), | 
 |     [0, 1, 2, 3].where((x) => x > 0), | 
 |     [0, 1, 2].map((x) => x + 1), | 
 |     [ | 
 |       [1, 2], | 
 |       [3] | 
 |     ].expand(id), | 
 |     [3, 2, 1].reversed, | 
 |     [0, 1, 2, 3].skip(1), | 
 |     [1, 2, 3, 4].take(3), | 
 |     new Uint8List(3) | 
 |       ..[0] = 1 | 
 |       ..[1] = 2 | 
 |       ..[2] = 3, | 
 |     (new HashMap() | 
 |           ..[1] = 1 | 
 |           ..[2] = 2 | 
 |           ..[3] = 3) | 
 |         .keys, | 
 |     (new HashMap() | 
 |           ..[1] = 1 | 
 |           ..[2] = 2 | 
 |           ..[3] = 3) | 
 |         .values, | 
 |     (new SplayTreeMap() | 
 |           ..[1] = 0 | 
 |           ..[2] = 0 | 
 |           ..[3] = 0) | 
 |         .keys, | 
 |     (new SplayTreeMap() | 
 |           ..[0] = 1 | 
 |           ..[1] = 2 | 
 |           ..[2] = 3) | 
 |         .values, | 
 |     new HashSet()..add(1)..add(2)..add(3), | 
 |     new LinkedHashSet()..add(1)..add(2)..add(3), | 
 |     new SplayTreeSet()..add(1)..add(2)..add(3), | 
 |     "\x01\x02\x03".codeUnits, | 
 |     "\x01\x02\x03".runes, | 
 |     new MyList([1, 2, 3]), | 
 |   ]) { | 
 |     int callCount = 0; | 
 |     var result = iterable.reduce((x, y) { | 
 |       callCount++; | 
 |       // Return type of reduce() callback should match element type. | 
 |       return (x + y) as int; | 
 |     }); | 
 |     Expect.equals(6, result, "${iterable.runtimeType}"); | 
 |     Expect.equals(2, callCount); | 
 |   } | 
 |  | 
 |   // Empty iterables not allowed. | 
 |   for (var iterable in [ | 
 |     const [], | 
 |     [], | 
 |     new List.empty(), | 
 |     {}.keys, | 
 |     {}.values, | 
 |     new Iterable.generate(0, (x) => x + 1), | 
 |     new List.generate(0, (x) => x + 1), | 
 |     [0, 1, 2, 3].where((x) => false), | 
 |     [].map((x) => x + 1), | 
 |     [[], []].expand(id), | 
 |     [].reversed, | 
 |     [0, 1, 2, 3].skip(4), | 
 |     [1, 2, 3, 4].take(0), | 
 |     new Uint8List(0), | 
 |     (new HashMap()).keys, | 
 |     (new HashMap()).values, | 
 |     (new SplayTreeMap()).keys, | 
 |     (new SplayTreeMap()).values, | 
 |     new HashSet(), | 
 |     new LinkedHashSet(), | 
 |     new SplayTreeSet(), | 
 |     "".codeUnits, | 
 |     "".runes, | 
 |     new MyList([]), | 
 |   ]) { | 
 |     Expect | 
 |         .throwsStateError(() => iterable.reduce((x, y) => throw "Unreachable")); | 
 |   } | 
 |  | 
 |   // Singleton iterables not calling reduce function. | 
 |   for (dynamic iterable in [ | 
 |     const [1], | 
 |     [1], | 
 |     new List.filled(1, 1), | 
 |     {1: 1}.keys, | 
 |     {1: 1}.values, | 
 |     new Iterable.generate(1, (x) => x + 1), | 
 |     new List.generate(1, (x) => x + 1), | 
 |     [0, 1, 2, 3].where((x) => x == 1), | 
 |     [0].map((x) => x + 1), | 
 |     [ | 
 |       [], | 
 |       [1] | 
 |     ].expand(id), | 
 |     [1].reversed, | 
 |     [0, 1].skip(1), | 
 |     [1, 2, 3, 4].take(1), | 
 |     new Uint8List(1)..[0] = 1, | 
 |     (new HashMap()..[1] = 0).keys, | 
 |     (new HashMap()..[0] = 1).values, | 
 |     (new SplayTreeMap()..[1] = 0).keys, | 
 |     (new SplayTreeMap()..[0] = 1).values, | 
 |     new HashSet()..add(1), | 
 |     new LinkedHashSet()..add(1), | 
 |     new SplayTreeSet()..add(1), | 
 |     "\x01".codeUnits, | 
 |     "\x01".runes, | 
 |     new MyList([1]), | 
 |   ]) { | 
 |     Expect.equals(1, iterable.reduce((x, y) => throw "Unreachable")); | 
 |   } | 
 |  | 
 |   // Concurrent modifications not allowed. | 
 |   testModification(base, modify, transform) { | 
 |     var iterable = transform(base); | 
 |     Expect.throws(() { | 
 |       iterable.reduce((x, y) { | 
 |         modify(base); | 
 |         // Return type of reduce() callback should match element type. | 
 |         return (x + y) as int; | 
 |       }); | 
 |     }, (e) => e is ConcurrentModificationError); | 
 |   } | 
 |  | 
 |   void add4(collection) { | 
 |     collection.add(4); | 
 |   } | 
 |  | 
 |   void addListOf4(collection) { | 
 |     collection.add([4]); | 
 |   } | 
 |  | 
 |   void put4(map) { | 
 |     map[4] = 4; | 
 |   } | 
 |  | 
 |   testModification([1, 2, 3], add4, id); | 
 |   testModification(new HashSet()..add(1)..add(2)..add(3), add4, id); | 
 |   testModification(new LinkedHashSet()..add(1)..add(2)..add(3), add4, id); | 
 |   testModification(new SplayTreeSet()..add(1)..add(2)..add(3), add4, id); | 
 |   testModification(new MyList([1, 2, 3]), add4, id); | 
 |  | 
 |   testModification([0, 1, 2, 3], add4, (x) => x.where((int x) => x > 0)); | 
 |   testModification([0, 1, 2], add4, (x) => x.map((x) => x + 1)); | 
 |   testModification([ | 
 |     [1, 2], | 
 |     [3] | 
 |   ], addListOf4, (x) => x.expand((List<int> x) => x)); | 
 |   testModification([3, 2, 1], add4, (x) => x.reversed); | 
 |   testModification({1: 1, 2: 2, 3: 3}, put4, (x) => x.keys); | 
 |   testModification({1: 1, 2: 2, 3: 3}, put4, (x) => x.values); | 
 |   var hashMap = new HashMap() | 
 |     ..[1] = 1 | 
 |     ..[2] = 2 | 
 |     ..[3] = 3; | 
 |   testModification(hashMap, put4, (x) => x.keys); | 
 |   hashMap = new HashMap() | 
 |     ..[1] = 1 | 
 |     ..[2] = 2 | 
 |     ..[3] = 3; | 
 |   testModification(hashMap, put4, (x) => x.values); | 
 |   var splayMap = new SplayTreeMap() | 
 |     ..[1] = 1 | 
 |     ..[2] = 2 | 
 |     ..[3] = 3; | 
 |   testModification(splayMap, put4, (x) => x.keys); | 
 |   splayMap = new SplayTreeMap() | 
 |     ..[1] = 1 | 
 |     ..[2] = 2 | 
 |     ..[3] = 3; | 
 |   testModification(splayMap, put4, (x) => x.values); | 
 | } |