fa2ad38a31
R=regis@google.com, srdjan@google.com Review URL: https://codereview.chromium.org//21363003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@25723 260f80e4-7a28-3924-810f-c04153c831b5
495 lines
15 KiB
Dart
495 lines
15 KiB
Dart
// Copyright (c) 2011, 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";
|
|
import "dart:typed_data";
|
|
import "package:expect/expect.dart";
|
|
|
|
void main() {
|
|
// Typed lists - fixed length and can only contain integers.
|
|
testTypedList(new Uint8List(4));
|
|
testTypedList(new Int8List(4));
|
|
testTypedList(new Uint16List(4));
|
|
testTypedList(new Int16List(4));
|
|
testTypedList(new Uint32List(4));
|
|
testTypedList(new Int32List(4));
|
|
testTypedList(new Uint8List(4).toList(growable: false));
|
|
testTypedList(new Int8List(4).toList(growable: false));
|
|
testTypedList(new Uint16List(4).toList(growable: false));
|
|
testTypedList(new Int16List(4).toList(growable: false));
|
|
testTypedList(new Uint32List(4).toList(growable: false));
|
|
testTypedList(new Int32List(4).toList(growable: false));
|
|
|
|
// Fixed length lists, length 4.
|
|
testFixedLengthList(new List(4));
|
|
testFixedLengthList(new List(4).toList(growable: false));
|
|
testFixedLengthList((new List()..length = 4).toList(growable: false));
|
|
// ListBase implementation of List.
|
|
testFixedLengthList(new MyFixedList(new List(4)));
|
|
testFixedLengthList(new MyFixedList(new List(4)).toList(growable: false));
|
|
|
|
// Growable lists. Initial length 0.
|
|
testGrowableList(new List());
|
|
testGrowableList(new List().toList());
|
|
testGrowableList(new List(0).toList());
|
|
testGrowableList([]);
|
|
testGrowableList((const []).toList());
|
|
testGrowableList(new MyList([]));
|
|
testGrowableList(new MyList([]).toList());
|
|
|
|
testTypedGrowableList(new Uint8List(0).toList());
|
|
testTypedGrowableList(new Int8List(0).toList());
|
|
testTypedGrowableList(new Uint16List(0).toList());
|
|
testTypedGrowableList(new Int16List(0).toList());
|
|
testTypedGrowableList(new Uint32List(0).toList());
|
|
testTypedGrowableList(new Int32List(0).toList());
|
|
}
|
|
|
|
void testLength(int length, List list) {
|
|
Expect.equals(length, list.length);
|
|
(length == 0 ? Expect.isTrue : Expect.isFalse)(list.isEmpty);
|
|
(length != 0 ? Expect.isTrue : Expect.isFalse)(list.isNotEmpty);
|
|
}
|
|
|
|
void testTypedLengthInvariantOperations(List list) {
|
|
// length
|
|
Expect.equals(list.length, 4);
|
|
// operators [], []=.
|
|
for (int i = 0; i < 4; i++) list[i] = 0;
|
|
list[0] = 4;
|
|
Expect.listEquals([4, 0, 0, 0], list);
|
|
list[1] = 7;
|
|
Expect.listEquals([4, 7, 0, 0], list);
|
|
list[3] = 2;
|
|
Expect.listEquals([4, 7, 0, 2], list);
|
|
|
|
for (int i = 0; i < list.length; i++) {
|
|
list[i] = i;
|
|
}
|
|
|
|
// indexOf, lastIndexOf
|
|
for (int i = 0; i < 4; i++) {
|
|
Expect.equals(i, list[i]);
|
|
Expect.equals(i, list.indexOf(i));
|
|
Expect.equals(i, list.lastIndexOf(i));
|
|
}
|
|
|
|
// setRange.
|
|
list.setRange(0, 4, [3, 2, 1, 0]);
|
|
Expect.listEquals([3, 2, 1, 0], list);
|
|
|
|
list.setRange(1, 4, list);
|
|
Expect.listEquals([3, 3, 2, 1], list);
|
|
|
|
list.setRange(0, 3, list, 1);
|
|
Expect.listEquals([3, 2, 1, 1], list);
|
|
list.setRange(0, 3, list, 1);
|
|
Expect.listEquals([2, 1, 1, 1], list);
|
|
|
|
list.setRange(2, 4, list, 0);
|
|
Expect.listEquals([2, 1, 2, 1], list);
|
|
|
|
// setAll.
|
|
list.setAll(0, [3, 2, 0, 1]);
|
|
Expect.listEquals([3, 2, 0, 1], list);
|
|
list.setAll(1, [0, 1]);
|
|
Expect.listEquals([3, 0, 1, 1], list);
|
|
|
|
// fillRange.
|
|
list.fillRange(1, 3, 7);
|
|
Expect.listEquals([3, 7, 7, 1], list);
|
|
list.fillRange(0, 0, 9);
|
|
Expect.listEquals([3, 7, 7, 1], list);
|
|
list.fillRange(4, 4, 9);
|
|
Expect.listEquals([3, 7, 7, 1], list);
|
|
list.fillRange(0, 4, 9);
|
|
Expect.listEquals([9, 9, 9, 9], list);
|
|
|
|
// sort.
|
|
list.setRange(0, 4, [3, 2, 1, 0]);
|
|
list.sort();
|
|
Expect.listEquals([0, 1, 2, 3], list);
|
|
list.setRange(0, 4, [1, 2, 3, 0]);
|
|
list.sort();
|
|
Expect.listEquals([0, 1, 2, 3], list);
|
|
list.setRange(0, 4, [1, 3, 0, 2]);
|
|
list.sort((a, b) => b - a); // reverse compare.
|
|
Expect.listEquals([3, 2, 1, 0], list);
|
|
list.setRange(0, 4, [1, 2, 3, 0]);
|
|
list.sort((a, b) => b - a);
|
|
Expect.listEquals([3, 2, 1, 0], list);
|
|
|
|
// Some Iterable methods.
|
|
|
|
list.setRange(0, 4, [0, 1, 2, 3]);
|
|
// map.
|
|
testMap(val) {return val * 2 + 10; }
|
|
List mapped = list.map(testMap).toList();
|
|
Expect.equals(mapped.length, list.length);
|
|
for (var i = 0; i < list.length; i++) {
|
|
Expect.equals(mapped[i], list[i] * 2 + 10);
|
|
}
|
|
|
|
matchAll(val) => true;
|
|
matchSome(val) { return (val == 1 || val == 2); }
|
|
matchSomeFirst(val) { return val == 0; }
|
|
matchSomeLast(val) { return val == 3; }
|
|
matchNone(val) => false;
|
|
|
|
// where.
|
|
Iterable filtered = list.where(matchSome);
|
|
Expect.equals(filtered.length, 2);
|
|
|
|
// every
|
|
Expect.isTrue(list.every(matchAll));
|
|
Expect.isFalse(list.every(matchSome));
|
|
Expect.isFalse(list.every(matchNone));
|
|
|
|
// any
|
|
Expect.isTrue(list.any(matchAll));
|
|
Expect.isTrue(list.any(matchSome));
|
|
Expect.isTrue(list.any(matchSomeFirst));
|
|
Expect.isTrue(list.any(matchSomeLast));
|
|
Expect.isFalse(list.any(matchNone));
|
|
|
|
// Argument checking isn't implemented for typed arrays in browsers,
|
|
// so it's moved to the method below for now.
|
|
}
|
|
|
|
void testLengthInvariantOperations(List list) {
|
|
testTypedLengthInvariantOperations(list);
|
|
// Tests that need untyped lists.
|
|
list.setAll(0, [0, 1, 2, 3]);
|
|
Expect.equals(-1, list.indexOf(100));
|
|
Expect.equals(-1, list.lastIndexOf(100));
|
|
list[2] = new Yes();
|
|
Expect.equals(2, list.indexOf(100));
|
|
Expect.equals(2, list.lastIndexOf(100));
|
|
list[3] = new Yes();
|
|
Expect.equals(2, list.indexOf(100));
|
|
Expect.equals(3, list.lastIndexOf(100));
|
|
list[2] = 2;
|
|
Expect.equals(3, list.indexOf(100));
|
|
Expect.equals(3, list.lastIndexOf(100));
|
|
list[3] = 3;
|
|
Expect.equals(-1, list.indexOf(100));
|
|
Expect.equals(-1, list.lastIndexOf(100));
|
|
|
|
// Argument errors on bad indices. List is still [0, 1, 2, 3].
|
|
testArgumentError(action()) {
|
|
Expect.throws(action, (e) => e is ArgumentError);
|
|
}
|
|
|
|
// Direct indices (0 <= index < length).
|
|
testArgumentError(() => list[-1]);
|
|
testArgumentError(() => list[4]);
|
|
testArgumentError(() => list[-1] = 99);
|
|
testArgumentError(() => list[4] = 99);
|
|
testArgumentError(() => list.elementAt(-1));
|
|
testArgumentError(() => list.elementAt(4));
|
|
// Ranges (0 <= start <= end <= length).
|
|
testArgumentError(() => list.sublist(-1, 2));
|
|
testArgumentError(() => list.sublist(-1, 5));
|
|
testArgumentError(() => list.sublist(2, 5));
|
|
testArgumentError(() => list.sublist(4, 2));
|
|
testArgumentError(() => list.getRange(-1, 2));
|
|
testArgumentError(() => list.getRange(-1, 5));
|
|
testArgumentError(() => list.getRange(2, 5));
|
|
testArgumentError(() => list.getRange(4, 2));
|
|
testArgumentError(() => list.setRange(-1, 2, [1, 2, 3]));
|
|
testArgumentError(() => list.setRange(-1, 5, [1, 2, 3, 4, 5, 6]));
|
|
testArgumentError(() => list.setRange(2, 5, [1, 2, 3]));
|
|
testArgumentError(() => list.setRange(4, 2, [1, 2]));
|
|
// for setAll, end is implictly start + values.length.
|
|
testArgumentError(() => list.setAll(-1, []));
|
|
testArgumentError(() => list.setAll(5, []));
|
|
testArgumentError(() => list.setAll(2, [1, 2, 3]));
|
|
testArgumentError(() => list.fillRange(-1, 2));
|
|
testArgumentError(() => list.fillRange(-1, 5));
|
|
testArgumentError(() => list.fillRange(2, 5));
|
|
testArgumentError(() => list.fillRange(4, 2));
|
|
}
|
|
|
|
void testTypedList(List list) {
|
|
testTypedLengthInvariantOperations(list);
|
|
testCannotChangeLength(list);
|
|
}
|
|
|
|
void testFixedLengthList(List list) {
|
|
testLengthInvariantOperations(list);
|
|
testCannotChangeLength(list);
|
|
}
|
|
|
|
void testCannotChangeLength(List list) {
|
|
isUnsupported(action()) {
|
|
Expect.throws(action, (e) => e is UnsupportedError);
|
|
}
|
|
isUnsupported(() => list.add(0));
|
|
isUnsupported(() => list.addAll([0]));
|
|
isUnsupported(() => list.removeLast());
|
|
isUnsupported(() => list.insert(0, 1));
|
|
isUnsupported(() => list.insertAll(0, [1]));
|
|
isUnsupported(() => list.clear());
|
|
isUnsupported(() => list.remove(1));
|
|
isUnsupported(() => list.removeAt(1));
|
|
isUnsupported(() => list.removeRange(0, 1));
|
|
isUnsupported(() => list.replaceRange(0, 1, []));
|
|
}
|
|
|
|
void testTypedGrowableList(List list) {
|
|
testLength(0, list);
|
|
// set length.
|
|
list.length = 4;
|
|
testLength(4, list);
|
|
|
|
testTypedLengthInvariantOperations(list);
|
|
|
|
testGrowableListOperations(list);
|
|
}
|
|
|
|
void testGrowableList(List list) {
|
|
testLength(0, list);
|
|
// set length.
|
|
list.length = 4;
|
|
testLength(4, list);
|
|
|
|
testLengthInvariantOperations(list);
|
|
|
|
testGrowableListOperations(list);
|
|
}
|
|
|
|
void testGrowableListOperations(List list) {
|
|
// add, removeLast.
|
|
list.clear();
|
|
testLength(0, list);
|
|
list.add(4);
|
|
testLength(1, list);
|
|
Expect.equals(4, list.removeLast());
|
|
testLength(0, list);
|
|
|
|
for (int i = 0; i < 100; i++) {
|
|
list.add(i);
|
|
}
|
|
|
|
Expect.equals(list.length, 100);
|
|
for (int i = 0; i < 100; i++) {
|
|
Expect.equals(i, list[i]);
|
|
}
|
|
|
|
Expect.equals(17, list.indexOf(17));
|
|
Expect.equals(17, list.lastIndexOf(17));
|
|
Expect.equals(-1, list.indexOf(999));
|
|
Expect.equals(-1, list.lastIndexOf(999));
|
|
|
|
Expect.equals(99, list.removeLast());
|
|
testLength(99, list);
|
|
|
|
// remove.
|
|
Expect.isTrue(list.remove(4));
|
|
testLength(98, list);
|
|
Expect.isFalse(list.remove(4));
|
|
testLength(98, list);
|
|
list.clear();
|
|
testLength(0, list);
|
|
|
|
list.add(4);
|
|
list.add(4);
|
|
testLength(2, list);
|
|
Expect.isTrue(list.remove(4));
|
|
testLength(1, list);
|
|
Expect.isTrue(list.remove(4));
|
|
testLength(0, list);
|
|
Expect.isFalse(list.remove(4));
|
|
testLength(0, list);
|
|
|
|
// removeWhere, retainWhere
|
|
for (int i = 0; i < 100; i++) {
|
|
list.add(i);
|
|
}
|
|
testLength(100, list);
|
|
list.removeWhere((int x) => x.isOdd);
|
|
testLength(50, list);
|
|
for (int i = 0; i < list.length; i++) {
|
|
Expect.isTrue(list[i].isEven);
|
|
}
|
|
list.retainWhere((int x) => (x % 3) == 0);
|
|
testLength(17, list);
|
|
for (int i = 0; i < list.length; i++) {
|
|
Expect.isTrue((list[i] % 6) == 0);
|
|
}
|
|
|
|
// insert, remove, removeAt
|
|
list.clear();
|
|
testLength(0, list);
|
|
|
|
list.insert(0, 0);
|
|
Expect.listEquals([0], list);
|
|
|
|
list.insert(0, 1);
|
|
Expect.listEquals([1, 0], list);
|
|
|
|
list.insert(0, 2);
|
|
Expect.listEquals([2, 1, 0], list);
|
|
|
|
Expect.isTrue(list.remove(1));
|
|
Expect.listEquals([2, 0], list);
|
|
|
|
list.insert(1, 1);
|
|
Expect.listEquals([2, 1, 0], list);
|
|
|
|
list.removeAt(1);
|
|
Expect.listEquals([2, 0], list);
|
|
|
|
list.removeAt(1);
|
|
Expect.listEquals([2], list);
|
|
|
|
// insertAll
|
|
list.insertAll(0, [1, 2, 3]);
|
|
Expect.listEquals([1, 2, 3, 2], list);
|
|
|
|
list.insertAll(2, []);
|
|
Expect.listEquals([1, 2, 3, 2], list);
|
|
|
|
list.insertAll(4, [7, 9]);
|
|
Expect.listEquals([1, 2, 3, 2, 7, 9], list);
|
|
|
|
// addAll
|
|
list.addAll(list.reversed.toList());
|
|
Expect.listEquals([1, 2, 3, 2, 7, 9, 9, 7, 2, 3, 2, 1], list);
|
|
|
|
list.addAll([]);
|
|
Expect.listEquals([1, 2, 3, 2, 7, 9, 9, 7, 2, 3, 2, 1], list);
|
|
|
|
// replaceRange
|
|
list.replaceRange(3, 7, [0, 0]);
|
|
Expect.listEquals([1, 2, 3, 0, 0, 7, 2, 3, 2, 1], list);
|
|
|
|
list.replaceRange(2, 3, [5, 5, 5]);
|
|
Expect.listEquals([1, 2, 5, 5, 5, 0, 0, 7, 2, 3, 2, 1], list);
|
|
|
|
list.replaceRange(2, 4, [6, 6]);
|
|
Expect.listEquals([1, 2, 6, 6, 5, 0, 0, 7, 2, 3, 2, 1], list);
|
|
|
|
list.replaceRange(6, 8, []);
|
|
Expect.listEquals([1, 2, 6, 6, 5, 0, 2, 3, 2, 1], list);
|
|
|
|
// Operations that change the length cause ConcurrentModificationError.
|
|
void testConcurrentModification(action()) {
|
|
testIterator(int when) {
|
|
list.length = 4;
|
|
list.setAll(0, [0, 1, 2, 3]);
|
|
Expect.throws(() {
|
|
for (var element in list) {
|
|
if (element == when) action();
|
|
}
|
|
}, (e) => e is ConcurrentModificationError);
|
|
}
|
|
testForEach(int when) {
|
|
list.length = 4;
|
|
list.setAll(0, [0, 1, 2, 3]);
|
|
Expect.throws(() {
|
|
list.forEach((var element) {
|
|
if (element == when) action();
|
|
});
|
|
}, (e) => e is ConcurrentModificationError);
|
|
}
|
|
// Test the change at different points of the iteration.
|
|
testIterator(0);
|
|
testIterator(1);
|
|
testIterator(3);
|
|
testForEach(0);
|
|
testForEach(1);
|
|
testForEach(3);
|
|
}
|
|
|
|
testConcurrentModification(() => list.add(5));
|
|
testConcurrentModification(() => list.addAll([5, 6]));
|
|
testConcurrentModification(() => list.removeLast());
|
|
for (int i = 0; i < 4; i++) {
|
|
testConcurrentModification(() => list.remove(i));
|
|
testConcurrentModification(() => list.removeAt(i));
|
|
testConcurrentModification(() => list.removeWhere((x) => x == i));
|
|
testConcurrentModification(() => list.retainWhere((x) => x != i));
|
|
testConcurrentModification(() => list.insert(i, 5));
|
|
testConcurrentModification(() => list.insertAll(i, [5, 6]));
|
|
testConcurrentModification(() => list.removeRange(i, i + 1));
|
|
testConcurrentModification(() => list.replaceRange(i, i + 1, [5, 6]));
|
|
}
|
|
|
|
// Any operation that doesn't change the length should be safe for iteration.
|
|
testSafeConcurrentModification(action()) {
|
|
list.length = 4;
|
|
list.setAll(0, [0, 1, 2, 3]);
|
|
for (var i in list) {
|
|
action();
|
|
}
|
|
list.forEach((e) => action());
|
|
}
|
|
|
|
testSafeConcurrentModification(() {
|
|
list.add(5);
|
|
list.removeLast();
|
|
});
|
|
testSafeConcurrentModification(() {
|
|
list.add(list[0]);
|
|
list.removeAt(0);
|
|
});
|
|
testSafeConcurrentModification(() {
|
|
list.insert(0, list.removeLast());
|
|
});
|
|
testSafeConcurrentModification(() {
|
|
list.replaceRange(1, 3, list.sublist(1, 3).reversed);
|
|
});
|
|
|
|
// Argument errors on bad indices for methods that are only allowed
|
|
// on growable lists.
|
|
list.length = 4;
|
|
list.setAll(0, [0, 1, 2, 3]);
|
|
testArgumentError(action()) {
|
|
Expect.throws(action, (e) => e is ArgumentError);
|
|
}
|
|
|
|
// Direct indices (0 <= index < length).
|
|
testArgumentError(() => list.removeAt(-1));
|
|
testArgumentError(() => list.removeAt(4));
|
|
// Direct indices including end (0 <= index <= length).
|
|
testArgumentError(() => list.insert(-1, 0));
|
|
testArgumentError(() => list.insert(5, 0));
|
|
testArgumentError(() => list.insertAll(-1, [0]));
|
|
testArgumentError(() => list.insertAll(5, [0]));
|
|
testArgumentError(() => list.insertAll(-1, [0]));
|
|
testArgumentError(() => list.insertAll(5, [0]));
|
|
// Ranges (0 <= start <= end <= length).
|
|
testArgumentError(() => list.removeRange(-1, 2));
|
|
testArgumentError(() => list.removeRange(2, 5));
|
|
testArgumentError(() => list.removeRange(-1, 5));
|
|
testArgumentError(() => list.removeRange(4, 2));
|
|
testArgumentError(() => list.replaceRange(-1, 2, [9]));
|
|
testArgumentError(() => list.replaceRange(2, 5, [9]));
|
|
testArgumentError(() => list.replaceRange(-1, 5, [9]));
|
|
testArgumentError(() => list.replaceRange(4, 2, [9]));
|
|
}
|
|
|
|
class Yes {
|
|
operator ==(var other) => true;
|
|
}
|
|
|
|
class MyList<E> extends ListBase<E> {
|
|
List<E> _source;
|
|
MyList(this._source);
|
|
int get length => _source.length;
|
|
void set length(int length) { _source.length = length; }
|
|
E operator[](int index) => _source[index];
|
|
void operator[]=(int index, E value) { _source[index] = value; }
|
|
}
|
|
|
|
class MyFixedList<E> extends ListBase<E> {
|
|
List<E> _source;
|
|
MyFixedList(this._source);
|
|
int get length => _source.length;
|
|
void set length(int length) { throw new UnsupportedError("Fixed length!"); }
|
|
E operator[](int index) => _source[index];
|
|
void operator[]=(int index, E value) { _source[index] = value; }
|
|
}
|