[tests] Fix cast_test and migrate to nnbd.

Also splits up cast_test to test collections separately and
updates corelib_2 version with the same changes, including
fixes in relevant pending CL:
https://dart-review.googlesource.com/c/sdk/+/126320

Fixes #39517

Bug: http://dartbug.com/39517
Change-Id: I8df1fde1d48ed23561ce9d0d8b87d7fc2ba52eb1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144469
Commit-Queue: Riley Porter <rileyporter@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
This commit is contained in:
Riley Porter 2020-04-30 02:33:53 +00:00 committed by commit-bot@chromium.org
parent ef1528aa78
commit 654b725ee4
15 changed files with 770 additions and 375 deletions

View file

@ -0,0 +1,36 @@
// Copyright (c) 2020, 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 'cast_helper.dart';
void main() {
testSetDowncast();
testMapDowncast();
}
void testSetDowncast() {
var setEls = new Set<C?>.from(elements);
var dSet = Set.castFrom<C?, D?>(setEls);
var newC = new C();
dSet.add(newC);
// ^^^^
// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] The argument type 'C' can't be assigned to the parameter type 'D?'.
}
void testMapDowncast() {
var map = new Map.fromIterables(elements, elements);
var dMap = Map.castFrom<C?, C?, D?, D?>(map);
dMap[c] = d;
// ^
// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'C' can't be assigned to a variable of type 'D?'.
dMap[d] = c;
// ^
// [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
// [cfe] A value of type 'C' can't be assigned to a variable of type 'D?'.
}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2020, 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.
final elements = <C?>[c, d, e, f, null];
class C {}
class D extends C {}
class E extends C {}
class F implements D, E {}
final c = C();
final d = D();
final e = E();
final f = F();

View file

@ -0,0 +1,68 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testDowncastDirectAccess();
testDowncastNoDirectAccess();
testDowncastUntouchableElements();
testUpcast();
}
void testDowncastDirectAccess() {
var iterable = new Iterable<C?>.generate(elements.length, (n) => elements[n]);
// An iterable that (likely) can do direct access.
var dIterable = Iterable.castFrom<C?, D?>(iterable);
Expect.throws(() => dIterable.first);
Expect.equals(d, dIterable.elementAt(1));
Expect.throws(() => dIterable.elementAt(2)); // E is not D?
Expect.equals(f, dIterable.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList());
}
void testDowncastNoDirectAccess() {
var iterable = new Iterable<C?>.generate(elements.length, (n) => elements[n]);
// An iterable that cannot do direct access.
var dIterable = Iterable.castFrom<C?, D?>(iterable.where((_) => true));
Expect.throws(() => dIterable.first);
Expect.equals(d, dIterable.elementAt(1));
// E is not D?.
Expect.throws(() => dIterable.elementAt(2));
Expect.equals(f, dIterable.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList());
}
void testDowncastUntouchableElements() {
// Iterable that definitely won't survive accessing element 3.
var iterable = new Iterable<C?>.generate(
elements.length, (n) => n == 3 ? throw "untouchable" : elements[n]);
var dIterable = Iterable.castFrom<C?, D?>(iterable);
Expect.throws(() => dIterable.first);
Expect.equals(d, dIterable.elementAt(1));
Expect.throws(() => dIterable.elementAt(3));
// Skip does not access element.
Expect.equals(null, dIterable.skip(4).first);
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList());
}
void testUpcast() {
var iterable = new Iterable<C?>.generate(elements.length, (n) => elements[n]);
var objectIterable = Iterable.castFrom<C?, Object?>(iterable);
Expect.listEquals(elements, objectIterable.toList());
}

View file

@ -0,0 +1,46 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testDowncast();
testUpcast();
testRegression();
}
void testDowncast() {
var list = new List<C?>.from(elements);
var dList = List.castFrom<C?, D?>(list);
Expect.throws(() => dList.first); // C is not D?.
Expect.equals(d, dList[1]);
Expect.throws(() => dList[2]); // E is not D?.
Expect.equals(f, dList[3]);
Expect.equals(null, dList.last);
Expect.throws(() => dList.toList());
// Setting works.
dList[2] = d;
Expect.equals(d, dList[2]);
}
void testUpcast() {
var list = new List<C?>.from(elements);
var objectList = List.castFrom<C?, Object?>(list);
Expect.listEquals(elements, objectList);
Expect.throws(() => objectList[2] = new Object()); // Cannot set non-C.
Expect.listEquals(elements, objectList);
}
void testRegression() {
var numList = <num>[4, 3, 2, 1];
var intList = numList.cast<int>();
intList.sort(null);
Expect.listEquals([1, 2, 3, 4], numList);
Expect.listEquals([1, 2, 3, 4], intList);
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testDowncast();
testUpcast();
}
void testDowncast() {
var map = new Map.fromIterables(elements, elements);
var dMap = Map.castFrom<C?, C?, D?, D?>(map);
Expect.isTrue(dMap is Map<D?, D?>);
Expect.equals(null, dMap[new C()]);
Expect.throws(() => dMap[c]); // C is not D?.
Expect.isTrue(dMap.containsKey(c)); // containsKey should not be typed.
Expect.equals(d, dMap[d]);
Expect.throws(() => dMap[e]); // E is not D?.
Expect.isTrue(dMap.containsKey(null));
Expect.equals(null, dMap[null]);
Expect.equals(5, dMap.length);
Expect.throws(() => dMap.remove(c)); // Removes key but fails to return value.
Expect.equals(4, dMap.length);
Expect.equals(null, dMap[c]);
// Test keys and values.
Expect.isTrue(dMap.keys is Iterable<D?>);
Expect.isTrue(dMap.values is Iterable<D?>);
Expect.throws(() => dMap.keys.toList());
Expect.throws(() => dMap.values.toList());
}
void testUpcast() {
var map = new Map.fromIterables(elements, elements);
var objectMap = Map.castFrom<C?, C?, Object?, Object?>(map);
Expect.equals(5, objectMap.length);
Expect.equals(c, objectMap[c]);
Expect.isTrue(objectMap.containsKey(c));
Expect.equals(c, objectMap.remove(c));
Expect.equals(4, objectMap.length);
// Test keys and values.
Expect.isTrue(objectMap.keys is Iterable<Object?>);
Expect.isTrue(objectMap.values is Iterable<Object?>);
var expected = new List<Object?>.from(elements);
expected.remove(c);
Expect.listEquals(expected, objectMap.keys.toList());
Expect.listEquals(expected, objectMap.values.toList());
}

View file

@ -0,0 +1,71 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testOrder();
testDowncast();
testUpcast();
testNewSet();
}
void testOrder() {
var setEls = new Set<C?>.from(elements); // Linked HashSet.
Expect.listEquals(elements, setEls.toList()); // Preserves order.
}
void testDowncast() {
var setEls = new Set<C?>.from(elements);
var dSet = Set.castFrom<C?, D?>(setEls);
// Preserves order.
Expect.throws(() => dSet.first); // C is not D?.
Expect.equals(d, dSet.elementAt(1));
Expect.throws(() => dSet.elementAt(2)); // E is not D?.
Expect.equals(f, dSet.elementAt(3));
Expect.equals(null, dSet.elementAt(4));
Expect.throws(() => dSet.toList());
// Contains should not be typed.
var newC = new C();
Expect.isFalse(dSet.contains(newC));
Expect.isTrue(dSet.contains(c));
// Remove and length should not be typed.
Expect.equals(5, dSet.length);
dSet.remove(c); // Success, no type checks.
Expect.equals(4, dSet.length);
}
void testUpcast() {
var setEls = new Set<C?>.from(elements);
var objectSet = Set.castFrom<C?, Object?>(setEls);
Expect.listEquals(elements, objectSet.toList());
var newObject = new Object();
Expect.throws(() => objectSet.add(newObject));
Expect.isFalse(objectSet.contains(newObject));
var toSet = objectSet.toSet();
Expect.isTrue(toSet is LinkedHashSet<Object?>);
Expect.isFalse(toSet is LinkedHashSet<C?>);
}
void testNewSet() {
// Specified custom newSet as empty HashSet.
var setEls = new Set<C?>.from(elements);
var customNewSet;
var objectSet2 = Set.castFrom<C?, Object?>(setEls,
newSet: <T>() => customNewSet = new HashSet<T>());
var customToSet = objectSet2.toSet();
Expect.isTrue(customToSet is HashSet<Object?>);
Expect.isFalse(customToSet is HashSet<C?>);
Expect.identical(customToSet, customNewSet);
}

View file

@ -0,0 +1,106 @@
// Copyright (c) 2020, 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.
// Requirements=nnbd-strong
import "dart:collection";
import "package:expect/expect.dart";
import 'cast_helper.dart';
void main() {
testIterable();
testList();
testMap();
testSet();
}
testIterable() {
var iterable = new Iterable<C?>.generate(elements.length, (n) => elements[n]);
var iterableNonNull = Iterable.castFrom<C?, C>(iterable);
// Downcast non-nullable.
// An iterable that (likely) can do direct access.
var dIterableDirect = Iterable.castFrom<C, D>(iterableNonNull);
Expect.equals(d, dIterableDirect.elementAt(1));
// null is not D.
Expect.throws(() => dIterableDirect.skip(3).elementAt(1));
// An iterable that cannot do direct access.
var dIterableNonDirect =
Iterable.castFrom<C, D>(iterableNonNull.where((_) => true));
Expect.equals(d, dIterableNonDirect.elementAt(1));
// null is not D.
Expect.throws(() => dIterableNonDirect.skip(3).elementAt(1));
// Iterable that definitely won't survive accessing element 3.
var iterableLimited = new Iterable<C?>.generate(
elements.length, (n) => n == 3 ? throw "untouchable" : elements[n]);
var iterableLimitedNonNull = Iterable.castFrom<C?, C>(iterableLimited);
var dIterableLimited = Iterable.castFrom<C, D>(iterableLimitedNonNull);
Expect.equals(d, dIterableLimited.elementAt(1));
// null is not D.
Expect.throws(() => dIterableLimited.skip(3).elementAt(1));
// Upcast non-nullable.
var objectIterable = Iterable.castFrom<C, Object>(iterableNonNull);
// null is not Object.
Expect.throws(() => objectIterable.skip(3).elementAt(1));
}
testList() {
var list = new List<C?>.from(elements);
var listNonNull = List.castFrom<C?, C>(list);
// Downcast non-nullable.
var dList = List.castFrom<C, D>(listNonNull);
Expect.equals(d, dList[1]);
Expect.throws(() => dList.last); // null is not D.
// Upcast non-nullable.
var objectList = List.castFrom<C, Object>(listNonNull);
Expect.throws(() => objectList.last); // null is not Object.
}
testMap() {
var map = new Map.fromIterables(elements, elements);
var mapNonNull = Map.castFrom<C?, C?, C, C>(map);
// Downcast non-nullable.
var dMap = Map.castFrom<C, C, D, D>(mapNonNull);
Expect.equals(d, dMap[d]);
Expect.isTrue(dMap.containsKey(null));
Expect.equals(null, dMap[null]);
// Test keys and values
Expect.isTrue(dMap.keys is Iterable<D>);
Expect.isTrue(dMap.values is Iterable<D>);
Expect.throws(() => dMap.keys.toList());
Expect.throws(() => dMap.values.toList());
// Upcast non-nullable.
var objectMap = Map.castFrom<C, C, Object, Object>(mapNonNull);
Expect.isTrue(objectMap.containsKey(null));
Expect.equals(null, objectMap[null]);
// Test keys and values
Expect.isTrue(objectMap.keys is Iterable<Object>);
Expect.isTrue(objectMap.values is Iterable<Object>);
// null is not Object.
Expect.throws(() => objectMap.keys.toList());
Expect.throws(() => objectMap.values.toList());
}
testSet() {
var setEls = new Set<C?>.from(elements);
var setNonNull = Set.castFrom<C?, C>(setEls);
// Downcast non-nullable.
var dSet = Set.castFrom<C, D>(setNonNull);
Expect.equals(d, dSet.elementAt(1));
Expect.throws(() => dSet.last); // null is not D.
// Upcast non-nullable.
var objectSet = Set.castFrom<C, Object>(setNonNull);
Expect.throws(() => objectSet.last); // null is not Object.
}

View file

@ -1,189 +0,0 @@
// 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";
// TODO(rnystrom): Not migrated to NNBD yet.
// See https://github.com/dart-lang/sdk/issues/39517.
void main() {
testIterable();
testList();
}
final elements = <C>[c, d, e, f, null];
void testIterable() {
var iterable = new Iterable<C>.generate(elements.length, (n) => elements[n]);
// Down-cast
{
// An iterable that (likely) can do direct access.
var dIterable = Iterable.castFrom<C, D>(iterable);
Expect.throws(() => dIterable.first, null, "1.first");
Expect.equals(d, dIterable.elementAt(1));
Expect.throws(() => dIterable.elementAt(2), null, "1.2"); // E is not D.
Expect.equals(f, dIterable.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList(), null, "1.toList");
}
{
// An iterable that cannot do direct access.
var dIterable2 = Iterable.castFrom<C, D>(iterable.where((_) => true));
Expect.throws(() => dIterable2.first, null, "2.first");
Expect.equals(d, dIterable2.elementAt(1));
Expect.throws(() => dIterable2.elementAt(2), null, "2.2"); // E is not D.
Expect.equals(f, dIterable2.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable2.skip(3).elementAt(1));
Expect.throws(() => dIterable2.toList(), null, "2.toList");
}
{
// Iterable that definitely won't survive accessing element 2.
var iterable3 = new Iterable<C>.generate(
elements.length, (n) => n == 3 ? throw "untouchable" : elements[n]);
var dIterable3 = Iterable.castFrom<C, D>(iterable3);
Expect.throws(() => dIterable3.first, null, "3.first");
Expect.equals(d, dIterable3.elementAt(1));
Expect.throws(() => dIterable3.elementAt(3), null, "3.3");
// Skip does not access element.
Expect.equals(null, dIterable3.skip(4).first);
Expect.equals(null, dIterable3.skip(3).elementAt(1));
Expect.throws(() => dIterable3.toList(), null, "3.toList");
}
// Up-cast.
{
var oIterable4 = Iterable.castFrom<C, Object>(iterable);
Expect.listEquals(elements, oIterable4.toList());
}
}
void testList() {
// Down-cast.
var list = new List<C>.from(elements);
var dList = List.castFrom<C, D>(list);
Expect.throws(() => dList.first); // C is not D.
Expect.equals(d, dList[1]);
Expect.throws(() => dList[2]); // E is not D.
Expect.equals(f, dList[3]);
Expect.equals(null, dList.last);
Expect.throws(() => dList.toList());
dList[2] = d;
Expect.equals(d, dList[2]); // Setting works.
// Up-cast.
var list2 = new List<C>.from(elements);
var dList2 = List.castFrom<C, Object>(list2);
Expect.listEquals(elements, dList2);
Expect.throws(() => dList2[2] = new Object()); // Cannot set non-C.
Expect.listEquals(elements, dList2);
// Regression test.
var list3 = <num>[4, 3, 2, 1];
var dList3 = list3.cast<int>();
dList3.sort(null);
Expect.listEquals([1, 2, 3, 4], list3);
}
void testSet() {
var set = new Set<C>.from(elements); // Linked HashSet.
Expect.listEquals(elements, set.toList()); // Preserves order.
var dSet = Set.castFrom<C, D>(set);
// Preserves order.
Expect.throws(() => dSet.first); // C is not D.
Expect.equals(d, dSet.elementAt(1));
Expect.throws(() => dSet.elementAt(2)); // E is not D.
Expect.throws(() => dSet.toList());
// Contains is not typed.
var newC = new C();
Expect.isFalse(dSet.contains(newC));
dSet.add(newC);
Expect.isTrue(dSet.contains(newC));
Expect.equals(5, dSet.length);
dSet.remove(newC);
Expect.equals(5, dSet.length);
dSet.remove(c); // Success, no type checks.
Expect.equals(4, dSet.length);
// Up-cast
var set2 = new Set<C>.from(elements);
var dSet2 = Set.castFrom<C, Object>(set2);
var newObject = new Object();
Expect.throws(() => dSet2.add(newObject));
Expect.isFalse(dSet.contains(newObject));
var toSet2 = dSet2.toSet();
Expect.isTrue(toSet2 is LinkedHashSet<Object>);
Expect.isTrue(toSet2 is! LinkedHashSet<C>);
// Custom emptySet.
var set3 = new Set<C>.from(elements);
var dSet3 = Set.castFrom<C, Object>(set3, newSet: <T>() => new HashSet<T>());
var toSet3 = dSet3.toSet();
Expect.isTrue(toSet3 is HashSet<Object>);
Expect.isTrue(toSet3 is HashSet<C>);
Expect.isTrue(toSet3 is! LinkedHashSet<Object>);
}
void testMap() {
var map = new Map.fromIterables(elements, elements);
var dMap = Map.castFrom<C, C, D, D>(map);
Expect.isTrue(dMap is Map<D, D>);
Expect.equals(null, dMap[new C()]);
Expect.throws(() => dMap[c]);
Expect.isTrue(dMap.containsKey(c));
Expect.equals(d, dMap[d]);
Expect.throws(() => dMap[e]);
Expect.equals(null, dMap[null]);
Expect.equals(5, dMap.length);
dMap.remove(c); // Success, no type checks along the way.
Expect.equals(4, dMap.length);
Expect.equals(null, dMap[c]);
Expect.throws(() => dMap[c] = d);
Expect.throws(() => dMap[d] = c);
Expect.equals(4, dMap.length);
Expect.isTrue(dMap.keys is Iterable<D>);
Expect.isTrue(dMap.values is Iterable<D>);
Expect.throws(() => dMap.keys.toList());
Expect.throws(() => dMap.values.toList());
}
class C {}
class D extends C {}
class E extends C {}
class F implements D, E {}
final c = new C();
final d = new D();
final e = new E();
final f = new F();

View file

@ -0,0 +1,101 @@
// Copyright (c) 2020, 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.
// Requirements=nnbd-weak
import "dart:collection";
import "package:expect/expect.dart";
import 'cast_helper.dart';
void main() {
testIterable();
testList();
testMap();
testSet();
}
testIterable() {
var iterable = new Iterable<C?>.generate(elements.length, (n) => elements[n]);
var iterableNonNull = Iterable.castFrom<C?, C>(iterable);
// Downcast non-nullable.
// An iterable that (likely) can do direct access.
var dIterableDirect = Iterable.castFrom<C, D>(iterableNonNull);
Expect.equals(d, dIterableDirect.elementAt(1));
Expect.equals(null, dIterableDirect.skip(3).elementAt(1));
// An iterable that cannot do direct access.
var dIterableNonDirect =
Iterable.castFrom<C, D>(iterableNonNull.where((_) => true));
Expect.equals(d, dIterableNonDirect.elementAt(1));
Expect.equals(null, dIterableNonDirect.skip(3).elementAt(1));
// Iterable that definitely won't survive accessing element 3.
var iterableLimited = new Iterable<C?>.generate(
elements.length, (n) => n == 3 ? throw "untouchable" : elements[n]);
var iterableLimitedNonNull = Iterable.castFrom<C?, C>(iterableLimited);
var dIterableLimited = Iterable.castFrom<C, D>(iterableLimitedNonNull);
Expect.equals(d, dIterableLimited.elementAt(1));
Expect.equals(null, dIterableLimited.skip(3).elementAt(1));
// Upcast non-nullable.
var objectIterable = Iterable.castFrom<C, Object>(iterableNonNull);
Expect.equals(null, objectIterable.skip(3).elementAt(1));
}
testList() {
var list = new List<C?>.from(elements);
var listNonNull = List.castFrom<C?, C>(list);
// Downcast non-nullable.
var dList = List.castFrom<C, D>(listNonNull);
Expect.equals(d, dList[1]);
Expect.equals(null, dList.last);
// Upcast non-nullable.
var objectList = List.castFrom<C, Object>(listNonNull);
Expect.equals(null, objectList.last);
}
testMap() {
var map = new Map.fromIterables(elements, elements);
var mapNonNull = Map.castFrom<C?, C?, C, C>(map);
// Downcast non-nullable.
var dMap = Map.castFrom<C, C, D, D>(mapNonNull);
Expect.equals(d, dMap[d]);
Expect.isTrue(dMap.containsKey(null));
Expect.equals(null, dMap[null]);
// Test keys and values
Expect.isTrue(dMap.keys is Iterable<D>);
Expect.isTrue(dMap.values is Iterable<D>);
Expect.throws(() => dMap.keys.toList());
Expect.throws(() => dMap.values.toList());
// Upcast non-nullable.
var objectMap = Map.castFrom<C, C, Object, Object>(mapNonNull);
Expect.isTrue(objectMap.containsKey(null));
Expect.equals(null, objectMap[null]);
// Test keys and values
Expect.isTrue(objectMap.keys is Iterable<Object>);
Expect.isTrue(objectMap.values is Iterable<Object>);
var expectedValues = new List<Object>.from(elements);
Expect.listEquals(expectedValues, objectMap.values.toList());
}
testSet() {
var setEls = new Set<C?>.from(elements);
var setNonNull = Set.castFrom<C?, C>(setEls);
// Downcast non-nullable.
var dSet = Set.castFrom<C, D>(setNonNull);
Expect.equals(d, dSet.elementAt(1));
Expect.equals(null, dSet.last);
// Upcast non-nullable.
var objectSet = Set.castFrom<C, Object>(setNonNull);
Expect.equals(null, objectSet.last);
}

View file

@ -0,0 +1,18 @@
// Copyright (c) 2020, 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.
final elements = <C>[c, d, e, f, null];
class C {}
class D extends C {}
class E extends C {}
class F implements D, E {}
final c = C();
final d = D();
final e = E();
final f = F();

View file

@ -0,0 +1,68 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testDowncastDirectAccess();
testDowncastNoDirectAccess();
testDowncastUntouchableElements();
testUpcast();
}
void testDowncastDirectAccess() {
var iterable = new Iterable<C>.generate(elements.length, (n) => elements[n]);
// An iterable that (likely) can do direct access.
var dIterable = Iterable.castFrom<C, D>(iterable);
Expect.throws(() => dIterable.first, null, "direct.first");
Expect.equals(d, dIterable.elementAt(1));
Expect.throws(() => dIterable.elementAt(2), null, "direct.2"); // E is not D.
Expect.equals(f, dIterable.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList(), null, "direct.toList");
}
void testDowncastNoDirectAccess() {
var iterable = new Iterable<C>.generate(elements.length, (n) => elements[n]);
// An iterable that cannot do direct access.
var dIterable = Iterable.castFrom<C, D>(iterable.where((_) => true));
Expect.throws(() => dIterable.first, null, "nonDirect.first");
Expect.equals(d, dIterable.elementAt(1));
// E is not D.
Expect.throws(() => dIterable.elementAt(2), null, "nonDirect.2");
Expect.equals(f, dIterable.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList(), null, "nonDirect.toList");
}
void testDowncastUntouchableElements() {
// Iterable that definitely won't survive accessing element 3.
var iterable = new Iterable<C>.generate(
elements.length, (n) => n == 3 ? throw "untouchable" : elements[n]);
var dIterable = Iterable.castFrom<C, D>(iterable);
Expect.throws(() => dIterable.first, null, "untouchable.first");
Expect.equals(d, dIterable.elementAt(1));
Expect.throws(() => dIterable.elementAt(3), null, "untouchable.3");
// Skip does not access element.
Expect.equals(null, dIterable.skip(4).first);
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList(), null, "untouchable.toList");
}
void testUpcast() {
var iterable = new Iterable<C>.generate(elements.length, (n) => elements[n]);
var objectIterable = Iterable.castFrom<C, Object>(iterable);
Expect.listEquals(elements, objectIterable.toList());
}

View file

@ -0,0 +1,46 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testDowncast();
testUpcast();
testRegression();
}
void testDowncast() {
var list = new List<C>.from(elements);
var dList = List.castFrom<C, D>(list);
Expect.throws(() => dList.first); // C is not D.
Expect.equals(d, dList[1]);
Expect.throws(() => dList[2]); // E is not D.
Expect.equals(f, dList[3]);
Expect.equals(null, dList.last);
Expect.throws(() => dList.toList());
// Setting works.
dList[2] = d;
Expect.equals(d, dList[2]);
}
void testUpcast() {
var list2 = new List<C>.from(elements);
var dList2 = List.castFrom<C, Object>(list2);
Expect.listEquals(elements, dList2);
Expect.throws(() => dList2[2] = new Object()); // Cannot set non-C.
Expect.listEquals(elements, dList2);
}
void testRegression() {
var numList = <num>[4, 3, 2, 1];
var intList = numList.cast<int>();
intList.sort(null);
Expect.listEquals([1, 2, 3, 4], numList);
Expect.listEquals([1, 2, 3, 4], intList);
}

View file

@ -0,0 +1,62 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testDowncast();
testUpcast();
}
void testDowncast() {
var map = new Map.fromIterables(elements, elements);
var dMap = Map.castFrom<C, C, D, D>(map);
Expect.isTrue(dMap is Map<D, D>);
Expect.equals(null, dMap[new C()]);
Expect.throws(() => dMap[c]); // C is not D.
Expect.isTrue(dMap.containsKey(c)); // containsKey should not be typed.
Expect.equals(d, dMap[d]);
Expect.throws(() => dMap[e]); // E is not D.
Expect.isTrue(dMap.containsKey(null));
Expect.equals(null, dMap[null]);
Expect.equals(5, dMap.length);
Expect.throws(() => dMap.remove(c)); // Removes key but fails to return value.
Expect.equals(4, dMap.length);
Expect.equals(null, dMap[c]);
// Runtime errors when assigning or accessing a C.
Expect.throws(() => dMap[c] = d);
Expect.throws(() => dMap[d] = c);
Expect.equals(4, dMap.length);
// Test keys and values.
Expect.isTrue(dMap.keys is Iterable<D>);
Expect.isTrue(dMap.values is Iterable<D>);
Expect.throws(() => dMap.keys.toList());
Expect.throws(() => dMap.values.toList());
}
void testUpcast() {
var map = new Map.fromIterables(elements, elements);
var objectMap = Map.castFrom<C, C, Object, Object>(map);
Expect.equals(5, objectMap.length);
Expect.equals(c, objectMap[c]);
Expect.isTrue(objectMap.containsKey(c));
Expect.equals(c, objectMap.remove(c));
Expect.equals(4, objectMap.length);
// Test keys and values.
Expect.isTrue(objectMap.keys is Iterable<Object>);
Expect.isTrue(objectMap.values is Iterable<Object>);
var expected = new List<Object>.from(elements);
expected.remove(c);
Expect.listEquals(expected, objectMap.keys.toList());
Expect.listEquals(expected, objectMap.values.toList());
}

View file

@ -0,0 +1,73 @@
// Copyright (c) 2020, 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";
import 'cast_helper.dart';
void main() {
testOrder();
testDowncast();
testUpcast();
testNewSet();
}
void testOrder() {
var setEls = new Set<C>.from(elements); // Linked HashSet.
Expect.listEquals(elements, setEls.toList()); // Preserves order.
}
void testDowncast() {
var setEls = new Set<C>.from(elements);
var dSet = Set.castFrom<C, D>(setEls);
// Preserves order.
Expect.throws(() => dSet.first); // C is not D.
Expect.equals(d, dSet.elementAt(1));
Expect.throws(() => dSet.elementAt(2)); // E is not D.
Expect.equals(f, dSet.elementAt(3));
Expect.equals(null, dSet.elementAt(4));
Expect.throws(() => dSet.toList());
// Contains should not be typed.
var newC = new C();
Expect.isFalse(dSet.contains(newC));
Expect.throws(() => dSet.add(newC));
Expect.isFalse(dSet.contains(newC));
Expect.isTrue(dSet.contains(c));
// Remove and length should not be typed.
Expect.equals(5, dSet.length);
dSet.remove(c); // Success, no type checks.
Expect.equals(4, dSet.length);
}
void testUpcast() {
var setEls = new Set<C>.from(elements);
var objectSet = Set.castFrom<C, Object>(setEls);
Expect.listEquals(elements, objectSet.toList());
var newObject = new Object();
Expect.throws(() => objectSet.add(newObject));
Expect.isFalse(objectSet.contains(newObject));
var toSet = objectSet.toSet();
Expect.isTrue(toSet is LinkedHashSet<Object>);
Expect.isFalse(toSet is LinkedHashSet<C>);
}
void testNewSet() {
// Specified custom newSet as empty HashSet.
var setEls = new Set<C>.from(elements);
var customNewSet;
var objectSet2 = Set.castFrom<C, Object>(setEls,
newSet: <T>() => customNewSet = new HashSet<T>());
var customToSet = objectSet2.toSet();
Expect.isTrue(customToSet is HashSet<Object>);
Expect.isFalse(customToSet is HashSet<C>);
Expect.identical(customToSet, customNewSet);
}

View file

@ -1,186 +0,0 @@
// 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() {
testIterable();
testList();
}
final elements = <C>[c, d, e, f, null];
void testIterable() {
var iterable = new Iterable<C>.generate(elements.length, (n) => elements[n]);
// Down-cast
{
// An iterable that (likely) can do direct access.
var dIterable = Iterable.castFrom<C, D>(iterable);
Expect.throws(() => dIterable.first, null, "1.first");
Expect.equals(d, dIterable.elementAt(1));
Expect.throws(() => dIterable.elementAt(2), null, "1.2"); // E is not D.
Expect.equals(f, dIterable.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable.skip(3).elementAt(1));
Expect.throws(() => dIterable.toList(), null, "1.toList");
}
{
// An iterable that cannot do direct access.
var dIterable2 = Iterable.castFrom<C, D>(iterable.where((_) => true));
Expect.throws(() => dIterable2.first, null, "2.first");
Expect.equals(d, dIterable2.elementAt(1));
Expect.throws(() => dIterable2.elementAt(2), null, "2.2"); // E is not D.
Expect.equals(f, dIterable2.skip(3).first); // Skip does not access element.
Expect.equals(null, dIterable2.skip(3).elementAt(1));
Expect.throws(() => dIterable2.toList(), null, "2.toList");
}
{
// Iterable that definitely won't survive accessing element 2.
var iterable3 = new Iterable<C>.generate(
elements.length, (n) => n == 3 ? throw "untouchable" : elements[n]);
var dIterable3 = Iterable.castFrom<C, D>(iterable3);
Expect.throws(() => dIterable3.first, null, "3.first");
Expect.equals(d, dIterable3.elementAt(1));
Expect.throws(() => dIterable3.elementAt(3), null, "3.3");
// Skip does not access element.
Expect.equals(null, dIterable3.skip(4).first);
Expect.equals(null, dIterable3.skip(3).elementAt(1));
Expect.throws(() => dIterable3.toList(), null, "3.toList");
}
// Up-cast.
{
var oIterable4 = Iterable.castFrom<C, Object>(iterable);
Expect.listEquals(elements, oIterable4.toList());
}
}
void testList() {
// Down-cast.
var list = new List<C>.from(elements);
var dList = List.castFrom<C, D>(list);
Expect.throws(() => dList.first); // C is not D.
Expect.equals(d, dList[1]);
Expect.throws(() => dList[2]); // E is not D.
Expect.equals(f, dList[3]);
Expect.equals(null, dList.last);
Expect.throws(() => dList.toList());
dList[2] = d;
Expect.equals(d, dList[2]); // Setting works.
// Up-cast.
var list2 = new List<C>.from(elements);
var dList2 = List.castFrom<C, Object>(list2);
Expect.listEquals(elements, dList2);
Expect.throws(() => dList2[2] = new Object()); // Cannot set non-C.
Expect.listEquals(elements, dList2);
// Regression test.
var list3 = <num>[4, 3, 2, 1];
var dList3 = list3.cast<int>();
dList3.sort(null);
Expect.listEquals([1, 2, 3, 4], list3);
}
void testSet() {
var set = new Set<C>.from(elements); // Linked HashSet.
Expect.listEquals(elements, set.toList()); // Preserves order.
var dSet = Set.castFrom<C, D>(set);
// Preserves order.
Expect.throws(() => dSet.first); // C is not D.
Expect.equals(d, dSet.elementAt(1));
Expect.throws(() => dSet.elementAt(2)); // E is not D.
Expect.throws(() => dSet.toList());
// Contains is not typed.
var newC = new C();
Expect.isFalse(dSet.contains(newC));
dSet.add(newC);
Expect.isTrue(dSet.contains(newC));
Expect.equals(5, dSet.length);
dSet.remove(newC);
Expect.equals(5, dSet.length);
dSet.remove(c); // Success, no type checks.
Expect.equals(4, dSet.length);
// Up-cast
var set2 = new Set<C>.from(elements);
var dSet2 = Set.castFrom<C, Object>(set2);
var newObject = new Object();
Expect.throws(() => dSet2.add(newObject));
Expect.isFalse(dSet.contains(newObject));
var toSet2 = dSet2.toSet();
Expect.isTrue(toSet2 is LinkedHashSet<Object>);
Expect.isTrue(toSet2 is! LinkedHashSet<C>);
// Custom emptySet.
var set3 = new Set<C>.from(elements);
var dSet3 = Set.castFrom<C, Object>(set3, newSet: <T>() => new HashSet<T>());
var toSet3 = dSet3.toSet();
Expect.isTrue(toSet3 is HashSet<Object>);
Expect.isTrue(toSet3 is HashSet<C>);
Expect.isTrue(toSet3 is! LinkedHashSet<Object>);
}
void testMap() {
var map = new Map.fromIterables(elements, elements);
var dMap = Map.castFrom<C, C, D, D>(map);
Expect.isTrue(dMap is Map<D, D>);
Expect.equals(null, dMap[new C()]);
Expect.throws(() => dMap[c]);
Expect.isTrue(dMap.containsKey(c));
Expect.equals(d, dMap[d]);
Expect.throws(() => dMap[e]);
Expect.equals(null, dMap[null]);
Expect.equals(5, dMap.length);
dMap.remove(c); // Success, no type checks along the way.
Expect.equals(4, dMap.length);
Expect.equals(null, dMap[c]);
Expect.throws(() => dMap[c] = d);
Expect.throws(() => dMap[d] = c);
Expect.equals(4, dMap.length);
Expect.isTrue(dMap.keys is Iterable<D>);
Expect.isTrue(dMap.values is Iterable<D>);
Expect.throws(() => dMap.keys.toList());
Expect.throws(() => dMap.values.toList());
}
class C {}
class D extends C {}
class E extends C {}
class F implements D, E {}
final c = new C();
final d = new D();
final e = new E();
final f = new F();