blob: 86a0ddd1b349621550f2afcc2d647f340ee61b3d [file] [log] [blame]
// 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.
/// Tests wrapper utilities.
import "dart:collection";
import "package:collection/collection.dart";
import "package:unittest/unittest.dart";
// Test that any member access/call on the wrapper object is equal to
// an expected access on the wrapped object.
// This is implemented by capturing accesses using noSuchMethod and comparing
// them to expected accesses captured previously.
// Compare two Invocations for having equal type and arguments.
void testInvocations(Invocation i1, Invocation i2) {
String name = "${i1.memberName}";
expect(i1.isGetter, equals(i2.isGetter), reason: name);
expect(i1.isSetter, equals(i2.isSetter), reason: name);
expect(i1.memberName, equals(i2.memberName), reason: name);
expect(i1.positionalArguments, equals(i2.positionalArguments), reason: name);
expect(i1.namedArguments, equals(i2.namedArguments), reason: name);
}
/**
* Utility class to record a member access and a member access on a wrapped
* object, and compare them for equality.
*/
abstract class Expector {
getWrappedObject(action(Invocation i));
// Hack to test assignment ([]=) because it doesn't return the result
// of the member call. Instead use (expect..[4]=5).equal[4]=5 where
// you would normally use expect[4].equals[4] for non-assignments.
var equals;
noSuchMethod(Invocation m) => new _Equals(equals = getWrappedObject((m2) {
testInvocations(m, m2);
}));
toString() => new _Equals(equals = getWrappedObject((m2) {
testInvocations(TO_STRING_INVOCATION, m2);
}));
}
// An object with a field called "equals", only introduced into the
// flow to allow writing expect.xxx.equals.xxx.
class _Equals {
final equals;
_Equals(this.equals);
}
class SyntheticInvocation implements Invocation {
static const int METHOD = 0x00;
static const int GETTER = 0x01;
static const int SETTER = 0x02;
final Symbol memberName;
final List positionalArguments;
final Map namedArguments;
final int _type;
const SyntheticInvocation(this.memberName,
this.positionalArguments,
this.namedArguments,
this._type);
bool get isMethod => _type == METHOD;
bool get isGetter => _type == GETTER;
bool get isSetter => _type == SETTER;
bool get isAccessor => isGetter || isSetter;
}
// Parameterization of noSuchMethod.
class NSM {
Function _action;
NSM(this._action);
noSuchMethod(Invocation i) => _action(i);
}
const TO_STRING_INVOCATION = const SyntheticInvocation(
#toString, const[], const{}, SyntheticInvocation.METHOD);
// LikeNSM, but has types Iterable, Set and List to allow it as
// argument to DelegatingIterable/Set/List.
class IterableNSM extends NSM implements Iterable, Set, List, Queue {
IterableNSM(action(Invocation i)) : super(action);
noSuchMethod(Invocation i) => super.noSuchMethod(i); // Silence warnings
toString() => super.noSuchMethod(TO_STRING_INVOCATION);
}
// Expector that wraps in DelegatingIterable.
class IterableExpector extends Expector {
getWrappedObject(void action(Invocation i)) {
return new DelegatingIterable(new IterableNSM(action));
}
}
// Expector that wraps in DelegatingList.
class ListExpector extends Expector {
getWrappedObject(void action(Invocation i)) {
return new DelegatingList(new IterableNSM(action));
}
}
// Expector that wraps in DelegatingSet.
class SetExpector extends Expector {
getWrappedObject(void action(Invocation i)) {
return new DelegatingSet(new IterableNSM(action));
}
}
// Expector that wraps in DelegatingSet.
class QueueExpector extends Expector {
getWrappedObject(void action(Invocation i)) {
return new DelegatingQueue(new IterableNSM(action));
}
}
// Like NSM but implements Map to allow as argument for DelegatingMap.
class MapNSM extends NSM implements Map {
MapNSM(action(Invocation i)) : super(action);
noSuchMethod(Invocation i) => super.noSuchMethod(i);
toString() => super.noSuchMethod(TO_STRING_INVOCATION);
}
// Expector that wraps in DelegatingMap.
class MapExpector extends Expector {
getWrappedObject(void action(Invocation i)) {
return new DelegatingMap(new MapNSM(action));
}
}
// Utility values to use as arguments in calls.
func0() {}
func1(x) {}
func2(x, y) {}
var val = new Object();
void main() {
testIterable(var expect) {
expect.any(func1).equals.any(func1);
expect.contains(val).equals.contains(val);
expect.elementAt(0).equals.elementAt(0);
expect.every(func1).equals.every(func1);
expect.expand(func1).equals.expand(func1);
expect.first.equals.first;
// Default values of the Iterable interface will be added in the
// second call to firstWhere, so we must record them in our
// expectation (which doesn't have the interface implementat or
// its default values).
expect.firstWhere(func1, orElse: null).equals.firstWhere(func1);
expect.firstWhere(func1, orElse: func0).equals.
firstWhere(func1, orElse: func0);
expect.fold(null, func2).equals.fold(null, func2);
expect.forEach(func1).equals.forEach(func1);
expect.isEmpty.equals.isEmpty;
expect.isNotEmpty.equals.isNotEmpty;
expect.iterator.equals.iterator;
expect.join('').equals.join();
expect.join("X").equals.join("X");
expect.last.equals.last;
expect.lastWhere(func1, orElse: null).equals.lastWhere(func1);
expect.lastWhere(func1, orElse: func0).equals.
lastWhere(func1, orElse: func0);
expect.length.equals.length;
expect.map(func1).equals.map(func1);
expect.reduce(func2).equals.reduce(func2);
expect.single.equals.single;
expect.singleWhere(func1).equals.singleWhere(func1);
expect.skip(5).equals.skip(5);
expect.skipWhile(func1).equals.skipWhile(func1);
expect.take(5).equals.take(5);
expect.takeWhile(func1).equals.takeWhile(func1);
expect.toList(growable: true).equals.toList();
expect.toList(growable: true).equals.toList(growable: true);
expect.toList(growable: false).equals.toList(growable: false);
expect.toSet().equals.toSet();
expect.toString().equals.toString();
expect.where(func1).equals.where(func1);
}
void testList(var expect) {
testIterable(expect);
expect[4].equals[4];
(expect..[4] = 5).equals[4] = 5;
expect.add(val).equals.add(val);
expect.addAll([val]).equals.addAll([val]);
expect.asMap().equals.asMap();
expect.clear().equals.clear();
expect.fillRange(4, 5, null).equals.fillRange(4, 5);
expect.fillRange(4, 5, val).equals.fillRange(4, 5, val);
expect.getRange(4, 5).equals.getRange(4, 5);
expect.indexOf(val, 0).equals.indexOf(val);
expect.indexOf(val, 4).equals.indexOf(val, 4);
expect.insert(4, val).equals.insert(4, val);
expect.insertAll(4, [val]).equals.insertAll(4, [val]);
expect.lastIndexOf(val, null).equals.lastIndexOf(val);
expect.lastIndexOf(val, 4).equals.lastIndexOf(val, 4);
(expect..length = 4).equals.length = 4;
expect.remove(val).equals.remove(val);
expect.removeAt(4).equals.removeAt(4);
expect.removeLast().equals.removeLast();
expect.removeRange(4, 5).equals.removeRange(4, 5);
expect.removeWhere(func1).equals.removeWhere(func1);
expect.replaceRange(4, 5, [val]).equals.replaceRange(4, 5, [val]);
expect.retainWhere(func1).equals.retainWhere(func1);
expect.reversed.equals.reversed;
expect.setAll(4, [val]).equals.setAll(4, [val]);
expect.setRange(4, 5, [val], 0).equals.setRange(4, 5, [val]);
expect.setRange(4, 5, [val], 3).equals.setRange(4, 5, [val], 3);
expect.sort(null).equals.sort();
expect.sort(func2).equals.sort(func2);
expect.sublist(4, null).equals.sublist(4);
expect.sublist(4, 5).equals.sublist(4, 5);
}
void testSet(var expect) {
testIterable(expect);
Set set = new Set();
expect.add(val).equals.add(val);
expect.addAll([val]).equals.addAll([val]);
expect.clear().equals.clear();
expect.containsAll([val]).equals.containsAll([val]);
expect.difference(set).equals.difference(set);
expect.intersection(set).equals.intersection(set);
expect.remove(val).equals.remove(val);
expect.removeAll([val]).equals.removeAll([val]);
expect.removeWhere(func1).equals.removeWhere(func1);
expect.retainAll([val]).equals.retainAll([val]);
expect.retainWhere(func1).equals.retainWhere(func1);
expect.union(set).equals.union(set);
}
void testQueue(var expect) {
testIterable(expect);
expect.add(val).equals.add(val);
expect.addAll([val]).equals.addAll([val]);
expect.addFirst(val).equals.addFirst(val);
expect.addLast(val).equals.addLast(val);
expect.clear().equals.clear();
expect.remove(val).equals.remove(val);
expect.removeFirst().equals.removeFirst();
expect.removeLast().equals.removeLast();
}
void testMap(var expect) {
Map map = new Map();
expect[val].equals[val];
(expect..[val] = val).equals[val] = val;
expect.addAll(map).equals.addAll(map);
expect.clear().equals.clear();
expect.containsKey(val).equals.containsKey(val);
expect.containsValue(val).equals.containsValue(val);
expect.forEach(func2).equals.forEach(func2);
expect.isEmpty.equals.isEmpty;
expect.isNotEmpty.equals.isNotEmpty;
expect.keys.equals.keys;
expect.length.equals.length;
expect.putIfAbsent(val, func0).equals.putIfAbsent(val, func0);
expect.remove(val).equals.remove(val);
expect.values.equals.values;
expect.toString().equals.toString();
}
test("Iterable", () {
testIterable(new IterableExpector());
});
test("List", () {
testList(new ListExpector());
});
test("Set", () {
testSet(new SetExpector());
});
test("Queue", () {
testQueue(new QueueExpector());
});
test("Map", () {
testMap(new MapExpector());
});
}