From 00dae36b474397880feec80457efae4ad01c6e4e Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Tue, 13 Mar 2018 12:57:49 +0000 Subject: [PATCH] Add `of` constructors to collections. Change-Id: Ic9a180cbb758cf8fe51369d904fa4b51fd1b8e27 Reviewed-on: https://dart-review.googlesource.com/44480 Commit-Queue: Lasse R.H. Nielsen Reviewed-by: Kevin Moore Reviewed-by: Erik Ernst Reviewed-by: Leaf Petersen --- CHANGELOG.md | 4 + runtime/lib/map_patch.dart | 2 +- .../js_runtime/lib/linked_hash_map.dart | 2 +- sdk/lib/collection/hash_map.dart | 8 ++ sdk/lib/collection/hash_set.dart | 22 +++- sdk/lib/collection/linked_hash_map.dart | 9 ++ sdk/lib/collection/linked_hash_set.dart | 11 +- sdk/lib/collection/queue.dart | 53 +++++++- sdk/lib/collection/splay_tree.dart | 31 ++++- sdk/lib/core/list.dart | 22 +++- sdk/lib/core/map.dart | 13 +- sdk/lib/core/set.dart | 14 ++- tests/corelib_2/collection_from_test.dart | 117 +++++++++++++----- tests/corelib_2/collection_of_test.dart | 84 +++++++++++++ tests/corelib_2/corelib_2.status | 7 +- tests/corelib_2/map_of_test.dart | 66 ++++++++++ 16 files changed, 416 insertions(+), 49 deletions(-) create mode 100644 tests/corelib_2/collection_of_test.dart create mode 100644 tests/corelib_2/map_of_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 75bf74fb737..59fa32c7f0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,9 @@ the assignment to `y`. * `MapBase`: added `mapToString`. * `LinkedHashMap` no longer implements `HashMap` * `LinkedHashSet` no longer implements `HashSet`. + * Added `of` constructor to `Queue`, `ListQueue`, + `DoubleLinkedQueue`, `HashSet`, `LinkedHashSet`, `SplayTreeSet`, + `Map`, `HashMap`, `LinkedHashMap`, `SplayTreeMap`. * `dart:convert` @@ -114,6 +117,7 @@ the assignment to `y`. * *Note*: if a class extends `IterableBase`, `ListBase`, `SetBase` or `MapBase` (or uses the corresponding mixins) from `dart:collection`, the new members are implemented automatically. + * Added `of` constructor to `List`, `Set`, `Map`. * Renamed `double.INFINITY`, `double.NEGATIVE_INFINITY`, `double.NAN`, `double.MAX_FINITE` and `double.MIN_POSITIVE` to `double.infinity`, `double.negativeInfinity`, `double.nan`, diff --git a/runtime/lib/map_patch.dart b/runtime/lib/map_patch.dart index 3e71459a2c6..0e41c85da46 100644 --- a/runtime/lib/map_patch.dart +++ b/runtime/lib/map_patch.dart @@ -22,7 +22,7 @@ class Map { @patch factory Map.unmodifiable(Map other) { - return new UnmodifiableMapView(new Map.from(other)); + return new UnmodifiableMapView(new Map.from(other)); } @patch diff --git a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart index 3cd22d2f651..341ce905de2 100644 --- a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart +++ b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart @@ -299,7 +299,7 @@ class JsLinkedHashMap extends MapBase return -1; } - String toString() => Maps.mapToString(this); + String toString() => MapBase.mapToString(this); LinkedHashMapCell _getTableCell(var table, var key) { return JS('var', '#[#]', table, key); diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart index 8050607cb57..08289f846b7 100644 --- a/sdk/lib/collection/hash_map.dart +++ b/sdk/lib/collection/hash_map.dart @@ -100,6 +100,9 @@ abstract class HashMap implements Map { /** * Creates a [HashMap] that contains all key/value pairs of [other]. + * + * The keys must all be instances of [K] and the values of [V]. + * The [other] map itself can have any type. */ factory HashMap.from(Map other) { Map result = new HashMap(); @@ -109,6 +112,11 @@ abstract class HashMap implements Map { return result; } + /** + * Creates a [HashMap] that contains all key/value pairs of [other]. + */ + factory HashMap.of(Map other) => new HashMap()..addAll(other); + /** * Creates a [HashMap] where the keys and values are computed from the * [iterable]. diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart index e77d31c6f4b..b652da3421d 100644 --- a/sdk/lib/collection/hash_set.dart +++ b/sdk/lib/collection/hash_set.dart @@ -129,13 +129,14 @@ abstract class HashSet implements Set { * two entries that are equal, but not identical, then the first one is * the one in the resulting set. * - * All the [elements] should be assignable to [E]. + * All the [elements] should be instances of [E]. * The `elements` iterable itself may have any element type, so this * constructor can be used to down-cast a `Set`, for example as: - * - * Set superSet = ...; - * Set subSet = - * new HashSet.from(superSet.where((e) => e is SubType)); + * ```dart + * Set superSet = ...; + * Set subSet = + * new HashSet.from(superSet.whereType()); + * ``` */ factory HashSet.from(Iterable elements) { HashSet result = new HashSet(); @@ -145,6 +146,17 @@ abstract class HashSet implements Set { return result; } + /** + * Create a hash set containing all [elements]. + * + * Creates a hash set as by `new HashSet()` and adds all given [elements] + * to the set. The elements are added in order. If [elements] contains + * two entries that are equal, but not identical, then the first one is + * the one in the resulting set. + */ + factory HashSet.of(Iterable elements) => + new HashSet()..addAll(elements); + /** * Provides an iterator that iterates over the elements of this set. * diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart index 7e075fc16c8..76029c373ab 100644 --- a/sdk/lib/collection/linked_hash_map.dart +++ b/sdk/lib/collection/linked_hash_map.dart @@ -87,6 +87,9 @@ abstract class LinkedHashMap implements Map { /** * Creates a [LinkedHashMap] that contains all key value pairs of [other]. + * + * The keys must all be instances of [K] and the values to [V]. + * The [other] map itself can have any type. */ factory LinkedHashMap.from(Map other) { LinkedHashMap result = new LinkedHashMap(); @@ -96,6 +99,12 @@ abstract class LinkedHashMap implements Map { return result; } + /** + * Creates a [LinkedHashMap] that contains all key value pairs of [other]. + */ + factory LinkedHashMap.of(Map other) => + new LinkedHashMap()..addAll(other); + /** * Creates a [LinkedHashMap] where the keys and values are computed from the * [iterable]. diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart index 672f58b15ef..2fff2ec28f6 100644 --- a/sdk/lib/collection/linked_hash_set.dart +++ b/sdk/lib/collection/linked_hash_set.dart @@ -95,7 +95,7 @@ abstract class LinkedHashSet implements Set { * Creates a linked hash set as by `new LinkedHashSet()` and adds each * element of `elements` to this set in the order they are iterated. * - * All the [elements] should be assignable to [E]. + * All the [elements] should be instances of [E]. * The `elements` iterable itself may have any element type, * so this constructor can be used to down-cast a `Set`, for example as: * @@ -111,6 +111,15 @@ abstract class LinkedHashSet implements Set { return result; } + /** + * Create a linked hash set from [elements]. + * + * Creates a linked hash set as by `new LinkedHashSet()` and adds each + * element of `elements` to this set in the order they are iterated. + */ + factory LinkedHashSet.of(Iterable elements) => + new LinkedHashSet()..addAll(elements); + /** * Executes a function on each element of the set. * diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart index b27c5c55327..48136e642be 100644 --- a/sdk/lib/collection/queue.dart +++ b/sdk/lib/collection/queue.dart @@ -28,9 +28,26 @@ abstract class Queue implements EfficientLengthIterable { * * The element order in the queue is as if the elements were added using * [addLast] in the order provided by [elements.iterator]. + * + * All the [elements] should be instances of [E]. + * The `elements` iterable itself may have any element type, so this + * constructor can be used to down-cast a `Queue`, for example as: + * ```dart + * Queue superQueue = ...; + * Queue subQueue = + * new Queue.from(superSet.whereType()); + * ``` */ factory Queue.from(Iterable elements) = ListQueue.from; + /** + * Creates a queue from [elements]. + * + * The element order in the queue is as if the elements were added using + * [addLast] in the order provided by [elements.iterator]. + */ + factory Queue.of(Iterable elements) = ListQueue.of; + /** * Adapts [source] to be a `Queue`. * @@ -312,6 +329,15 @@ class DoubleLinkedQueue extends Iterable implements Queue { * * The element order in the queue is as if the elements were added using * [addLast] in the order provided by [elements.iterator]. + * + * All the [elements] should be instances of [E]. + * The `elements` iterable itself may have any element type, so this + * constructor can be used to down-cast a `Queue`, for example as: + * ```dart + * Queue superQueue = ...; + * Queue subQueue = + * new DoubleLinkedQueue.from(superQueue.whereType()); + * ``` */ factory DoubleLinkedQueue.from(Iterable elements) { Queue list = new DoubleLinkedQueue(); @@ -321,6 +347,15 @@ class DoubleLinkedQueue extends Iterable implements Queue { return list; } + /** + * Creates a double-linked queue from [elements]. + * + * The element order in the queue is as if the elements were added using + * [addLast] in the order provided by [elements.iterator]. + */ + factory DoubleLinkedQueue.of(Iterable elements) => + new DoubleLinkedQueue()..addAll(elements); + Queue cast() { Queue self = this; return self is Queue ? self : Queue.castFrom(this); @@ -579,7 +614,14 @@ class ListQueue extends ListIterable implements Queue { * The elements are added to the queue, as by [addLast], in the order given by * `elements.iterator`. * - * All `elements` should be assignable to [E]. + * All the [elements] should be instances of [E]. + * The `elements` iterable itself may have any element type, so this + * constructor can be used to down-cast a `Queue`, for example as: + * ```dart + * Queue superQueue = ...; + * Queue subQueue = + * new ListQueue.from(superQueue.whereType()); + * ``` */ factory ListQueue.from(Iterable elements) { if (elements is List) { @@ -604,6 +646,15 @@ class ListQueue extends ListIterable implements Queue { } } + /** + * Create a `ListQueue` from [elements]. + * + * The elements are added to the queue, as by [addLast], in the order given by + * `elements.iterator`. + */ + factory ListQueue.of(Iterable elements) => + new ListQueue()..addAll(elements); + // Iterable interface. Queue cast() { diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart index 3022df2c1a0..99234f3300c 100644 --- a/sdk/lib/collection/splay_tree.dart +++ b/sdk/lib/collection/splay_tree.dart @@ -295,6 +295,9 @@ class SplayTreeMap extends _SplayTree> /** * Creates a [SplayTreeMap] that contains all key/value pairs of [other]. + * + * The keys must all be instances of [K] and the values of [V]. + * The [other] map itself can have any type. */ factory SplayTreeMap.from(Map other, [int compare(K key1, K key2), bool isValidKey(potentialKey)]) { @@ -305,6 +308,13 @@ class SplayTreeMap extends _SplayTree> return result; } + /** + * Creates a [SplayTreeMap] that contains all key/value pairs of [other]. + */ + factory SplayTreeMap.of(Map other, + [int compare(K key1, K key2), bool isValidKey(potentialKey)]) => + new SplayTreeMap(compare, isValidKey)..addAll(other); + /** * Creates a [SplayTreeMap] where the keys and values are computed from the * [iterable]. @@ -721,7 +731,15 @@ class SplayTreeSet extends _SplayTree> * * The set works as if created by `new SplayTreeSet(compare, isValidKey)`. * - * All the [elements] should be valid as arguments to the [compare] function. + * All the [elements] should be instances of [E] and valid arguments to + * [compare]. + * The `elements` iterable itself may have any element type, so this + * constructor can be used to down-cast a `Set`, for example as: + * ```dart + * Set superSet = ...; + * Set subSet = + * new SplayTreeSet.from(superSet.whereType()); + * ``` */ factory SplayTreeSet.from(Iterable elements, [int compare(E key1, E key2), bool isValidKey(potentialKey)]) { @@ -733,6 +751,17 @@ class SplayTreeSet extends _SplayTree> return result; } + /** + * Creates a [SplayTreeSet] from [elements]. + * + * The set works as if created by `new SplayTreeSet(compare, isValidKey)`. + * + * All the [elements] should be valid as arguments to the [compare] function. + */ + factory SplayTreeSet.of(Iterable elements, + [int compare(E key1, E key2), bool isValidKey(potentialKey)]) => + new SplayTreeSet(compare, isValidKey)..addAll(elements); + Set _newSet() => new SplayTreeSet((T a, T b) => _comparator(a as E, b as E), _validKey); diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart index 77e40e09a30..8df6ca5b3b6 100644 --- a/sdk/lib/core/list.dart +++ b/sdk/lib/core/list.dart @@ -114,11 +114,31 @@ abstract class List implements EfficientLengthIterable { * * The [Iterator] of [elements] provides the order of the elements. * - * This constructor returns a growable list when [growable] is true; + * All the [elements] should be instances of [E]. + * The `elements` iterable itself may have any element type, so this + * constructor can be used to down-cast a `List`, for example as: + * ```dart + * List superList = ...; + * List subList = + * new List.from(superList.whereType()); + * ``` + * + * This constructor creates a growable list when [growable] is true; * otherwise, it returns a fixed-length list. */ external factory List.from(Iterable elements, {bool growable: true}); + /** + * Creates a list from [elements]. + * + * The [Iterator] of [elements] provides the order of the elements. + * + * This constructor creates a growable list when [growable] is true; + * otherwise, it returns a fixed-length list. + */ + factory List.of(Iterable elements, {bool growable: true}) => + new List.from(elements, growable: growable); + /** * Generates a list of values. * diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart index 9e9741adb21..a802a52cbb5 100644 --- a/sdk/lib/core/map.dart +++ b/sdk/lib/core/map.dart @@ -45,7 +45,7 @@ abstract class Map { * Creates a [LinkedHashMap] instance that contains all key/value pairs of * [other]. * - * The keys must all be assignable to [K] and the values to [V]. + * The keys must all be instances of [K] and the values of [V]. * The [other] map itself can have any type. * * A `LinkedHashMap` requires the keys to implement compatible @@ -54,10 +54,19 @@ abstract class Map { */ factory Map.from(Map other) = LinkedHashMap.from; + /** + * Creates a [LinkedHashMap] with the same keys and values as [other]. + * + * A `LinkedHashMap` requires the keys to implement compatible + * `operator==` and `hashCode`, and it allows `null` as a key. + * It iterates in key insertion order. + */ + factory Map.of(Map other) = LinkedHashMap.of; + /** * Creates an unmodifiable hash based map containing the entries of [other]. * - * The keys must all be assignable to [K] and the values to [V]. + * The keys must all be instances of [K] and the values of [V]. * The [other] map itself can have any type. * * The map requires the keys to implement compatible diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart index e58ea101e21..8d95d2dd406 100644 --- a/sdk/lib/core/set.dart +++ b/sdk/lib/core/set.dart @@ -61,7 +61,7 @@ abstract class Set extends EfficientLengthIterable { /** * Creates a [Set] that contains all [elements]. * - * All the [elements] should be assignable to [E]. + * All the [elements] should be instances of [E]. * The `elements` iterable itself can have any type, * so this constructor can be used to down-cast a `Set`, for example as: * @@ -78,6 +78,18 @@ abstract class Set extends EfficientLengthIterable { */ factory Set.from(Iterable elements) = LinkedHashSet.from; + /** + * Creates a [Set] from [elements]. + * + * The created [Set] is a [LinkedHashSet]. As such, it considers elements that + * are equal (using [==]) to be indistinguishable, and requires them to + * have a compatible [Object.hashCode] implementation. + * + * The set is equivalent to one created by + * `new LinkedHashSet.of(elements)`. + */ + factory Set.of(Iterable elements) = LinkedHashSet.of; + /** * Adapts [source] to be a `Set`. * diff --git a/tests/corelib_2/collection_from_test.dart b/tests/corelib_2/collection_from_test.dart index 057d4e259ba..bc7dc7aba70 100644 --- a/tests/corelib_2/collection_from_test.dart +++ b/tests/corelib_2/collection_from_test.dart @@ -5,40 +5,89 @@ library collection.from.test; import "package:expect/expect.dart"; -import 'dart:collection' show Queue; - -class CollectionFromTest { - static testMain() { - var set = new Set(); - set.add(1); - set.add(2); - set.add(4); - check(set, new List.from(set)); - check(set, new List.from(set)); - check(set, new Queue.from(set)); - check(set, new Queue.from(set)); - check(set, new Set.from(set)); - check(set, new Set.from(set)); - } - - static check(Iterable initial, Iterable other) { - Expect.equals(3, initial.length); - Expect.equals(initial.length, other.length); - - int initialSum = 0; - int otherSum = 0; - - initial.forEach((e) { - initialSum += e; - }); - other.forEach((e) { - otherSum += e; - }); - Expect.equals(4 + 2 + 1, otherSum); - Expect.equals(otherSum, initialSum); - } -} +import 'dart:collection'; main() { - CollectionFromTest.testMain(); + for (Iterable elements in [ + new Set(), + [], + const [], + const {}.keys, + const {}.values, + new Iterable.generate(0), + new Set()..add(1)..add(2)..add(4), + [1, 2, 4], + new Iterable.generate(3, (i) => [1, 2, 4][i]), + const [1, 2, 4], + const {1: 0, 2: 0, 4: 0}.keys, + const {1: 1, 2: 2, 4: 4}.values, + ]) { + int elementCount = elements.length; + check(elements, new List.from(elements)); + check(elements, new List.from(elements)); + check(elements, new List.from(elements)); + check(elements, new List.from(elements, growable: true)); + check(elements, new List.from(elements, growable: true)); + check(elements, new List.from(elements, growable: true)); + check(elements, new List.from(elements, growable: false)); + check(elements, new List.from(elements, growable: false)); + check(elements, new List.from(elements, growable: false)); + check(elements, new Queue.from(elements)); + check(elements, new Queue.from(elements)); + check(elements, new Queue.from(elements)); + check(elements, new ListQueue.from(elements)); + check(elements, new ListQueue.from(elements)); + check(elements, new ListQueue.from(elements)); + check(elements, new DoubleLinkedQueue.from(elements)); + check(elements, new DoubleLinkedQueue.from(elements)); + check(elements, new DoubleLinkedQueue.from(elements)); + check(elements, new Set.from(elements)); + check(elements, new Set.from(elements)); + check(elements, new Set.from(elements)); + check(elements, new HashSet.from(elements)); + check(elements, new HashSet.from(elements)); + check(elements, new HashSet.from(elements)); + check(elements, new LinkedHashSet.from(elements)); + check(elements, new LinkedHashSet.from(elements)); + check(elements, new LinkedHashSet.from(elements)); + check(elements, new SplayTreeSet.from(elements)); + check(elements, new SplayTreeSet.from(elements)); + check(elements, new SplayTreeSet.from(elements)); + // Sanity check that elements didn't change. + Expect.equals(elementCount, elements.length); + + // Lists may be growable or not growable. + { + var list = new List.from(elements, growable: true); + Expect.equals(elementCount, list.length); + list.add(42); + Expect.equals(elementCount + 1, list.length); + } + { + var list = new List.from(elements); + Expect.equals(elementCount, list.length); + list.add(42); + Expect.equals(elementCount + 1, list.length); + } + { + var list = new List.from(elements, growable: false); + Expect.equals(elementCount, list.length); + Expect.throwsUnsupportedError(() { + list.add(42); + }); + Expect.equals(elementCount, list.length); + } + } +} + +void check(Iterable initial, Iterable other) { + Expect.equals(initial.length, other.length); + + for (var element in other) { + initial.contains(element); + } + + for (var element in initial) { + other.contains(element); + } } diff --git a/tests/corelib_2/collection_of_test.dart b/tests/corelib_2/collection_of_test.dart new file mode 100644 index 00000000000..d93c7e43f96 --- /dev/null +++ b/tests/corelib_2/collection_of_test.dart @@ -0,0 +1,84 @@ +// 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 collection.from.test; + +import "package:expect/expect.dart"; +import 'dart:collection'; + +main() { + for (Iterable elements in [ + new Set(), + [], + const [], + const {}.keys, + const {}.values, + new Iterable.generate(0), + new Set()..add(1)..add(2)..add(4), + [1, 2, 4], + new Iterable.generate(3, (i) => [1, 2, 4][i]), + const [1, 2, 4], + const {1: 0, 2: 0, 4: 0}.keys, + const {1: 1, 2: 2, 4: 4}.values, + ]) { + String sourceType = elements.runtimeType.toString(); + check(sourceType, elements, new List.of(elements)); + Expect.throwsTypeError(() => new List.of(elements)); + check(sourceType, elements, new List.of(elements)); + check(sourceType, elements, new Queue.of(elements)); + Expect.throwsTypeError(() => new Queue.of(elements)); + check(sourceType, elements, new Queue.of(elements)); + check(sourceType, elements, new ListQueue.of(elements)); + Expect.throwsTypeError(() => new ListQueue.of(elements)); + check(sourceType, elements, new ListQueue.of(elements)); + check(sourceType, elements, new DoubleLinkedQueue.of(elements)); + Expect.throwsTypeError(() => new DoubleLinkedQueue.of(elements)); + check(sourceType, elements, new DoubleLinkedQueue.of(elements)); + check(sourceType, elements, new Set.of(elements)); + Expect.throwsTypeError(() => new Set.of(elements)); + check(sourceType, elements, new Set.of(elements)); + check(sourceType, elements, new HashSet.of(elements)); + Expect.throwsTypeError(() => new HashSet.of(elements)); + check(sourceType, elements, new HashSet.of(elements)); + check(sourceType, elements, new LinkedHashSet.of(elements)); + Expect.throwsTypeError(() => new LinkedHashSet.of(elements)); + check(sourceType, elements, new LinkedHashSet.of(elements)); + check(sourceType, elements, new SplayTreeSet.of(elements)); + Expect.throwsTypeError(() => new SplayTreeSet.of(elements)); + check(sourceType, elements, new SplayTreeSet.of(elements)); + + // Inference applies to the `of` constructor, unlike the `from` constructor. + Expect.isTrue(new List.of(elements) is Iterable); + Expect.isTrue(new Queue.of(elements) is Iterable); + Expect.isTrue(new ListQueue.of(elements) is Iterable); + Expect.isTrue(new DoubleLinkedQueue.of(elements) is Iterable); + Expect.isTrue(new Set.of(elements) is Iterable); + Expect.isTrue(new HashSet.of(elements) is Iterable); + Expect.isTrue(new LinkedHashSet.of(elements) is Iterable); + Expect.isTrue(new SplayTreeSet.of(elements) is Iterable); + + Expect.isTrue(new List.of(elements) is! Iterable); + Expect.isTrue(new Queue.of(elements) is! Iterable); + Expect.isTrue(new ListQueue.of(elements) is! Iterable); + Expect.isTrue(new DoubleLinkedQueue.of(elements) is! Iterable); + Expect.isTrue(new Set.of(elements) is! Iterable); + Expect.isTrue(new HashSet.of(elements) is! Iterable); + Expect.isTrue(new LinkedHashSet.of(elements) is! Iterable); + Expect.isTrue(new SplayTreeSet.of(elements) is! Iterable); + } +} + +void check(String sourceType, Iterable source, Iterable target) { + String targetType = target.runtimeType.toString(); + String name = "$sourceType->$targetType"; + Expect.equals(source.length, target.length, "$name.length"); + + for (var element in target) { + Expect.isTrue(source.contains(element), "$name:$element in source"); + } + + for (var element in source) { + Expect.isTrue(target.contains(element), "$name:$element in target"); + } +} diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status index 0602e0454b1..55120cd04c9 100644 --- a/tests/corelib_2/corelib_2.status +++ b/tests/corelib_2/corelib_2.status @@ -1,7 +1,6 @@ # Copyright (c) 2017, 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. - iterable_where_type_test: RuntimeError # Disabled. Issue 32463 [ $compiler == dart2analyzer ] @@ -323,6 +322,9 @@ shuffle_test: RuntimeError [ $compiler == dart2js && !$fasta ] *: SkipByDesign +[ $compiler == dart2js && $strong ] +collection_of_test: RuntimeError + [ $compiler != dart2js && $compiler != dartdevc && $compiler != dartdevk && $compiler != dartk && $compiler != dartkp && $compiler != fasta ] iterable_element_at_test/static: MissingCompileTimeError @@ -524,6 +526,9 @@ symbol_reserved_word_test/12: RuntimeError # Issue 29921 symbol_test/none: RuntimeError # Issue 29921 typed_data_with_limited_ints_test: Skip # dartdevc doesn't know about --limit-ints-to-64-bits +[ $runtime == vm && !$strong ] +collection_of_test: RuntimeError + [ !$checked && !$strong ] core_runtime_types_static_test: MissingCompileTimeError splay_tree_test/01: MissingCompileTimeError diff --git a/tests/corelib_2/map_of_test.dart b/tests/corelib_2/map_of_test.dart new file mode 100644 index 00000000000..4761b619450 --- /dev/null +++ b/tests/corelib_2/map_of_test.dart @@ -0,0 +1,66 @@ +// 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)); + expectThrows(() => new Map.of(map)); + check(sourceType, map, new HashMap.of(map)); + check(sourceType, map, new HashMap.of(map)); + expectThrows(() => new HashMap.of(map)); + check(sourceType, map, new LinkedHashMap.of(map)); + check(sourceType, map, new LinkedHashMap.of(map)); + expectThrows(() => new LinkedHashMap.of(map)); + check(sourceType, map, new SplayTreeMap.of(map)); + check(sourceType, map, new SplayTreeMap.of(map)); + expectThrows(() => 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]"); + } +}