blob: 36efe9e7531d45b4f0112deaaaebdc84a4f8664b [file] [log] [blame]
// 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();