| // Copyright (c) 2018, 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:collection" show Queue; | 
 | import "dart:typed_data" show Int32List; | 
 |  | 
 | import "package:expect/expect.dart"; | 
 |  | 
 | // Tests behavior of result of an operation on a followedBy iterable. | 
 | test(List expects, Iterable iterable, [String name]) { | 
 |   try { | 
 |     Expect.isFalse(iterable is List, "$name is! List"); | 
 |     Expect.isFalse(iterable is Set, "$name is! Set"); | 
 |     Expect.isFalse(iterable is Queue, "$name is! Queue"); | 
 |     if (expects.isNotEmpty) { | 
 |       Expect.equals(expects.first, iterable.first, "$name: first"); | 
 |       Expect.equals(expects.last, iterable.last, "$name: last"); | 
 |     } else { | 
 |       Expect.throwsStateError(() => iterable.first, "$name: first"); | 
 |       Expect.throwsStateError(() => iterable.last, "$name: last"); | 
 |     } | 
 |     var it = iterable.iterator; | 
 |     for (int index = 0; index < expects.length; index++) { | 
 |       Expect.isTrue(it.moveNext(), "$name: has element $index"); | 
 |       var expect = expects[index]; | 
 |       Expect.equals(expect, it.current, "$name at $index"); | 
 |       Expect.equals( | 
 |           expect, iterable.elementAt(index), "$name: elementAt($index)"); | 
 |       Expect.isTrue(iterable.contains(expect), "$name:contains $index"); | 
 |     } | 
 |     Expect.isFalse(it.moveNext(), | 
 |         "$name: extra element at ${expects.length}: ${it.current}"); | 
 |   } on Error { | 
 |     print("Failed during: $name"); | 
 |     rethrow; | 
 |   } | 
 | } | 
 |  | 
 | // Tests various operations on the a followedBy iterable. | 
 | tests(List<int> expects, Iterable<int> follow, [String name]) { | 
 |   int length = expects.length; | 
 |   test(expects, follow, name); | 
 |   for (int i = 0; i <= length; i++) { | 
 |     test(expects.sublist(i), follow.skip(i), "$name.skip($i)"); | 
 |   } | 
 |   for (int i = 0; i <= length; i++) { | 
 |     test(expects.sublist(0, i), follow.take(i), "$name.take($i)"); | 
 |   } | 
 |   for (int i = 0; i <= length; i++) { | 
 |     for (int j = 0; j <= length - i; j++) { | 
 |       test(expects.sublist(i, i + j), follow.skip(i).take(j), | 
 |           "$name.skiptake($i,${i+j})"); | 
 |       test(expects.sublist(i, i + j), follow.take(i + j).skip(i), | 
 |           "$name.takeskip($i,${i+j})"); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Tests various different types of iterables as first and second operand. | 
 | types(List expects, List<int> first, List<int> second, [String name]) { | 
 |   var conversions = <String, Iterable<int> Function(List<int>)>{ | 
 |     "const": toConst, | 
 |     "list": toList, | 
 |     "unmod": toUnmodifiable, | 
 |     "set": toSet, | 
 |     "queue": toQueue, | 
 |     "eff-len-iter": toELIter, | 
 |     "non-eff-iter": toNEIter, | 
 |     "typed": toTyped, | 
 |     "keys": toKeys, | 
 |     "values": toValues, | 
 |   }; | 
 |   conversions.forEach((n1, c1) { | 
 |     conversions.forEach((n2, c2) { | 
 |       tests(expects, c1(first).followedBy(c2(second)), "$name:$n1/$n2"); | 
 |     }); | 
 |   }); | 
 | } | 
 |  | 
 | List<int> toConst(List<int> elements) => elements; | 
 | List<int> toList(List<int> elements) => elements.toList(); | 
 | List<int> toUnmodifiable(List<int> elements) => | 
 |     new List<int>.unmodifiable(elements); | 
 | Set<int> toSet(List<int> elements) => elements.toSet(); | 
 | Queue<int> toQueue(List<int> elements) => new Queue<int>.from(elements); | 
 | // Creates an efficient-length iterable. | 
 | Iterable<int> toELIter(List<int> elements) => elements.map<int>((x) => x); | 
 | // Creates a non-efficient-length iterable. | 
 | Iterable<int> toNEIter(List<int> elements) => elements.where((x) => true); | 
 | List<int> toTyped(List<int> elements) => new Int32List.fromList(elements); | 
 | Iterable<int> toKeys(List<int> elements) => | 
 |     new Map<int, int>.fromIterables(elements, elements).keys; | 
 | Iterable<int> toValues(List<int> elements) => | 
 |     new Map<int, int>.fromIterables(elements, elements).values; | 
 |  | 
 | main() { | 
 |   types(<int>[], const <int>[], const <int>[], "0+0"); | 
 |   types(<int>[1, 2, 3, 4], const <int>[], const <int>[1, 2, 3, 4], "0+4"); | 
 |   types(<int>[1, 2, 3, 4], const <int>[1, 2], const <int>[3, 4], "2+2"); | 
 |   types(<int>[1, 2, 3, 4], const <int>[1, 2, 3, 4], const <int>[], "4+0"); | 
 | } |