diff --git a/tests/corelib/json_map_test.dart b/tests/corelib/json_map_test.dart new file mode 100644 index 000000000000..080c61b3165e --- /dev/null +++ b/tests/corelib/json_map_test.dart @@ -0,0 +1,343 @@ +// 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. + +library json_map_test; + +import "package:expect/expect.dart"; +import 'dart:convert' show json; +import 'dart:collection' show LinkedHashMap, HashMap; + +bool useReviver = false; +Map jsonify(Map map) { + String encoded = json.encode(map); + return useReviver + ? json.decode(encoded, reviver: (key, value) => value) + : json.decode(encoded); +} + +List listEach(Map map) { + var result = []; + map.forEach((key, value) { + result.add(key); + result.add(value); + }); + return result; +} + +void main() { + test(false); + test(true); +} + +void test(bool revive) { + useReviver = revive; + testEmpty(jsonify({})); + testAtoB(jsonify({'a': 'b'})); + + // You can write 'Map' here (or 'var' which infers the + // same), but if you write just 'Map' as the type, then the type of the + // constant argument in the addAll below is not inferred correctly. + var map = jsonify({}); + map['a'] = 'b'; + testAtoB(map); + + map = jsonify({}); + Expect.equals('b', map.putIfAbsent('a', () => 'b')); + testAtoB(map); + + map = jsonify({}); + map.addAll({'a': 'b'}); + testAtoB(map); + + testOrder(['a', 'b', 'c', 'd', 'e', 'f']); + + testProto(); + testToString(); + testConcurrentModifications(); + testType(); + testClear(); + + testListEntry(); + testMutation(); +} + +void testEmpty(Map map) { + for (int i = 0; i < 2; i++) { + Expect.equals(0, map.length); + Expect.isTrue(map.isEmpty); + Expect.isFalse(map.isNotEmpty); + Expect.listEquals([], map.keys.toList()); + Expect.listEquals([], map.values.toList()); + Expect.isNull(map['a']); + Expect.listEquals([], listEach(map)); + Expect.isFalse(map.containsKey('a')); + Expect.isFalse(map.containsValue('a')); + Expect.isNull(map.remove('a')); + testLookupNonExistingKeys(map); + testLookupNonExistingValues(map); + map.clear(); + } +} + +void testAtoB(Map map) { + Expect.equals(1, map.length); + Expect.isFalse(map.isEmpty); + Expect.isTrue(map.isNotEmpty); + Expect.listEquals(['a'], map.keys.toList()); + Expect.listEquals(['b'], map.values.toList()); + Expect.equals('b', map['a']); + Expect.listEquals(['a', 'b'], listEach(map)); + Expect.isTrue(map.containsKey('a')); + Expect.isFalse(map.containsKey('b')); + Expect.isTrue(map.containsValue('b')); + Expect.isFalse(map.containsValue('a')); + + testLookupNonExistingKeys(map); + testLookupNonExistingValues(map); + Expect.equals('b', map.remove('a')); + Expect.isNull(map.remove('b')); + testLookupNonExistingKeys(map); + testLookupNonExistingValues(map); + + map.clear(); + testEmpty(map); +} + +void testLookupNonExistingKeys(Map map) { + for (var key in ['__proto__', 'null', null]) { + Expect.isNull(map[key]); + Expect.isFalse(map.containsKey(key)); + } +} + +void testLookupNonExistingValues(Map map) { + for (var value in ['__proto__', 'null', null]) { + Expect.isFalse(map.containsValue(value)); + } +} + +void testOrder(List list) { + if (list.isEmpty) + return; + else + testOrder(list.skip(1).toList()); + + Map original = {}; + for (int i = 0; i < list.length; i++) { + original[list[i]] = i; + } + + Map map = jsonify(original); + Expect.equals(list.length, map.length); + Expect.listEquals(list, map.keys.toList()); + + for (int i = 0; i < 10; i++) { + map["$i"] = i; + Expect.equals(list.length + i + 1, map.length); + Expect.listEquals(list, map.keys.take(list.length).toList()); + } +} + +void testProto() { + Map map = jsonify({'__proto__': 0}); + Expect.equals(1, map.length); + Expect.isTrue(map.containsKey('__proto__')); + Expect.listEquals(['__proto__'], map.keys.toList()); + Expect.equals(0, map['__proto__']); + Expect.equals(0, map.remove('__proto__')); + testEmpty(map); + + map = jsonify({'__proto__': null}); + Expect.equals(1, map.length); + Expect.isTrue(map.containsKey('__proto__')); + Expect.listEquals(['__proto__'], map.keys.toList()); + Expect.isNull(map['__proto__']); + Expect.isNull(map.remove('__proto__')); + testEmpty(map); +} + +void testToString() { + Expect.equals("{}", jsonify({}).toString()); + Expect.equals("{a: 0}", jsonify({'a': 0}).toString()); +} + +void testConcurrentModifications() { + void testIterate(Map map, Iterable iterable, Function f) { + Iterator iterator = iterable.iterator; + f(map); + iterator.moveNext(); + } + + void testKeys(Map map, Function f) => testIterate(map, map.keys, f); + void testValues(Map map, Function f) => testIterate(map, map.values, f); + + void testForEach(Map map, Function f) { + map.forEach((key, value) { + f(map); + }); + } + + bool throwsCME(Function f) { + try { + f(); + } on ConcurrentModificationError catch (e) { + return true; + } catch (e) { + return false; + } + return false; + } + + Map map = {}; + Expect.isTrue(throwsCME(() => testKeys(jsonify(map), (map) => map['a'] = 0))); + Expect + .isTrue(throwsCME(() => testValues(jsonify(map), (map) => map['a'] = 0))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map['a'] = 0))); + + Expect.isFalse(throwsCME(() => testKeys(jsonify(map), (map) => map.clear()))); + Expect + .isFalse(throwsCME(() => testValues(jsonify(map), (map) => map.clear()))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map.clear()))); + + Expect.isFalse( + throwsCME(() => testKeys(jsonify(map), (map) => map.remove('a')))); + Expect.isFalse( + throwsCME(() => testValues(jsonify(map), (map) => map.remove('a')))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map.remove('a')))); + + Expect.isTrue(throwsCME( + () => testKeys(jsonify(map), (map) => map.putIfAbsent('a', () => 0)))); + Expect.isTrue(throwsCME( + () => testValues(jsonify(map), (map) => map.putIfAbsent('a', () => 0)))); + Expect.isFalse(throwsCME( + () => testForEach(jsonify(map), (map) => map.putIfAbsent('a', () => 0)))); + + Expect.isFalse( + throwsCME(() => testKeys(jsonify(map), (map) => map.addAll({})))); + Expect.isFalse( + throwsCME(() => testValues(jsonify(map), (map) => map.addAll({})))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map.addAll({})))); + + Expect.isTrue( + throwsCME(() => testKeys(jsonify(map), (map) => map.addAll({'a': 0})))); + Expect.isTrue( + throwsCME(() => testValues(jsonify(map), (map) => map.addAll({'a': 0})))); + Expect.isFalse(throwsCME( + () => testForEach(jsonify(map), (map) => map.addAll({'a': 0})))); + + map = {'a': 1}; + Expect + .isFalse(throwsCME(() => testKeys(jsonify(map), (map) => map['a'] = 0))); + Expect.isFalse( + throwsCME(() => testValues(jsonify(map), (map) => map['a'] = 0))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map['a'] = 0))); + + Expect.isTrue(throwsCME(() => testKeys(jsonify(map), (map) => map['b'] = 0))); + Expect + .isTrue(throwsCME(() => testValues(jsonify(map), (map) => map['b'] = 0))); + Expect.isTrue( + throwsCME(() => testForEach(jsonify(map), (map) => map['b'] = 0))); + + Expect.isTrue(throwsCME(() => testKeys(jsonify(map), (map) => map.clear()))); + Expect + .isTrue(throwsCME(() => testValues(jsonify(map), (map) => map.clear()))); + Expect + .isTrue(throwsCME(() => testForEach(jsonify(map), (map) => map.clear()))); + + Expect.isTrue( + throwsCME(() => testKeys(jsonify(map), (map) => map.remove('a')))); + Expect.isTrue( + throwsCME(() => testValues(jsonify(map), (map) => map.remove('a')))); + Expect.isTrue( + throwsCME(() => testForEach(jsonify(map), (map) => map.remove('a')))); + + Expect.isFalse( + throwsCME(() => testKeys(jsonify(map), (map) => map.remove('b')))); + Expect.isFalse( + throwsCME(() => testValues(jsonify(map), (map) => map.remove('b')))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map.remove('b')))); + + Expect.isFalse(throwsCME( + () => testKeys(jsonify(map), (map) => map.putIfAbsent('a', () => 0)))); + Expect.isFalse(throwsCME( + () => testValues(jsonify(map), (map) => map.putIfAbsent('a', () => 0)))); + Expect.isFalse(throwsCME( + () => testForEach(jsonify(map), (map) => map.putIfAbsent('a', () => 0)))); + + Expect.isTrue(throwsCME( + () => testKeys(jsonify(map), (map) => map.putIfAbsent('b', () => 0)))); + Expect.isTrue(throwsCME( + () => testValues(jsonify(map), (map) => map.putIfAbsent('b', () => 0)))); + Expect.isTrue(throwsCME( + () => testForEach(jsonify(map), (map) => map.putIfAbsent('b', () => 0)))); + + Expect.isFalse( + throwsCME(() => testKeys(jsonify(map), (map) => map.addAll({})))); + Expect.isFalse( + throwsCME(() => testValues(jsonify(map), (map) => map.addAll({})))); + Expect.isFalse( + throwsCME(() => testForEach(jsonify(map), (map) => map.addAll({})))); + + Expect.isFalse( + throwsCME(() => testKeys(jsonify(map), (map) => map.addAll({'a': 0})))); + Expect.isFalse( + throwsCME(() => testValues(jsonify(map), (map) => map.addAll({'a': 0})))); + Expect.isFalse(throwsCME( + () => testForEach(jsonify(map), (map) => map.addAll({'a': 0})))); + + Expect.isTrue( + throwsCME(() => testKeys(jsonify(map), (map) => map.addAll({'b': 0})))); + Expect.isTrue( + throwsCME(() => testValues(jsonify(map), (map) => map.addAll({'b': 0})))); + Expect.isTrue(throwsCME( + () => testForEach(jsonify(map), (map) => map.addAll({'b': 0})))); +} + +void testType() { + var map = jsonify({}); + var type = "${map.runtimeType}"; + + // The documentation of json.decode doesn't actually specify that it returns + // a map (it's marked dynamic), but it's a reasonable expectation if you + // don't provide a reviver function. + Expect.isTrue(map is Map, type); + Expect.isTrue(map is Map, type); + Expect.isFalse(map is Map, type); +} + +void testClear() { + Map map = jsonify({'a': 0}); + map.clear(); + Expect.equals(0, map.length); +} + +void testListEntry() { + Map map = jsonify({ + 'a': [ + 7, + 8, + {'b': 9} + ] + }); + List list = map['a']; + Expect.equals(3, list.length); + Expect.equals(7, list[0]); + Expect.equals(8, list[1]); + Expect.equals(9, list[2]['b']); +} + +void testMutation() { + Map map = jsonify({'a': 0}); + Expect.listEquals(['a', 0], listEach(map)); + map['a'] = 1; + Expect.listEquals(['a', 1], listEach(map)); + map['a']++; + Expect.listEquals(['a', 2], listEach(map)); +} diff --git a/tests/corelib/linked_hash_map_from_iterable_test.dart b/tests/corelib/linked_hash_map_from_iterable_test.dart new file mode 100644 index 000000000000..ed348e76e47a --- /dev/null +++ b/tests/corelib/linked_hash_map_from_iterable_test.dart @@ -0,0 +1,117 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + defaultFunctionValuesTest(); + defaultKeyFunctionTest(); + defaultValueFunctionTest(); + noDefaultValuesTest(); + emptyIterableTest(); + equalElementsTest(); + genericTypeTest(); +} + +void defaultFunctionValuesTest() { + var map = new LinkedHashMap.fromIterable([1, 2, 3]); + + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(1, map[1]); + Expect.equals(2, map[2]); + Expect.equals(3, map[3]); +} + +void defaultKeyFunctionTest() { + var map = new LinkedHashMap.fromIterable([1, 2, 3], value: (x) => x + 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(2, map[1]); + Expect.equals(3, map[2]); + Expect.equals(4, map[3]); +} + +void defaultValueFunctionTest() { + var map = new LinkedHashMap.fromIterable([1, 2, 3], key: (x) => x + 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(1, map[2]); + Expect.equals(2, map[3]); + Expect.equals(3, map[4]); +} + +void noDefaultValuesTest() { + var map = new LinkedHashMap.fromIterable([1, 2, 3], + key: (x) => x + 1, value: (x) => x - 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(0, map[2]); + Expect.equals(1, map[3]); + Expect.equals(2, map[4]); +} + +void emptyIterableTest() { + var map = new LinkedHashMap.fromIterable([]); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(0, map.length); + Expect.equals(0, map.keys.length); + Expect.equals(0, map.values.length); +} + +void equalElementsTest() { + var map = new LinkedHashMap.fromIterable([1, 2, 2], key: (x) => x + 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(2, map.length); + Expect.equals(2, map.keys.length); + Expect.equals(2, map.values.length); + + Expect.equals(1, map[2]); + Expect.equals(2, map[3]); +} + +void genericTypeTest() { + dynamic map = new LinkedHashMap.fromIterable([1, 2, 3], + value: (x) => '$x'); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + map = new LinkedHashMap.fromIterable([1, 2, 3], + key: (x) => '$x', value: (x) => '$x'); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + // Make sure it is not just LinkedHashMap. + Expect.isFalse(map is LinkedHashMap); + Expect.isFalse(map is LinkedHashMap); +} diff --git a/tests/corelib/linked_hash_map_from_iterables_test.dart b/tests/corelib/linked_hash_map_from_iterables_test.dart new file mode 100644 index 000000000000..a63b20608c2a --- /dev/null +++ b/tests/corelib/linked_hash_map_from_iterables_test.dart @@ -0,0 +1,79 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + positiveTest(); + emptyMapTest(); + fewerKeysIterableTest(); + fewerValuesIterableTest(); + equalElementsTest(); + genericTypeTest(); +} + +void positiveTest() { + var map = new LinkedHashMap.fromIterables([1, 2, 3], ["one", "two", "three"]); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals("one", map[1]); + Expect.equals("two", map[2]); + Expect.equals("three", map[3]); +} + +void emptyMapTest() { + var map = new LinkedHashMap.fromIterables([], []); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(0, map.length); + Expect.equals(0, map.keys.length); + Expect.equals(0, map.values.length); +} + +void fewerValuesIterableTest() { + Expect.throws(() => new LinkedHashMap.fromIterables([1, 2], [0])); +} + +void fewerKeysIterableTest() { + Expect.throws(() => new LinkedHashMap.fromIterables([1], [0, 2])); +} + +void equalElementsTest() { + var map = new LinkedHashMap.fromIterables([1, 2, 2], ["one", "two", "three"]); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(2, map.length); + Expect.equals(2, map.keys.length); + Expect.equals(2, map.values.length); + + Expect.equals("one", map[1]); + Expect.equals("three", map[2]); +} + +void genericTypeTest() { + var map = new LinkedHashMap.fromIterables( + [1, 2, 3], ["one", "two", "three"]); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + // Make sure it is not just LinkedHashMap. + Expect.isFalse(map is LinkedHashMap); + Expect.isFalse(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals("one", map[1]); + Expect.equals("two", map[2]); + Expect.equals("three", map[3]); +} diff --git a/tests/corelib/linked_hash_map_test.dart b/tests/corelib/linked_hash_map_test.dart new file mode 100644 index 000000000000..1cbca3b51a57 --- /dev/null +++ b/tests/corelib/linked_hash_map_test.dart @@ -0,0 +1,116 @@ +// 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. + +// Dart test for linked hash-maps. +library linkedHashMap.test; + +import "package:expect/expect.dart"; +import 'dart:collection' show LinkedHashMap; + +class LinkedHashMapTest { + static void testMain() { + Map map = new LinkedHashMap(); + map["a"] = 1; + map["b"] = 2; + map["c"] = 3; + map["d"] = 4; + map["e"] = 5; + + List keys = new List(5); + List values = new List(5); + + int index = 0; + + clear() { + index = 0; + for (int i = 0; i < keys.length; i++) { + keys[i] = null; + values[i] = null; + } + } + + verifyKeys(List correctKeys) { + for (int i = 0; i < correctKeys.length; i++) { + Expect.equals(correctKeys[i], keys[i]); + } + } + + verifyValues(List correctValues) { + for (int i = 0; i < correctValues.length; i++) { + Expect.equals(correctValues[i], values[i]); + } + } + + testForEachMap(dynamic key, dynamic value) { + Expect.equals(map[key], value); + keys[index] = key; + values[index] = value; + index++; + } + + testForEachValue(dynamic v) { + values[index++] = v; + } + + testForEachKey(dynamic v) { + keys[index++] = v; + } + + final keysInOrder = const ["a", "b", "c", "d", "e"]; + final valuesInOrder = const [1, 2, 3, 4, 5]; + + clear(); + map.forEach(testForEachMap); + verifyKeys(keysInOrder); + verifyValues(valuesInOrder); + + clear(); + map.keys.forEach(testForEachKey); + verifyKeys(keysInOrder); + + clear(); + map.values.forEach(testForEachValue); + verifyValues(valuesInOrder); + + // Remove and then insert. + map.remove("b"); + map["b"] = 6; + final keysAfterBMove = const ["a", "c", "d", "e", "b"]; + final valuesAfterBMove = const [1, 3, 4, 5, 6]; + + clear(); + map.forEach(testForEachMap); + verifyKeys(keysAfterBMove); + verifyValues(valuesAfterBMove); + + clear(); + map.keys.forEach(testForEachKey); + verifyKeys(keysAfterBMove); + + clear(); + map.values.forEach(testForEachValue); + verifyValues(valuesAfterBMove); + + // Update. + map["a"] = 0; + final valuesAfterAUpdate = const [0, 3, 4, 5, 6]; + + clear(); + map.forEach(testForEachMap); + verifyKeys(keysAfterBMove); + verifyValues(valuesAfterAUpdate); + + clear(); + map.keys.forEach(testForEachKey); + verifyKeys(keysAfterBMove); + + clear(); + map.values.forEach(testForEachValue); + verifyValues(valuesAfterAUpdate); + } +} + +main() { + LinkedHashMapTest.testMain(); +} diff --git a/tests/corelib/list_as_map_test.dart b/tests/corelib/list_as_map_test.dart new file mode 100644 index 000000000000..fcbd12ef495d --- /dev/null +++ b/tests/corelib/list_as_map_test.dart @@ -0,0 +1,95 @@ +// 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 "package:expect/expect.dart"; + +void testListMapCorrespondence(List list, Map map) { + Expect.equals(list.length, map.length); + for (int i = 0; i < list.length; i++) { + Expect.equals(list[i], map[i]); + } + Expect.isNull(map[list.length]); + Expect.isNull(map[-1]); + + Iterable keys = map.keys; + Iterable values = map.values; + Expect.isFalse(keys is List); + Expect.isFalse(values is List); + Expect.equals(list.length, keys.length); + Expect.equals(list.length, values.length); + for (int i = 0; i < list.length; i++) { + Expect.equals(i, keys.elementAt(i)); + Expect.equals(list[i], values.elementAt(i)); + } + + int forEachCount = 0; + map.forEach((key, value) { + Expect.equals(forEachCount, key); + Expect.equals(list[key], value); + forEachCount++; + }); + + for (int i = 0; i < list.length; i++) { + Expect.isTrue(map.containsKey(i)); + Expect.isTrue(map.containsValue(list[i])); + } + Expect.isFalse(map.containsKey(-1)); + Expect.isFalse(map.containsKey(list.length)); + + Expect.equals(list.length, forEachCount); + + Expect.equals(list.isEmpty, map.isEmpty); +} + +void testConstAsMap(List list) { + Map map = list.asMap(); + + testListMapCorrespondence(list, map); + + Expect.throwsUnsupportedError(() => map[0] = 499); + Expect.throwsUnsupportedError(() => map.putIfAbsent(0, () => 499)); + Expect.throwsUnsupportedError(() => map.clear()); +} + +void testFixedAsMap(List list) { + testConstAsMap(list); + + Map map = list.asMap(); + + if (!list.isEmpty) { + list[0] = 499; + // Check again to make sure the map is backed by the list. + testListMapCorrespondence(list, map); + } +} + +void testAsMap(List list) { + testFixedAsMap(list); + + Map map = list.asMap(); + + Iterable keys = map.keys; + Iterable values = map.values; + + list.add(42); + // Check again to make sure the map is backed by the list and that the + // length is not cached. + testListMapCorrespondence(list, map); + // Also check that the keys and values iterable from the map are backed by + // the list. + Expect.equals(list.length, keys.length); + Expect.equals(values.length, values.length); +} + +main() { + testConstAsMap(const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + testAsMap([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + List list = new List(10); + for (int i = 0; i < 10; i++) list[i] = i + 1; + testFixedAsMap(list); + + testConstAsMap(const []); + testAsMap([]); + testFixedAsMap(new List(0)); +} diff --git a/tests/corelib/list_concurrent_modify_test.dart b/tests/corelib/list_concurrent_modify_test.dart new file mode 100644 index 000000000000..011106337d14 --- /dev/null +++ b/tests/corelib/list_concurrent_modify_test.dart @@ -0,0 +1,100 @@ +// 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() { + // Growable lists. Initial length 0. + testConcurrentModification(new List()); + testConcurrentModification(new List().toList()); + testConcurrentModification(new List(0).toList()); + testConcurrentModification(new List.filled(0, null, growable: true)); + testConcurrentModification([]); + testConcurrentModification(new List.from(const [])); + testConcurrentModification(new MyList([])); + testConcurrentModification(new MyList([]).toList()); + + testConcurrentModification(new Uint8List(0).toList()); + testConcurrentModification(new Int8List(0).toList()); + testConcurrentModification(new Uint16List(0).toList()); + testConcurrentModification(new Int16List(0).toList()); + testConcurrentModification(new Uint32List(0).toList()); + testConcurrentModification(new Int32List(0).toList()); + + testConcurrentAddSelf([]); + testConcurrentAddSelf([1, 2, 3]); +} + +void testConcurrentModification(List list) { + // add, removeLast. + list.clear(); + list.addAll([1, 2, 3, 2, 7, 9, 9, 7, 2, 3, 2, 1]); + + // Operations that change the length cause ConcurrentModificationError. + void testModification(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); + } + + testModification(() => list.add(5)); + testModification(() => list.addAll([5, 6])); + testModification(() => list.removeLast()); + for (int i = 0; i < 4; i++) { + testModification(() => list.remove(i)); + testModification(() => list.removeAt(i)); + testModification(() => list.removeWhere((x) => x == i)); + testModification(() => list.retainWhere((x) => x != i)); + testModification(() => list.insert(i, 5)); + testModification(() => list.insertAll(i, [5, 6])); + testModification(() => list.removeRange(i, i + 1)); + testModification(() => list.replaceRange(i, i + 1, [5, 6])); + } +} + +testConcurrentAddSelf(List list) { + Expect.throws(() { + list.addAll(list); + }, (e) => e is ConcurrentModificationError, "testConcurrentAddSelf($list)"); +} + +class MyList extends ListBase { + List _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; + } +} diff --git a/tests/corelib/list_contains_argument_order_test.dart b/tests/corelib/list_contains_argument_order_test.dart new file mode 100644 index 000000000000..bed7e209bf96 --- /dev/null +++ b/tests/corelib/list_contains_argument_order_test.dart @@ -0,0 +1,40 @@ +// 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 "package:expect/expect.dart"; + +class A { + const A(); + bool operator ==(Object other) { + return false; + } +} + +class B { + bool operator ==(Object other) { + Expect.fail("Bad equality order."); + } +} + +main() { + test(iterable) { + Expect.isFalse(iterable.contains(new B())); + } + + var iterables = [ + [new A()], + new List.filled(1, new A()), + new List()..add(new A()), + const [const A()], + new Set()..add(new A()), + (new Map()..[new A()] = 0).keys, + (new Map()..[0] = new A()).values + ]; + + for (var iterable in iterables) { + test(iterable); + test(iterable.map((x) => x)); + test(iterable.take(1)); + } +} diff --git a/tests/corelib/list_copy_range_test.dart b/tests/corelib/list_copy_range_test.dart new file mode 100644 index 000000000000..8740877d20ed --- /dev/null +++ b/tests/corelib/list_copy_range_test.dart @@ -0,0 +1,115 @@ +// 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:typed_data"; +import "package:expect/expect.dart"; + +// Tests of List.copyRange. + +void main() { + var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + List.copyRange(list, 3, [10, 11, 12, 13], 0, 4); + + Expect.listEquals([0, 1, 2, 10, 11, 12, 13, 7, 8, 9], list); + + List.copyRange(list, 6, [20, 21, 22, 23], 1, 3); + + Expect.listEquals([0, 1, 2, 10, 11, 12, 21, 22, 8, 9], list); + + // Empty ranges won't change anything. + List.copyRange(list, 7, [30, 31, 32, 33], 3, 3); + List.copyRange(list, list.length, [30, 31, 32, 33], 3, 3); + + Expect.listEquals([0, 1, 2, 10, 11, 12, 21, 22, 8, 9], list); + + List.copyRange(list, 0, [40, 41, 42, 43], 0, 2); + + Expect.listEquals([40, 41, 2, 10, 11, 12, 21, 22, 8, 9], list); + + // Overlapping self-ranges + + List.copyRange(list, 2, list, 0, 4); + + Expect.listEquals([40, 41, 40, 41, 2, 10, 21, 22, 8, 9], list); + + List.copyRange(list, 4, list, 6, 10); + + Expect.listEquals([40, 41, 40, 41, 21, 22, 8, 9, 8, 9], list); + + // Invalid source ranges. + + Expect.throwsArgumentError(() { + List.copyRange(list, 0, [0, 0, 0], -1, 1); + }); + + Expect.throwsArgumentError(() { + List.copyRange(list, 0, [0, 0, 0], 0, 4); + }); + + Expect.throwsArgumentError(() { + List.copyRange(list, 0, [0, 0, 0], 2, 1); + }); + + Expect.throwsArgumentError(() { + List.copyRange(list, 0, [], 1, 1); + }); + + // Invalid target range. + Expect.throwsArgumentError(() { + List.copyRange(list, list.length - 3, [0, 0, 0, 0], 0, 4); + }); + + // Invalid target range. + Expect.throwsArgumentError(() { + List.copyRange(list, list.length + 1, [0, 0, 0, 0], 0, 0); + }); + + // Argument errors throw before changing anything, so list is unchanged. + Expect.listEquals([40, 41, 40, 41, 21, 22, 8, 9, 8, 9], list); + + // Omitting start/end (or passing null). + List.copyRange(list, 2, [1, 2, 3]); + + Expect.listEquals([40, 41, 1, 2, 3, 22, 8, 9, 8, 9], list); + + List.copyRange(list, 5, [1, 2, 3], 1); + + Expect.listEquals([40, 41, 1, 2, 3, 2, 3, 9, 8, 9], list); + + // Other kinds of lists. + var listu8 = new Uint8List.fromList([1, 2, 3, 4]); + var list16 = new Int16List.fromList([11, 12, -13, -14]); + List.copyRange(listu8, 2, list16, 1, 3); + Expect.listEquals([1, 2, 12, 256 - 13], listu8); + + var clist = const [1, 2, 3, 4]; + var flist = new List.filled(4, -1)..setAll(0, [10, 11, 12, 13]); + List.copyRange(flist, 1, clist, 1, 3); + Expect.listEquals([10, 2, 3, 13], flist); + + // Invoking with a type parameter that is a supertype of the list types + // is valid and useful. + List ilist = [1, 2, 3, 4]; + List nlist = [11, 12, 13, 14]; + + List.copyRange(ilist, 1, nlist, 1, 3); + Expect.listEquals([1, 12, 13, 4], ilist); + List.copyRange(ilist, 1, nlist, 0, 2); + Expect.listEquals([1, 11, 12, 4], ilist); + List.copyRange(ilist, 1, nlist, 2, 4); + Expect.listEquals([1, 13, 14, 4], ilist); + + var d = new D(); + List bdlist = [d]; + List cdlist = [null]; + List.copyRange(cdlist, 0, bdlist, 0, 1); + Expect.identical(d, cdlist[0]); +} + +class B {} + +class C {} + +class D implements B, C {} diff --git a/tests/corelib/list_fill_range_test.dart b/tests/corelib/list_fill_range_test.dart new file mode 100644 index 000000000000..2f8fa03bc5f5 --- /dev/null +++ b/tests/corelib/list_fill_range_test.dart @@ -0,0 +1,72 @@ +// 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 "package:expect/expect.dart"; +import "dart:collection"; + +test(List list, int start, int end, [fillValue]) { + List copy = list.toList(); + list.fillRange(start, end, fillValue); + Expect.equals(copy.length, list.length); + for (int i = 0; i < start; i++) { + Expect.equals(copy[i], list[i]); + } + for (int i = start; i < end; i++) { + Expect.equals(fillValue, list[i]); + } + for (int i = end; i < list.length; i++) { + Expect.equals(copy[i], list[i]); + } +} + +class MyList extends ListBase { + List list; + MyList(this.list); + get length => list.length; + set length(value) { + list.length = value; + } + + operator [](index) => list[index]; + operator []=(index, val) { + list[index] = val; + } + + toString() => list.toString(); +} + +main() { + test([1, 2, 3], 0, 1); + test([1, 2, 3], 0, 1, 99); + test([1, 2, 3], 1, 1); + test([1, 2, 3], 1, 1, 499); + test([1, 2, 3], 3, 3); + test([1, 2, 3], 3, 3, 499); + test([1, 2, 3].toList(growable: false), 0, 1); + test([1, 2, 3].toList(growable: false), 0, 1, 99); + test([1, 2, 3].toList(growable: false), 1, 1); + test([1, 2, 3].toList(growable: false), 1, 1, 499); + test([1, 2, 3].toList(growable: false), 3, 3); + test([1, 2, 3].toList(growable: false), 3, 3, 499); + test(new MyList([1, 2, 3]), 0, 1); + test(new MyList([1, 2, 3]), 0, 1, 99); + test(new MyList([1, 2, 3]), 1, 1); + test(new MyList([1, 2, 3]), 1, 1, 499); + test(new MyList([1, 2, 3]), 3, 3); + test(new MyList([1, 2, 3]), 3, 3, 499); + + Expect.throwsRangeError(() => test([1, 2, 3], -1, 0)); + Expect.throwsRangeError(() => test([1, 2, 3], 2, 1)); + Expect.throwsRangeError(() => test([1, 2, 3], 0, -1)); + Expect.throwsRangeError(() => test([1, 2, 3], 1, 4)); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), -1, 0)); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 2, 1)); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 0, -1)); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 1, 4)); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 2, 3)); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], -1, 0)); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 2, 1)); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 0, -1)); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 1, 4)); +} diff --git a/tests/corelib/list_filled_type_argument_test.dart b/tests/corelib/list_filled_type_argument_test.dart new file mode 100644 index 000000000000..1c3aff49e8db --- /dev/null +++ b/tests/corelib/list_filled_type_argument_test.dart @@ -0,0 +1,15 @@ +// 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 "package:expect/expect.dart"; + +main() { + var a = new List.filled(42, 42); + Expect.isTrue(a is List); + Expect.isFalse(a is List); + + a = new List.filled(42, 42, growable: true); + Expect.isTrue(a is List); + Expect.isFalse(a is List); +} diff --git a/tests/corelib/list_first_test.dart b/tests/corelib/list_first_test.dart new file mode 100644 index 000000000000..70bdc0390090 --- /dev/null +++ b/tests/corelib/list_first_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2012, 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"; + +void test(List list) { + if (list.isEmpty) { + Expect.throwsStateError(() => list.first); + } else { + Expect.equals(list[0], list.first); + } +} + +main() { + test([1, 2, 3]); + test(const ["foo", "bar"]); + test([]); + test(const []); +} diff --git a/tests/corelib/list_fixed_test.dart b/tests/corelib/list_fixed_test.dart new file mode 100644 index 000000000000..06193c596cf4 --- /dev/null +++ b/tests/corelib/list_fixed_test.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2012, 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"; + +main() { + var a; + + a = new List(42); + Expect.equals(42, a.length); + Expect.throwsUnsupportedError(() => a.add(499)); + Expect.equals(42, a.length); + for (int i = 0; i < 42; i++) { + Expect.equals(null, a[i]); + } + Expect.throwsUnsupportedError(() => a.clear()); + Expect.equals(42, a.length); + + a = new List.filled(42, -2); + Expect.equals(42, a.length); + Expect.throwsUnsupportedError(() => a.add(499)); + Expect.equals(42, a.length); + for (int i = 0; i < 42; i++) { + Expect.equals(-2, a[i]); + } + Expect.throwsUnsupportedError(() => a.clear()); + Expect.equals(42, a.length); +} diff --git a/tests/corelib/list_for_each_test.dart b/tests/corelib/list_for_each_test.dart new file mode 100644 index 000000000000..b59a2d730707 --- /dev/null +++ b/tests/corelib/list_for_each_test.dart @@ -0,0 +1,67 @@ +// 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 "package:expect/expect.dart"; +import "dart:collection"; + +class MyList extends ListBase { + List list; + MyList(this.list); + get length => list.length; + set length(value) { + list.length = value; + } + + operator [](index) => list[index]; + operator []=(index, val) { + list[index] = val; + } + + toString() => list.toString(); +} + +void testWithoutModification(List list) { + var seen = []; + list.forEach(seen.add); + + Expect.listEquals(list, seen); +} + +void testWithModification(List list) { + if (list.isEmpty) return; + Expect.throws(() => list.forEach((_) => list.add(0)), + (e) => e is ConcurrentModificationError); +} + +main() { + List fixedLengthList = new List(10); + for (int i = 0; i < 10; i++) fixedLengthList[i] = i + 1; + + List growableList = new List(); + growableList.length = 10; + for (int i = 0; i < 10; i++) growableList[i] = i + 1; + + var growableLists = [ + [], + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + new MyList([1, 2, 3, 4, 5]), + growableList, + ]; + var fixedLengthLists = [ + const [], + fixedLengthList, + const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + new MyList(const [1, 2]), + ]; + + for (var list in growableLists) { + print(list); + testWithoutModification(list); + testWithModification(list); + } + + for (var list in fixedLengthLists) { + testWithoutModification(list); + } +} diff --git a/tests/corelib/list_get_range_test.dart b/tests/corelib/list_get_range_test.dart new file mode 100644 index 000000000000..5d996e3f5777 --- /dev/null +++ b/tests/corelib/list_get_range_test.dart @@ -0,0 +1,69 @@ +// 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 "package:expect/expect.dart"; + +testGetRange(list, start, end, bool isModifiable) { + Expect.throwsRangeError(() => list.getRange(-1, 0)); + Expect.throwsRangeError(() => list.getRange(0, -1)); + Expect.throwsRangeError(() => list.getRange(1, 0)); + Expect.throwsRangeError(() => list.getRange(0, list.length + 1)); + Expect.throwsRangeError( + () => list.getRange(list.length + 1, list.length + 1)); + Iterable iterable = list.getRange(start, end); + Expect.isFalse(iterable is List); + if (start == end) { + Expect.isTrue(iterable.isEmpty); + return; + } + + var iterator = iterable.iterator; + for (int i = start; i < end; i++) { + Expect.isTrue(iterator.moveNext()); + Expect.equals(iterator.current, list[i]); + } + Expect.isFalse(iterator.moveNext()); + + if (isModifiable) { + for (int i = 0; i < list.length; i++) { + list[i]++; + } + + iterator = iterable.iterator; + for (int i = start; i < end; i++) { + Expect.isTrue(iterator.moveNext()); + Expect.equals(iterator.current, list[i]); + } + } +} + +main() { + testGetRange([1, 2], 0, 1, true); + testGetRange([], 0, 0, true); + testGetRange([1, 2, 3], 0, 0, true); + testGetRange([1, 2, 3], 1, 3, true); + testGetRange(const [1, 2], 0, 1, false); + testGetRange(const [], 0, 0, false); + testGetRange(const [1, 2, 3], 0, 0, false); + testGetRange(const [1, 2, 3], 1, 3, false); + testGetRange("abcd".codeUnits, 0, 1, false); + testGetRange("abcd".codeUnits, 0, 0, false); + testGetRange("abcd".codeUnits, 1, 3, false); + + Expect.throwsRangeError(() => [1].getRange(-1, 1)); + Expect.throwsRangeError(() => [3].getRange(0, -1)); + Expect.throwsRangeError(() => [4].getRange(1, 0)); + + var list = [1, 2, 3, 4]; + var iterable = list.getRange(1, 3); + Expect.equals(2, iterable.first); + Expect.equals(3, iterable.last); + list.length = 1; + Expect.isTrue(iterable.isEmpty); + list.add(99); + Expect.equals(99, iterable.single); + list.add(499); + Expect.equals(499, iterable.last); + Expect.equals(2, iterable.length); +} diff --git a/tests/corelib/list_growable_test.dart b/tests/corelib/list_growable_test.dart new file mode 100644 index 000000000000..df59f035efac --- /dev/null +++ b/tests/corelib/list_growable_test.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2012, 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"; + +main() { + var a; + a = new List(); + a.add(499); + Expect.equals(1, a.length); + Expect.equals(499, a[0]); + a.clear(); + Expect.equals(0, a.length); + Expect.throwsRangeError(() => a[0]); + + a = new List(42).toList(); + Expect.equals(42, a.length); + a.add(499); + Expect.equals(43, a.length); + Expect.equals(499, a[42]); + Expect.equals(null, a[23]); + a.clear(); + Expect.equals(0, a.length); + Expect.throwsRangeError(() => a[0]); + + a = new List(42).toList(); + Expect.equals(42, a.length); + a.add(499); + Expect.equals(43, a.length); + Expect.equals(499, a[42]); + for (int i = 0; i < 42; i++) { + Expect.equals(null, a[i]); + } + a.clear(); + Expect.equals(0, a.length); + Expect.throwsRangeError(() => a[0]); +} diff --git a/tests/corelib/list_index_of_test.dart b/tests/corelib/list_index_of_test.dart new file mode 100644 index 000000000000..0020b52e6475 --- /dev/null +++ b/tests/corelib/list_index_of_test.dart @@ -0,0 +1,35 @@ +// 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 "package:expect/expect.dart"; + +main() { + test(new List(5)); + var l = new List(); + l.length = 5; + test(l); +} + +void test(List list) { + list[0] = 1; + list[1] = 2; + list[2] = 3; + list[3] = 4; + list[4] = 1; + + Expect.equals(3, list.indexOf(4, 0)); + Expect.equals(0, list.indexOf(1, 0)); + Expect.equals(4, list.lastIndexOf(1, list.length - 1)); + + Expect.equals(4, list.indexOf(1, 1)); + Expect.equals(-1, list.lastIndexOf(4, 2)); + + Expect.equals(3, list.indexOf(4, 2)); + Expect.equals(3, list.indexOf(4, -5)); + Expect.equals(-1, list.indexOf(4, 50)); + + Expect.equals(-1, list.lastIndexOf(4, 2)); + Expect.equals(-1, list.lastIndexOf(4, -5)); + Expect.equals(3, list.lastIndexOf(4, 50)); +} diff --git a/tests/corelib/list_insert_all_test.dart b/tests/corelib/list_insert_all_test.dart new file mode 100644 index 000000000000..d089dc8ecb8d --- /dev/null +++ b/tests/corelib/list_insert_all_test.dart @@ -0,0 +1,84 @@ +// 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 "package:expect/expect.dart"; +import "dart:collection"; + +test(List list, int index, Iterable iterable) { + List copy = list.toList(); + list.insertAll(index, iterable); + List iterableList = iterable.toList(); + Expect.equals(copy.length + iterableList.length, list.length); + for (int i = 0; i < index; i++) { + Expect.equals(copy[i], list[i]); + } + for (int i = 0; i < iterableList.length; i++) { + Expect.equals(iterableList[i], list[i + index]); + } + for (int i = index + iterableList.length; i < copy.length; i++) { + Expect.equals(copy[i], list[i + iterableList.length]); + } +} + +class MyList extends ListBase { + List list; + MyList(this.list); + get length => list.length; + set length(value) { + list.length = value; + } + + operator [](index) => list[index]; + operator []=(index, val) { + list[index] = val; + } + + toString() => list.toString(); +} + +main() { + test([1, 2, 3], 0, [4, 5]); + test([1, 2, 3], 1, [4, 5]); + test([1, 2, 3], 2, [4, 5]); + test([1, 2, 3], 3, [4, 5]); + test([1, 2, 3], 2, [4]); + test([1, 2, 3], 3, []); + test([1, 2, 3], 0, [4, 5].map((x) => x)); + test([1, 2, 3], 1, [4, 5].map((x) => x)); + test([1, 2, 3], 2, [4, 5].map((x) => x)); + test([1, 2, 3], 3, [4, 5].map((x) => x)); + test([1, 2, 3], 2, [4].map((x) => x)); + test([1, 2, 3], 3, [].map((x) => x)); + test([1, 2, 3], 0, const [4, 5]); + test([1, 2, 3], 1, const [4, 5]); + test([1, 2, 3], 2, const [4, 5]); + test([1, 2, 3], 3, const [4, 5]); + test([1, 2, 3], 2, const [4]); + test([1, 2, 3], 3, const []); + test([1, 2, 3], 0, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 1, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 2, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 3, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 2, new Iterable.generate(1, (x) => x + 4)); + test([1, 2, 3], 3, new Iterable.generate(0, (x) => x + 4)); + test(new MyList([1, 2, 3]), 0, [4, 5]); + test(new MyList([1, 2, 3]), 1, [4, 5]); + test(new MyList([1, 2, 3]), 2, [4]); + test(new MyList([1, 2, 3]), 3, []); + test(new MyList([1, 2, 3]), 2, [4, 5]); + test(new MyList([1, 2, 3]), 3, [4, 5]); + test(new MyList([1, 2, 3]), 0, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 1, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 2, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 3, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 2, [4].map((x) => x)); + test(new MyList([1, 2, 3]), 3, [].map((x) => x)); + + Expect.throwsRangeError(() => test([1, 2, 3], -1, [4, 5])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), -1, [4, 5])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), -1, [4, 5])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), 0, [4, 5])); +} diff --git a/tests/corelib/list_insert_test.dart b/tests/corelib/list_insert_test.dart new file mode 100644 index 000000000000..cd29c4e65101 --- /dev/null +++ b/tests/corelib/list_insert_test.dart @@ -0,0 +1,62 @@ +// 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 'package:expect/expect.dart'; +import 'dart:collection'; + +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; + + String toString() => "[" + join(", ") + "]"; +} + +// l1 must be a modifiable list with 5 elements from 0 to 4. +void testModifiableList(l1) { + // Index must be integer and in range. + Expect.throwsRangeError(() => l1.insert(-1, 5), "negative"); + Expect.throwsRangeError(() => l1.insert(6, 5), "too large"); + Expect.throws(() => l1.insert(null, 5)); + Expect.throws(() => l1.insert("1", 5)); + Expect.throws(() => l1.insert(1.5, 5)); + + l1.insert(5, 5); + Expect.equals(6, l1.length); + Expect.equals(5, l1[5]); + Expect.equals("[0, 1, 2, 3, 4, 5]", l1.toString()); + + l1.insert(0, -1); + Expect.equals(7, l1.length); + Expect.equals(-1, l1[0]); + Expect.equals("[-1, 0, 1, 2, 3, 4, 5]", l1.toString()); +} + +void main() { + // Normal modifiable list. + testModifiableList([0, 1, 2, 3, 4]); + testModifiableList(new MyList([0, 1, 2, 3, 4])); + + // Fixed size list. + var l2 = new List(5); + for (var i = 0; i < 5; i++) l2[i] = i; + Expect.throwsUnsupportedError(() => l2.insert(2, 5), "fixed-length"); + + // Unmodifiable list. + var l3 = const [0, 1, 2, 3, 4]; + Expect.throwsUnsupportedError(() => l3.insert(2, 5), "unmodifiable"); + + // Empty list is not special. + var l4 = []; + l4.insert(0, 499); + Expect.equals(1, l4.length); + Expect.equals(499, l4[0]); +} diff --git a/tests/corelib/list_iterators_test.dart b/tests/corelib/list_iterators_test.dart new file mode 100644 index 000000000000..092082e4e160 --- /dev/null +++ b/tests/corelib/list_iterators_test.dart @@ -0,0 +1,50 @@ +// 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 "package:expect/expect.dart"; + +class ListIteratorsTest { + static void checkListIterator(List a) { + Iterator it = a.iterator; + Expect.isNull(it.current); + for (int i = 0; i < a.length; i++) { + Expect.isTrue(it.moveNext()); + var elem = it.current; + Expect.equals(a[i], elem); + } + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + } + + static testMain() { + checkListIterator([]); + checkListIterator([1, 2]); + checkListIterator(new List(0)); + checkListIterator(new List(10)); + checkListIterator(new List()); + List g = new List(); + g.addAll([1, 2, 3]); + checkListIterator(g); + + // This is mostly undefined behavior. + Iterator it = g.iterator; + Expect.isTrue(it.moveNext()); + Expect.equals(1, it.current); + Expect.isTrue(it.moveNext()); + g[1] = 49; + // The iterator keeps the last value. + Expect.equals(2, it.current); + Expect.isTrue(it.moveNext()); + g.removeLast(); + // The iterator keeps the last value. + Expect.equals(3, it.current); + Expect.throws(it.moveNext, (e) => e is ConcurrentModificationError); + // No progress when throwing. + Expect.equals(3, it.current); + } +} + +main() { + ListIteratorsTest.testMain(); +} diff --git a/tests/corelib/list_last_test.dart b/tests/corelib/list_last_test.dart new file mode 100644 index 000000000000..3f93ac6cc3a2 --- /dev/null +++ b/tests/corelib/list_last_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2012, 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"; + +void test(List list) { + if (list.isEmpty) { + Expect.throwsStateError(() => list.last); + } else { + Expect.equals(list[list.length - 1], list.last); + } +} + +main() { + test([1, 2, 3]); + test(const ["foo", "bar"]); + test([]); + test(const []); +} diff --git a/tests/corelib/list_literal_is_growable_test.dart b/tests/corelib/list_literal_is_growable_test.dart new file mode 100644 index 000000000000..061a72d1c0cf --- /dev/null +++ b/tests/corelib/list_literal_is_growable_test.dart @@ -0,0 +1,12 @@ +// 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 "package:expect/expect.dart"; + +main() { + var l = []; + l.add(1); + Expect.equals(1, l.length); + Expect.equals(1, l[0]); +} diff --git a/tests/corelib/list_literal_test.dart b/tests/corelib/list_literal_test.dart new file mode 100644 index 000000000000..abc38c1bff98 --- /dev/null +++ b/tests/corelib/list_literal_test.dart @@ -0,0 +1,24 @@ +// 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 "package:expect/expect.dart"; + +// Test that a list literal is expandable and modifiable. + +class ListLiteralTest { + static void testMain() { + var list = [1, 2, 3]; + Expect.equals(3, list.length); + list.add(4); + Expect.equals(4, list.length); + list.addAll([5, 6]); + Expect.equals(6, list.length); + list[0] = 0; + Expect.equals(0, list[0]); + } +} + +main() { + ListLiteralTest.testMain(); +} diff --git a/tests/corelib/list_map_test.dart b/tests/corelib/list_map_test.dart new file mode 100644 index 000000000000..19ce07e77c1c --- /dev/null +++ b/tests/corelib/list_map_test.dart @@ -0,0 +1,164 @@ +// Copyright (c) 2012, 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"; + +main() { + testOperations(); +} + +class ThrowMarker { + const ThrowMarker(); + String toString() => "<>"; +} + +void testOperations() { + // Comparison lists. + List l = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + List r = const [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + // Function that reverses l and r lists when used to map. + int rev(dynamic x) => 11 - (x as int); + // A base list that starts out like l, but isn't const. + List base = l.map((x) => x).toList(); + + Iterable reversed = l.map(rev); + + Expect.listEquals(r, l.map(rev).toList()); + Expect.listEquals(l, l.map(rev).map(rev).toList()); + for (int i = 0; i < r.length; i++) { + Expect.equals(r[i], reversed.elementAt(i)); + } + Expect.equals(4, base.indexOf(5)); + Expect.equals(5, reversed.toList().indexOf(5)); + + // Reversed followed by combinations of skip and take. + List subr = [8, 7, 6, 5, 4, 3]; + Expect.listEquals(subr, reversed.skip(2).take(6).toList()); + Expect.listEquals(subr, reversed.take(8).skip(2).toList()); + Expect.listEquals(subr, + reversed.toList().reversed.skip(2).take(6).toList().reversed.toList()); + Expect.listEquals(subr, + reversed.toList().reversed.take(8).skip(2).toList().reversed.toList()); + Expect.listEquals(subr, + reversed.take(8).toList().reversed.take(6).toList().reversed.toList()); + Expect.listEquals(subr, + reversed.toList().reversed.take(8).toList().reversed.take(6).toList()); + Expect.listEquals(subr, + reversed.toList().reversed.skip(2).toList().reversed.skip(2).toList()); + Expect.listEquals(subr, + reversed.skip(2).toList().reversed.skip(2).toList().reversed.toList()); + + void testList(List list) { + var throws = const ThrowMarker(); + var mappedList = new List.filled(list.length, -1); + for (int i = 0; i < list.length; i++) { + mappedList[i] = rev(list[i]); + } + Iterable reversed = list.map(rev); + + void testEquals(v1, v2, path) { + if (v1 is Iterable) { + Iterator i1 = v1.iterator; + Iterator i2 = v2.iterator; + int index = 0; + while (i1.moveNext()) { + Expect.isTrue(i2.moveNext(), + "Too few actual values. Expected[$index] == ${i1.current}"); + testEquals(i1.current, i2.current, "$path[$index]"); + index++; + } + if (i2.moveNext()) { + Expect + .fail("Too many actual values. Actual[$index] == ${i2.current}"); + } + } else { + Expect.equals(v1, v2, path); + } + } + + void testOp(operation(Iterable mappedList), name) { + var expect; + try { + expect = operation(mappedList); + } catch (e) { + expect = throws; + } + var actual; + try { + actual = operation(reversed); + } catch (e) { + actual = throws; + } + testEquals(expect, actual, "$name: $list"); + } + + testOp((i) => i.first, "first"); + testOp((i) => i.last, "last"); + testOp((i) => i.single, "single"); + testOp((i) => i.firstWhere((n) => false), "firstWhere i.firstWhere((n) => n < 10), "firstWhere<10"); + testOp((i) => i.firstWhere((n) => n < 5), "firstWhere<5"); + testOp((i) => i.firstWhere((n) => true), "firstWhere i.lastWhere((n) => false), "lastWhere i.lastWhere((n) => n < 5), "lastWhere<5"); + testOp((i) => i.lastWhere((n) => n < 10), "lastWhere<10"); + testOp((i) => i.lastWhere((n) => true), "lastWhere i.singleWhere((n) => false), "singleWhere i.singleWhere((n) => n < 5), "singelWhere<5"); + testOp((i) => i.singleWhere((n) => n < 10), "singelWhere<10"); + testOp((i) => i.singleWhere((n) => true), "singleWhere i.contains(5), "contains(5)"); + testOp((i) => i.contains(10), "contains(10)"); + testOp((i) => i.any((n) => n < 5), "any<5"); + testOp((i) => i.any((n) => n < 10), "any<10"); + testOp((i) => i.every((n) => n < 5), "every<5"); + testOp((i) => i.every((n) => n < 10), "every<10"); + testOp((i) => i.reduce((a, b) => a + b), "reduce-sum"); + testOp((i) => i.fold/**/(0, (a, b) => a + b), "fold-sum"); + testOp((i) => i.join("-"), "join-"); + testOp((i) => i.join(""), "join"); + testOp((i) => i.join(), "join-null"); + testOp((i) => i.map((n) => n * 2), "map*2"); + testOp((i) => i.where((n) => n < 5), "where<5"); + testOp((i) => i.where((n) => n < 10), "where<10"); + testOp((i) => i.expand((n) => []), "expand[]"); + testOp((i) => i.expand((n) => [n]), "expand[n]"); + testOp((i) => i.expand((n) => [n, n]), "expand[n, n]"); + testOp((i) => i.take(0), "take(0)"); + testOp((i) => i.take(5), "take(5)"); + testOp((i) => i.take(10), "take(10)"); + testOp((i) => i.take(15), "take(15)"); + testOp((i) => i.skip(0), "skip(0)"); + testOp((i) => i.skip(5), "skip(5)"); + testOp((i) => i.skip(10), "skip(10)"); + testOp((i) => i.skip(15), "skip(15)"); + testOp((i) => i.takeWhile((n) => false), "takeWhile(t)"); + testOp((i) => i.takeWhile((n) => n < 5), "takeWhile(n<5)"); + testOp((i) => i.takeWhile((n) => n > 5), "takeWhile(n>5)"); + testOp((i) => i.takeWhile((n) => true), "takeWhile(f)"); + testOp((i) => i.skipWhile((n) => false), "skipWhile(t)"); + testOp((i) => i.skipWhile((n) => n < 5), "skipWhile(n<5)"); + testOp((i) => i.skipWhile((n) => n > 5), "skipWhile(n>5)"); + testOp((i) => i.skipWhile((n) => true), "skipWhile(f)"); + } + + // Combinations of lists with 0, 1 and more elements. + testList([]); + testList([0]); + testList([10]); + testList([0, 1]); + testList([0, 10]); + testList([10, 11]); + testList([0, 5, 10]); + testList([10, 5, 0]); + testList([0, 1, 2, 3]); + testList([3, 4, 5, 6]); + testList([10, 11, 12, 13]); + testList(l); + testList(r); + testList(base); + + // Reverse const list. + Expect.listEquals(r, l.map(rev).toList()); +} diff --git a/tests/corelib/list_remove_range_test.dart b/tests/corelib/list_remove_range_test.dart new file mode 100644 index 000000000000..6cfd9e5ada64 --- /dev/null +++ b/tests/corelib/list_remove_range_test.dart @@ -0,0 +1,59 @@ +// 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 "package:expect/expect.dart"; + +main() { + var list = []; + list.removeRange(0, 0); + Expect.equals(0, list.length); + Expect.throwsRangeError(() => list.removeRange(0, 1)); + + list.add(1); + list.removeRange(0, 0); + Expect.equals(1, list.length); + Expect.equals(1, list[0]); + + Expect.throwsRangeError(() => list.removeRange(0, 2)); + Expect.equals(1, list.length); + Expect.equals(1, list[0]); + + list.removeRange(0, 1); + Expect.equals(0, list.length); + + list.addAll([3, 4, 5, 6]); + Expect.equals(4, list.length); + list.removeRange(0, 4); + Expect.listEquals([], list); + + list.addAll([3, 4, 5, 6]); + list.removeRange(2, 4); + Expect.listEquals([3, 4], list); + list.addAll([5, 6]); + + Expect.throwsRangeError(() => list.removeRange(4, 5)); + Expect.listEquals([3, 4, 5, 6], list); + + list.removeRange(1, 3); + Expect.listEquals([3, 6], list); + + testNegativeIndices(); +} + +void testNegativeIndices() { + var list = [1, 2]; + Expect.throwsRangeError(() => list.removeRange(-1, 1)); + Expect.listEquals([1, 2], list); + + Expect.throwsRangeError(() => list.removeRange(0, -1)); + Expect.listEquals([1, 2], list); + + Expect.throwsRangeError(() => list.removeRange(-1, -1)); + Expect.listEquals([1, 2], list); + + Expect.throwsRangeError(() => list.removeRange(-1, 0)); + + Expect.throwsRangeError(() => list.removeRange(4, 4)); + Expect.listEquals([1, 2], list); +} diff --git a/tests/corelib/list_removeat_test.dart b/tests/corelib/list_removeat_test.dart new file mode 100644 index 000000000000..6fedda8c0dc1 --- /dev/null +++ b/tests/corelib/list_removeat_test.dart @@ -0,0 +1,61 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; + +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; + + String toString() => "[" + join(", ") + "]"; +} + +// l1 must be a modifiable list with 5 elements from 0 to 4. +void testModifiableList(l1) { + // Index must be integer and in range. + Expect.throwsRangeError(() => l1.removeAt(-1), "negative"); + Expect.throwsRangeError(() => l1.removeAt(5), "too large"); + Expect.throwsArgumentError(() => l1.removeAt(null), "too large"); + + Expect.equals(2, l1.removeAt(2), "l1-remove2"); + Expect.equals(1, l1[1], "l1-1[1]"); + + Expect.equals(3, l1[2], "l1-1[2]"); + Expect.equals(4, l1[3], "l1-1[3]"); + Expect.equals(4, l1.length, "length-1"); + + Expect.equals(0, l1.removeAt(0), "l1-remove0"); + Expect.equals(1, l1[0], "l1-2[0]"); + Expect.equals(3, l1[1], "l1-2[1]"); + Expect.equals(4, l1[2], "l1-2[2]"); + Expect.equals(3, l1.length, "length-2"); +} + +void main() { + // Normal modifiable list. + testModifiableList([0, 1, 2, 3, 4]); + testModifiableList(new MyList([0, 1, 2, 3, 4])); + + // Fixed size list. + var l2 = new List(5); + for (var i = 0; i < 5; i++) l2[i] = i; + Expect.throwsUnsupportedError(() => l2.removeAt(2), "fixed-length"); + + // Unmodifiable list. + var l3 = const [0, 1, 2, 3, 4]; + Expect.throwsUnsupportedError(() => l3.removeAt(2), "unmodifiable"); + + // Empty list is not special. + var l4 = []; + Expect.throwsRangeError(() => l4.removeAt(0), "empty"); +} diff --git a/tests/corelib/list_replace_range_test.dart b/tests/corelib/list_replace_range_test.dart new file mode 100644 index 000000000000..964ed444b91f --- /dev/null +++ b/tests/corelib/list_replace_range_test.dart @@ -0,0 +1,120 @@ +// 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 "package:expect/expect.dart"; +import "dart:collection"; + +test(List list, int start, int end, Iterable iterable) { + List copy = list.toList(); + list.replaceRange(start, end, iterable); + List iterableList = iterable.toList(); + Expect.equals(copy.length + iterableList.length - (end - start), list.length); + for (int i = 0; i < start; i++) { + Expect.equals(copy[i], list[i]); + } + for (int i = 0; i < iterableList.length; i++) { + Expect.equals(iterableList[i], list[i + start]); + } + int removedLength = end - start; + for (int i = end; i < copy.length; i++) { + Expect.equals(copy[i], list[i + iterableList.length - removedLength]); + } +} + +class MyList extends ListBase { + List list; + MyList(this.list); + get length => list.length; + set length(value) { + list.length = value; + } + + operator [](index) => list[index]; + operator []=(index, val) { + list[index] = val; + } + + toString() => list.toString(); +} + +main() { + test([1, 2, 3], 0, 1, [4, 5]); + test([1, 2, 3], 1, 1, [4, 5]); + test([1, 2, 3], 2, 3, [4, 5]); + test([1, 2, 3], 3, 3, [4, 5]); + test([1, 2, 3], 0, 3, [4, 5]); + test([1, 2, 3], 2, 3, [4]); + test([1, 2, 3], 0, 3, []); + test([1, 2, 3], 0, 1, [4, 5].map((x) => x)); + test([1, 2, 3], 1, 1, [4, 5].map((x) => x)); + test([1, 2, 3], 2, 3, [4, 5].map((x) => x)); + test([1, 2, 3], 3, 3, [4, 5].map((x) => x)); + test([1, 2, 3], 0, 3, [4, 5].map((x) => x)); + test([1, 2, 3], 2, 3, [4].map((x) => x)); + test([1, 2, 3], 0, 3, [].map((x) => x)); + test([1, 2, 3], 0, 1, const [4, 5]); + test([1, 2, 3], 1, 1, const [4, 5]); + test([1, 2, 3], 2, 3, const [4, 5]); + test([1, 2, 3], 3, 3, const [4, 5]); + test([1, 2, 3], 0, 3, const [4, 5]); + test([1, 2, 3], 2, 3, const [4]); + test([1, 2, 3], 0, 3, const []); + test([1, 2, 3], 0, 1, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 1, 1, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 2, 3, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 3, 3, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 0, 3, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 2, 3, new Iterable.generate(2, (x) => x + 4)); + test(new MyList([1, 2, 3]), 0, 1, [4, 5]); + test(new MyList([1, 2, 3]), 1, 1, [4, 5]); + test(new MyList([1, 2, 3]), 2, 3, [4, 5]); + test(new MyList([1, 2, 3]), 3, 3, [4, 5]); + test(new MyList([1, 2, 3]), 0, 3, [4, 5]); + test(new MyList([1, 2, 3]), 2, 3, [4]); + test(new MyList([1, 2, 3]), 0, 3, []); + test(new MyList([1, 2, 3]), 0, 1, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 1, 1, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 2, 3, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 3, 3, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 0, 3, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 2, 3, [4].map((x) => x)); + test(new MyList([1, 2, 3]), 0, 3, [].map((x) => x)); + test(new MyList([1, 2, 3]), 0, 1, const [4, 5]); + test(new MyList([1, 2, 3]), 1, 1, const [4, 5]); + test(new MyList([1, 2, 3]), 2, 3, const [4, 5]); + test(new MyList([1, 2, 3]), 3, 3, const [4, 5]); + test(new MyList([1, 2, 3]), 0, 3, const [4, 5]); + test(new MyList([1, 2, 3]), 2, 3, const [4]); + test(new MyList([1, 2, 3]), 0, 3, const []); + test(new MyList([1, 2, 3]), 0, 1, new Iterable.generate(2, (x) => x + 4)); + test(new MyList([1, 2, 3]), 1, 1, new Iterable.generate(2, (x) => x + 4)); + test(new MyList([1, 2, 3]), 2, 3, new Iterable.generate(2, (x) => x + 4)); + test(new MyList([1, 2, 3]), 3, 3, new Iterable.generate(2, (x) => x + 4)); + test(new MyList([1, 2, 3]), 0, 3, new Iterable.generate(2, (x) => x + 4)); + test(new MyList([1, 2, 3]), 2, 3, new Iterable.generate(2, (x) => x + 4)); + + Expect.throwsRangeError(() => test([1, 2, 3], -1, 0, [])); + Expect.throwsRangeError(() => test([1, 2, 3], 2, 1, [])); + Expect.throwsRangeError(() => test([1, 2, 3], 0, -1, [])); + Expect.throwsRangeError(() => test([1, 2, 3], 1, 4, [])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), -1, 0, [])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 2, 1, [])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 0, -1, [])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 1, 4, [])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), 2, 3, [])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), -1, 0, [])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), 2, 1, [])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), 0, -1, [])); + Expect.throwsUnsupportedError( + () => test([1, 2, 3].toList(growable: false), 1, 4, [])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 2, 3, [])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], -1, 0, [])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 2, 1, [])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 0, -1, [])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 1, 4, [])); +} diff --git a/tests/corelib/list_reversed_test.dart b/tests/corelib/list_reversed_test.dart new file mode 100644 index 000000000000..e331f8cb0293 --- /dev/null +++ b/tests/corelib/list_reversed_test.dart @@ -0,0 +1,136 @@ +// Copyright (c) 2012, 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"; + +main() { + testOperations(); +} + +class ThrowMarker { + const ThrowMarker(); + String toString() => "<>"; +} + +void testOperations() { + // Comparison lists. + var l = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + var r = const [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + // A base list that starts out like l. + var base = l.toList(); + // A lazy reverse of base. + var reversed = base.reversed; + + Expect.listEquals(r, reversed.toList()); + Expect.listEquals(l, reversed.toList().reversed.toList()); + for (int i = 0; i < r.length; i++) { + Expect.equals(r[i], reversed.elementAt(i)); + } + Expect.equals(4, base.indexOf(5)); + Expect.equals(5, reversed.toList().indexOf(5)); + + // Reversed followed by combinations of skip and take. + List subr = [8, 7, 6, 5, 4, 3]; + Expect.listEquals(subr, reversed.skip(2).take(6).toList()); + Expect.listEquals(subr, reversed.take(8).skip(2).toList()); + Expect.listEquals(subr, + reversed.toList().reversed.skip(2).take(6).toList().reversed.toList()); + Expect.listEquals(subr, + reversed.toList().reversed.take(8).skip(2).toList().reversed.toList()); + Expect.listEquals(subr, + reversed.take(8).toList().reversed.take(6).toList().reversed.toList()); + Expect.listEquals(subr, + reversed.toList().reversed.take(8).toList().reversed.take(6).toList()); + Expect.listEquals(subr, + reversed.toList().reversed.skip(2).toList().reversed.skip(2).toList()); + Expect.listEquals(subr, + reversed.skip(2).toList().reversed.skip(2).toList().reversed.toList()); + + void testList(List list) { + var throws = const ThrowMarker(); + void testEquals(v1, v2, path) { + if (v1 is Iterable) { + Iterator i1 = v1.iterator; + Iterator i2 = v2.iterator; + int index = 0; + while (i1.moveNext()) { + Expect.isTrue(i2.moveNext(), + "Too few actual values. Expected[$index] == ${i1.current}"); + testEquals(i1.current, i2.current, "$path[$index]"); + index++; + } + if (i2.moveNext()) { + Expect.fail( + "Too many actual values. Actual[$index] == ${i2.current}"); + } + } else { + Expect.equals(v1, v2, path); + } + } + + void testOp(operation(Iterable reversedList), name) { + var reversedList = [ + for (var i = 0; i < list.length; i++) list[list.length - 1 - i] + ]; + + var reversed = list.reversed; + var expect; + try { + expect = operation(reversedList); + } catch (e) { + expect = throws; + } + var actual; + try { + actual = operation(reversed); + } catch (e) { + actual = throws; + } + testEquals(expect, actual, "$name: $list"); + } + + testOp((i) => i.first, "first"); + testOp((i) => i.last, "last"); + testOp((i) => i.single, "single"); + testOp((i) => i.firstWhere((n) => n < 5), "firstWhere<5"); + testOp((i) => i.firstWhere((n) => n < 10), "firstWhere<10"); + testOp((i) => i.lastWhere((n) => n < 5), "lastWhere<5"); + testOp((i) => i.lastWhere((n) => n < 10), "lastWhere<10"); + testOp((i) => i.singleWhere((n) => n < 5), "singelWhere<5"); + testOp((i) => i.singleWhere((n) => n < 10), "singelWhere<10"); + testOp((i) => i.contains(5), "contains(5)"); + testOp((i) => i.contains(10), "contains(10)"); + testOp((i) => i.any((n) => n < 5), "any<5"); + testOp((i) => i.any((n) => n < 10), "any<10"); + testOp((i) => i.every((n) => n < 5), "every<5"); + testOp((i) => i.every((n) => n < 10), "every<10"); + testOp((i) => i.reduce((a, b) => a + b), "reduce-sum"); + testOp((i) => i.fold/**/(0, (a, b) => a + b), "fold-sum"); + testOp((i) => i.join("-"), "join-"); + testOp((i) => i.join(""), "join"); + testOp((i) => i.join(), "join-null"); + testOp((i) => i.map((n) => n * 2), "map*2"); + testOp((i) => i.where((n) => n < 5), "where<5"); + testOp((i) => i.where((n) => n < 10), "where<10"); + testOp((i) => i.expand((n) => []), "expand[]"); + testOp((i) => i.expand((n) => [n]), "expand[n]"); + testOp((i) => i.expand((n) => [n, n]), "expand[n, n]"); + } + + // Combinations of lists with 0, 1 and more elements. + testList([]); + testList([0]); + testList([10]); + testList([0, 1]); + testList([0, 10]); + testList([10, 11]); + testList([0, 5, 10]); + testList([10, 5, 0]); + testList([0, 1, 2, 3]); + testList([3, 4, 5, 6]); + testList([10, 11, 12, 13]); + + // Reverse const list. + Expect.listEquals(r, l.reversed.toList()); +} diff --git a/tests/corelib/list_set_all_test.dart b/tests/corelib/list_set_all_test.dart new file mode 100644 index 000000000000..85f208100bce --- /dev/null +++ b/tests/corelib/list_set_all_test.dart @@ -0,0 +1,97 @@ +// 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 "package:expect/expect.dart"; +import "dart:collection"; + +test(List list, int index, Iterable iterable) { + List copy = list.toList(); + list.setAll(index, iterable); + Expect.equals(copy.length, list.length); + for (int i = 0; i < index; i++) { + Expect.equals(copy[i], list[i]); + } + List iterableList = iterable.toList(); + for (int i = 0; i < iterableList.length; i++) { + Expect.equals(iterableList[i], list[i + index]); + } + for (int i = index + iterableList.length; i < copy.length; i++) { + Expect.equals(copy[i], list[i]); + } +} + +class MyList extends ListBase { + List list; + MyList(this.list); + get length => list.length; + set length(value) { + list.length = value; + } + + operator [](index) => list[index]; + operator []=(index, val) { + list[index] = val; + } + + toString() => list.toString(); +} + +main() { + test([1, 2, 3], 0, [4, 5]); + test([1, 2, 3], 1, [4, 5]); + test([1, 2, 3], 2, [4]); + test([1, 2, 3], 3, []); + test([1, 2, 3], 0, [4, 5].map((x) => x)); + test([1, 2, 3], 1, [4, 5].map((x) => x)); + test([1, 2, 3], 2, [4].map((x) => x)); + test([1, 2, 3], 3, [].map((x) => x)); + test([1, 2, 3], 0, const [4, 5]); + test([1, 2, 3], 1, const [4, 5]); + test([1, 2, 3], 2, const [4]); + test([1, 2, 3], 3, const []); + test([1, 2, 3], 0, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 1, new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3], 2, new Iterable.generate(1, (x) => x + 4)); + test([1, 2, 3], 3, new Iterable.generate(0, (x) => x + 4)); + test([1, 2, 3].toList(growable: false), 0, [4, 5]); + test([1, 2, 3].toList(growable: false), 1, [4, 5]); + test([1, 2, 3].toList(growable: false), 2, [4]); + test([1, 2, 3].toList(growable: false), 3, []); + test([1, 2, 3].toList(growable: false), 0, [4, 5].map((x) => x)); + test([1, 2, 3].toList(growable: false), 1, [4, 5].map((x) => x)); + test([1, 2, 3].toList(growable: false), 2, [4].map((x) => x)); + test([1, 2, 3].toList(growable: false), 3, [].map((x) => x)); + test([1, 2, 3].toList(growable: false), 0, const [4, 5]); + test([1, 2, 3].toList(growable: false), 1, const [4, 5]); + test([1, 2, 3].toList(growable: false), 2, const [4]); + test([1, 2, 3].toList(growable: false), 3, const []); + test([1, 2, 3].toList(growable: false), 0, + new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3].toList(growable: false), 1, + new Iterable.generate(2, (x) => x + 4)); + test([1, 2, 3].toList(growable: false), 2, + new Iterable.generate(1, (x) => x + 4)); + test([1, 2, 3].toList(growable: false), 3, + new Iterable.generate(0, (x) => x + 4)); + test(new MyList([1, 2, 3]), 0, [4, 5]); + test(new MyList([1, 2, 3]), 1, [4, 5]); + test(new MyList([1, 2, 3]), 2, [4]); + test(new MyList([1, 2, 3]), 3, []); + test(new MyList([1, 2, 3]), 0, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 1, [4, 5].map((x) => x)); + test(new MyList([1, 2, 3]), 2, [4].map((x) => x)); + test(new MyList([1, 2, 3]), 3, [].map((x) => x)); + + Expect.throwsRangeError(() => test([1, 2, 3], -1, [4, 5])); + Expect.throwsRangeError( + () => test([1, 2, 3].toList(growable: false), -1, [4, 5])); + Expect.throwsRangeError(() => test([1, 2, 3], 1, [4, 5, 6])); + Expect.throwsRangeError( + () => test([1, 2, 3].toList(growable: false), 1, [4, 5, 6])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), -1, [4, 5])); + Expect.throwsRangeError(() => test(new MyList([1, 2, 3]), 1, [4, 5, 6])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 0, [4, 5])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], -1, [4, 5])); + Expect.throwsUnsupportedError(() => test(const [1, 2, 3], 1, [4, 5, 6])); +} diff --git a/tests/corelib/list_set_range_test.dart b/tests/corelib/list_set_range_test.dart new file mode 100644 index 000000000000..399b6ae6d2be --- /dev/null +++ b/tests/corelib/list_set_range_test.dart @@ -0,0 +1,85 @@ +// 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 "package:expect/expect.dart"; + +main() { + var list = []; + list.setRange(0, 0, const []); + list.setRange(0, 0, []); + list.setRange(0, 0, const [], 1); + list.setRange(0, 0, [], 1); + Expect.equals(0, list.length); + Expect.throwsRangeError(() => list.setRange(0, 1, [])); + Expect.throwsRangeError(() => list.setRange(0, 1, [], 1)); + Expect.throwsRangeError(() => list.setRange(0, 1, [1], 0)); + + list.add(1); + list.setRange(0, 0, [], 0); + Expect.equals(1, list.length); + Expect.equals(1, list[0]); + list.setRange(0, 0, const [], 0); + Expect.equals(1, list.length); + Expect.equals(1, list[0]); + + Expect.throwsRangeError(() => list.setRange(0, 2, [1, 2])); + Expect.equals(1, list.length); + Expect.equals(1, list[0]); + + Expect.throwsStateError(() => list.setRange(0, 1, [1, 2], 2)); + Expect.equals(1, list.length); + Expect.equals(1, list[0]); + + list.setRange(0, 1, [2], 0); + Expect.equals(1, list.length); + Expect.equals(2, list[0]); + + list.setRange(0, 1, const [3], 0); + Expect.equals(1, list.length); + Expect.equals(3, list[0]); + + list.addAll([4, 5, 6]); + Expect.equals(4, list.length); + list.setRange(0, 4, [1, 2, 3, 4]); + Expect.listEquals([1, 2, 3, 4], list); + + list.setRange(2, 4, [5, 6, 7, 8]); + Expect.listEquals([1, 2, 5, 6], list); + + Expect.throwsRangeError(() => list.setRange(4, 5, [5, 6, 7, 8])); + Expect.listEquals([1, 2, 5, 6], list); + + list.setRange(1, 3, [9, 10, 11, 12]); + Expect.listEquals([1, 9, 10, 6], list); + + testNegativeIndices(); + + testNonExtendableList(); +} + +void testNegativeIndices() { + var list = [1, 2]; + Expect.throwsRangeError(() => list.setRange(-1, 1, [1])); + Expect.throwsArgumentError(() => list.setRange(0, 1, [1], -1)); + + Expect.throwsRangeError(() => list.setRange(2, 1, [1])); + + Expect.throwsArgumentError(() => list.setRange(-1, -2, [1], -1)); + Expect.listEquals([1, 2], list); + + Expect.throwsRangeError(() => list.setRange(-1, -1, [1])); + Expect.listEquals([1, 2], list); + + // The skipCount is only used if the length is not 0. + list.setRange(0, 0, [1], -1); + Expect.listEquals([1, 2], list); +} + +void testNonExtendableList() { + var list = new List(6); + Expect.listEquals([null, null, null, null, null, null], list); + list.setRange(0, 3, [1, 2, 3, 4]); + list.setRange(3, 6, [1, 2, 3, 4]); + Expect.listEquals([1, 2, 3, 1, 2, 3], list); +} diff --git a/tests/corelib/list_sort_test.dart b/tests/corelib/list_sort_test.dart new file mode 100644 index 000000000000..d251e2376ea8 --- /dev/null +++ b/tests/corelib/list_sort_test.dart @@ -0,0 +1,24 @@ +// 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. + +library list_sort_test; + +import 'sort_helper.dart'; + +class ListSortTest { + static void testMain() { + var compare = Comparable.compare; + var sort = (List list) => list.sort(compare); + new SortHelper(sort, compare).run(); + + new SortHelper((List list) => list.sort(), compare).run(); + + compare = (a, b) => -a.compareTo(b); + new SortHelper(sort, compare).run(); + } +} + +main() { + ListSortTest.testMain(); +} diff --git a/tests/corelib/list_sublist_test.dart b/tests/corelib/list_sublist_test.dart new file mode 100644 index 000000000000..610501fcbfd5 --- /dev/null +++ b/tests/corelib/list_sublist_test.dart @@ -0,0 +1,53 @@ +// 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 "package:expect/expect.dart"; + +main() { + Expect.listEquals([], [].sublist(0, 0)); + Expect.listEquals([], const [].sublist(0, 0)); + + Expect.listEquals([1, 2], [1, 2].sublist(0, 2)); + Expect.listEquals([1, 2], const [1, 2].sublist(0, 2)); + + Expect.listEquals([1], [1, 2].sublist(0, 1)); + Expect.listEquals([1], const [1, 2].sublist(0, 1)); + + Expect.listEquals([2], [1, 2].sublist(1, 2)); + Expect.listEquals([2], const [1, 2].sublist(1, 2)); + + Expect.listEquals([], [1, 2].sublist(0, 0)); + Expect.listEquals([], const [1, 2].sublist(0, 0)); + + Expect.listEquals([2, 3], [1, 2, 3, 4].sublist(1, 3)); + Expect.listEquals([2, 3], const [1, 2, 3, 4].sublist(1, 3)); + + Expect.listEquals([2, 3], [1, 2, 3, 4].sublist(1, 3)); + Expect.listEquals([2, 3], const [1, 2, 3, 4].sublist(1, 3)); + + Expect.throwsArgumentError(() => [].sublist(-1, null)); + Expect.throwsArgumentError(() => const [].sublist(-1, null)); + Expect.throwsArgumentError(() => [].sublist(-1, 0)); + Expect.throwsArgumentError(() => const [].sublist(-1, 0)); + Expect.throwsArgumentError(() => [].sublist(-1, -1)); + Expect.throwsArgumentError(() => const [].sublist(-1, -1)); + Expect.throwsArgumentError(() => [].sublist(-1, 1)); + Expect.throwsArgumentError(() => const [].sublist(-1, 1)); + Expect.throwsArgumentError(() => [].sublist(0, -1)); + Expect.throwsArgumentError(() => const [].sublist(0, -1)); + Expect.throwsArgumentError(() => [].sublist(0, 1)); + Expect.throwsArgumentError(() => const [].sublist(0, 1)); + Expect.throwsArgumentError(() => [].sublist(1, null)); + Expect.throwsArgumentError(() => const [].sublist(1, null)); + Expect.throwsArgumentError(() => [].sublist(1, 0)); + Expect.throwsArgumentError(() => const [].sublist(1, 0)); + Expect.throwsArgumentError(() => [].sublist(1, -1)); + Expect.throwsArgumentError(() => const [].sublist(1, -1)); + Expect.throwsArgumentError(() => [].sublist(1, 1)); + Expect.throwsArgumentError(() => const [].sublist(1, 1)); + + Expect.throwsArgumentError(() => [1].sublist(0, 2)); + Expect.throwsArgumentError(() => [1].sublist(1, 2)); + Expect.throwsArgumentError(() => [1].sublist(1, 0)); +} diff --git a/tests/corelib/list_test.dart b/tests/corelib/list_test.dart new file mode 100644 index 000000000000..18f27493f71a --- /dev/null +++ b/tests/corelib/list_test.dart @@ -0,0 +1,580 @@ +// 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(() => new List.filled(0, null, growable: true)); + testGrowableList(() => []); + testGrowableList(() => new List.from(const [])); + 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()); + + testListConstructor(); + + testErrors(); +} + +void testErrors() { + // Regression for issue http://dartbug.com/24295 + testIndexError(list, index, name) { + try { + list[list.length]; + } catch (err, s) { + Expect.isTrue(err is RangeError, "$name[$index]"); + Expect.equals(list.length, err.invalidValue, "$name[$index] value"); + Expect.equals(list.length - 1, err.end, "$name[$index] end"); + Expect.equals(0, err.start, "$name[$index] start"); + } + } + + testIndex(list, name) { + testIndexError(list, list.length, name); // Just too big. + testIndexError(list, -1, name); // Negative. + testIndexError(list, 0x123456789, name); // > 2^32. + testIndexError(list, -0x123456789, name); // < -2^32. + } + + // Slices. + testSliceError(list, start, end, name) { + name = "$name[$start:$end]"; + var realError; + try { + RangeError.checkValidRange(start, end, list.length); + } catch (e) { + realError = e; + } + var result; + try { + result = list.sublist(start, end); + } catch (actualError) { + Expect.isNotNull(realError, "$name should not fail"); + Expect.isTrue(actualError is RangeError, "$name is-error: $actualError"); + Expect.equals(realError.name, actualError.name, "$name name"); + Expect.equals(realError.invalidValue, actualError.invalidValue, + "$name[0:l+1] value"); + Expect.equals(realError.start, actualError.start, "$name[0:l+1] start"); + Expect.equals(realError.end, actualError.end, "$name[0:l+1] end"); + return; + } + // Didn't throw. + Expect.isNull(realError, "$name should fail"); + Expect.equals(end - start, result.length, "$name result length"); + } + + testSlice(list, name) { + testSliceError(list, 0, list.length, name); // Should not fail. + testSliceError(list, 0, list.length + 1, name); + testSliceError(list, 0, 0x123456789, name); + testSliceError(list, -1, list.length, name); + testSliceError(list, -0x123456789, list.length, name); + testSliceError(list, list.length + 1, list.length + 1, name); + testSliceError(list, -1, null, name); + if (list.length > 0) { + testSliceError(list, list.length, list.length - 1, name); + } + } + + testRangeErrors(list, name) { + testIndex(list, "$name#${list.length} index"); + testSlice(list, "$name#${list.length} slice"); + } + + // Empty lists. + testRangeErrors([], "list"); + testRangeErrors(new List(0), "fixed-list"); + testRangeErrors(const [], "const-list"); + testRangeErrors(new List.unmodifiable([]), "unmodifiable"); + testRangeErrors(new Uint8List(0), "typed-list"); + testRangeErrors(new Uint8List.view(new Uint8List(0).buffer), "typed-list"); + testRangeErrors([1, 2, 3].sublist(1, 1), "sub-list"); + // Non-empty lists. + testRangeErrors([1, 2, 3], "list"); + testRangeErrors(new List(3), "fixed-list"); + testRangeErrors(const [1, 2, 3], "const-list"); + testRangeErrors(new List.unmodifiable([1, 2, 3]), "unmodifiable"); + testRangeErrors(new Uint8List(3), "typed-list"); + testRangeErrors(new Uint8List.view(new Uint8List(3).buffer), "typed-list"); + testRangeErrors([1, 2, 3, 4, 5].sublist(1, 3), "sub-list"); +} + +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 testUntypedListTests(List 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)); +} + +void testLengthInvariantOperations(List list) { + testTypedLengthInvariantOperations(list); + + Expect.throwsTypeError(() => testUntypedListTests(list), + 'List cannot store non-ints'); + + // Argument errors on bad indices. List is still [0, 1, 2, 3]. + + // Direct indices (0 <= index < length). + Expect.throwsArgumentError(() => list[-1]); + Expect.throwsArgumentError(() => list[4]); + Expect.throwsArgumentError(() => list[-1] = 99); + Expect.throwsArgumentError(() => list[4] = 99); + Expect.throwsArgumentError(() => list.elementAt(-1)); + Expect.throwsArgumentError(() => list.elementAt(4)); + // Ranges (0 <= start <= end <= length). + Expect.throwsArgumentError(() => list.sublist(-1, 2)); + Expect.throwsArgumentError(() => list.sublist(-1, 5)); + Expect.throwsArgumentError(() => list.sublist(2, 5)); + Expect.throwsArgumentError(() => list.sublist(4, 2)); + Expect.throwsArgumentError(() => list.getRange(-1, 2)); + Expect.throwsArgumentError(() => list.getRange(-1, 5)); + Expect.throwsArgumentError(() => list.getRange(2, 5)); + Expect.throwsArgumentError(() => list.getRange(4, 2)); + Expect.throwsArgumentError(() => list.setRange(-1, 2, [1, 2, 3])); + Expect.throwsArgumentError(() => list.setRange(-1, 5, [1, 2, 3, 4, 5, 6])); + Expect.throwsArgumentError(() => list.setRange(2, 5, [1, 2, 3])); + Expect.throwsArgumentError(() => list.setRange(4, 2, [1, 2])); + // for setAll, end is implicitly start + values.length. + Expect.throwsArgumentError(() => list.setAll(-1, [])); + Expect.throwsArgumentError(() => list.setAll(5, [])); + Expect.throwsArgumentError(() => list.setAll(2, [1, 2, 3])); + Expect.throwsArgumentError(() => list.fillRange(-1, 2)); + Expect.throwsArgumentError(() => list.fillRange(-1, 5)); + Expect.throwsArgumentError(() => list.fillRange(2, 5)); + Expect.throwsArgumentError(() => list.fillRange(4, 2)); +} + +void testTypedList(List list) { + testTypedLengthInvariantOperations(list); + testCannotChangeLength(list); +} + +void testFixedLengthList(List Function() createList) { + testLengthInvariantOperations(createList()); + testCannotChangeLength(createList()); + testUntypedListTests(createList()); +} + +void testCannotChangeLength(List list) { + list.setAll(0, [0, 1, 2, 3]); + Expect.throwsUnsupportedError(() => list.add(0)); + Expect.throwsUnsupportedError(() => list.addAll([0])); + Expect.throwsUnsupportedError(() => list.removeLast()); + Expect.throwsUnsupportedError(() => list.insert(0, 1)); + Expect.throwsUnsupportedError(() => list.insertAll(0, [1])); + Expect.throwsUnsupportedError(() => list.clear()); + Expect.throwsUnsupportedError(() => list.remove(1)); + Expect.throwsUnsupportedError(() => list.removeAt(1)); + Expect.throwsUnsupportedError(() => list.removeRange(0, 1)); + Expect.throwsUnsupportedError(() => 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 Function() createList) { + List list = createList(); + testLength(0, list); + list.length = 4; + testLength(4, list); + + testLengthInvariantOperations(list); + testGrowableListOperations(list); + + List listDynamic = createList(); + testLength(0, listDynamic); + listDynamic.length = 4; + testLength(4, listDynamic); + + testUntypedListTests(listDynamic); +} + +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); + + // 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]); + + // Direct indices (0 <= index < length). + Expect.throwsArgumentError(() => list.removeAt(-1)); + Expect.throwsArgumentError(() => list.removeAt(4)); + // Direct indices including end (0 <= index <= length). + Expect.throwsArgumentError(() => list.insert(-1, 0)); + Expect.throwsArgumentError(() => list.insert(5, 0)); + Expect.throwsArgumentError(() => list.insertAll(-1, [0])); + Expect.throwsArgumentError(() => list.insertAll(5, [0])); + Expect.throwsArgumentError(() => list.insertAll(-1, [0])); + Expect.throwsArgumentError(() => list.insertAll(5, [0])); + // Ranges (0 <= start <= end <= length). + Expect.throwsArgumentError(() => list.removeRange(-1, 2)); + Expect.throwsArgumentError(() => list.removeRange(2, 5)); + Expect.throwsArgumentError(() => list.removeRange(-1, 5)); + Expect.throwsArgumentError(() => list.removeRange(4, 2)); + Expect.throwsArgumentError(() => list.replaceRange(-1, 2, [9])); + Expect.throwsArgumentError(() => list.replaceRange(2, 5, [9])); + Expect.throwsArgumentError(() => list.replaceRange(-1, 5, [9])); + Expect.throwsArgumentError(() => list.replaceRange(4, 2, [9])); +} + +class Yes { + operator ==(var other) => true; + int get hashCode => 0; +} + +class MyList extends ListBase { + List _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 extends ListBase { + List _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; + } +} + +void testListConstructor() { + // Is fixed-length. + Expect.throws(() => new List(0).add(4)); + Expect.throws(() => new List(-2)); // Not negative. //# 01: ok + // Not null. + Expect.throws(() => new List(null)); + Expect.listEquals([4], new List()..add(4)); + // Is fixed-length. + Expect.throws(() => new List.filled(0, 42).add(4)); + // Not negative. + Expect.throws(() => new List.filled(-2, 42)); +} diff --git a/tests/corelib/list_to_string2_test.dart b/tests/corelib/list_to_string2_test.dart new file mode 100644 index 000000000000..d46e9d542ddc --- /dev/null +++ b/tests/corelib/list_to_string2_test.dart @@ -0,0 +1,32 @@ +// 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 "package:expect/expect.dart"; + +main() { + List list = [1, 2]; + list.add(list); + + List list2 = new List(4); + list2[0] = 1; + list2[1] = 2; + list2[2] = list2; + list2[3] = list; + + Expect.equals("[1, 2, [...]]", list.toString()); + Expect.equals("[1, 2, [...], [1, 2, [...]]]", list2.toString()); + + // Throwing in the middle of a toString does not leave the + // list as being visited. + List list3 = [1, 2, new ThrowOnToString(), 4]; + Expect.throws(list3.toString, (e) => e == "Bad!"); + list3[2] = 3; + Expect.equals("[1, 2, 3, 4]", list3.toString()); +} + +class ThrowOnToString { + String toString() { + throw "Bad!"; + } +} diff --git a/tests/corelib/list_to_string_test.dart b/tests/corelib/list_to_string_test.dart new file mode 100644 index 000000000000..fed5277fe18e --- /dev/null +++ b/tests/corelib/list_to_string_test.dart @@ -0,0 +1,31 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; + +class MyList extends ListBase { + final list; + MyList(this.list); + + get length => list.length; + set length(val) { + list.length = val; + } + + operator [](index) => list[index]; + operator []=(index, val) => list[index] = val; +} + +main() { + Expect.equals("[]", [].toString()); + Expect.equals("[1]", [1].toString()); + Expect.equals("[1, 2]", [1, 2].toString()); + Expect.equals("[]", const [].toString()); + Expect.equals("[1]", const [1].toString()); + Expect.equals("[1, 2]", const [1, 2].toString()); + Expect.equals("[]", new MyList([]).toString()); + Expect.equals("[1]", new MyList([1]).toString()); + Expect.equals("[1, 2]", new MyList([1, 2]).toString()); +} diff --git a/tests/corelib/list_unmodifiable_cast_test.dart b/tests/corelib/list_unmodifiable_cast_test.dart new file mode 100644 index 000000000000..7b5a3bcc9181 --- /dev/null +++ b/tests/corelib/list_unmodifiable_cast_test.dart @@ -0,0 +1,41 @@ +// 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. + +library list_unmodifiable_cast_test; + +import "package:expect/expect.dart"; +import 'dart:collection'; + +void main() { + test(const [37]); + test(new UnmodifiableListView([37])); + + test(new UnmodifiableListView([37])); + test(new UnmodifiableListView([37])); + + test(new UnmodifiableListView([37]).cast()); + test(new UnmodifiableListView([37]).cast()); + test(new UnmodifiableListView([37]).cast()); + test(new UnmodifiableListView([37]).cast()); + + var m2 = new List.unmodifiable([37]); + test(m2); + test(m2.cast()); +} + +void test(List list) { + Expect.equals(1, list.length); + Expect.equals(37, list.first); + + Expect.throws(list.clear); + Expect.throws(() { + list.remove(37); + }); + Expect.throws(() { + list[0] = 42; + }); + Expect.throws(() { + list.addAll([42]); + }); +} diff --git a/tests/corelib/list_unmodifiable_test.dart b/tests/corelib/list_unmodifiable_test.dart new file mode 100644 index 000000000000..7c4c307aafc7 --- /dev/null +++ b/tests/corelib/list_unmodifiable_test.dart @@ -0,0 +1,308 @@ +// Copyright (c) 2015, 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"; + +main() { + var intTest = new Test(); + intTest.run("ConstList", createConstList); + intTest.run("FixedList", createFixedList); + intTest.run("GrowableList", createGrowableList); + intTest.run("ConstMapKeys", createConstMapKeys); + intTest.run("ConstMapValues", createConstMapValues); + intTest.run("MapKeys", createMapKeys); + intTest.run("MapValues", createMapValues); + intTest.run("SplayMapKeys", createSplayMapKeys); + intTest.run("SplayMapValues", createSplayMapValues); + intTest.run("Set", createSet); + intTest.run("SplaySet", createSplaySet); + intTest.run("Queue", createQueue); + intTest.run("ListMapKeys", createListMapKeys); + intTest.run("ListMapValues", createListMapValues); + intTest.run("CodeUnits", createCodeUnits); + intTest.run("TypedList", createTypedList); + + new Test().test("strings", ["a", "b", "c"]); + + new Test().test("superclass", [1, 2, 3]); + new Test().test("subclass", [1, 2, 3]); +} + +class Test { + run(name, Iterable create(int size)) { + test(name, create(0)); + test(name, create(1)); + test(name, create(3)); + } + + test(name, iterable) { + testSingle(name, iterable); + testSingle("$name-where", iterable.where((x) => true)); + testSingle("$name-map", iterable.map((x) => x)); + testSingle("$name-expand", iterable.expand((x) => [x, x])); + testSingle("$name-skip", iterable.skip(1)); + testSingle("$name-take", iterable.take(2)); + testSingle("$name-skipWhile", iterable.skipWhile((x) => false)); + testSingle("$name-takeWhile", iterable.takeWhile((x) => true)); + } + + testSingle(name, iterable) { + var elements = iterable.toList(); + int length = elements.length; + + var list = new List.unmodifiable(iterable); + + Expect.isTrue(list is List, "$name-type-$E"); + Expect.isTrue(list is! List, "$name-!type-!$E"); + + checkElements() { + Expect.equals(length, list.length); + for (int i = 0; i < length; i++) { + Expect.identical(elements[i], list[i], "$name-identical-$i"); + } + } + + checkElements(); + + throws(funcName, func) { + try { + func(); + } catch (e, s) { + Expect.isTrue(e is UnsupportedError, "$name: $funcName threw $e"); + return; + } + checkElements(); + Expect.fail("$name: $funcName didn't throw"); + } + + throws("[]=", () { + list[0] = null; + }); + throws("length=", () { + list.length = length + 1; + }); + throws("length=", () { + list.length = length - 1; + }); + throws("setAll", () { + list.setAll(0, []); + }); + throws("add", () { + list.add(null); + }); + throws("insert", () { + list.insert(0, null); + }); + throws("insertAll", () { + list.insertAll(0, []); + }); + throws("addAll", () { + list.addAll([]); + }); + throws("remove", () { + list.remove(null); + }); + throws("removeWhere", () { + list.removeWhere((x) => true); + }); + throws("retainWhere", () { + list.retainWhere((x) => false); + }); + throws("sort", () { + list.sort(); + }); + throws("shuffle", () { + list.shuffle(); + }); + throws("clear", () { + list.clear(); + }); + throws("removeAt", () { + list.removeAt(0); + }); + throws("removeLast", () { + list.removeLast(); + }); + throws("setRange", () { + list.setRange(0, 1, []); + }); + throws("removeRange", () { + list.removeRange(0, 1); + }); + throws("replaceRange", () { + list.replaceRange(0, 1, []); + }); + throws("fillRange", () { + list.fillRange(0, 1, null); + }); + + success(opName, op(List list), [bool throws = false]) { + if (throws) { + var e1, e2; + Expect.throws(() => op(elements), (e) { + e1 = e; + return true; + }, '$name :: $opName should throw for $elements'); + Expect.throws(() => op(list), (e) { + e2 = e; + return true; + }, '$name :: $opName should throw for $list'); + Expect.equals( + e1.runtimeType, + e2.runtimeType, + "$name :: $opName threw different errors for $elements and $list: " + "${e1.runtimeType} vs ${e2.runtimeType}"); + return; + } + var expect = op(elements); + var actual = op(list); + checkElements(); + if (expect is List) { + Expect.listEquals(expect, actual, "$name-$opName"); + } else if (expect is Iterable) { + Expect.isTrue(actual is Iterable); + Expect.listEquals(expect.toList(), actual.toList(), "$name-$opName"); + } else { + Expect.equals(expect, actual, "$name-$opName"); + } + } + + success("indexOf", (l) => l.indexOf(null)); + success("lastIndexOf", (l) => l.lastIndexOf(null)); + success("contains", (l) => l.contains(2)); + success("elementAt", (l) => l.elementAt(1), list.length < 2); + success("reversed", (l) => l.reversed); + success("sublist0-1", (l) => l.sublist(0, 1), list.isEmpty); + success("getRange0-1", (l) => l.getRange(0, 1), list.isEmpty); + success("asMap-keys", (l) => l.asMap().keys); + success("asMap-values", (l) => l.asMap().values); + success("where", (l) => l.where((x) => true)); + success("map", (l) => l.map((x) => x)); + success("expand", (l) => l.expand((x) => [x, x])); + success("skip", (l) => l.skip(1)); + success("take", (l) => l.take(1)); + success("skipWhile", (l) => l.skipWhile((x) => false)); + success("takeWhile", (l) => l.takeWhile((x) => true)); + success("first", (l) => l.first, list.isEmpty); + success("last", (l) => l.last, list.isEmpty); + success("single", (l) => l.single, list.length != 1); + success("firstWhere", (l) => l.firstWhere((x) => true), list.isEmpty); + success("lastWhere", (l) => l.lastWhere((x) => true), list.isEmpty); + success("singleWhere", (l) => l.singleWhere((x) => true), list.length != 1); + success("isEmpty", (l) => l.isEmpty); + success("isNotEmpty", (l) => l.isNotEmpty); + success("join", (l) => l.join("/")); + success("fold", (l) => l.fold("--", (a, b) => "$a/$b")); + if (elements is List && list is List) { + success( + "reduce", + (l) => (l as List).reduce((a, b) => (a + b).floor()), + list.isEmpty); + } + success("every", (l) => l.every((x) => x == 0)); + success("any", (l) => l.any((x) => x == 2)); + success("toList", (l) => l.toList()); + success("toSet", (l) => l.toSet()); + success("toString", (l) => l.toString()); + + var it = elements.iterator; + list.forEach((v) { + Expect.isTrue(it.moveNext()); + Expect.equals(it.current, v); + }); + Expect.isFalse(it.moveNext()); + + if (elements is List && list is List) { + success("String.fromCharCodes", + (l) => new String.fromCharCodes(l as List)); + } + } +} + +List createConstList(int n) { + if (n == 0) return const []; + return const [1, 2, 3]; +} + +List createFixedList(int n) { + return new List.filled(n, n); +} + +List createGrowableList(int n) { + return new List.filled(n, n, growable: true); +} + +Iterable createIterable(int n) => new Iterable.generate(n); +Iterable createConstMapKeys(int n) { + if (n == 0) return const {}.keys; + return const {0: 0, 1: 1, 2: 2}.keys; +} + +Iterable createConstMapValues(int n) { + if (n == 0) return const {}.values; + return const {0: 0, 1: 1, 2: 2}.values; +} + +Iterable createMapKeys(int n) { + var map = {}; + for (int i = 0; i < n; i++) map[i] = i; + return map.keys; +} + +Iterable createMapValues(int n) { + var map = {}; + for (int i = 0; i < n; i++) map[i] = i; + return map.values; +} + +Iterable createSplayMapKeys(int n) { + var map = new SplayTreeMap(); + for (int i = 0; i < n; i++) map[i] = i; + return map.keys; +} + +Iterable createSplayMapValues(int n) { + var map = new SplayTreeMap(); + for (int i = 0; i < n; i++) map[i] = i; + return map.values; +} + +Set createSet(int n) { + var set = new Set(); + for (int i = 0; i < n; i++) set.add(i); + return set; +} + +SplayTreeSet createSplaySet(int n) { + var set = new SplayTreeSet(); + for (int i = 0; i < n; i++) set.add(i); + return set; +} + +Queue createQueue(int n) { + var queue = new Queue(); + for (int i = 0; i < n; i++) queue.add(i); + return queue; +} + +Iterable createListMapKeys(int n) { + return createGrowableList(n).asMap().keys; +} + +Iterable createListMapValues(int n) { + return createGrowableList(n).asMap().values; +} + +Iterable createCodeUnits(int n) { + var string = new String.fromCharCodes(new Iterable.generate(n)); + return string.codeUnits; +} + +Uint8List createTypedList(int n) { + var tl = new Uint8List(n); + for (int i = 0; i < n; i++) tl[i] = i; + return tl; +} diff --git a/tests/corelib/list_write_elements_test.dart b/tests/corelib/list_write_elements_test.dart new file mode 100644 index 000000000000..55b63d97c63a --- /dev/null +++ b/tests/corelib/list_write_elements_test.dart @@ -0,0 +1,75 @@ +// 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:typed_data"; +import "package:expect/expect.dart"; + +void main() { + test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]); + test([1, 2, 3, 4], [5, 6], 0, [5, 6, 3, 4]); + test([1, 2, 3, 4], [5, 6], 1, [1, 5, 6, 4]); + test([1, 2, 3, 4], [], 2, [1, 2, 3, 4]); + test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]); + test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]); + test([1, 2, 3, 4], [5, 6], 2, [1, 2, 5, 6]); + test([], [], 0, []); + test([1], [2], 0, [2]); + + // Other (non-list) iterables. + test([1, 2, 3, 4], new Iterable.generate(2, (x) => x + 7), 1, [1, 7, 8, 4]); + test([1, 2, 3, 4], [9, 9, 5, 6].skip(2), 1, [1, 5, 6, 4]); + test([1, 2, 3, 4], [5, 6, 9, 9].take(2), 1, [1, 5, 6, 4]); + test([1, 2, 3, 4], [9, 5, 9, 6, 9, 9].where((x) => x != 9), 1, [1, 5, 6, 4]); + test([1, 2, 3, 4], new Set.from([5, 6]), 1, [1, 5, 6, 4]); + + // Other types of lists. + test(new Uint8List(4), [5, 6], 1, [0, 5, 6, 0]); + test(new Uint8List(4), [-5, 6], 1, [0, 256 - 5, 6, 0]); + + // Over-long iterables. Updates until end, then throws. + testThrows([], [1], 0); + testThrows([2], [1], 1); + testThrows([2], [1], 1); + testThrows([1, 2, 3, 4], [5, 6, 7, 8], 2, [1, 2, 5, 6]); + + // Throwing iterable. + Expect.throws(() { + Iterable throwingIterable() sync* { + yield 1; + throw "2"; + } + + List.writeIterable([1, 2, 3], 1, throwingIterable()); + }, (e) => e == "2"); + + // Bad start index. + testThrows([1, 2], [1], -1); + testThrows([1, 2], [1], 2); + + // Working at a supertype is practical and useful. + test([1, 2, 3, 4], [5, 6], 1, [1, 5, 6, 4]); + + var d = new D(); + test([null], [d], 0, [d]); +} + +testThrows(list, iterable, start, [expect]) { + Expect.throws(() { + List.writeIterable(list, start, iterable); + }); + if (expect != null) { + Expect.listEquals(expect, list); + } +} + +test(List list, Iterable iterable, int start, List expect) { + List.writeIterable(list, start, iterable); + Expect.listEquals(expect, list); +} + +class B {} + +class C {} + +class D implements B, C {} diff --git a/tests/corelib/main_test.dart b/tests/corelib/main_test.dart new file mode 100644 index 000000000000..024e91fab462 --- /dev/null +++ b/tests/corelib/main_test.dart @@ -0,0 +1,11 @@ +// 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. + +library main_test; + +import "package:expect/expect.dart"; + +main(List args) { + Expect.equals(0, args.length); +} diff --git a/tests/corelib/map_contains_key_test.dart b/tests/corelib/map_contains_key_test.dart new file mode 100644 index 000000000000..d597a991672c --- /dev/null +++ b/tests/corelib/map_contains_key_test.dart @@ -0,0 +1,27 @@ +// 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 "package:expect/expect.dart"; + +class A { + const A(); +} + +class B extends A { + const B(); +} + +main() { + var map1 = new Map(); + map1[const B()] = const B(); + var map2 = new Map(); + var list = [const B()]; + + var maps = [map1, map2]; + for (var map in maps) { + // Test that the map accepts a key is not of the same type: + // Map.containsValue(A) + Expect.isFalse(map.containsKey(new A())); + } +} diff --git a/tests/corelib/map_contains_value_test.dart b/tests/corelib/map_contains_value_test.dart new file mode 100644 index 000000000000..7837417e3fd6 --- /dev/null +++ b/tests/corelib/map_contains_value_test.dart @@ -0,0 +1,28 @@ +// 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 "package:expect/expect.dart"; + +class A { + const A(); +} + +class B extends A { + const B(); +} + +main() { + var map1 = new Map(); + map1[const B()] = const B(); + var map2 = new Map(); + var list = [const B()]; + Map map3 = list.asMap(); + + var maps = [map1, map2, map3]; + for (var map in maps) { + // Test that the map accepts a value is not of the same type: + // Map.containsValue(A) + Expect.isFalse(map.containsValue(new A())); + } +} diff --git a/tests/corelib/map_entry_test.dart b/tests/corelib/map_entry_test.dart new file mode 100644 index 000000000000..640b8cc805dc --- /dev/null +++ b/tests/corelib/map_entry_test.dart @@ -0,0 +1,63 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; +import 'dart:convert' show json; + +var baseMap = const {"x": 0, "y": 1}; + +void main() { + var entry = new MapEntry(1, 2); + Expect.isTrue(entry is MapEntry); + Expect.isTrue(entry is! MapEntry); + Expect.isTrue(entry is! MapEntry); + Expect.equals(1, entry.key); + Expect.equals(2, entry.value); + Expect.equals("MapEntry(1: 2)", "$entry"); + dynamic dynEntry = entry; + Expect.throwsNoSuchMethodError(() { + dynEntry.key = 0; + }, "key not settable"); + Expect.throwsNoSuchMethodError(() { + dynEntry.value = 0; + }, "value not settable"); + + checkEntries(baseMap, baseMap); + checkEntries(baseMap, new Map.unmodifiable(baseMap)); + checkMap({"x": 0, "y": 1}); + checkMap(new Map.from(baseMap)); + checkMap(new HashMap.from(baseMap)); + checkMap(new LinkedHashMap.from(baseMap)); + checkMap(new SplayTreeMap.from(baseMap)); + checkMap(json.decode('{"x":0,"y":1}')); +} + +void checkMap(Map map) { + checkEntries(baseMap, map); + map.addEntries([new MapEntry("z", 2)]); + checkEntries({"x": 0, "y": 1, "z": 2}, map); + map.addEntries(>[ + new MapEntry("y", 11), + new MapEntry("v", 3), + new MapEntry("w", 4) + ]); + checkEntries({"v": 3, "w": 4, "x": 0, "y": 11, "z": 2}, map); + + var valueMap = + map.map((key, value) => new MapEntry(value as int, key)); + checkEntries({0: "x", 2: "z", 3: "v", 4: "w", 11: "y"}, valueMap); +} + +void checkEntries(Map expected, Map map) { + int byKey(MapEntry e1, MapEntry e2) => e1.key.compareTo(e2.key); + Expect.equals(expected.length, map.entries.length); + var sorted = map.entries.toList()..sort(byKey); + Expect.equals(expected.length, sorted.length); + var expectedEntries = expected.entries.toList(); + for (int i = 0; i < sorted.length; i++) { + Expect.equals(expectedEntries[i].key, sorted[i].key); + Expect.equals(expectedEntries[i].value, sorted[i].value); + } +} diff --git a/tests/corelib/map_from_entries_test.dart b/tests/corelib/map_from_entries_test.dart new file mode 100644 index 000000000000..ef114a733635 --- /dev/null +++ b/tests/corelib/map_from_entries_test.dart @@ -0,0 +1,47 @@ +// 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'; + +import 'package:expect/expect.dart'; + +main() { + runTests((entries) => Map.fromEntries(entries)); + runTests((entries) => HashMap.fromEntries(entries)); + runTests((entries) => LinkedHashMap.fromEntries(entries)); +} + +void runTests(Map Function(Iterable>) ctor) { + fromEntriesTest(ctor); + emptyIterableTest(ctor); + equalElementsTest(ctor); +} + +void fromEntriesTest(Map Function(Iterable>) ctor) { + var map = ctor([MapEntry(1, "one"), MapEntry(2, "two")]); + Expect.equals(2, map.length); + Expect.equals(2, map.keys.length); + Expect.equals(2, map.values.length); + Expect.equals("one", map[1]); + Expect.equals("two", map[2]); +} + +void emptyIterableTest( + Map Function(Iterable>) ctor) { + var map = ctor([]); + Expect.equals(0, map.length); + Expect.equals(0, map.keys.length); + Expect.equals(0, map.values.length); +} + +void equalElementsTest( + Map Function(Iterable>) ctor) { + var map = + ctor([MapEntry(1, "one"), MapEntry(2, "two"), MapEntry(2, "other")]); + Expect.equals(2, map.length); + Expect.equals(2, map.keys.length); + Expect.equals(2, map.values.length); + Expect.equals("one", map[1]); + Expect.equals("other", map[2]); +} diff --git a/tests/corelib/map_from_iterable_test.dart b/tests/corelib/map_from_iterable_test.dart new file mode 100644 index 000000000000..b4e7571ec5dc --- /dev/null +++ b/tests/corelib/map_from_iterable_test.dart @@ -0,0 +1,111 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + defaultFunctionValuesTest(); + defaultKeyFunctionTest(); + defaultValueFunctionTest(); + noDefaultValuesTest(); + emptyIterableTest(); + equalElementsTest(); + genericTypeTest(); +} + +void defaultFunctionValuesTest() { + var map = new HashMap.fromIterable([1, 2, 3]); + + Expect.isTrue(map is Map); + Expect.isTrue(map is HashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(1, map[1]); + Expect.equals(2, map[2]); + Expect.equals(3, map[3]); +} + +void defaultKeyFunctionTest() { + var map = new HashMap.fromIterable([1, 2, 3], value: (x) => x + 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is HashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(2, map[1]); + Expect.equals(3, map[2]); + Expect.equals(4, map[3]); +} + +void defaultValueFunctionTest() { + var map = new HashMap.fromIterable([1, 2, 3], key: (x) => x + 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is HashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(1, map[2]); + Expect.equals(2, map[3]); + Expect.equals(3, map[4]); +} + +void noDefaultValuesTest() { + var map = new HashMap.fromIterable([1, 2, 3], + key: (x) => x + 1, value: (x) => x - 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is HashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals(0, map[2]); + Expect.equals(1, map[3]); + Expect.equals(2, map[4]); +} + +void emptyIterableTest() { + var map = new HashMap.fromIterable([]); + Expect.isTrue(map is Map); + Expect.isTrue(map is HashMap); + + Expect.equals(0, map.length); + Expect.equals(0, map.keys.length); + Expect.equals(0, map.values.length); +} + +void equalElementsTest() { + var map = new HashMap.fromIterable([1, 2, 2], key: (x) => x + 1); + + Expect.isTrue(map is Map); + Expect.isTrue(map is HashMap); + + Expect.equals(2, map.length); + Expect.equals(2, map.keys.length); + Expect.equals(2, map.values.length); + + Expect.equals(1, map[2]); + Expect.equals(2, map[3]); +} + +void genericTypeTest() { + var map = new HashMap.fromIterable([1, 2, 3], + key: (x) => '$x', value: (x) => '$x'); + Expect.isTrue(map is Map); + + // Make sure it is not just Map. + Expect.isFalse(map is Map); + Expect.isFalse(map is Map); +} diff --git a/tests/corelib/map_from_iterables_test.dart b/tests/corelib/map_from_iterables_test.dart new file mode 100644 index 000000000000..73958c5f4b10 --- /dev/null +++ b/tests/corelib/map_from_iterables_test.dart @@ -0,0 +1,78 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + positiveTest(); + emptyMapTest(); + fewerKeysIterableTest(); + fewerValuesIterableTest(); + equalElementsTest(); + genericTypeTest(); +} + +void positiveTest() { + var map = new Map.fromIterables([1, 2, 3], ["one", "two", "three"]); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals("one", map[1]); + Expect.equals("two", map[2]); + Expect.equals("three", map[3]); +} + +void emptyMapTest() { + var map = new Map.fromIterables([], []); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(0, map.length); + Expect.equals(0, map.keys.length); + Expect.equals(0, map.values.length); +} + +void fewerValuesIterableTest() { + Expect.throws(() => new Map.fromIterables([1, 2], [0])); +} + +void fewerKeysIterableTest() { + Expect.throws(() => new Map.fromIterables([1], [0, 2])); +} + +void equalElementsTest() { + var map = new Map.fromIterables([1, 2, 2], ["one", "two", "three"]); + Expect.isTrue(map is Map); + Expect.isTrue(map is LinkedHashMap); + + Expect.equals(2, map.length); + Expect.equals(2, map.keys.length); + Expect.equals(2, map.values.length); + + Expect.equals("one", map[1]); + Expect.equals("three", map[2]); +} + +void genericTypeTest() { + var map = + new Map.fromIterables([1, 2, 3], ["one", "two", "three"]); + Expect.isTrue(map is Map); + + // Make sure it is not just Map. + Expect.isFalse(map is Map); + Expect.isFalse(map is Map); + + Expect.equals(3, map.length); + Expect.equals(3, map.keys.length); + Expect.equals(3, map.values.length); + + Expect.equals("one", map[1]); + Expect.equals("two", map[2]); + Expect.equals("three", map[3]); +} diff --git a/tests/corelib/map_from_test.dart b/tests/corelib/map_from_test.dart new file mode 100644 index 000000000000..eee99687ec4e --- /dev/null +++ b/tests/corelib/map_from_test.dart @@ -0,0 +1,97 @@ +// 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. + +library map.from.test; + +import "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + testWithConstMap(); + testWithNonConstMap(); + testWithHashMap(); + testWithLinkedMap(); +} + +testWithConstMap() { + var map = const {'b': 42, 'a': 43}; + var otherMap = new Map.from(map); + Expect.isTrue(otherMap is Map); + Expect.isTrue(otherMap is LinkedHashMap); + + Expect.equals(2, otherMap.length); + Expect.equals(2, otherMap.keys.length); + Expect.equals(2, otherMap.values.length); + + int count(Map map) { + int cnt = 0; + map.forEach((a, b) { + cnt += b; + }); + return cnt; + }; + + Expect.equals(42 + 43, count(map)); + Expect.equals(count(map), count(otherMap)); +} + +testWithNonConstMap() { + var map = {'b': 42, 'a': 43}; + var otherMap = new Map.from(map); + Expect.isTrue(otherMap is Map); + Expect.isTrue(otherMap is LinkedHashMap); + + Expect.equals(2, otherMap.length); + Expect.equals(2, otherMap.keys.length); + Expect.equals(2, otherMap.values.length); + + int count(Map map) { + int count = 0; + map.forEach((a, b) { + count += b; + }); + return count; + } + + ; + + Expect.equals(42 + 43, count(map)); + Expect.equals(count(map), count(otherMap)); + + // Test that adding to the original map does not change otherMap. + map['c'] = 44; + Expect.equals(3, map.length); + Expect.equals(2, otherMap.length); + Expect.equals(2, otherMap.keys.length); + Expect.equals(2, otherMap.values.length); + + // Test that adding to otherMap does not change the original map. + otherMap['c'] = 44; + Expect.equals(3, map.length); + Expect.equals(3, otherMap.length); + Expect.equals(3, otherMap.keys.length); + Expect.equals(3, otherMap.values.length); +} + +testWithHashMap() { + var map = const {'b': 1, 'a': 2, 'c': 3}; + var otherMap = new HashMap.from(map); + Expect.isTrue(otherMap is Map); + Expect.isTrue(otherMap is HashMap); + var i = 1; + for (var val in map.values) { + Expect.equals(i++, val); + } +} + +testWithLinkedMap() { + var map = const {'b': 1, 'a': 2, 'c': 3}; + var otherMap = new LinkedHashMap.from(map); + Expect.isTrue(otherMap is Map); + Expect.isTrue(otherMap is LinkedHashMap); + var i = 1; + for (var val in map.values) { + Expect.equals(i++, val); + } +} diff --git a/tests/corelib/map_index_test.dart b/tests/corelib/map_index_test.dart new file mode 100644 index 000000000000..05387a4a9235 --- /dev/null +++ b/tests/corelib/map_index_test.dart @@ -0,0 +1,27 @@ +// 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 "package:expect/expect.dart"; + +class A { + const A(); +} + +class B extends A { + const B(); +} + +main() { + var map1 = new Map(); + map1[const B()] = const B(); + var map2 = new Map(); + var list = [const B()]; + + var maps = [map1, map2]; + for (var map in maps) { + // Test that the map accepts a key is not of the same type: + // Map[A] + Expect.isNull(map[new A()]); + } +} diff --git a/tests/corelib/map_keys2_test.dart b/tests/corelib/map_keys2_test.dart new file mode 100644 index 000000000000..ddc743180858 --- /dev/null +++ b/tests/corelib/map_keys2_test.dart @@ -0,0 +1,34 @@ +// 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 "package:expect/expect.dart"; + +main() { + var map1 = {"foo": 42, "bar": 499}; + var map2 = {}; + var map3 = const {"foo": 42, "bar": 499}; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.keys is Iterable); + Expect.isFalse(map1.keys is Iterable); + + Expect.isFalse(map2.keys is Iterable); + Expect.isFalse(map2.keys is Iterable); + + Expect.isTrue(map3.keys is Iterable); + Expect.isFalse(map3.keys is Iterable); + + Expect.isFalse(map4.keys is Iterable); + Expect.isFalse(map4.keys is Iterable); + + Expect.isTrue(map5.keys is Iterable); + Expect.isFalse(map5.keys is Iterable); + + Expect.isTrue(map6.keys is Iterable); + Expect.isFalse(map6.keys is Iterable); +} diff --git a/tests/corelib/map_keys_test.dart b/tests/corelib/map_keys_test.dart new file mode 100644 index 000000000000..d3eaeda66eb6 --- /dev/null +++ b/tests/corelib/map_keys_test.dart @@ -0,0 +1,47 @@ +// 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 "package:expect/expect.dart"; + +main() { + var map1 = {"foo": 42, "bar": 499}; + var map2 = {}; + var map3 = const {"foo": 42, "bar": 499}; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.keys is Iterable); + Expect.isFalse(map1.keys is List); + Expect.equals(2, map1.keys.length); + Expect.equals("foo", map1.keys.first); + Expect.equals("bar", map1.keys.last); + + Expect.isTrue(map2.keys is Iterable); + Expect.isFalse(map2.keys is List); + Expect.equals(0, map2.keys.length); + + Expect.isTrue(map3.keys is Iterable); + Expect.isFalse(map3.keys is List); + Expect.equals(2, map3.keys.length); + Expect.equals("foo", map3.keys.first); + Expect.equals("bar", map3.keys.last); + + Expect.isTrue(map4.keys is Iterable); + Expect.isFalse(map4.keys is List); + Expect.equals(0, map4.keys.length); + + Expect.isTrue(map5.keys is Iterable); + Expect.isFalse(map5.keys is List); + Expect.equals(2, map5.keys.length); + Expect.isTrue(map5.keys.first == "foo" || map5.keys.first == "bar"); + Expect.isTrue(map5.keys.last == "foo" || map5.keys.last == "bar"); + Expect.notEquals(map5.keys.first, map5.keys.last); + + Expect.isTrue(map6.keys is Iterable); + Expect.isFalse(map6.keys is List); + Expect.equals(0, map6.keys.length); +} diff --git a/tests/corelib/map_of_test.dart b/tests/corelib/map_of_test.dart new file mode 100644 index 000000000000..562007272699 --- /dev/null +++ b/tests/corelib/map_of_test.dart @@ -0,0 +1,62 @@ +// 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. + +library map.from.test; + +import "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + for (Map map in [ + {}, + const {}, + new HashMap(), + new LinkedHashMap(), + new SplayTreeMap(), + {1: 11, 2: 12, 4: 14}, + const {1: 11, 2: 12, 4: 14}, + new Map() + ..[1] = 11 + ..[2] = 12 + ..[3] = 13, + new HashMap() + ..[1] = 11 + ..[2] = 12 + ..[3] = 13, + new LinkedHashMap() + ..[1] = 11 + ..[2] = 12 + ..[3] = 13, + new SplayTreeMap() + ..[1] = 11 + ..[2] = 12 + ..[3] = 13, + ]) { + expectThrows(void operation()) { + // Allow CastError as well as TypeError. Dart2js creates a CastError + // here for some reason, and it's not wront. + Expect.throws(operation, (e) => e is TypeError || e is CastError); + } + + var sourceType = map.runtimeType.toString(); + check(sourceType, map, new Map.of(map)); + check(sourceType, map, new Map.of(map)); + check(sourceType, map, new HashMap.of(map)); + check(sourceType, map, new HashMap.of(map)); + check(sourceType, map, new LinkedHashMap.of(map)); + check(sourceType, map, new LinkedHashMap.of(map)); + check(sourceType, map, new SplayTreeMap.of(map)); + check(sourceType, map, new SplayTreeMap.of(map)); + } +} + +check(String sourceType, Map expect, Map actual) { + var targetType = actual.runtimeType.toString(); + var name = "$sourceType->$targetType"; + Expect.equals(expect.length, actual.length, "$name.length"); + for (var key in expect.keys) { + Expect.isTrue(actual.containsKey(key), "$name?[$key]"); + Expect.equals(expect[key], actual[key], "$name[$key]"); + } +} diff --git a/tests/corelib/map_remove_test.dart b/tests/corelib/map_remove_test.dart new file mode 100644 index 000000000000..cb252348affe --- /dev/null +++ b/tests/corelib/map_remove_test.dart @@ -0,0 +1,27 @@ +// 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 "package:expect/expect.dart"; + +class A { + const A(); +} + +class B extends A { + const B(); +} + +main() { + var map1 = new Map(); + map1[const B()] = const B(); + var map2 = new Map(); + var list = [const B()]; + + var maps = [map1, map2]; + for (var map in maps) { + // Test that the map accepts a key is not of the same type: + // Map.remove(A) + Expect.isNull(map.remove(new A())); + } +} diff --git a/tests/corelib/map_set_undefined_test.dart b/tests/corelib/map_set_undefined_test.dart new file mode 100644 index 000000000000..338259e9c828 --- /dev/null +++ b/tests/corelib/map_set_undefined_test.dart @@ -0,0 +1,57 @@ +// Copyright (c) 2019, 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 'package:expect/expect.dart'; + +main() { + // Regression test for https://github.com/dart-lang/sdk/issues/36052. + // JS compilers shouldn't produce `undefined` when a Map/Set key is not found. + testMap({}); + testMap(Map.identity()); + testMap(LinkedHashMap( + equals: (x, y) => x == y, + hashCode: (x) => x.hashCode, + isValidKey: (_) => true)); + + testSet(Set()); + testSet(Set.identity()); + testSet(LinkedHashSet( + equals: (x, y) => x == y, + hashCode: (x) => x.hashCode, + isValidKey: (_) => true)); +} + +testMap(Map map) { + var t = map.runtimeType.toString(); + var s = ' (length ${map.length})'; + checkUndefined('$t.[]$s', map['hi']); + checkUndefined('$t.putIfAbsent$s', map.putIfAbsent('hi', () {})); + checkUndefined('$t.remove$s', map.remove('hi')); + if (map.isEmpty) { + map['hello'] = 'there'; + testMap(map); + } +} + +testSet(Set set) { + var t = set.runtimeType.toString(); + var s = ' (length ${set.length})'; + checkUndefined('$t.lookup$s', set.lookup('hi')); + if (set.isEmpty) { + set.add('hello'); + testSet(set); + } +} + +/// Fails if [x] incorrectly uses the default argument instead of being `null` +/// (i.e. because `x` is undefined). +checkUndefined(String method, [Object? x = 'error']) { + // TODO(jmesserly): this check is specific to implementation details of DDC's + // current calling conventions. These conventions may change. + // Ideally we'd have an `undefined` constant in "package:js" and use that + // here instead. + Expect.isNull(x, + 'error in $method: result treated as missing argument (JS undefined?)'); +} diff --git a/tests/corelib/map_test.dart b/tests/corelib/map_test.dart new file mode 100644 index 000000000000..a768aa3ad276 --- /dev/null +++ b/tests/corelib/map_test.dart @@ -0,0 +1,1047 @@ +// 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. + +library map_test; + +import "package:expect/expect.dart"; +import 'dart:collection'; +import 'dart:convert' show json; + +Map newJsonMap() => json.decode('{}'); +Map newJsonMapCustomReviver() => + json.decode('{}', reviver: (key, value) => value); + +void main() { + test(new HashMap()); + test(new LinkedHashMap()); + test(new SplayTreeMap()); + test(new SplayTreeMap(Comparable.compare)); + test(new MapView(new HashMap())); + test(new MapView(new SplayTreeMap())); + test(new MapBaseMap()); + test(new MapMixinMap()); + test(newJsonMap()); + test(newJsonMapCustomReviver()); + testLinkedHashMap(); + testMapLiteral(); + testNullValue(); + testTypes(); + testUnmodifiableMaps(); + + testWeirdStringKeys(new Map()); + testWeirdStringKeys(new Map()); + testWeirdStringKeys(new HashMap()); + testWeirdStringKeys(new HashMap()); + testWeirdStringKeys(new LinkedHashMap()); + testWeirdStringKeys(new LinkedHashMap()); + testWeirdStringKeys(new SplayTreeMap()); + testWeirdStringKeys(new SplayTreeMap()); + testWeirdStringKeys(new MapBaseMap()); + testWeirdStringKeys(new MapMixinMap()); + testWeirdStringKeys(newJsonMap()); + testWeirdStringKeys(newJsonMapCustomReviver()); + + testNumericKeys(new Map()); + testNumericKeys(new Map()); + testNumericKeys(new HashMap()); + testNumericKeys(new HashMap()); + testNumericKeys(new HashMap.identity()); + testNumericKeys(new HashMap.identity()); + testNumericKeys(new LinkedHashMap()); + testNumericKeys(new LinkedHashMap()); + testNumericKeys(new LinkedHashMap.identity()); + testNumericKeys(new LinkedHashMap.identity()); + testNumericKeys(new MapBaseMap()); + testNumericKeys(new MapMixinMap()); + + testNaNKeys(new Map()); + testNaNKeys(new Map()); + testNaNKeys(new HashMap()); + testNaNKeys(new HashMap()); + testNaNKeys(new LinkedHashMap()); + testNaNKeys(new LinkedHashMap()); + testNaNKeys(new MapBaseMap()); + testNaNKeys(new MapMixinMap()); + // Identity maps fail the NaN-keys tests because the test assumes that + // NaN is not equal to NaN. + + testIdentityMap(new Map.identity()); + testIdentityMap(new HashMap.identity()); + testIdentityMap(new LinkedHashMap.identity()); + testIdentityMap(new HashMap(equals: identical, hashCode: identityHashCode)); + testIdentityMap( + new LinkedHashMap(equals: identical, hashCode: identityHashCode)); + testIdentityMap(new HashMap( + equals: (x, y) => identical(x, y), hashCode: (x) => identityHashCode(x))); + testIdentityMap(new LinkedHashMap( + equals: (x, y) => identical(x, y), hashCode: (x) => identityHashCode(x))); + + testCustomMap(new HashMap( + equals: myEquals, + hashCode: myHashCode, + isValidKey: (v) => v is Customer)); + testCustomMap(new LinkedHashMap( + equals: myEquals, + hashCode: myHashCode, + isValidKey: (v) => v is Customer)); + testCustomMap( + new HashMap(equals: myEquals, hashCode: myHashCode)); + + testCustomMap(new LinkedHashMap( + equals: myEquals, hashCode: myHashCode)); + + testIterationOrder(new LinkedHashMap()); + testIterationOrder(new LinkedHashMap.identity()); + testIterationOrder(newJsonMap()); + testIterationOrder(newJsonMapCustomReviver()); + + testOtherKeys(new SplayTreeMap()); + testOtherKeys( + new SplayTreeMap((int a, int b) => a - b, (v) => v is int)); + testOtherKeys(new SplayTreeMap((int a, int b) => a - b, (v) => v is int)); + testOtherKeys(new HashMap()); + testOtherKeys(new HashMap.identity()); + testOtherKeys(new HashMap( + hashCode: (v) => v.hashCode, isValidKey: (v) => v is int)); + testOtherKeys(new HashMap( + equals: (int x, int y) => x == y, + hashCode: (int v) => v.hashCode, + isValidKey: (v) => v is int)); + testOtherKeys(new LinkedHashMap()); + testOtherKeys(new LinkedHashMap.identity()); + testOtherKeys(new LinkedHashMap( + hashCode: (v) => v.hashCode, isValidKey: (v) => v is int)); + testOtherKeys(new LinkedHashMap( + equals: (int x, int y) => x == y, + hashCode: (int v) => v.hashCode, + isValidKey: (v) => v is int)); + testOtherKeys(new MapBaseMap()); + testOtherKeys(new MapMixinMap()); + + testUnmodifiableMap(const {1: 37}); + testUnmodifiableMap(new UnmodifiableMapView({1: 37})); + testUnmodifiableMap(new UnmodifiableMapBaseMap([1, 37])); + + testTypeAnnotations(new HashMap()); + testTypeAnnotations(new LinkedHashMap()); + testTypeAnnotations(new HashMap(equals: identical)); + testTypeAnnotations(new LinkedHashMap(equals: identical)); + testTypeAnnotations(new HashMap( + equals: (int a, int b) => a == b, + hashCode: (int a) => a.hashCode, + isValidKey: (a) => a is int)); + testTypeAnnotations(new LinkedHashMap( + equals: (int a, int b) => a == b, + hashCode: (int a) => a.hashCode, + isValidKey: (a) => a is int)); + + testFrom(); +} + +void test(Map map) { + testDeletedElement(map); + if (map is Map) { + testMap(map, 1, 2, 3, 4, 5, 6, 7, 8); + } else { + map.clear(); + testMap(map, "value1", "value2", "value3", "value4", "value5", "value6", + "value7", "value8"); + } +} + +void testLinkedHashMap() { + LinkedHashMap map = new LinkedHashMap(); + Expect.isFalse(map.containsKey(1)); + map[1] = 1; + map[1] = 2; + testLength(1, map); +} + +void testMap( + Map typedMap, key1, key2, key3, key4, key5, key6, key7, key8) { + Map map = typedMap; + int value1 = 10; + int value2 = 20; + int value3 = 30; + int value4 = 40; + int value5 = 50; + int value6 = 60; + int value7 = 70; + int value8 = 80; + + testLength(0, map); + + map[key1] = value1; + Expect.equals(value1, map[key1]); + map[key1] = value2; + Expect.isFalse(map.containsKey(key2)); + testLength(1, map); + + map[key1] = value1; + Expect.equals(value1, map[key1]); + // Add enough entries to make sure the table grows. + map[key2] = value2; + Expect.equals(value2, map[key2]); + testLength(2, map); + map[key3] = value3; + Expect.equals(value2, map[key2]); + Expect.equals(value3, map[key3]); + map[key4] = value4; + Expect.equals(value3, map[key3]); + Expect.equals(value4, map[key4]); + map[key5] = value5; + Expect.equals(value4, map[key4]); + Expect.equals(value5, map[key5]); + map[key6] = value6; + Expect.equals(value5, map[key5]); + Expect.equals(value6, map[key6]); + map[key7] = value7; + Expect.equals(value6, map[key6]); + Expect.equals(value7, map[key7]); + map[key8] = value8; + Expect.equals(value1, map[key1]); + Expect.equals(value2, map[key2]); + Expect.equals(value3, map[key3]); + Expect.equals(value4, map[key4]); + Expect.equals(value5, map[key5]); + Expect.equals(value6, map[key6]); + Expect.equals(value7, map[key7]); + Expect.equals(value8, map[key8]); + testLength(8, map); + + map.remove(key4); + Expect.isFalse(map.containsKey(key4)); + testLength(7, map); + + // Test clearing the table. + map.clear(); + testLength(0, map); + Expect.isFalse(map.containsKey(key1)); + Expect.isFalse(map.containsKey(key2)); + Expect.isFalse(map.containsKey(key3)); + Expect.isFalse(map.containsKey(key4)); + Expect.isFalse(map.containsKey(key5)); + Expect.isFalse(map.containsKey(key6)); + Expect.isFalse(map.containsKey(key7)); + Expect.isFalse(map.containsKey(key8)); + + // Test adding and removing again. + map[key1] = value1; + Expect.equals(value1, map[key1]); + testLength(1, map); + map[key2] = value2; + Expect.equals(value2, map[key2]); + testLength(2, map); + map[key3] = value3; + Expect.equals(value3, map[key3]); + map.remove(key3); + testLength(2, map); + map[key4] = value4; + Expect.equals(value4, map[key4]); + map.remove(key4); + testLength(2, map); + map[key5] = value5; + Expect.equals(value5, map[key5]); + map.remove(key5); + testLength(2, map); + map[key6] = value6; + Expect.equals(value6, map[key6]); + map.remove(key6); + testLength(2, map); + map[key7] = value7; + Expect.equals(value7, map[key7]); + map.remove(key7); + testLength(2, map); + map[key8] = value8; + Expect.equals(value8, map[key8]); + map.remove(key8); + testLength(2, map); + + Expect.isTrue(map.containsKey(key1)); + Expect.isTrue(map.containsValue(value1)); + + // Test Map.forEach. + Map otherMap = new Map(); + void testForEachMap(key, value) { + otherMap[key] = value; + } + + map.forEach(testForEachMap); + Expect.isTrue(otherMap.containsKey(key1)); + Expect.isTrue(otherMap.containsKey(key2)); + Expect.isTrue(otherMap.containsValue(value1)); + Expect.isTrue(otherMap.containsValue(value2)); + Expect.equals(2, otherMap.length); + + otherMap.clear(); + Expect.equals(0, otherMap.length); + + // Test Collection.keys. + void testForEachKey(key) { + otherMap[key] = null; + } + + Iterable keys = map.keys; + keys.forEach(testForEachKey); + Expect.isTrue(otherMap.containsKey(key1)); + Expect.isTrue(otherMap.containsKey(key2)); + Expect.isFalse(otherMap.containsKey(value1)); + Expect.isFalse(otherMap.containsKey(value2)); + + Expect.isTrue(otherMap.containsValue(null)); + Expect.isFalse(otherMap.containsValue(value1)); + Expect.isFalse(otherMap.containsValue(value2)); + Expect.equals(2, otherMap.length); + otherMap.clear(); + Expect.equals(0, otherMap.length); + + // Test Collection.values. + void testForEachValue(value) { + if (value == value1) { + otherMap[key1] = value; + } else if (value == value2) { + otherMap[key2] = value; + } else { + otherMap[key3] = null; + } + } + + Iterable values = map.values; + values.forEach(testForEachValue); + Expect.isTrue(otherMap.containsKey(key1)); + Expect.isTrue(otherMap.containsKey(key2)); + Expect.isFalse(otherMap.containsKey(value1)); + Expect.isFalse(otherMap.containsKey(value2)); + + Expect.isTrue(otherMap.containsValue(value1)); + Expect.isTrue(otherMap.containsValue(value2)); + Expect.isFalse(otherMap.containsValue(value3)); + Expect.isFalse(otherMap.containsValue(key1)); + Expect.isFalse(otherMap.containsValue(null)); + Expect.equals(2, otherMap.length); + otherMap.clear(); + Expect.equals(0, otherMap.length); + + // Test Map.putIfAbsent. + map.clear(); + Expect.isFalse(map.containsKey(key1)); + map.putIfAbsent(key1, () => 10); + Expect.isTrue(map.containsKey(key1)); + Expect.equals(10, map[key1]); + Expect.equals(10, map.putIfAbsent(key1, () => 11)); + + // Test Map.addAll. + map.clear(); + otherMap.clear(); + otherMap['99'] = 1; + otherMap['50'] = 50; + otherMap['1'] = 99; + map.addAll(otherMap); + Expect.equals(3, map.length); + Expect.equals(1, map['99']); + Expect.equals(50, map['50']); + Expect.equals(99, map['1']); + otherMap['50'] = 42; + map.addAll(new HashMap.from(otherMap)); + Expect.equals(3, map.length); + Expect.equals(1, map['99']); + Expect.equals(42, map['50']); + Expect.equals(99, map['1']); + otherMap['99'] = 7; + map.addAll(new SplayTreeMap.from(otherMap)); + Expect.equals(3, map.length); + Expect.equals(7, map['99']); + Expect.equals(42, map['50']); + Expect.equals(99, map['1']); + otherMap.remove('99'); + map['99'] = 0; + map.addAll(otherMap); + Expect.equals(3, map.length); + Expect.equals(0, map['99']); + Expect.equals(42, map['50']); + Expect.equals(99, map['1']); + map.clear(); + otherMap.clear(); + map.addAll(otherMap); + Expect.equals(0, map.length); +} + +void testDeletedElement(Map map) { + map.clear(); + for (int i = 0; i < 100; i++) { + map['1'] = 2; + testLength(1, map); + map.remove('1'); + testLength(0, map); + } + testLength(0, map); +} + +void testMapLiteral() { + Map m = {"a": 1, "b": 2, "c": 3}; + Expect.equals(3, m.length); + int sum = 0; + m.forEach((a, int b) { + sum += b; + }); + Expect.equals(6, sum); + + List values = m.keys.toList(); + Expect.equals(3, values.length); + String first = values[0]; + String second = values[1]; + String third = values[2]; + String all = "${first}${second}${third}"; + Expect.equals(3, all.length); + Expect.isTrue(all.contains("a", 0)); + Expect.isTrue(all.contains("b", 0)); + Expect.isTrue(all.contains("c", 0)); +} + +void testNullValue() { + Map m = {"a": 1, "b": null, "c": 3}; + + Expect.equals(null, m["b"]); + Expect.isTrue(m.containsKey("b")); + Expect.equals(3, m.length); + + m["a"] = null; + m["c"] = null; + Expect.equals(null, m["a"]); + Expect.isTrue(m.containsKey("a")); + Expect.equals(null, m["c"]); + Expect.isTrue(m.containsKey("c")); + Expect.equals(3, m.length); + + m.remove("a"); + Expect.equals(2, m.length); + Expect.equals(null, m["a"]); + Expect.isFalse(m.containsKey("a")); +} + +void testTypes() { + testMap(Map map) { + Expect.isTrue(map is Map); + Expect.isTrue(map is! Map); + Expect.isTrue(map is! Map); + + // Use with properly typed keys and values. + map[42] = "text1"; + map[43] = "text2"; + map[42] = "text3"; + Expect.equals("text3", map.remove(42)); + Expect.equals(null, map[42]); + map[42] = "text4"; + + // Ensure that "containsKey", "containsValue" and "remove" + // accepts any object. + for (var object in [true, null, new Object()]) { + Expect.isFalse(map.containsKey(object)); + Expect.isFalse(map.containsValue(object)); + Expect.isNull(map.remove(object)); + Expect.isNull(map[object]); + } + } + + testMap(new HashMap()); + testMap(new LinkedHashMap()); + testMap(new SplayTreeMap()); + testMap(new SplayTreeMap(Comparable.compare)); + testMap(new SplayTreeMap((int a, int b) => a.compareTo(b))); + testMap(new HashMap()); + testMap(new LinkedHashMap()); + testMap(new SplayTreeMap()); + testMap(new SplayTreeMap(Comparable.compare)); + testMap(new SplayTreeMap((num a, num b) => a.compareTo(b))); +} + +void testWeirdStringKeys(Map map) { + // Test weird keys. + var weirdKeys = const [ + 'hasOwnProperty', + 'constructor', + 'toLocaleString', + 'propertyIsEnumerable', + '__defineGetter__', + '__defineSetter__', + '__lookupGetter__', + '__lookupSetter__', + 'isPrototypeOf', + 'toString', + 'valueOf', + '__proto__', + '__count__', + '__parent__', + '' + ]; + Expect.isTrue(map.isEmpty); + for (var key in weirdKeys) { + Expect.isFalse(map.containsKey(key)); + Expect.equals(null, map[key]); + var value = 'value:$key'; + map[key] = value; + Expect.isTrue(map.containsKey(key)); + Expect.equals(value, map[key]); + Expect.equals(value, map.remove(key)); + Expect.isFalse(map.containsKey(key)); + Expect.equals(null, map[key]); + } + Expect.isTrue(map.isEmpty); +} + +void testNumericKeys(Map map) { + var numericKeys = const [ + double.infinity, + double.negativeInfinity, + 0, + 0.0, + -0.0 + ]; + + Expect.isTrue(map.isEmpty); + for (var key in numericKeys) { + Expect.isFalse(map.containsKey(key)); + Expect.equals(null, map[key]); + var value = 'value:$key'; + map[key] = value; + Expect.isTrue(map.containsKey(key)); + Expect.equals(value, map[key]); + Expect.equals(value, map.remove(key)); + Expect.isFalse(map.containsKey(key)); + Expect.equals(null, map[key]); + } + Expect.isTrue(map.isEmpty); +} + +void testNaNKeys(Map map) { + Object nan = double.nan; + // Skip this test on platforms that use native-JS NaN semantics for speed. + if (!identical(nan, nan)) return; + + Expect.isTrue(map.isEmpty); + // Test NaN. + Expect.isFalse(map.containsKey(nan)); + Expect.equals(null, map[nan]); + + map[nan] = 'value:0'; + Expect.isFalse(map.containsKey(nan)); + Expect.equals(null, map[nan]); + testLength(1, map); + + map[nan] = 'value:1'; + Expect.isFalse(map.containsKey(nan)); + Expect.equals(null, map[nan]); + testLength(2, map); + + Expect.equals(null, map.remove(nan)); + testLength(2, map); + + var count = 0; + map.forEach((key, value) { + if (key.isNaN) count++; + }); + Expect.equals(2, count); + + map.clear(); + Expect.isTrue(map.isEmpty); +} + +void testLength(int length, Map map) { + Expect.equals(length, map.length); + Expect.equals(length, map.keys.length); + Expect.equals(length, map.values.length); + // Check being-empty. + var ifEmpty = (length == 0) ? Expect.isTrue : Expect.isFalse; + var ifNotEmpty = (length != 0) ? Expect.isTrue : Expect.isFalse; + ifEmpty(map.isEmpty); + ifNotEmpty(map.isNotEmpty); + ifEmpty(map.keys.isEmpty); + ifNotEmpty(map.keys.isNotEmpty); + ifEmpty(map.values.isEmpty); + ifNotEmpty(map.values.isNotEmpty); + // Test key/value iterators match their isEmpty/isNotEmpty. + ifNotEmpty(map.keys.iterator.moveNext()); + ifNotEmpty(map.values.iterator.moveNext()); + if (length == 0) { + for (var k in map.keys) Expect.fail("contains key when iterating: $k"); + for (var v in map.values) Expect.fail("contains values when iterating: $v"); + } +} + +testIdentityMap(Map typedMap) { + Map map = typedMap; + Expect.isTrue(map.isEmpty); + + var nan = double.nan; + // TODO(11551): Remove guard when dart2js makes identical(NaN, NaN) true. + if (identical(nan, nan)) { + map[nan] = 42; + testLength(1, map); + Expect.isTrue(map.containsKey(nan)); + Expect.equals(42, map[nan]); + map[nan] = 37; + testLength(1, map); + Expect.equals(37, map[nan]); + Expect.equals(37, map.remove(nan)); + testLength(0, map); + } + + Vampire v1 = const Vampire(1); + Vampire v2 = const Vampire(2); + Expect.isFalse(v1 == v1); + Expect.isFalse(v2 == v2); + Expect.isTrue(v2 == v1); // Snob! + + map[v1] = 1; + map[v2] = 2; + testLength(2, map); + + Expect.isTrue(map.containsKey(v1)); + Expect.isTrue(map.containsKey(v2)); + + Expect.equals(1, map[v1]); + Expect.equals(2, map[v2]); + + Expect.equals(1, map.remove(v1)); + testLength(1, map); + Expect.isFalse(map.containsKey(v1)); + Expect.isTrue(map.containsKey(v2)); + + Expect.isNull(map.remove(v1)); + Expect.equals(2, map.remove(v2)); + testLength(0, map); + + var eq01 = new Equalizer(0); + var eq02 = new Equalizer(0); + var eq11 = new Equalizer(1); + var eq12 = new Equalizer(1); + // Sanity. + Expect.equals(eq01, eq02); + Expect.equals(eq02, eq01); + Expect.equals(eq11, eq12); + Expect.equals(eq12, eq11); + Expect.notEquals(eq01, eq11); + Expect.notEquals(eq01, eq12); + Expect.notEquals(eq02, eq11); + Expect.notEquals(eq02, eq12); + Expect.notEquals(eq11, eq01); + Expect.notEquals(eq11, eq02); + Expect.notEquals(eq12, eq01); + Expect.notEquals(eq12, eq02); + + map[eq01] = 0; + map[eq02] = 1; + map[eq11] = 2; + map[eq12] = 3; + testLength(4, map); + + Expect.equals(0, map[eq01]); + Expect.equals(1, map[eq02]); + Expect.equals(2, map[eq11]); + Expect.equals(3, map[eq12]); + + Expect.isTrue(map.containsKey(eq01)); + Expect.isTrue(map.containsKey(eq02)); + Expect.isTrue(map.containsKey(eq11)); + Expect.isTrue(map.containsKey(eq12)); + + Expect.equals(1, map.remove(eq02)); + Expect.equals(3, map.remove(eq12)); + testLength(2, map); + Expect.isTrue(map.containsKey(eq01)); + Expect.isFalse(map.containsKey(eq02)); + Expect.isTrue(map.containsKey(eq11)); + Expect.isFalse(map.containsKey(eq12)); + + Expect.equals(0, map[eq01]); + Expect.equals(null, map[eq02]); + Expect.equals(2, map[eq11]); + Expect.equals(null, map[eq12]); + + Expect.equals(0, map.remove(eq01)); + Expect.equals(2, map.remove(eq11)); + testLength(0, map); + + map[eq01] = 0; + map[eq02] = 1; + map[eq11] = 2; + map[eq12] = 3; + testLength(4, map); + + // Transfer to equality-based map will collapse elements. + Map eqMap = new HashMap(); + eqMap.addAll(map); + testLength(2, eqMap); + Expect.isTrue(eqMap.containsKey(eq01)); + Expect.isTrue(eqMap.containsKey(eq02)); + Expect.isTrue(eqMap.containsKey(eq11)); + Expect.isTrue(eqMap.containsKey(eq12)); + + // Changing objects will not affect identity map. + map.clear(); + var m1 = new Mutable(1); + var m2 = new Mutable(2); + var m3 = new Mutable(3); + map[m1] = 1; + map[m2] = 2; + map[m3] = 3; + Expect.equals(3, map.length); + Expect.isTrue(map.containsKey(m1)); + Expect.isTrue(map.containsKey(m2)); + Expect.isTrue(map.containsKey(m3)); + Expect.notEquals(m1, m3); + m3.id = 1; + Expect.equals(m1, m3); + // Even if keys are equal, they are still not identical. + // Even if hashcode of m3 changed, it can still be found. + Expect.equals(1, map[m1]); + Expect.equals(3, map[m3]); +} + +/** Class of objects that are equal if they hold the same id. */ +class Equalizer { + int id; + Equalizer(this.id); + int get hashCode => id; + bool operator ==(Object other) => other is Equalizer && id == other.id; +} + +/** + * Objects that are not reflexive. + * + * They think they are better than their equals. + */ +class Vampire { + final int generation; + const Vampire(this.generation); + + int get hashCode => generation; + + // The double-fang operator falsely claims that a vampire is equal to + // any of its sire's generation. + bool operator ==(Object other) => + other is Vampire && generation - 1 == other.generation; +} + +void testCustomMap(Map typedMap) { + Map map = typedMap; + testLength(0, map); + var c11 = const Customer(1, 1); + var c12 = const Customer(1, 2); + var c21 = const Customer(2, 1); + var c22 = const Customer(2, 2); + // Sanity. + Expect.equals(c11, c12); + Expect.notEquals(c11, c21); + Expect.notEquals(c11, c22); + Expect.equals(c21, c22); + Expect.notEquals(c21, c11); + Expect.notEquals(c21, c12); + + Expect.isTrue(myEquals(c11, c21)); + Expect.isFalse(myEquals(c11, c12)); + Expect.isFalse(myEquals(c11, c22)); + Expect.isTrue(myEquals(c12, c22)); + Expect.isFalse(myEquals(c12, c11)); + Expect.isFalse(myEquals(c12, c21)); + + map[c11] = 42; + testLength(1, map); + Expect.isTrue(map.containsKey(c11)); + Expect.isTrue(map.containsKey(c21)); + Expect.isFalse(map.containsKey(c12)); + Expect.isFalse(map.containsKey(c22)); + Expect.equals(42, map[c11]); + Expect.equals(42, map[c21]); + + map[c21] = 37; + testLength(1, map); + Expect.isTrue(map.containsKey(c11)); + Expect.isTrue(map.containsKey(c21)); + Expect.isFalse(map.containsKey(c12)); + Expect.isFalse(map.containsKey(c22)); + Expect.equals(37, map[c11]); + Expect.equals(37, map[c21]); + + map[c22] = 42; + testLength(2, map); + Expect.isTrue(map.containsKey(c11)); + Expect.isTrue(map.containsKey(c21)); + Expect.isTrue(map.containsKey(c12)); + Expect.isTrue(map.containsKey(c22)); + Expect.equals(37, map[c11]); + Expect.equals(37, map[c21]); + Expect.equals(42, map[c12]); + Expect.equals(42, map[c22]); + + Expect.equals(42, map.remove(c12)); + testLength(1, map); + Expect.isTrue(map.containsKey(c11)); + Expect.isTrue(map.containsKey(c21)); + Expect.isFalse(map.containsKey(c12)); + Expect.isFalse(map.containsKey(c22)); + Expect.equals(37, map[c11]); + Expect.equals(37, map[c21]); + + Expect.equals(37, map.remove(c11)); + testLength(0, map); +} + +void testUnmodifiableMap(Map map) { + Expect.isTrue(map.containsKey(1)); + testLength(1, map); + Expect.equals(1, map.keys.first); + Expect.equals(37, map.values.first); + + Expect.throws(map.clear); + Expect.throws(() { + map.remove(1); + }); + Expect.throws(() { + map[2] = 42; + }); + Expect.throws(() { + map.addAll({2: 42}); + }); +} + +class Customer { + final int id; + final int secondId; + const Customer(this.id, this.secondId); + int get hashCode => id; + bool operator ==(Object other) { + if (other is! Customer) return false; + Customer otherCustomer = other; + return id == otherCustomer.id; + } +} + +int myHashCode(Customer c) => c.secondId; +bool myEquals(Customer a, Customer b) => a.secondId == b.secondId; + +void testIterationOrder(Map map) { + var order = ['0', '6', '4', '2', '7', '9', '7', '1', '2', '5', '3']; + for (int i = 0; i < order.length; i++) map[order[i]] = i; + Expect.listEquals( + map.keys.toList(), ['0', '6', '4', '2', '7', '9', '1', '5', '3']); + Expect.listEquals(map.values.toList(), [0, 1, 2, 8, 6, 5, 7, 9, 10]); +} + +void testOtherKeys(Map map) { + // Test that non-int keys are allowed in containsKey/remove/lookup. + // Custom hash sets and tree sets must be constructed so they don't + // use the equality/comparator on incompatible objects. + + // This should not throw in either checked or unchecked mode. + Expect.isFalse(map.containsKey("not an int")); + Expect.isFalse(map.containsKey(1.5)); + Expect.isNull(map.remove("not an int")); + Expect.isNull(map.remove(1.5)); + Expect.isNull(map["not an int"]); + Expect.isNull(map[1.5]); +} + +class Mutable { + int id; + Mutable(this.id); + int get hashCode => id; + bool operator ==(other) => other is Mutable && other.id == id; +} + +// Slow implementation of Map based on MapBase. +abstract class MapBaseOperations { + final List _keys = []; + final List _values = []; + int _modCount = 0; + + V? operator [](Object? key) { + int index = _keys.indexOf(key); + if (index < 0) return null; + return _values[index]; + } + + Iterable get keys => new TestKeyIterable(this); + + void operator []=(K key, V value) { + int index = _keys.indexOf(key); + if (index >= 0) { + _values[index] = value; + } else { + _modCount++; + _keys.add(key); + _values.add(value); + } + } + + V? remove(Object? key) { + int index = _keys.indexOf(key); + if (index >= 0) { + var result = _values[index]; + key = _keys.removeLast(); + var value = _values.removeLast(); + if (index != _keys.length) { + _keys[index] = key; + _values[index] = value; + } + _modCount++; + return result; + } + return null; + } + + void clear() { + // Clear cannot be based on remove, since remove won't remove keys that + // are not equal to themselves. It will fail the testNaNKeys test. + _keys.clear(); + _values.clear(); + _modCount++; + } +} + +class MapBaseMap = MapBase with MapBaseOperations; +class MapMixinMap = MapBaseOperations with MapMixin; + +class TestKeyIterable extends IterableBase { + final _map; + TestKeyIterable(this._map); + int get length => _map._keys.length; + Iterator get iterator => new TestKeyIterator(_map); +} + +class TestKeyIterator implements Iterator { + final _map; + final int _modCount; + int _index = 0; + var _current; + TestKeyIterator(map) + : _map = map, + _modCount = map._modCount; + bool moveNext() { + if (_modCount != _map._modCount) { + throw new ConcurrentModificationError(_map); + } + if (_index == _map._keys.length) { + _current = null; + return false; + } + _current = _map._keys[_index++]; + return true; + } + + K get current => _current; +} + +// Slow implementation of Map based on MapBase. +class UnmodifiableMapBaseMap extends UnmodifiableMapBase { + final List _keys = []; + final List _values = []; + UnmodifiableMapBaseMap(List pairs) { + for (int i = 0; i < pairs.length; i += 2) { + _keys.add(pairs[i]); + _values.add(pairs[i + 1]); + } + } + + int get _modCount => 0; + + V? operator [](Object? key) { + int index = _keys.indexOf(key as K); + if (index < 0) return null; + return _values[index]; + } + + Iterable get keys => _keys.skip(0); +} + +abstract class Super implements Comparable {} + +abstract class Interface implements Comparable {} + +class Sub extends Super implements Interface, Comparable { + int compareTo(dynamic other) => 0; + int get hashCode => 0; + bool operator ==(other) => other is Sub; +} + +expectMap(Map expect, Map actual) { + Expect.equals(expect.length, actual.length, "length"); + for (var key in expect.keys) { + Expect.isTrue(actual.containsKey(key), "containsKey $key"); + Expect.equals(expect[key], actual[key]); + } +} + +void testFrom() { + // Check contents. + for (var map in [ + {}, + {1: 1}, + {1: 2, 3: 4, 5: 6, 7: 8} + ]) { + expectMap(map, new Map.from(map)); + expectMap(map, new HashMap.from(map)); + expectMap(map, new LinkedHashMap.from(map)); + expectMap(map, new SplayTreeMap.from(map)); + } + // Test type combinations allowed. + Map intMap = {1: 2, 3: 4}; + Map numMap = {1: 2, 3: 4}; + expectMap(intMap, new Map.from(numMap)); + expectMap(intMap, new Map.from(intMap)); + expectMap(intMap, new HashMap.from(numMap)); + expectMap(intMap, new HashMap.from(intMap)); + expectMap(intMap, new LinkedHashMap.from(numMap)); + expectMap(intMap, new LinkedHashMap.from(intMap)); + expectMap(intMap, new SplayTreeMap.from(numMap)); + expectMap(intMap, new SplayTreeMap.from(intMap)); + + var sub = new Sub(); + Map superMap = {sub: sub}; + Map interfaceMap = {sub: sub}; + expectMap(superMap, new Map.from(interfaceMap)); + expectMap(superMap, new Map.from(superMap)); + expectMap(superMap, new HashMap.from(interfaceMap)); + expectMap(superMap, new HashMap.from(superMap)); + expectMap(superMap, new LinkedHashMap.from(interfaceMap)); + expectMap(superMap, new LinkedHashMap.from(superMap)); + expectMap(superMap, new SplayTreeMap.from(interfaceMap)); + expectMap(superMap, new SplayTreeMap.from(superMap)); +} + +void testTypeAnnotations(Map map) { + map[0] = 100; + map[999] = 101; + map[0x800000000] = 102; + map[0x20000000000000] = 103; + Expect.isFalse(map.containsKey("not an it")); + Expect.isNull(map.remove("not an it")); + + testLength(4, map); + Expect.equals(101, map.remove(999)); + testLength(3, map); + Expect.equals(102, map.remove(0x800000000)); + testLength(2, map); + Expect.equals(103, map.remove(0x20000000000000)); + testLength(1, map); +} + +void testUnmodifiableMaps() { + void checkUnmodifiable(Map map) { + Expect.throws(() => map[0] = 0); + Expect.throws(() => map.addAll({0: 0})); + Expect.throws(() => map.addEntries({0: 0}.entries)); + Expect.throws(() => map.clear()); + Expect.throws(() => map.putIfAbsent(0, () => 0)); + Expect.throws(() => map.remove(0)); + Expect.throws(() => map.removeWhere((k, v) => true)); + Expect.throws(() => map.update(0, (v) => v, ifAbsent: () => 0)); + Expect.throws(() => map.updateAll((k, v) => v)); + } + + checkUnmodifiable(const {1: 1}); + checkUnmodifiable(Map.unmodifiable({1: 1})); + checkUnmodifiable(UnmodifiableMapView({1: 1})); + checkUnmodifiable(const MapView({1: 1})); +} diff --git a/tests/corelib/map_to_string_test.dart b/tests/corelib/map_to_string_test.dart new file mode 100644 index 000000000000..8a50bf613586 --- /dev/null +++ b/tests/corelib/map_to_string_test.dart @@ -0,0 +1,32 @@ +// 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 "package:expect/expect.dart"; + +void main() { + Map m = new Map(); + + m[0] = 0; + m[1] = 1; + m[2] = m; + + Expect.equals('{0: 0, 1: 1, 2: {...}}', m.toString()); + + // Throwing in the middle of a toString does not leave the + // map as being visited + ThrowOnToString err = new ThrowOnToString(); + m[1] = err; + Expect.throws(m.toString, (e) => e == "Bad!"); + m[1] = 1; + Expect.equals('{0: 0, 1: 1, 2: {...}}', m.toString()); + m[err] = 1; + Expect.throws(m.toString, (e) => e == "Bad!"); + m.remove(err); +} + +class ThrowOnToString { + String toString() { + throw "Bad!"; + } +} diff --git a/tests/corelib/map_unmodifiable_cast_test.dart b/tests/corelib/map_unmodifiable_cast_test.dart new file mode 100644 index 000000000000..2eca99f6ae40 --- /dev/null +++ b/tests/corelib/map_unmodifiable_cast_test.dart @@ -0,0 +1,67 @@ +// 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. + +library map_unmodifiable_cast_test; + +import "package:expect/expect.dart"; +import 'dart:collection'; + +void main() { + testNum(const {1: 37}, "const"); + testNum(const {1: 37}.cast(), "const.cast"); + + testNum(new UnmodifiableMapView({1: 37}), "unmod"); + testNum(new UnmodifiableMapView({1: 37}), "unmod.cast"); + testNum(new UnmodifiableMapView({1: 37}).cast(), + "unmodView(num).cast"); + testNum(new UnmodifiableMapView({1: 37}).cast(), + "unmodView(int).cast"); + testNum( + new UnmodifiableMapView({1: 37}) + .cast(), + "unmodView(num).cast"); + testNum( + new UnmodifiableMapView({1: 37}) + .cast(), + "unmodView(int).cast"); + + var m2 = new Map.unmodifiable({1: 37}); + testNum(m2, "Map.unmod"); + testNum(m2.cast(), "Map.unmod.cast"); + + Map nsm = new NsmMap().foo(a: 0); + test(nsm, #a, 0, "nsm", noSuchMethodMap: true); + test(nsm.cast(), #a, 0, "nsm.cast", noSuchMethodMap: true); +} + +void testNum(Map map, String name) { + test(map, 1, 37, name); +} + +void test( + Map map, Object firstKey, Object firstValue, String name, + {bool noSuchMethodMap: false}) { + if (!noSuchMethodMap) { + Expect.isTrue(map.containsKey(firstKey), "$name.containsKey"); + Expect.equals(1, map.length, "$name.length"); + Expect.equals(firstKey, map.keys.first, "$name.keys.first"); + Expect.equals(firstValue, map.values.first, "$name.values.first"); + } + + Expect.throwsUnsupportedError(map.clear, "$name.clear"); + Expect.throwsUnsupportedError(() { + map.remove(firstKey); + }, "$name.remove"); + Expect.throwsUnsupportedError(() { + map[null] = null; + }, "$name[]="); + Expect.throwsUnsupportedError(() { + map.addAll({null: null}); + }, "$name.addAll"); +} + +class NsmMap { + noSuchMethod(i) => i.namedArguments; + foo({a, b, c, d}); +} diff --git a/tests/corelib/map_update_test.dart b/tests/corelib/map_update_test.dart new file mode 100644 index 000000000000..8bb85ed9ab91 --- /dev/null +++ b/tests/corelib/map_update_test.dart @@ -0,0 +1,212 @@ +// 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 "package:expect/expect.dart"; +import 'dart:collection'; +import 'dart:convert' show json; + +Map newJsonMap() => json.decode('{}'); +Map newJsonMapCustomReviver() => + json.decode('{}', reviver: (key, value) => value); + +void main() { + test({}); + test(new LinkedHashMap()); + test(new HashMap()); + test(new LinkedHashMap.identity()); + test(new HashMap.identity()); + test(new MapView(new HashMap())); + test(new MapBaseMap()); + test(new MapMixinMap()); + test(newJsonMap()); + test(newJsonMapCustomReviver()); + testNonNull(new SplayTreeMap()); + testNonNull(new SplayTreeMap((a, b) => Comparable.compare(a!, b!))); + testNonNull(new MapView(new SplayTreeMap())); +} + +void test(Map map) { + testNonNull(map); + + // Also works with null keys and values (omitted for splay-tree based maps) + map.clear(); + map.update(null, unreachable, ifAbsent: () => null); + Expect.mapEquals({null: null}, map); + map.update(null, (v) => "$v", ifAbsent: unreachable); + Expect.mapEquals({null: "null"}, map); + map.update(null, (v) => null, ifAbsent: unreachable); + Expect.mapEquals({null: null}, map); +} + +void testNonNull(Map map) { + // Only use literal String keys since JSON maps only accept strings, + // and literals works with identity-maps, and it's comparable for SplayTreeMap + // maps. + Expect.mapEquals({}, map); + map.update("key1", unreachable, ifAbsent: () => 42); + Expect.mapEquals({"key1": 42}, map); + map.clear(); + map["key1"] = 42; + map.update("key1", (v) => 1 + (v as int), ifAbsent: unreachable); + Expect.mapEquals({"key1": 43}, map); + map.clear(); + + // Operations on maps with multiple elements. + var multi = { + "k1": 1, + "k2": 2, + "k3": 3, + "k4": 4, + "k5": 5, + "k6": 6, + "k7": 7, + "k8": 8, + "k9": 9, + "k10": 10, + }; + map.addAll(multi); + Expect.mapEquals(multi, map); + map.update("k3", (v) => 13); + map.update("k6", (v) => 16); + map.update("k11", unreachable, ifAbsent: () => 21); + Expect.mapEquals({ + "k1": 1, + "k2": 2, + "k3": 13, + "k4": 4, + "k5": 5, + "k6": 16, + "k7": 7, + "k8": 8, + "k9": 9, + "k10": 10, + "k11": 21, + }, map); + + map.clear(); + map.updateAll((k, v) => throw "unreachable"); + Expect.mapEquals({}, map); + + map.addAll(multi); + map.updateAll((k, v) => "$k:$v"); + Expect.mapEquals({ + "k1": "k1:1", + "k2": "k2:2", + "k3": "k3:3", + "k4": "k4:4", + "k5": "k5:5", + "k6": "k6:6", + "k7": "k7:7", + "k8": "k8:8", + "k9": "k9:9", + "k10": "k10:10", + }, map); + + map.clear(); + Expect.throws( + () => map.update("key1", unreachable, ifAbsent: () => throw "expected"), + (t) => t == "expected"); + + map["key1"] = 42; + Expect.throws(() => map.update("key1", (_) => throw "expected"), + (t) => t == "expected"); + + // No ifAbsent means throw if key not there. + Expect.throws(() => map.update("key-not", unreachable), (e) => e is Error); + + // Works with null values. + map.clear(); + map.update("key1", unreachable, ifAbsent: () => null); + Expect.mapEquals({"key1": null}, map); + map.update("key1", (v) => "$v", ifAbsent: unreachable); + Expect.mapEquals({"key1": "null"}, map); + map.update("key1", (v) => null, ifAbsent: unreachable); + Expect.mapEquals({"key1": null}, map); +} + +// Slow implementation of Map based on MapBase. +abstract class MapBaseOperations { + final List _keys = []; + final List _values = []; + int _modCount = 0; + + V? operator [](Object? key) { + int index = _keys.indexOf(key); + if (index < 0) return null; + return _values[index]; + } + + Iterable get keys => new TestKeyIterable(this); + + void operator []=(K key, V value) { + int index = _keys.indexOf(key); + if (index >= 0) { + _values[index] = value; + } else { + _modCount++; + _keys.add(key); + _values.add(value); + } + } + + V? remove(Object? key) { + int index = _keys.indexOf(key); + if (index >= 0) { + var result = _values[index]; + key = _keys.removeLast(); + var value = _values.removeLast(); + if (index != _keys.length) { + _keys[index] = key; + _values[index] = value; + } + _modCount++; + return result; + } + return null; + } + + void clear() { + // Clear cannot be based on remove, since remove won't remove keys that + // are not equal to themselves. It will fail the testNaNKeys test. + _keys.clear(); + _values.clear(); + _modCount++; + } +} + +class MapBaseMap = MapBase with MapBaseOperations; +class MapMixinMap = MapBaseOperations with MapMixin; + +class TestKeyIterable extends IterableBase { + final _map; + TestKeyIterable(this._map); + int get length => _map._keys.length; + Iterator get iterator => new TestKeyIterator(_map); +} + +class TestKeyIterator implements Iterator { + final _map; + final int _modCount; + int _index = 0; + var _current; + TestKeyIterator(map) + : _map = map, + _modCount = map._modCount; + + bool moveNext() { + if (_modCount != _map._modCount) { + throw new ConcurrentModificationError(_map); + } + if (_index == _map._keys.length) { + _current = null; + return false; + } + _current = _map._keys[_index++]; + return true; + } + + K get current => _current; +} + +Null unreachable([_, __]) => throw "unreachable"; diff --git a/tests/corelib/map_values2_test.dart b/tests/corelib/map_values2_test.dart new file mode 100644 index 000000000000..5fc754e62ca6 --- /dev/null +++ b/tests/corelib/map_values2_test.dart @@ -0,0 +1,53 @@ +// 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 "package:expect/expect.dart"; + +main() { + var map1 = {"foo": 42, "bar": 499}; + var map2 = {}; + var map3 = const {"foo": 42, "bar": 499}; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.values is Iterable); + Expect.isFalse(map1.values is Iterable); + Expect.isFalse(map1.values is List); + Expect.equals(2, map1.values.length); + Expect.equals(42, map1.values.first); + Expect.equals(499, map1.values.last); + + Expect.isTrue(map2.values is Iterable); + Expect.isFalse(map2.values is Iterable); + Expect.isFalse(map2.values is List); + Expect.equals(0, map2.values.length); + + Expect.isTrue(map3.values is Iterable); + Expect.isFalse(map3.values is Iterable); + Expect.isFalse(map3.values is List); + Expect.equals(2, map3.values.length); + Expect.equals(42, map3.values.first); + Expect.equals(499, map3.values.last); + + Expect.isTrue(map4.values is Iterable); + Expect.isFalse(map4.values is Iterable); + Expect.isFalse(map4.values is List); + Expect.equals(0, map4.values.length); + + Expect.isTrue(map5.values is Iterable); + Expect.isFalse(map5.values is Iterable); + Expect.isFalse(map5.values is List); + Expect.equals(2, map5.values.length); + // new Map gives a LinkedHashMap, so we know the order. + Expect.isTrue(map5.values.first == 43); + Expect.isTrue(map5.values.last == 500); + + Expect.isTrue(map6.values is Iterable); + Expect.isFalse(map6.values is Iterable); + Expect.isFalse(map6.values is List); + Expect.equals(0, map6.values.length); +} diff --git a/tests/corelib/map_values3_test.dart b/tests/corelib/map_values3_test.dart new file mode 100644 index 000000000000..44c356ce67ea --- /dev/null +++ b/tests/corelib/map_values3_test.dart @@ -0,0 +1,53 @@ +// 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 "package:expect/expect.dart"; + +main() { + var map1 = {1: "42", 2: "499"}; + var map2 = {}; + var map3 = const {3: "42", 4: "499"}; + var map4 = const {}; + var map5 = new Map(); + map5[5] = "43"; + map5[6] = "500"; + var map6 = new Map(); + + Expect.isTrue(map1.values is Iterable); + Expect.isFalse(map1.values is Iterable); + Expect.isFalse(map1.values is List); + Expect.equals(2, map1.values.length); + Expect.equals("42", map1.values.first); + Expect.equals("499", map1.values.last); + + Expect.isTrue(map2.values is Iterable); + Expect.isFalse(map2.values is Iterable); + Expect.isFalse(map2.values is List); + Expect.equals(0, map2.values.length); + + Expect.isTrue(map3.values is Iterable); + Expect.isFalse(map3.values is Iterable); + Expect.isFalse(map3.values is List); + Expect.equals(2, map3.values.length); + Expect.equals("42", map3.values.first); + Expect.equals("499", map3.values.last); + + Expect.isTrue(map4.values is Iterable); + Expect.isFalse(map4.values is Iterable); + Expect.isFalse(map4.values is List); + Expect.equals(0, map4.values.length); + + Expect.isTrue(map5.values is Iterable); + Expect.isFalse(map5.values is Iterable); + Expect.isFalse(map5.values is List); + Expect.equals(2, map5.values.length); + // new Map gives a LinkedHashMap, so we know the order. + Expect.isTrue(map5.values.first == "43"); + Expect.isTrue(map5.values.last == "500"); + + Expect.isTrue(map6.values is Iterable); + Expect.isFalse(map6.values is Iterable); + Expect.isFalse(map6.values is List); + Expect.equals(0, map6.values.length); +} diff --git a/tests/corelib/map_values4_test.dart b/tests/corelib/map_values4_test.dart new file mode 100644 index 000000000000..4f99056128d5 --- /dev/null +++ b/tests/corelib/map_values4_test.dart @@ -0,0 +1,15 @@ +// 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 "package:expect/expect.dart"; + +// Dart2js had a bug where the type information was not set correctly if the +// generic type of the map was not directly used (but only indirectly through +// map.values). + +main() { + var map1 = {1: "42", 2: "499"}; + Expect.isTrue(map1.values is Iterable); + Expect.isFalse(map1.values is Iterable); +} diff --git a/tests/corelib/map_values_test.dart b/tests/corelib/map_values_test.dart new file mode 100644 index 000000000000..e5c367080e01 --- /dev/null +++ b/tests/corelib/map_values_test.dart @@ -0,0 +1,47 @@ +// 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 "package:expect/expect.dart"; + +main() { + var map1 = {"foo": 42, "bar": 499}; + var map2 = {}; + var map3 = const {"foo": 42, "bar": 499}; + var map4 = const {}; + var map5 = new Map(); + map5["foo"] = 43; + map5["bar"] = 500; + var map6 = new Map(); + + Expect.isTrue(map1.values is Iterable); + Expect.isFalse(map1.values is List); + Expect.equals(2, map1.values.length); + Expect.equals(42, map1.values.first); + Expect.equals(499, map1.values.last); + + Expect.isTrue(map2.values is Iterable); + Expect.isFalse(map2.values is List); + Expect.equals(0, map2.values.length); + + Expect.isTrue(map3.values is Iterable); + Expect.isFalse(map3.values is List); + Expect.equals(2, map3.values.length); + Expect.equals(42, map3.values.first); + Expect.equals(499, map3.values.last); + + Expect.isTrue(map4.values is Iterable); + Expect.isFalse(map4.values is List); + Expect.equals(0, map4.values.length); + + Expect.isTrue(map5.values is Iterable); + Expect.isFalse(map5.values is List); + Expect.equals(2, map5.values.length); + Expect.isTrue(map5.values.first == 43 || map5.values.first == 500); + Expect.isTrue(map5.values.last == 43 || map5.values.last == 500); + Expect.notEquals(map5.values.first, map5.values.last); + + Expect.isTrue(map6.values is Iterable); + Expect.isFalse(map6.values is List); + Expect.equals(0, map6.values.length); +} diff --git a/tests/corelib/nan_infinity_test.dart b/tests/corelib/nan_infinity_test.dart new file mode 100644 index 000000000000..b90e11463973 --- /dev/null +++ b/tests/corelib/nan_infinity_test.dart @@ -0,0 +1,90 @@ +// 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 "package:expect/expect.dart"; + +// Dart test program for testing NaN and Infinity. + +void main() { + // Sanity tests. + Expect.isFalse(1.5.isNaN); + Expect.isFalse(1.5.isInfinite); + Expect.isTrue(1.5.isFinite); + Expect.isFalse(1.5.isNegative); + Expect.isTrue((-1.5).isNegative); + Expect.isFalse(0.0.isNegative); + Expect.isTrue((-0.0).isNegative); + Expect.isTrue((-0.0).isFinite); + + Expect.isFalse(1.isNaN); + Expect.isFalse(1.isInfinite); + Expect.isTrue(1.isFinite); + Expect.isFalse(1.isNegative); + Expect.isTrue((-1).isNegative); + + // Test that predicates give the correct result. + Expect.isTrue(double.nan.isNaN); + Expect.isFalse(double.nan.isInfinite); + Expect.isFalse(double.nan.isFinite); + Expect.isFalse(double.nan.isNegative); + Expect.isFalse((-double.nan).isNegative); + + Expect.isFalse(double.infinity.isNaN); + Expect.isTrue(double.infinity.isInfinite); + Expect.isFalse(double.infinity.isFinite); + Expect.isFalse(double.infinity.isNegative); + Expect.isTrue((-double.infinity).isNegative); + + Expect.isFalse(double.negativeInfinity.isNaN); + Expect.isTrue(double.negativeInfinity.isInfinite); + Expect.isFalse(double.negativeInfinity.isFinite); + Expect.isTrue(double.negativeInfinity.isNegative); + Expect.isFalse((-double.negativeInfinity).isNegative); + + // Test toString. + Expect.equals("NaN", double.nan.toString()); + Expect.equals("Infinity", double.infinity.toString()); + Expect.equals("-Infinity", double.negativeInfinity.toString()); + + // Test identities. + Expect.isTrue(identical(double.nan, double.nan)); // //# 01: ok + Expect.isTrue(identical(double.infinity, double.infinity)); + Expect.isTrue(identical(double.negativeInfinity, double.negativeInfinity)); + Expect.isFalse(identical(double.nan, double.infinity)); + Expect.isFalse(identical(double.nan, double.negativeInfinity)); + Expect.isFalse(identical(double.infinity, double.negativeInfinity)); + Expect.isFalse(identical(double.nan, -double.nan)); + Expect.isTrue(identical(double.infinity, -double.negativeInfinity)); + Expect.isTrue(identical(double.negativeInfinity, -double.infinity)); + + // Test equalities + Expect.isTrue(double.infinity == double.infinity); + Expect.isTrue(double.negativeInfinity == double.negativeInfinity); + Expect.isFalse(double.infinity == double.negativeInfinity); + Expect.isFalse(double.negativeInfinity == double.infinity); + Expect.isFalse(double.nan == double.nan); + Expect.isFalse(double.nan == double.infinity); + Expect.isFalse(double.nan == double.negativeInfinity); + Expect.isFalse(double.infinity == double.nan); + Expect.isFalse(double.negativeInfinity == double.nan); + + // Test relational order. + Expect.isFalse(double.nan < double.nan); + Expect.isFalse(double.nan < double.infinity); + Expect.isFalse(double.nan < double.negativeInfinity); + Expect.isFalse(double.nan > double.nan); + Expect.isFalse(double.nan > double.infinity); + Expect.isFalse(double.nan > double.negativeInfinity); + Expect.isFalse(double.infinity < double.nan); + Expect.isFalse(double.negativeInfinity < double.nan); + Expect.isFalse(double.infinity > double.nan); + Expect.isFalse(double.negativeInfinity > double.nan); + Expect.isTrue(double.infinity > double.negativeInfinity); + Expect.isFalse(double.infinity < double.negativeInfinity); + + // NaN is contagious. + Expect.isTrue((3.0 * double.nan).isNaN); + Expect.isTrue((3.0 + double.nan).isNaN); + Expect.isTrue((-double.nan).isNaN); +} diff --git a/tests/corelib/nsm_invocation_generic_test.dart b/tests/corelib/nsm_invocation_generic_test.dart new file mode 100644 index 000000000000..ba64f570fbc5 --- /dev/null +++ b/tests/corelib/nsm_invocation_generic_test.dart @@ -0,0 +1,78 @@ +// 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 "package:expect/expect.dart"; + +// Test the invocations passed to noSuchMethod for generic invocations. + +main() { + var argument = new Object(); + var argument2 = new Object(); + // Method invocation. + expectInvocation( + new Invocation.genericMethod(#name, [int], []), nsm.name()); + expectInvocation(new Invocation.genericMethod(#name, [int], [argument]), + nsm.name(argument)); + expectInvocation( + new Invocation.genericMethod(#name, [int], [], {#arg: argument}), + nsm.name(arg: argument)); + expectInvocation( + new Invocation.genericMethod(#name, [int], [argument], {#arg: argument2}), + nsm.name(argument, arg: argument2)); + // Call invocation. + expectInvocation(new Invocation.genericMethod(#call, [int], []), nsm()); + expectInvocation(new Invocation.genericMethod(#call, [int], [argument]), + nsm(argument)); + expectInvocation( + new Invocation.genericMethod(#call, [int], [], {#arg: argument}), + nsm(arg: argument)); + expectInvocation( + new Invocation.genericMethod(#call, [int], [argument], {#arg: argument2}), + nsm(argument, arg: argument2)); +} + +dynamic nsm = new Recorder(); + +class Recorder { + noSuchMethod(Invocation invocation) { + return invocation; + } +} + +void checkUnmodifiableList(List list) { + if (list.isNotEmpty) { + Expect.throws(() { + list[0] = null; + }); + } + Expect.throws(() { + list.add(null); + }); +} + +void checkUnmodifiableMap(Map map) { + Expect.throws(() { + map[#key] = null; + }); +} + +expectInvocation(Invocation expect, Invocation actual) { + Expect.equals(expect.isGetter, actual.isGetter, "isGetter"); + Expect.equals(expect.isSetter, actual.isSetter, "isSetter"); + Expect.equals(expect.isAccessor, actual.isAccessor, "isAccessor"); + Expect.equals(actual.isGetter || actual.isSetter, actual.isAccessor); + Expect.equals(expect.isMethod, actual.isMethod, "isMethod"); + Expect.isTrue(actual.isMethod || actual.isGetter || actual.isSetter); + Expect.isFalse(actual.isMethod && actual.isGetter); + Expect.isFalse(actual.isMethod && actual.isSetter); + Expect.isFalse(actual.isSetter && actual.isGetter); + Expect.equals(expect.memberName, actual.memberName, "memberName"); + Expect.listEquals(expect.typeArguments, actual.typeArguments, "types"); + Expect.listEquals( + expect.positionalArguments, actual.positionalArguments, "positional"); + Expect.mapEquals(expect.namedArguments, actual.namedArguments, "named"); + checkUnmodifiableList(actual.typeArguments); + checkUnmodifiableList(actual.positionalArguments); + checkUnmodifiableMap(actual.namedArguments); +} diff --git a/tests/corelib/nsm_invocation_test.dart b/tests/corelib/nsm_invocation_test.dart new file mode 100644 index 000000000000..4c4f3663c31d --- /dev/null +++ b/tests/corelib/nsm_invocation_test.dart @@ -0,0 +1,88 @@ +// 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 "package:expect/expect.dart"; + +// Tests the constructors of the Invocation class. + +main() { + var argument = new Object(); + var argument2 = new Object(); + // Getter Invocation. + expectInvocation(new Invocation.getter(#name), nsm.name); + // Setter Invocation. + expectInvocation(new Invocation.setter(const Symbol("name="), argument), + (nsm..name = argument).last); + // Method invocation. + expectInvocation(new Invocation.method(#name, []), nsm.name()); + expectInvocation( + new Invocation.method(#name, [argument]), nsm.name(argument)); + expectInvocation(new Invocation.method(#name, [], {#arg: argument}), + nsm.name(arg: argument)); + expectInvocation(new Invocation.method(#name, [argument], {#arg: argument2}), + nsm.name(argument, arg: argument2)); + // Operator invocation. + expectInvocation(new Invocation.method(#+, [argument]), nsm + argument); + expectInvocation(new Invocation.method(#-, [argument]), nsm - argument); + expectInvocation(new Invocation.method(#~, []), ~nsm); + expectInvocation(new Invocation.method(Symbol.unaryMinus, []), -nsm); + expectInvocation(new Invocation.method(#[], [argument]), nsm[argument]); + nsm[argument] = argument2; + expectInvocation( + new Invocation.method(#[]=, [argument, argument2]), nsm.last); + // Call invocation. + expectInvocation(new Invocation.method(#call, []), nsm()); + expectInvocation(new Invocation.method(#call, [argument]), nsm(argument)); + expectInvocation( + new Invocation.method(#call, [], {#arg: argument}), nsm(arg: argument)); + expectInvocation(new Invocation.method(#call, [argument], {#arg: argument2}), + nsm(argument, arg: argument2)); +} + +dynamic nsm = new Recorder(); + +class Recorder { + Invocation? last; + noSuchMethod(Invocation invocation) { + last = invocation; + return invocation; + } +} + +void checkUnmodifiableList(List list) { + if (list.isNotEmpty) { + Expect.throws(() { + list[0] = null; + }); + } + Expect.throws(() { + list.add(null); + }); +} + +void checkUnmodifiableMap(Map map) { + Expect.throws(() { + map[#key] = null; + }); +} + +expectInvocation(Invocation expect, Invocation actual) { + Expect.equals(expect.isGetter, actual.isGetter, "isGetter"); + Expect.equals(expect.isSetter, actual.isSetter, "isSetter"); + Expect.equals(expect.isAccessor, actual.isAccessor, "isAccessor"); + Expect.equals(actual.isGetter || actual.isSetter, actual.isAccessor); + Expect.equals(expect.isMethod, actual.isMethod, "isMethod"); + Expect.isTrue(actual.isMethod || actual.isGetter || actual.isSetter); + Expect.isFalse(actual.isMethod && actual.isGetter); + Expect.isFalse(actual.isMethod && actual.isSetter); + Expect.isFalse(actual.isSetter && actual.isGetter); + Expect.equals(expect.memberName, actual.memberName, "memberName"); + Expect.listEquals(expect.typeArguments, actual.typeArguments, "types"); + Expect.listEquals( + expect.positionalArguments, actual.positionalArguments, "positional"); + Expect.mapEquals(expect.namedArguments, actual.namedArguments, "named"); + checkUnmodifiableList(actual.typeArguments); + checkUnmodifiableList(actual.positionalArguments); + checkUnmodifiableMap(actual.namedArguments); +} diff --git a/tests/corelib/null_nosuchmethod_test.dart b/tests/corelib/null_nosuchmethod_test.dart new file mode 100644 index 000000000000..37ff4171f81c --- /dev/null +++ b/tests/corelib/null_nosuchmethod_test.dart @@ -0,0 +1,35 @@ +// Copyright (c) 2012, 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"; + +// Test that Null's noSuchMethod can be closurized and called directly. + +class InvocationFactory { + static final dynamic instance = new InvocationFactory(); + noSuchMethod(i) => i; +} + +main() { + dynamic x; + // Non-existing method calls noSuchMethod. + Expect.throwsNoSuchMethodError(() => x.foo()); + + var invocation = InvocationFactory.instance.foo; + + // Calling noSuchMethod directly. + Expect.throwsNoSuchMethodError(() => x.noSuchMethod(invocation, [])); + + // Closurizing noSuchMethod and calling it. + dynamic nsm = x.noSuchMethod; + Expect.notEquals(null, nsm); + Expect.throwsTypeError(() => nsm("foo")); + + Expect.throwsNoSuchMethodError(() => nsm(invocation)); + Expect.throwsNoSuchMethodError( + () => nsm(invocation, [])); // wrong number of args + + // Wrong number and type of arguments. + Expect.throwsNoSuchMethodError(() => nsm("foo", [])); //# 01: ok +} diff --git a/tests/corelib/null_test.dart b/tests/corelib/null_test.dart new file mode 100644 index 000000000000..994ca40d39ef --- /dev/null +++ b/tests/corelib/null_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2012, 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"; + +// Test that Null inherits properties from Object. + +main() { + var x; + + Expect.isTrue(x is Object); + Expect.isTrue(x is dynamic); + Expect.isTrue(x is! String); + Expect.isTrue(x is! int); + + // These shouldn't throw. + x.runtimeType; + x.toString(); + x.hashCode; + + // operator== is inherited from Object. It's the same as identical. + // It's not really testable. + Expect.isTrue(identical(x, null)); + Expect.isTrue(x == null); + + // Methods can be closurized and yields the same result. + var ts = x.toString; + Expect.equals(null.toString(), ts()); + + // noSuchMethod is tested in null_nosuchmethod_test.dart. +} diff --git a/tests/corelib/num_clamp_test.dart b/tests/corelib/num_clamp_test.dart new file mode 100644 index 000000000000..a9b650f5de4e --- /dev/null +++ b/tests/corelib/num_clamp_test.dart @@ -0,0 +1,67 @@ +// Copyright (c) 2012, 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. +// Test num.clamp. + +import "package:expect/expect.dart"; + +testIntClamp() { + Expect.equals(2, 2.clamp(1, 3)); + Expect.equals(1, 0.clamp(1, 3)); + Expect.equals(3, 4.clamp(1, 3)); + Expect.equals(-2, (-2).clamp(-3, -1)); + Expect.equals(-1, 0.clamp(-3, -1)); + Expect.equals(-3, (-4).clamp(-3, -1)); + Expect.equals(0, 1.clamp(0, 0)); + Expect.equals(0, (-1).clamp(0, 0)); + Expect.equals(0, 0.clamp(0, 0)); + Expect.throwsArgumentError(() => 0.clamp(0, -1)); +} + +testDoubleClamp() { + Expect.equals(2.0, 2.clamp(1.0, 3.0)); + Expect.equals(1.0, 0.clamp(1.0, 3.0)); + Expect.equals(3.0, 4.clamp(1.0, 3.0)); + Expect.equals(-2.0, (-2.0).clamp(-3.0, -1.0)); + Expect.equals(-1.0, 0.0.clamp(-3.0, -1.0)); + Expect.equals(-3.0, (-4.0).clamp(-3.0, -1.0)); + Expect.equals(0.0, 1.0.clamp(0.0, 0.0)); + Expect.equals(0.0, (-1.0).clamp(0.0, 0.0)); + Expect.equals(0.0, 0.0.clamp(0.0, 0.0)); + Expect.throwsArgumentError(() => 0.0.clamp(0.0, -1.0)); +} + +testDoubleClampInt() { + Expect.equals(2.0, 2.0.clamp(1, 3)); + Expect.equals(1, 0.0.clamp(1, 3)); + Expect.isTrue(0.0.clamp(1, 3) is int); + Expect.equals(3, 4.0.clamp(1, 3)); + Expect.isTrue(4.0.clamp(1, 3) is int); + Expect.equals(-2.0, (-2.0).clamp(-3, -1)); + Expect.equals(-1, 0.0.clamp(-3, -1)); + Expect.isTrue(0.0.clamp(-3, -1) is int); + Expect.equals(-3, (-4.0).clamp(-3, -1)); + Expect.isTrue((-4.0).clamp(-3, -1) is int); + Expect.equals(0, 1.0.clamp(0, 0)); + Expect.isTrue(1.0.clamp(0, 0) is int); + Expect.equals(0, (-1.0).clamp(0, 0)); + Expect.isTrue((-1.0).clamp(0, 0) is int); + Expect.equals(0.0, 0.0.clamp(0, 0)); + Expect.isTrue(0.0.clamp(0, 0) is double); + Expect.throwsArgumentError(() => 0.0.clamp(0, -1)); +} + +testDoubleClampExtremes() { + Expect.equals(2.0, 2.0.clamp(-double.infinity, double.infinity)); + Expect.equals(2.0, 2.0.clamp(-double.infinity, double.nan)); + Expect.equals(double.infinity, 2.0.clamp(double.infinity, double.nan)); + Expect.isTrue(2.0.clamp(double.nan, double.nan).isNaN); + Expect.throwsArgumentError(() => 0.0.clamp(double.nan, double.infinity)); +} + +main() { + testIntClamp(); + testDoubleClamp(); + testDoubleClampInt(); + testDoubleClampExtremes(); +} diff --git a/tests/corelib/num_parse_test.dart b/tests/corelib/num_parse_test.dart new file mode 100644 index 000000000000..b1049e520c94 --- /dev/null +++ b/tests/corelib/num_parse_test.dart @@ -0,0 +1,234 @@ +// 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 "package:expect/expect.dart"; + +const whiteSpace = const [ + "", + "\x09", + "\x0a", + "\x0b", + "\x0c", + "\x0d", + "\x85", + "\xa0", + "\u1680", + "\u2000", + "\u2001", + "\u2002", + "\u2003", + "\u2004", + "\u2005", + "\u2006", + "\u2007", + "\u2008", + "\u2009", + "\u200a", + "\u2028", + "\u2029", + "\u202f", + "\u205f", + "\u3000", + "\uFEFF" +]; + +void expectNumEquals(num expect, num actual, String message) { + if (expect is double && expect.isNaN) { + Expect.isTrue(actual is double && actual.isNaN, "isNaN: $message"); + } else { + Expect.identical(expect, actual, message); + } +} + +// Test source surrounded by any combination of whitespace. +void testParseAllWhitespace(String source, num result) { + for (String ws1 in whiteSpace) { + for (String ws2 in whiteSpace) { + String padded = "$ws1$source$ws2"; + // Use Expect.identical because it also handles NaN and 0.0/-0.0. + // Except on dart2js: http://dartbug.com/11551 + expectNumEquals(result, num.parse(padded), "parse '$padded'"); + padded = "$ws1$ws2$source"; + expectNumEquals(result, num.parse(padded), "parse '$padded'"); + padded = "$source$ws1$ws2"; + expectNumEquals(result, num.parse(padded), "parse '$padded'"); + } + } +} + +// Test source and -source surrounded by any combination of whitespace. +void testParseWhitespace(String source, num result) { + assert(result >= 0); + testParseAllWhitespace(source, result); + testParseAllWhitespace("-$source", -result); +} + +// Test parsing source, optionally preceeded and/or followed by whitespace. +void testParse(String source, num result) { + expectNumEquals(result, num.parse(source), "parse '$source'"); + expectNumEquals(result, num.parse(" $source"), "parse ' $source'"); + expectNumEquals(result, num.parse("$source "), "parse '$source '"); + expectNumEquals(result, num.parse(" $source "), "parse ' $source '"); +} + +// Test parsing an integer in decimal or hex format, with or without signs. +void testInt(int value) { + testParse("$value", value); + testParse("+$value", value); + testParse("-$value", -value); + var hex = "0x${value.toRadixString(16)}"; + var lchex = hex.toLowerCase(); + testParse(lchex, value); + testParse("+$lchex", value); + testParse("-$lchex", -value); + var uchex = hex.toUpperCase(); + testParse(uchex, value); + testParse("+$uchex", value); + testParse("-$uchex", -value); +} + +// Test parsing an integer, and the integers just around it. +void testIntAround(int value) { + testInt(value - 1); + testInt(value); + testInt(value + 1); +} + +void testDouble(double value) { + testParse("$value", value); + testParse("+$value", value); + testParse("-$value", -value); + if (value.isFinite) { + String exp = value.toStringAsExponential(); + String lcexp = exp.toLowerCase(); + testParse(lcexp, value); + testParse("+$lcexp", value); + testParse("-$lcexp", -value); + String ucexp = exp.toUpperCase(); + testParse(ucexp, value); + testParse("+$ucexp", value); + testParse("-$ucexp", -value); + } +} + +void testFail(String source) { + var object = new Object(); + Expect.throws(() { + num.parse(source, (s) { + Expect.equals(source, s); + throw object; + }); + }, (e) => identical(object, e), "Fail: '$source'"); +} + +void main() { + testInt(0); + testInt(1); + testInt(9); + testInt(10); + testInt(99); + testInt(100); + testIntAround(256); + testIntAround(0x80000000); // 2^31 + testIntAround(0x100000000); // 2^32 + testIntAround(0x10000000000000); // 2^52 + testIntAround(0x20000000000000); // 2^53 + testIntAround(0x40000000000000); // 2^54 + // 0x7ffffffffffffffe on int-is-64-bit implementations, rounded up on + // int-is-double implementations. + testIntAround(0x7ffffffffffff000 + 0xffe); // 2^63 + + testDouble(0.0); + testDouble(5e-324); + testDouble(2.225073858507201e-308); + testDouble(2.2250738585072014e-308); + testDouble(0.49999999999999994); + testDouble(0.5); + testDouble(0.50000000000000006); + testDouble(0.9999999999999999); + testDouble(1.0); + testDouble(1.0000000000000002); + testDouble(4294967295.0); + testDouble(4294967296.0); + testDouble(4503599627370495.5); + testDouble(4503599627370497.0); + testDouble(9007199254740991.0); + testDouble(9007199254740992.0); + testDouble(1.7976931348623157e+308); + testDouble(double.infinity); + testDouble(double.nan); // //# 01: ok + + // Strings that cannot occur from toString of a number. + testParse("000000000000", 0); + testParse("000000000001", 1); + testParse("000000000000.0000000000000", 0.0); + testParse("000000000001.0000000000000", 1.0); + testParse("0x0000000000", 0); + testParse("0e0", 0.0); + testParse("0e+0", 0.0); + testParse("0e-0", 0.0); + testParse("-0e0", -0.0); + testParse("-0e+0", -0.0); + testParse("-0e-0", -0.0); + testParse("1e0", 1.0); + testParse("1e+0", 1.0); + testParse("1e-0", 1.0); + testParse("-1e0", -1.0); + testParse("-1e+0", -1.0); + testParse("-1e-0", -1.0); + testParse("1.", 1.0); + testParse(".1", 0.1); + testParse("1.e1", 10.0); + testParse(".1e1", 1.0); + + testParseWhitespace("0x1", 1); + testParseWhitespace("1", 1); + testParseWhitespace("1.0", 1.0); + testParseWhitespace("1e1", 10.0); + testParseWhitespace(".1e1", 1.0); + testParseWhitespace("1.e1", 10.0); + testParseWhitespace("1e+1", 10.0); + testParseWhitespace("1e-1", 0.1); + + // Negative tests - things not to allow. + + // Spaces inside the numeral. + testFail("- 1"); + testFail("+ 1"); + testFail("2 2"); + testFail("0x 42"); + testFail("1 ."); + testFail(". 1"); + testFail("1e 2"); + testFail("1 e2"); + // Invalid characters. + testFail("0x1H"); + testFail("12H"); + testFail("1x2"); + testFail("00x2"); + testFail("0x2.2"); + // Empty hex number. + testFail("0x"); + testFail("-0x"); + testFail("+0x"); + // Double exponent without value. + testFail(".e1"); + testFail("e1"); + testFail("e+1"); + testFail("e-1"); + testFail("-e1"); + testFail("-e+1"); + testFail("-e-1"); + // Incorrect ways to write NaN/Infinity. + testFail("infinity"); + testFail("INFINITY"); + testFail("1.#INF"); + testFail("inf"); + testFail("nan"); + testFail("NAN"); + testFail("1.#IND"); + testFail("indef"); + testFail("qnan"); + testFail("snan"); +} diff --git a/tests/corelib/num_sign_test.dart b/tests/corelib/num_sign_test.dart new file mode 100644 index 000000000000..db5f4976e769 --- /dev/null +++ b/tests/corelib/num_sign_test.dart @@ -0,0 +1,106 @@ +// 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. +// Test num.clamp. +// VMOptions=--no-use-field-guards +// VMOptions= + +import "package:expect/expect.dart"; + +// Pedestrian implementation of sign, following its specification directly. +num sign(num value) { + if (value is int) { + if (value < 0) return -1; + if (value > 0) return 1; + return 0; + } + if (value.isNaN) return value; + if (value == 0.0) return value; + if (value > 0.0) return 1.0; + return -1.0; +} + +var numbers = [ + // Integers + 0, + 1, + 2, + 0x7f, // ~7 bits + 0x80, + 0xff, // ~8 bits + 0x100, + 0xffff, // ~16 bits + 0x10000, + 0x3fffffff, // ~30 bits (max positive 32-bit tagged smi) + 0x40000000, + 0x40000001, + 0x7fffffff, // ~31 bits + 0x80000000, + 0x80000001, + 0xfffffffff, // ~32 bits + 0x100000000, + 0x100000001, + 0x10000000000000, // ~53 bits + 0x10000000000001, + 0x1fffffffffffff, + 0x20000000000000, + // Use arithmetic to construct values below since they are not valid 'web + // integers'. On platforms that use doubles to represent integers, there will + // be some rounding in the arithmetic, testing a nearby value instead. + 0x20000000000000 + 1, // first integer not representable as double. + 0x20000000000000 + 2, + 0x7ffffffffffff000 + 0xfff, // ~63 bits + 0x8000000000000000, + 0x8000000000000000 + 1, + 0xfffffffffffff000 + 0xfff, // ~64 bits + // Doubles. + 0.0, + 5e-324, // min positive + 2.225073858507201e-308, // max denormal + 2.2250738585072014e-308, // min normal + 0.49999999999999994, // ~0.5 + 0.5, + 0.5000000000000001, + 0.9999999999999999, // ~1.0 + 1.0, + 1.0000000000000002, + 4294967295.0, // ~32 bits + 4294967296.0, + 4503599627370495.5, // max fractional + 4503599627370497.0, + 9007199254740991.0, + 9007199254740992.0, // max exact (+1 is not a double) + 1.7976931348623157e+308, // max finite double + 1.0 / 0.0, // Infinity + 0.0 / 0.0, // NaN +]; + +main() { + for (num number in numbers) { + test(number); + test(-number); + } +} + +void test(number) { + num expectSign = sign(number); + num actualSign = number.sign; + if (expectSign.isNaN) { + Expect.isTrue(actualSign.isNaN, "$number: $actualSign != NaN"); + } else { + if (number is int) { + Expect.isTrue(actualSign is int, "$number.sign is int"); + } else { + Expect.isTrue(actualSign is double, "$number.sign is double"); + } + Expect.equals(expectSign, actualSign, "$number"); + Expect.equals(number.isNegative, actualSign.isNegative, "$number:negative"); + var renumber = actualSign * number.abs(); + Expect.equals(number, renumber, "$number (sign*abs)"); + if (number is int) { + Expect.isTrue(renumber is int, "$number (sign*abs) is int"); + } else { + Expect.isTrue(renumber is double, "$number (sign*abs) is double"); + } + } +} diff --git a/tests/corelib/num_try_parse_test.dart b/tests/corelib/num_try_parse_test.dart new file mode 100644 index 000000000000..ccf634eaafc4 --- /dev/null +++ b/tests/corelib/num_try_parse_test.dart @@ -0,0 +1,222 @@ +// 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 "package:expect/expect.dart"; + +const whiteSpace = const [ + "", + "\x09", + "\x0a", + "\x0b", + "\x0c", + "\x0d", + "\xa0", + "\u1680", + "\u2000", + "\u2001", + "\u2002", + "\u2003", + "\u2004", + "\u2005", + "\u2006", + "\u2007", + "\u2008", + "\u2009", + "\u200a", + "\u2028", + "\u2029", + "\u202f", + "\u205f", + "\u3000", + "\uFEFF" +]; + +void expectNumEquals(num expect, num? actual, String message) { + if (expect is double && expect.isNaN) { + Expect.isTrue(actual is double && actual.isNaN, "isNaN: $message"); + } else { + Expect.identical(expect, actual, message); + } +} + +// Test source surrounded by any combination of whitespace. +void testParseAllWhitespace(String source, num result) { + for (String ws1 in whiteSpace) { + for (String ws2 in whiteSpace) { + String padded = "$ws1$source$ws2"; + // Use Expect.identical because it also handles NaN and 0.0/-0.0. + // Except on dart2js: http://dartbug.com/11551 + expectNumEquals(result, num.parse(padded), "parse '$padded'"); + padded = "$ws1$ws2$source"; + expectNumEquals(result, num.parse(padded), "parse '$padded'"); + padded = "$source$ws1$ws2"; + expectNumEquals(result, num.parse(padded), "parse '$padded'"); + } + } +} + +// Test source and -source surrounded by any combination of whitespace. +void testParseWhitespace(String source, num result) { + assert(result >= 0); + testParseAllWhitespace(source, result); + testParseAllWhitespace("-$source", -result); +} + +void testParse(String source, num result) { + expectNumEquals(result, num.tryParse(source), "parse '$source'"); + expectNumEquals(result, num.tryParse(" $source"), "parse ' $source'"); + expectNumEquals(result, num.tryParse("$source "), "parse '$source '"); + expectNumEquals(result, num.tryParse(" $source "), "parse ' $source '"); +} + +// Test parsing an integer in decimal or hex format, with or without signs. +void testInt(int value) { + testParse("$value", value); + testParse("+$value", value); + testParse("-$value", -value); + var hex = "0x${value.toRadixString(16)}"; + var lchex = hex.toLowerCase(); + testParse(lchex, value); + testParse("+$lchex", value); + testParse("-$lchex", -value); + var uchex = hex.toUpperCase(); + testParse(uchex, value); + testParse("+$uchex", value); + testParse("-$uchex", -value); +} + +// Test parsing an integer, and the integers just around it. +void testIntAround(int value) { + testInt(value - 1); + testInt(value); + testInt(value + 1); +} + +void testDouble(double value) { + testParse("$value", value); + testParse("+$value", value); + testParse("-$value", -value); + if (value.isFinite) { + String exp = value.toStringAsExponential(); + String lcexp = exp.toLowerCase(); + testParse(lcexp, value); + testParse("+$lcexp", value); + testParse("-$lcexp", -value); + String ucexp = exp.toUpperCase(); + testParse(ucexp, value); + testParse("+$ucexp", value); + testParse("-$ucexp", -value); + } +} + +void testFail(String source) { + Expect.isNull(num.tryParse(source)); +} + +void main() { + testInt(0); + testInt(1); + testInt(9); + testInt(10); + testInt(99); + testInt(100); + testIntAround(256); + testIntAround(0x80000000); // 2^31 + testIntAround(0x100000000); // 2^32 + testIntAround(0x10000000000000); // 2^52 + testIntAround(0x1FFFFFFFFFFFFF); // 2^53 - 1 + + testDouble(0.0); + testDouble(5e-324); + testDouble(2.225073858507201e-308); + testDouble(2.2250738585072014e-308); + testDouble(0.49999999999999994); + testDouble(0.5); + testDouble(0.50000000000000006); + testDouble(0.9999999999999999); + testDouble(1.0); + testDouble(1.0000000000000002); + testDouble(4294967295.0); + testDouble(4294967296.0); + testDouble(4503599627370495.5); + testDouble(4503599627370497.0); + testDouble(9007199254740991.0); + testDouble(9007199254740992.0); + testDouble(1.7976931348623157e+308); + testDouble(double.infinity); + testDouble(double.nan); + + // Strings that cannot occur from toString of a number. + testParse("000000000000", 0); + testParse("000000000001", 1); + testParse("000000000000.0000000000000", 0.0); + testParse("000000000001.0000000000000", 1.0); + testParse("0x0000000000", 0); + testParse("0e0", 0.0); + testParse("0e+0", 0.0); + testParse("0e-0", 0.0); + testParse("-0e0", -0.0); + testParse("-0e+0", -0.0); + testParse("-0e-0", -0.0); + testParse("1e0", 1.0); + testParse("1e+0", 1.0); + testParse("1e-0", 1.0); + testParse("-1e0", -1.0); + testParse("-1e+0", -1.0); + testParse("-1e-0", -1.0); + testParse("1.", 1.0); + testParse(".1", 0.1); + testParse("1.e1", 10.0); + testParse(".1e1", 1.0); + + testParseWhitespace("0x1", 1); + testParseWhitespace("1", 1); + testParseWhitespace("1.0", 1.0); + testParseWhitespace("1e1", 10.0); + testParseWhitespace(".1e1", 1.0); + testParseWhitespace("1.e1", 10.0); + testParseWhitespace("1e+1", 10.0); + testParseWhitespace("1e-1", 0.1); + + // Negative tests - things not to allow. + + // Spaces inside the numeral. + testFail("- 1"); + testFail("+ 1"); + testFail("2 2"); + testFail("0x 42"); + testFail("1 ."); + testFail(". 1"); + testFail("1e 2"); + testFail("1 e2"); + // Invalid characters. + testFail("0x1H"); + testFail("12H"); + testFail("1x2"); + testFail("00x2"); + testFail("0x2.2"); + // Empty hex number. + testFail("0x"); + testFail("-0x"); + testFail("+0x"); + // Double exponent without value. + testFail(".e1"); + testFail("e1"); + testFail("e+1"); + testFail("e-1"); + testFail("-e1"); + testFail("-e+1"); + testFail("-e-1"); + // Incorrect ways to write NaN/Infinity. + testFail("infinity"); + testFail("INFINITY"); + testFail("1.#INF"); + testFail("inf"); + testFail("nan"); + testFail("NAN"); + testFail("1.#IND"); + testFail("indef"); + testFail("qnan"); + testFail("snan"); +} diff --git a/tests/corelib/queue_first_test.dart b/tests/corelib/queue_first_test.dart new file mode 100644 index 000000000000..d0baf997b628 --- /dev/null +++ b/tests/corelib/queue_first_test.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2012, 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. + +library queue.first.test; + +import "package:expect/expect.dart"; +import 'dart:collection' show Queue; + +main() { + Queue queue1 = new Queue(); + queue1..add(11)..add(12)..add(13); + Queue queue2 = new Queue(); + + Expect.equals(11, queue1.first); + Expect.throwsStateError(() => queue2.first); +} diff --git a/tests/corelib/queue_iterator_test.dart b/tests/corelib/queue_iterator_test.dart new file mode 100644 index 000000000000..af0458b73dca --- /dev/null +++ b/tests/corelib/queue_iterator_test.dart @@ -0,0 +1,61 @@ +// 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. + +library queue.iterator.test; + +import "package:expect/expect.dart"; +import 'dart:collection' show Queue; + +class QueueIteratorTest { + static testMain() { + testSmallQueue(); + testLargeQueue(); + testEmptyQueue(); + } + + static int sum(int expected, Iterator it) { + int count = 0; + while (it.moveNext()) { + count += it.current; + } + Expect.equals(expected, count); + } + + static void testSmallQueue() { + Queue queue = new Queue(); + queue.addLast(1); + queue.addLast(2); + queue.addLast(3); + + Iterator it = queue.iterator; + sum(6, it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + } + + static void testLargeQueue() { + Queue queue = new Queue(); + int count = 0; + for (int i = 0; i < 100; i++) { + count += i; + queue.addLast(i); + } + Iterator it = queue.iterator; + sum(count, it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + } + + static void testEmptyQueue() { + Queue queue = new Queue(); + Iterator it = queue.iterator; + sum(0, it); + Expect.isFalse(it.moveNext()); + Expect.isNull(it.current); + } +} + +main() { + QueueIteratorTest.testMain(); +} diff --git a/tests/corelib/queue_last_test.dart b/tests/corelib/queue_last_test.dart new file mode 100644 index 000000000000..3ea2eff0af78 --- /dev/null +++ b/tests/corelib/queue_last_test.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2012, 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. + +library queue.last.test; + +import "package:expect/expect.dart"; +import 'dart:collection' show Queue; + +main() { + Queue queue1 = new Queue(); + queue1..add(11)..add(12)..add(13); + Queue queue2 = new Queue(); + + Expect.equals(13, queue1.last); + Expect.throwsStateError(() => queue2.last); +} diff --git a/tests/corelib/queue_single_test.dart b/tests/corelib/queue_single_test.dart new file mode 100644 index 000000000000..1ef6b59bd139 --- /dev/null +++ b/tests/corelib/queue_single_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2012, 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. + +library queue.single.test; + +import "package:expect/expect.dart"; +import 'dart:collection' show Queue; + +main() { + Queue queue1 = new Queue(); + queue1.add(42); + Queue queue2 = new Queue(); + queue2..add(11)..add(12)..add(13); + Queue queue3 = new Queue(); + + Expect.equals(42, queue1.single); + Expect.throwsStateError(() => queue2.single); + Expect.throwsStateError(() => queue3.single); +} diff --git a/tests/corelib/queue_test.dart b/tests/corelib/queue_test.dart new file mode 100644 index 000000000000..0729bf6b8c3c --- /dev/null +++ b/tests/corelib/queue_test.dart @@ -0,0 +1,484 @@ +// 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. + +library queue.test; + +import "package:expect/expect.dart"; +import 'dart:collection'; + +abstract class QueueTest { + Queue newQueue(); + Queue newQueueFrom(Iterable iterable); + + void testMain() { + Queue queue = newQueue(); + checkQueue(queue, 0, 0); + + queue.addFirst(1); + checkQueue(queue, 1, 1); + + queue.addLast(10); + checkQueue(queue, 2, 11); + + Expect.equals(10, queue.removeLast()); + checkQueue(queue, 1, 1); + + queue.addLast(10); + Expect.equals(1, queue.removeFirst()); + checkQueue(queue, 1, 10); + + queue.addFirst(1); + queue.addLast(100); + queue.addLast(1000); + Expect.equals(1000, queue.removeLast()); + queue.addLast(1000); + checkQueue(queue, 4, 1111); + + queue.removeFirst(); + checkQueue(queue, 3, 1110); + + dynamic mapTest(dynamic value) { + return (value as int) ~/ 10; + } + + bool is10(dynamic value) { + return (value == 10); + } + + Queue mapped = newQueueFrom(queue.map(mapTest)); + checkQueue(mapped, 3, 111); + checkQueue(queue, 3, 1110); + Expect.equals(1, mapped.removeFirst()); + Expect.equals(100, mapped.removeLast()); + Expect.equals(10, mapped.removeFirst()); + + Queue other = newQueueFrom(queue.where(is10)); + checkQueue(other, 1, 10); + + Expect.equals(true, queue.any(is10)); + + bool isInstanceOfInt(dynamic value) { + return (value is int); + } + + Expect.equals(true, queue.every(isInstanceOfInt)); + + Expect.equals(false, queue.every(is10)); + + bool is1(dynamic value) { + return (value == 1); + } + + Expect.equals(false, queue.any(is1)); + + queue.clear(); + Expect.equals(0, queue.length); + + var exception = null; + try { + queue.removeFirst(); + } on StateError catch (e) { + exception = e; + } + Expect.equals(true, exception != null); + Expect.equals(0, queue.length); + + exception = null; + try { + queue.removeLast(); + } on StateError catch (e) { + exception = e; + } + Expect.equals(true, exception != null); + Expect.equals(0, queue.length); + + queue.addFirst(1); + queue.addFirst(2); + Expect.equals(2, queue.first); + Expect.equals(1, queue.last); + + queue.addLast(3); + Expect.equals(3, queue.last); + bool isGreaterThanOne(dynamic value) { + return ((value as int) > 1); + } + + other = newQueueFrom(queue.where(isGreaterThanOne)); + checkQueue(other, 2, 5); + + // Cycle through values without ever having large element count. + queue = newQueue(); + queue.add(0); + for (int i = 0; i < 255; i++) { + queue.add(i + 1); + Expect.equals(i, queue.removeFirst()); + } + Expect.equals(255, queue.removeFirst()); + Expect.isTrue(queue.isEmpty); + + testAddAll(); + testLengthChanges(); + testLarge(); + testFromListToList(); + } + + void checkQueue(Queue queue, int expectedSize, int expectedSum) { + testLength(expectedSize, queue); + int sum = 0; + void sumElements(dynamic value) { + sum += value as int; + } + + queue.forEach(sumElements); + Expect.equals(expectedSum, sum); + } + + testLength(int length, Queue queue) { + Expect.equals(length, queue.length); + ((length == 0) ? Expect.isTrue : Expect.isFalse)(queue.isEmpty); + ((length != 0) ? Expect.isTrue : Expect.isFalse)(queue.isNotEmpty); + } + + void testAddAll() { + Set set = new Set.from([1, 2, 4]); + Expect.equals(3, set.length); + + Queue queue1 = newQueueFrom(set); + Queue queue2 = newQueue(); + Queue queue3 = newQueue(); + testLength(3, queue1); + testLength(0, queue2); + testLength(0, queue3); + + queue2.addAll(set); + testLength(3, queue2); + + queue3.addAll(queue1); + testLength(3, queue3); + + int sum = 0; + void f(dynamic e) { + sum += (e as int); + } + + set.forEach(f); + Expect.equals(7, sum); + sum = 0; + + queue1.forEach(f); + Expect.equals(7, sum); + sum = 0; + + queue2.forEach(f); + Expect.equals(7, sum); + sum = 0; + + queue3.forEach(f); + Expect.equals(7, sum); + sum = 0; + + set = new Set.from([]); + queue1 = newQueueFrom(set); + queue2 = newQueue(); + queue3 = newQueue(); + + queue2.addAll(set); + queue3.addAll(queue1); + + Expect.equals(0, set.length); + Expect.equals(0, queue1.length); + Expect.equals(0, queue2.length); + Expect.equals(0, queue3.length); + } + + void testLengthChanges() { + // Test that the length property is updated properly by + // modifications; + Queue queue = newQueue(); + testLength(0, queue); + + for (int i = 1; i <= 10; i++) { + queue.add(i); + testLength(i, queue); + } + + for (int i = 1; i <= 10; i++) { + queue.addFirst(11 - i); + testLength(10 + i, queue); + } + + for (int i = 1; i <= 10; i++) { + queue.addLast(i); + testLength(20 + i, queue); + } + + queue.addAll([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + testLength(40, queue); + + for (int i = 1; i <= 5; i++) { + Expect.equals(i, queue.removeFirst()); + testLength(40 - i, queue); + } + + for (int i = 1; i <= 5; i++) { + Expect.equals(11 - i, queue.removeLast()); + testLength(35 - i, queue); + } + + Expect.isTrue(queue.remove(10)); + testLength(29, queue); + Expect.isFalse(queue.remove(999)); + testLength(29, queue); + + queue.removeWhere((x) => x == 7); + testLength(26, queue); + + queue.retainWhere((x) => x != 3); + testLength(23, queue); + + Expect.listEquals( + [6, 8, 9, 1, 2, 4, 5, 6, 8, 9, 10, 1, 2, 4, 5, 6, 8, 9, 10, 1, 2, 4, 5], + queue.toList()); + + // Regression test: http://dartbug.com/16270 + // This should do nothing, and should not throw. + Queue emptyQueue = newQueue(); + emptyQueue.remove(0); + } + + void testLarge() { + int N = 10000; + Set set = new Set(); + + Queue queue = newQueue(); + Expect.isTrue(queue.isEmpty); + + for (int i = 0; i < N; i++) { + queue.add(i); + set.add(i); + } + Expect.equals(N, queue.length); + Expect.isFalse(queue.isEmpty); + + Expect.equals(0, queue.elementAt(0)); + Expect.equals(N - 1, queue.elementAt(N - 1)); + Expect.throws(() { + queue.elementAt(-1); + }); + Expect.throws(() { + queue.elementAt(N); + }); + + Iterable skip1 = queue.skip(1); + Iterable take1 = queue.take(1); + Iterable mapped = queue.map((e) => -e); + + for (int i = 0; i < 500; i++) { + Expect.equals(i, take1.first); + Expect.equals(i, queue.first); + Expect.equals(-i, mapped.first); + Expect.equals(i + 1, skip1.first); + Expect.equals(i, queue.removeFirst()); + Expect.equals(i + 1, take1.first); + Expect.equals(-i - 1, mapped.first); + Expect.equals(N - 1 - i, queue.last); + Expect.equals(N - 1 - i, queue.removeLast()); + } + Expect.equals(N - 1000, queue.length); + + Expect.isTrue(queue.remove(N >> 1)); + Expect.equals(N - 1001, queue.length); + + queue.clear(); + Expect.equals(0, queue.length); + Expect.isTrue(queue.isEmpty); + + queue.addAll(set); + Expect.equals(N, queue.length); + Expect.isFalse(queue.isEmpty); + + // Iterate. + for (var element in queue) { + Expect.isTrue(set.contains(element)); + } + + queue.forEach((element) { + Expect.isTrue(set.contains(element)); + }); + + queue.addAll(set); + Expect.equals(N * 2, queue.length); + Expect.isFalse(queue.isEmpty); + + queue.clear(); + Expect.equals(0, queue.length); + Expect.isTrue(queue.isEmpty); + } + + void testFromListToList() { + const int N = 256; + List list = []; + for (int i = 0; i < N; i++) { + Queue queue = newQueueFrom(list); + + Expect.equals(list.length, queue.length); + List to = queue.toList(); + Expect.listEquals(list, to); + + queue.add(i); + list.add(i); + Expect.equals(list.length, queue.length); + to = queue.toList(); + Expect.listEquals(list, to); + } + } +} + +class ListQueueTest extends QueueTest { + Queue newQueue() => new ListQueue(); + Queue newQueueFrom(Iterable elements) => new ListQueue.from(elements); + + void testMain() { + super.testMain(); + trickyTest(); + } + + void trickyTest() { + // Test behavior around the know growing capacities of a ListQueue. + Queue q = new ListQueue(); + + for (int i = 0; i < 255; i++) { + q.add(i); + } + for (int i = 0; i < 128; i++) { + Expect.equals(i, q.removeFirst()); + } + q.add(255); + for (int i = 0; i < 127; i++) { + q.add(i); + } + + Expect.equals(255, q.length); + + // Remove element at end of internal buffer. + q.removeWhere((v) => v == 255); + // Remove element at beginning of internal buffer. + q.removeWhere((v) => v == 0); + // Remove element at both ends of internal buffer. + q.removeWhere((v) => v == 254 || v == 1); + + Expect.equals(251, q.length); + + Iterable i255 = new Iterable.generate(255, (x) => x); + + q = new ListQueue(); + q.addAll(i255); + Expect.listEquals(i255.toList(), q.toList()); + + q = new ListQueue(); + q.addAll(i255.toList()); + Expect.listEquals(i255.toList(), q.toList()); + + q = new ListQueue.from(i255); + for (int i = 0; i < 128; i++) q.removeFirst(); + q.add(256); + q.add(0); + q.addAll(i255.toList()); + Expect.equals(129 + 255, q.length); + + // Test addAll that requires the queue to grow. + q = new ListQueue(); + q.addAll(i255.take(35)); + q.addAll(i255.skip(35).take(96)); + q.addAll(i255.skip(35 + 96)); + Expect.listEquals(i255.toList(), q.toList()); + } +} + +class DoubleLinkedQueueTest extends QueueTest { + Queue newQueue() => new DoubleLinkedQueue(); + Queue newQueueFrom(Iterable elements) => new DoubleLinkedQueue.from(elements); + + void testMain() { + super.testMain(); + testQueueElements(); + } + + void testQueueElements() { + DoubleLinkedQueue queue1 = new DoubleLinkedQueue.from([1, 2, 3]); + DoubleLinkedQueue queue2 = new DoubleLinkedQueue(); + queue2.addAll(queue1); + + Expect.equals(queue1.length, queue2.length); + DoubleLinkedQueueEntry? entry1 = queue1.firstEntry(); + DoubleLinkedQueueEntry? entry2 = queue2.firstEntry(); + while (entry1 != null) { + Expect.equals(true, !identical(entry1, entry2)); + entry1 = entry1.nextEntry(); + entry2 = entry2!.nextEntry(); + } + Expect.equals(null, entry2); + + var firstEntry = queue1.firstEntry(); + var secondEntry = queue1.firstEntry().nextEntry(); + var thirdEntry = queue1.lastEntry(); + firstEntry.prepend(4); + firstEntry.append(5); + secondEntry!.prepend(6); + secondEntry.append(7); + thirdEntry.prepend(8); + thirdEntry.append(9); + Expect.equals(9, queue1.length); + Expect.listEquals(queue1.toList(), [4, 1, 5, 6, 2, 7, 8, 3, 9]); + Expect.equals(1, firstEntry.remove()); + Expect.equals(2, secondEntry.remove()); + Expect.equals(3, thirdEntry.remove()); + Expect.equals(6, queue1.length); + Expect.listEquals(queue1.toList(), [4, 5, 6, 7, 8, 9]); + } +} + +void linkEntryTest() { + var entry = new DoubleLinkedQueueEntry(42); + Expect.equals(null, entry.previousEntry()); + Expect.equals(null, entry.nextEntry()); + + entry.append(37); + entry.prepend(87); + var prev = entry.previousEntry(); + var next = entry.nextEntry(); + Expect.equals(42, entry.element); + Expect.equals(37, next!.element); + Expect.equals(87, prev!.element); + Expect.identical(entry, prev.nextEntry()); + Expect.identical(entry, next.previousEntry()); + Expect.equals(null, next.nextEntry()); + Expect.equals(null, prev.previousEntry()); + + entry.element = 117; + Expect.equals(117, entry.element); + Expect.identical(next, entry.nextEntry()); + Expect.identical(prev, entry.previousEntry()); + + Expect.equals(117, entry.remove()); + Expect.identical(next, prev.nextEntry()); + Expect.identical(prev, next.previousEntry()); + Expect.equals(null, next.nextEntry()); + Expect.equals(null, prev.previousEntry()); + Expect.equals(37, next.element); + Expect.equals(87, prev.element); + + Expect.equals(37, next.remove()); + Expect.equals(87, prev.element); + Expect.equals(null, prev.nextEntry()); + Expect.equals(null, prev.previousEntry()); + + Expect.equals(87, prev.remove()); +} + +main() { + new DoubleLinkedQueueTest().testMain(); + new ListQueueTest().testMain(); + linkEntryTest(); +}