mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:07:57 +00:00
[dartdevc] Move opted out tests to tests/dartdevc and optin.
Change-Id: Ia032182ae94e9215c22fe1627dc93495946d4074 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151640 Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Joshua Litt <joshualitt@google.com>
This commit is contained in:
parent
4f1294e495
commit
f0625ac010
29
tests/dartdevc/assertion_failure_message_test.dart
Normal file
29
tests/dartdevc/assertion_failure_message_test.dart
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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 "utils.dart";
|
||||
|
||||
void main() {
|
||||
try {
|
||||
assert(false, "failure message");
|
||||
} on AssertionError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains('Assertion failed:', message);
|
||||
expectStringContains('assertion_failure_message_test.dart:9:12', message);
|
||||
expectStringContains('false', message);
|
||||
expectStringContains('failure message', message);
|
||||
}
|
||||
|
||||
// 失 All offsets and source code extractions should still be correct after
|
||||
// non-UTF8 characters. See: https://github.com/dart-lang/sdk/issues/39271
|
||||
try {
|
||||
assert(false, "after a non-UTF8 character");
|
||||
} on AssertionError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains('Assertion failed:', message);
|
||||
expectStringContains('assertion_failure_message_test.dart:21:12', message);
|
||||
expectStringContains('false', message);
|
||||
expectStringContains('after a non-UTF8 character', message);
|
||||
}
|
||||
}
|
30
tests/dartdevc/const_test.dart
Normal file
30
tests/dartdevc/const_test.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
// 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 "package:expect/expect.dart";
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
import 'dart:_runtime' as dart;
|
||||
|
||||
void main() {
|
||||
var data = JS('', '[1, 2, 3, 4]');
|
||||
Expect.isFalse(data is List<int>);
|
||||
|
||||
var list = dart.constList(data, dart.unwrapType(int));
|
||||
Expect.isTrue(list is List<int>);
|
||||
Expect.throws(() {
|
||||
list[0] = 0;
|
||||
});
|
||||
|
||||
var set = dart.constSet<int>(data);
|
||||
Expect.isTrue(set is Set<int>);
|
||||
Expect.isTrue(set.contains(3));
|
||||
Expect.throws(() => set.clear());
|
||||
|
||||
var map = dart.constMap<int, int>(data);
|
||||
Expect.isTrue(map is Map<int, int>);
|
||||
Expect.equals(map[1], 2);
|
||||
Expect.throws(() {
|
||||
map[1] = 42;
|
||||
});
|
||||
}
|
357
tests/dartdevc/debugger/debugger_test.dart
Normal file
357
tests/dartdevc/debugger/debugger_test.dart
Normal file
|
@ -0,0 +1,357 @@
|
|||
/// Debugger custom formatter tests.
|
||||
/// If the tests fail, paste the expected output into the [expectedGolden]
|
||||
/// string literal in this file and audit the diff to ensure changes are
|
||||
/// expected.
|
||||
///
|
||||
/// Currently only DDC supports debugging objects with custom formatters
|
||||
/// but it is reasonable to add support to Dart2JS in the future.
|
||||
@JS()
|
||||
library debugger_test;
|
||||
|
||||
import 'dart:html';
|
||||
import 'package:js/js.dart';
|
||||
import 'package:js/js_util.dart' as js_util;
|
||||
|
||||
import 'package:expect/minitest.dart';
|
||||
|
||||
import 'dart:_debugger' as _debugger;
|
||||
|
||||
class TestClass {
|
||||
String name = 'test class';
|
||||
int date;
|
||||
static List<int> foo = [1, 2, 3, 4];
|
||||
static String greeting = 'Hello world';
|
||||
static Object bar = new Object();
|
||||
|
||||
static exampleStaticMethod(x) => x * 2;
|
||||
|
||||
TestClass(this.date);
|
||||
|
||||
String nameAndDate() => '$name on day $date';
|
||||
|
||||
int last(List<int> list) => list.last;
|
||||
|
||||
void addOne(String name) {
|
||||
name = '${name}1';
|
||||
}
|
||||
|
||||
get someInt => 42;
|
||||
get someString => "Hello world";
|
||||
get someObject => this;
|
||||
|
||||
Object returnObject() => bar;
|
||||
}
|
||||
|
||||
class TestGenericClass<X, Y> {
|
||||
TestGenericClass(this.x);
|
||||
X x;
|
||||
}
|
||||
|
||||
@JS('Object.getOwnPropertyNames')
|
||||
external List getOwnPropertyNames(obj);
|
||||
|
||||
@JS('devtoolsFormatters')
|
||||
external List get _devtoolsFormatters;
|
||||
List get devtoolsFormatters => _devtoolsFormatters;
|
||||
|
||||
@JS('JSON.stringify')
|
||||
external stringify(value, [Function replacer, int space]);
|
||||
|
||||
// TODO(jacobr): this is only valid if the legacy library loader is used.
|
||||
// We need a solution that works with all library loaders.
|
||||
@JS('dart_library.import')
|
||||
external importDartLibrary(String path);
|
||||
|
||||
@JS('ExampleJSClass')
|
||||
class ExampleJSClass<T> {
|
||||
external factory ExampleJSClass(T x);
|
||||
external T get x;
|
||||
}
|
||||
|
||||
// Replacer normalizes file names that could vary depending on the test runner.
|
||||
// styles.
|
||||
replacer(String key, value) {
|
||||
// The values for keys with name 'object' may be arbitrary Dart nested
|
||||
// Objects so are not safe to stringify.
|
||||
if (key == 'object') return '<OBJECT>';
|
||||
if (value is String) {
|
||||
if (value.contains('dart_sdk.js')) return '<DART_SDK>';
|
||||
if (new RegExp(r'[.](js|dart|html)').hasMatch(value)) return '<FILE>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
String format(value) {
|
||||
// Avoid double-escaping strings.
|
||||
if (value is String) return value;
|
||||
return stringify(value, allowInterop(replacer), 4);
|
||||
}
|
||||
|
||||
class FormattedObject {
|
||||
FormattedObject(this.object, this.config);
|
||||
|
||||
Object object;
|
||||
Object config;
|
||||
}
|
||||
|
||||
/// Extract all object tags from a json ml expression to enable
|
||||
/// calling the custom formatter on the extracted object tag.
|
||||
List<FormattedObject> extractNestedFormattedObjects(json) {
|
||||
var ret = <FormattedObject>[];
|
||||
if (json is String || json is bool || json is num) return ret;
|
||||
if (json is List) {
|
||||
for (var e in json) {
|
||||
ret.addAll(extractNestedFormattedObjects(e));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (var name in getOwnPropertyNames(json)) {
|
||||
if (name == 'object') {
|
||||
// Found a nested formatted object.
|
||||
ret.add(new FormattedObject(js_util.getProperty(json, 'object'),
|
||||
js_util.getProperty(json, 'config')));
|
||||
return ret;
|
||||
}
|
||||
ret.addAll(extractNestedFormattedObjects(js_util.getProperty(json, name)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
main() async {
|
||||
if (devtoolsFormatters == null) {
|
||||
print("Warning: no devtools custom formatters specified. Skipping tests.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache blocker is a workaround for:
|
||||
// https://code.google.com/p/dart/issues/detail?id=11834
|
||||
var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
|
||||
var goldenUrl = '/root_dart/tests/dartdevc_2/debugger/'
|
||||
'debugger_test_golden.txt?cacheBlock=$cacheBlocker';
|
||||
|
||||
String golden;
|
||||
try {
|
||||
golden = (await HttpRequest.getString(goldenUrl)).trim();
|
||||
} catch (e) {
|
||||
print("Warning: couldn't load golden file from $goldenUrl");
|
||||
}
|
||||
|
||||
document.body.append(new ScriptElement()
|
||||
..type = 'text/javascript'
|
||||
..innerHtml = r"""
|
||||
window.ExampleJSClass = function ExampleJSClass(x) {
|
||||
this.x = x;
|
||||
};
|
||||
""");
|
||||
|
||||
var _devtoolsFormatter = devtoolsFormatters.first;
|
||||
|
||||
var actual = new StringBuffer();
|
||||
|
||||
// Accumulate the entire expected custom formatted data as a single
|
||||
// massive string buffer so it is simple to update expectations when
|
||||
// modifying the formatting code.
|
||||
// Otherwise a small formatting change would result in tweaking lots
|
||||
// of expectations.
|
||||
// The verify golden match test cases does the final comparison of golden
|
||||
// to expected output.
|
||||
addGolden(String name, value) {
|
||||
var text = format(value);
|
||||
actual.write('Test: $name\n'
|
||||
'Value:\n'
|
||||
'$text\n'
|
||||
'-----------------------------------\n');
|
||||
}
|
||||
|
||||
addFormatterGoldens(String name, object, [config]) {
|
||||
addGolden(
|
||||
'$name formatting header', _devtoolsFormatter.header(object, config));
|
||||
addGolden('$name formatting body', _devtoolsFormatter.body(object, config));
|
||||
}
|
||||
|
||||
// Include goldens for the nested [[class]] definition field.
|
||||
addNestedFormatterGoldens(String name, obj) {
|
||||
addGolden('$name instance header', _devtoolsFormatter.header(obj, null));
|
||||
var body = _devtoolsFormatter.body(obj, null);
|
||||
addGolden('$name instance body', body);
|
||||
|
||||
var nestedObjects = extractNestedFormattedObjects(body);
|
||||
var clazz = nestedObjects.last;
|
||||
// By convention assume last nested object is the [[class]] definition
|
||||
// describing the object's static members and inheritance hierarchy
|
||||
addFormatterGoldens('$name definition', clazz.object, clazz.config);
|
||||
}
|
||||
|
||||
// Include goldens for the nested [[class]] definition field.
|
||||
addAllNestedFormatterGoldens(String name, obj) {
|
||||
addGolden('$name header', _devtoolsFormatter.header(obj, null));
|
||||
var body = _devtoolsFormatter.body(obj, null);
|
||||
addGolden('$name body', body);
|
||||
|
||||
var nestedObjects = extractNestedFormattedObjects(body);
|
||||
var i = 0;
|
||||
for (var nested in nestedObjects) {
|
||||
addFormatterGoldens('$name child $i', nested.object, nested.config);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
group('Iterable formatting', () {
|
||||
var list = ['foo', 'bar', 'baz'];
|
||||
var iterable = list.map((x) => x * 5);
|
||||
addFormatterGoldens('List<String>', list);
|
||||
|
||||
var listOfObjects = <Object>[42, 'bar', true];
|
||||
|
||||
addNestedFormatterGoldens('List<Object>', listOfObjects);
|
||||
|
||||
var largeList = <int>[];
|
||||
for (var i = 0; i < 200; ++i) {
|
||||
largeList.add(i * 10);
|
||||
}
|
||||
addNestedFormatterGoldens('List<int> large', largeList);
|
||||
|
||||
addNestedFormatterGoldens('Iterable', iterable);
|
||||
|
||||
var s = new Set()..add("foo")..add(42)..add(true);
|
||||
addNestedFormatterGoldens('Set', s);
|
||||
});
|
||||
|
||||
group('Map formatting', () {
|
||||
Map<String, int> foo = new Map();
|
||||
foo = {'1': 2, 'x': 4, '5': 6};
|
||||
|
||||
addFormatterGoldens('Map<String, int>', foo);
|
||||
test('hasBody', () {
|
||||
expect(_devtoolsFormatter.hasBody(foo, null), isTrue);
|
||||
});
|
||||
|
||||
Map<dynamic, dynamic> dynamicMap = new Map();
|
||||
dynamicMap = {1: 2, 'x': 4, true: "truthy"};
|
||||
|
||||
addNestedFormatterGoldens('Map<dynamic, dynamic>', dynamicMap);
|
||||
});
|
||||
|
||||
group('Function formatting', () {
|
||||
adder(int a, int b) => a + b;
|
||||
|
||||
addFormatterGoldens('Function', adder);
|
||||
|
||||
test('hasBody', () {
|
||||
expect(_devtoolsFormatter.hasBody(adder, null), isTrue);
|
||||
});
|
||||
|
||||
addEventListener(String name, bool callback(Event e)) => null;
|
||||
|
||||
addFormatterGoldens('Function with functon arguments', addEventListener);
|
||||
|
||||
// Closure
|
||||
addGolden('dart:html method', window.addEventListener);
|
||||
|
||||
// Get a reference to the JS constructor for a Dart class.
|
||||
// This tracks a regression bug where overly verbose and confusing output
|
||||
// was shown for this case.
|
||||
var testClass = new TestClass(17);
|
||||
var dartConstructor = js_util.getProperty(
|
||||
js_util.getProperty(testClass, '__proto__'), 'constructor');
|
||||
addFormatterGoldens('Raw reference to dart constructor', dartConstructor);
|
||||
});
|
||||
|
||||
group('Object formatting', () {
|
||||
var object = new Object();
|
||||
addFormatterGoldens('Object', object);
|
||||
test('hasBody', () {
|
||||
expect(_devtoolsFormatter.hasBody(object, null), isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
group('Type formatting', () {
|
||||
addFormatterGoldens('Type TestClass', TestClass);
|
||||
addFormatterGoldens('Type HttpRequest', HttpRequest);
|
||||
});
|
||||
|
||||
group('JS interop object formatting', () {
|
||||
var object = js_util.newObject();
|
||||
js_util.setProperty(object, 'foo', 'bar');
|
||||
// Make sure we don't apply the Dart custom formatter to JS interop objects.
|
||||
expect(_devtoolsFormatter.header(object, null), isNull);
|
||||
});
|
||||
|
||||
group('Module formatting', () {
|
||||
var moduleNames = _debugger.getModuleNames();
|
||||
var testModuleName = "debugger_test";
|
||||
expect(moduleNames.contains(testModuleName), isTrue);
|
||||
|
||||
addAllNestedFormatterGoldens(
|
||||
'Test library Module', _debugger.getModuleLibraries(testModuleName));
|
||||
});
|
||||
|
||||
group('StackTrace formatting', () {
|
||||
StackTrace stack;
|
||||
try {
|
||||
throw new Error();
|
||||
} catch (exception, stackTrace) {
|
||||
stack = stackTrace;
|
||||
}
|
||||
addFormatterGoldens('StackTrace', stack);
|
||||
test('hasBody', () {
|
||||
expect(_devtoolsFormatter.hasBody(stack, null), isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
group('Class formatting', () {
|
||||
addNestedFormatterGoldens('TestClass', new TestClass(17));
|
||||
// TODO(jmesserly): this includes a timeStamp, so it varies each run.
|
||||
//addNestedFormatterGoldens('MouseEvent', new MouseEvent("click"));
|
||||
// This is a good class to test as it has statics and a deep inheritance hierarchy
|
||||
addNestedFormatterGoldens('HttpRequest', new HttpRequest());
|
||||
});
|
||||
|
||||
group('Generics formatting', () {
|
||||
addNestedFormatterGoldens(
|
||||
'TestGenericClass', new TestGenericClass<int, List>(42));
|
||||
addNestedFormatterGoldens(
|
||||
'TestGenericClassJSInterop',
|
||||
new TestGenericClass<ExampleJSClass<String>, int>(
|
||||
new ExampleJSClass("Hello")));
|
||||
});
|
||||
|
||||
test('verify golden match', () {
|
||||
// Warning: all other test groups must have run for this test to be meaningful
|
||||
var actualStr = actual.toString().trim();
|
||||
|
||||
if (actualStr != golden) {
|
||||
var helpMessage =
|
||||
'Debugger output does not match the golden data found in:\n'
|
||||
'tests/dartdevc_2/debugger/debugger_test_golden.txt\n'
|
||||
'The new golden data is copied to the clipboard when you click on '
|
||||
'this window.\n'
|
||||
'Please update the golden file with the following output and review '
|
||||
'the diff using your favorite diff tool to make sure the custom '
|
||||
'formatting output has not regressed.';
|
||||
print(helpMessage);
|
||||
// Copy text to clipboard on page click. We can't copy to the clipboard
|
||||
// without a click due to Chrome security.
|
||||
TextAreaElement textField = new Element.tag('textarea');
|
||||
textField.maxLength = 100000000;
|
||||
textField.text = actualStr;
|
||||
textField.style
|
||||
..width = '800px'
|
||||
..height = '400px';
|
||||
document.body.append(new Element.tag('h3')
|
||||
..innerHtml = helpMessage.replaceAll('\n', '<br>'));
|
||||
document.body.append(textField);
|
||||
document.body.onClick.listen((_) {
|
||||
textField.select();
|
||||
var result = document.execCommand('copy');
|
||||
if (result) {
|
||||
print("Copy to clipboard successful");
|
||||
} else {
|
||||
print("Copy to clipboard failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
expect(actualStr == golden, isTrue);
|
||||
});
|
||||
}
|
42
tests/dartdevc/hot_restart_test.dart
Normal file
42
tests/dartdevc/hot_restart_test.dart
Normal file
|
@ -0,0 +1,42 @@
|
|||
// 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 'package:expect/expect.dart';
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
import 'dart:_runtime' as dart;
|
||||
|
||||
class Foo<T> {
|
||||
Type type() => typeOf<Foo<T>>();
|
||||
}
|
||||
|
||||
class Bar {}
|
||||
|
||||
Type typeOf<T>() => T;
|
||||
|
||||
Type fooOf<T>() => typeOf<Foo<T>>();
|
||||
|
||||
typedef funcType = Function(String);
|
||||
|
||||
void func(Object o) {}
|
||||
|
||||
void main() {
|
||||
var f1 = Foo<Bar>();
|
||||
var t1 = typeOf<Foo<Bar>>();
|
||||
Expect.equals(f1.type(), t1);
|
||||
var s1 = fooOf<Bar>();
|
||||
Expect.equals(t1, s1);
|
||||
|
||||
Expect.isTrue(func is funcType);
|
||||
|
||||
dart.hotRestart();
|
||||
|
||||
var f2 = Foo<Bar>();
|
||||
Expect.isTrue(f2 is Foo<Bar>);
|
||||
var t2 = typeOf<Foo<Bar>>();
|
||||
Expect.equals(f2.type(), t2);
|
||||
var s2 = fooOf<Bar>();
|
||||
Expect.equals(t2, s2);
|
||||
|
||||
Expect.isTrue(func is funcType);
|
||||
}
|
53
tests/dartdevc/hot_restart_timer_test.dart
Normal file
53
tests/dartdevc/hot_restart_timer_test.dart
Normal file
|
@ -0,0 +1,53 @@
|
|||
// 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 'package:expect/expect.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:_runtime' as dart;
|
||||
|
||||
void main() async {
|
||||
await timeoutTest();
|
||||
await periodicTest();
|
||||
}
|
||||
|
||||
void timeoutTest() async {
|
||||
bool beforeRestart = true;
|
||||
bool calledBeforeRestart = false;
|
||||
bool calledAfterRestart = false;
|
||||
void callback() {
|
||||
if (beforeRestart) {
|
||||
calledBeforeRestart = true;
|
||||
} else {
|
||||
calledAfterRestart = true;
|
||||
}
|
||||
}
|
||||
|
||||
Timer(Duration(milliseconds: 500), callback);
|
||||
dart.hotRestart();
|
||||
beforeRestart = false;
|
||||
await new Future.delayed(Duration(milliseconds: 600));
|
||||
Expect.isFalse(calledBeforeRestart);
|
||||
Expect.isFalse(calledAfterRestart);
|
||||
}
|
||||
|
||||
void periodicTest() async {
|
||||
bool beforeRestart = true;
|
||||
bool calledBeforeRestart = false;
|
||||
bool calledAfterRestart = false;
|
||||
void callback(_) {
|
||||
if (beforeRestart) {
|
||||
calledBeforeRestart = true;
|
||||
} else {
|
||||
calledAfterRestart = true;
|
||||
}
|
||||
}
|
||||
|
||||
Timer.periodic(Duration(milliseconds: 10), callback);
|
||||
await new Future.delayed(Duration(milliseconds: 100));
|
||||
dart.hotRestart();
|
||||
beforeRestart = false;
|
||||
await new Future.delayed(Duration(milliseconds: 100));
|
||||
Expect.isTrue(calledBeforeRestart);
|
||||
Expect.isFalse(calledAfterRestart);
|
||||
}
|
5
tests/dartdevc/libraries_part.dart
Normal file
5
tests/dartdevc/libraries_part.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
// 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.
|
||||
|
||||
part of 'libraries_test.dart';
|
32
tests/dartdevc/libraries_test.dart
Normal file
32
tests/dartdevc/libraries_test.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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 'package:expect/expect.dart';
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
import 'dart:_runtime' as dart;
|
||||
|
||||
part 'libraries_part.dart';
|
||||
|
||||
void main() {
|
||||
// Test getLibraries()
|
||||
var libraries = dart.getLibraries();
|
||||
Expect.isTrue(libraries.contains('dart:core'));
|
||||
Expect.isTrue(libraries.contains('package:expect/expect.dart'));
|
||||
|
||||
// Test getParts(...)
|
||||
var expectParts = dart.getParts('package:expect/expect.dart');
|
||||
Expect.isTrue(expectParts.isEmpty);
|
||||
|
||||
var testLibraries =
|
||||
libraries.where((l) => l.endsWith('libraries_test.dart')).toList();
|
||||
Expect.isTrue(testLibraries.length == 1);
|
||||
var testParts = dart.getParts(testLibraries.first);
|
||||
Expect.isTrue(testParts.length == 1);
|
||||
Expect.isTrue(testParts.first.endsWith('libraries_part.dart'));
|
||||
|
||||
// Test getLibrary(...)
|
||||
var core = dart.getLibrary('dart:core');
|
||||
var stackTraceType = dart.wrapType(JS('', '#.StackTrace', core));
|
||||
Expect.equals(StackTrace, stackTraceType);
|
||||
}
|
87
tests/dartdevc/no_such_method_errors_test.dart
Normal file
87
tests/dartdevc/no_such_method_errors_test.dart
Normal file
|
@ -0,0 +1,87 @@
|
|||
// 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 "utils.dart";
|
||||
|
||||
class A {
|
||||
int x = 42;
|
||||
String arity1(int val) {
|
||||
val += 10;
|
||||
return val.toString();
|
||||
}
|
||||
}
|
||||
|
||||
String arity1(int val) {
|
||||
val += 10;
|
||||
return val.toString();
|
||||
}
|
||||
|
||||
dynamic dynamicFunction = arity1;
|
||||
|
||||
void main() {
|
||||
dynamic instanceOfA = A();
|
||||
// Call an instance of a class with no call() method.
|
||||
try {
|
||||
instanceOfA();
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'call'", message);
|
||||
expectStringContains("Receiver: Instance of 'A'", message);
|
||||
}
|
||||
|
||||
dynamic tearOff = instanceOfA.arity1;
|
||||
// Dynamic call of a class method with too many arguments.
|
||||
try {
|
||||
tearOff(1, 2);
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'bound arity1'", message);
|
||||
expectStringContains("too many arguments", message);
|
||||
}
|
||||
|
||||
// Dynamic call of a class method with too few arguments.
|
||||
try {
|
||||
tearOff();
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'bound arity1'", message);
|
||||
expectStringContains("too few arguments", message);
|
||||
}
|
||||
|
||||
// Dynamic call of a top level funciton with too many arguments.
|
||||
try {
|
||||
dynamicFunction(1, 2);
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'arity1'", message);
|
||||
expectStringContains("too many arguments", message);
|
||||
}
|
||||
|
||||
// Dynamic call of a top level funciton with too few arguments.
|
||||
try {
|
||||
dynamicFunction();
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'arity1'", message);
|
||||
expectStringContains("too few arguments", message);
|
||||
}
|
||||
|
||||
// Function.apply() with too many arguments.
|
||||
try {
|
||||
Function.apply(dynamicFunction, [1, 2]);
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'arity1'", message);
|
||||
expectStringContains("too many arguments", message);
|
||||
}
|
||||
|
||||
// Function.apply() with too few arguments.
|
||||
try {
|
||||
Function.apply(dynamicFunction, []);
|
||||
} on NoSuchMethodError catch (error) {
|
||||
var message = error.toString();
|
||||
expectStringContains("NoSuchMethodError: 'arity1'", message);
|
||||
expectStringContains("too few arguments", message);
|
||||
}
|
||||
}
|
11
tests/dartdevc/utils.dart
Normal file
11
tests/dartdevc/utils.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
// 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 "package:expect/expect.dart";
|
||||
|
||||
/// Expects that [expected] appears as a substring in [actual].
|
||||
expectStringContains(String expected, String actual) {
|
||||
Expect.isTrue(actual.contains(expected),
|
||||
'Failure: "$expected" should appear in: "$actual".');
|
||||
}
|
189
tests/dartdevc/variance_subtype_test.dart
Normal file
189
tests/dartdevc/variance_subtype_test.dart
Normal file
|
@ -0,0 +1,189 @@
|
|||
// 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.
|
||||
|
||||
// SharedOptions=--enable-experiment=variance
|
||||
|
||||
// Tests runtime subtyping with explicit variance modifiers.
|
||||
|
||||
import 'dart:_runtime' show typeRep;
|
||||
import 'dart:async' show FutureOr;
|
||||
|
||||
import 'runtime_utils.dart';
|
||||
|
||||
class Upper {}
|
||||
|
||||
class Middle extends Upper {}
|
||||
|
||||
class Lower extends Middle {}
|
||||
|
||||
class Covariant<out T> {}
|
||||
|
||||
class Contravariant<in T> {}
|
||||
|
||||
class Invariant<inout T> {}
|
||||
|
||||
class LegacyCovariant<T> {}
|
||||
|
||||
void main() {
|
||||
// Covariant<Lower> <: Covariant<Middle>
|
||||
checkProperSubtype(typeRep<Covariant<Lower>>(), typeRep<Covariant<Middle>>());
|
||||
|
||||
// Covariant<Middle> <: Covariant<Middle>
|
||||
checkSubtype(typeRep<Covariant<Middle>>(), typeRep<Covariant<Middle>>());
|
||||
|
||||
// Contravariant<Upper> <: Contravariant<Middle>
|
||||
checkProperSubtype(
|
||||
typeRep<Contravariant<Upper>>(), typeRep<Contravariant<Middle>>());
|
||||
|
||||
// Contravariant<Middle> <: Contravariant<Middle>
|
||||
checkSubtype(
|
||||
typeRep<Contravariant<Middle>>(), typeRep<Contravariant<Middle>>());
|
||||
|
||||
// Invariant<Middle> <: Invariant<Middle>
|
||||
checkSubtype(typeRep<Invariant<Middle>>(), typeRep<Invariant<Middle>>());
|
||||
|
||||
// Invariant<dynamic> <:> Invariant<Object>
|
||||
checkMutualSubtype(
|
||||
typeRep<Invariant<dynamic>>(), typeRep<Invariant<Object>>());
|
||||
|
||||
// Invariant<FutureOr<dynamic>> <:> Invariant<dynamic>
|
||||
checkMutualSubtype(
|
||||
typeRep<Invariant<FutureOr<dynamic>>>(), typeRep<Invariant<dynamic>>());
|
||||
|
||||
// Invariant<FutureOr<Null>> <:> Invariant<Future<Null>>
|
||||
checkMutualSubtype(
|
||||
typeRep<Invariant<FutureOr<Null>>>(), typeRep<Invariant<Future<Null>>>());
|
||||
|
||||
// LegacyCovariant<Lower> <: LegacyCovariant<Middle>
|
||||
checkProperSubtype(
|
||||
typeRep<LegacyCovariant<Lower>>(), typeRep<LegacyCovariant<Middle>>());
|
||||
|
||||
// List<Covariant<Lower>> <: Iterable<Covariant<Middle>>
|
||||
checkProperSubtype(typeRep<List<Covariant<Lower>>>(),
|
||||
typeRep<Iterable<Covariant<Middle>>>());
|
||||
|
||||
// List<Contravariant<Upper>> <: Iterable<Contravariant<Middle>>
|
||||
checkProperSubtype(typeRep<List<Contravariant<Upper>>>(),
|
||||
typeRep<Iterable<Contravariant<Middle>>>());
|
||||
|
||||
// List<Invariant<Middle>> <: Iterable<Invariant<Middle>>
|
||||
checkProperSubtype(typeRep<List<Invariant<Middle>>>(),
|
||||
typeRep<Iterable<Invariant<Middle>>>());
|
||||
|
||||
// List<LegacyCovariant<Lower>> <: Iterable<LegacyCovariant<Middle>>
|
||||
checkProperSubtype(typeRep<List<LegacyCovariant<Lower>>>(),
|
||||
typeRep<Iterable<LegacyCovariant<Middle>>>());
|
||||
|
||||
// String -> Covariant<Lower> <: String -> Covariant<Middle>
|
||||
checkProperSubtype(typeRep<Covariant<Lower> Function(String)>(),
|
||||
typeRep<Covariant<Middle> Function(String)>());
|
||||
|
||||
// Covariant<Upper> -> String <: Covariant<Middle> -> String
|
||||
checkProperSubtype(typeRep<String Function(Covariant<Upper>)>(),
|
||||
typeRep<String Function(Covariant<Middle>)>());
|
||||
|
||||
// String -> Contravariant<Upper> <: String -> Contravariant<Middle>
|
||||
checkProperSubtype(typeRep<Contravariant<Upper> Function(String)>(),
|
||||
typeRep<Contravariant<Middle> Function(String)>());
|
||||
|
||||
// Contravariant<Lower> -> String <: Contravariant<Middle> -> String
|
||||
checkProperSubtype(typeRep<String Function(Contravariant<Lower>)>(),
|
||||
typeRep<String Function(Contravariant<Middle>)>());
|
||||
|
||||
// String -> Invariant<Middle> <: String -> Invariant<Middle>
|
||||
checkSubtype(typeRep<String Function(Invariant<Middle>)>(),
|
||||
typeRep<String Function(Invariant<Middle>)>());
|
||||
|
||||
// Invariant<Middle> -> String <: Invariant<Middle> -> String
|
||||
checkSubtype(typeRep<String Function(Invariant<Middle>)>(),
|
||||
typeRep<String Function(Invariant<Middle>)>());
|
||||
|
||||
// String -> LegacyCovariant<Lower> <: String -> LegacyCovariant<Middle>
|
||||
checkProperSubtype(typeRep<LegacyCovariant<Lower> Function(String)>(),
|
||||
typeRep<LegacyCovariant<Middle> Function(String)>());
|
||||
|
||||
// LegacyCovariant<Upper> -> String <: LegacyCovariant<Middle> -> String
|
||||
checkProperSubtype(typeRep<String Function(LegacyCovariant<Upper>)>(),
|
||||
typeRep<String Function(LegacyCovariant<Middle>)>());
|
||||
|
||||
// Covariant<Upper> </: Covariant<Middle>
|
||||
checkSubtypeFailure(
|
||||
typeRep<Covariant<Upper>>(), typeRep<Covariant<Middle>>());
|
||||
|
||||
// Contravariant<Lower> </: Contravariant<Middle>
|
||||
checkSubtypeFailure(
|
||||
typeRep<Contravariant<Lower>>(), typeRep<Contravariant<Middle>>());
|
||||
|
||||
// Invariant<Upper> </: Invariant<Middle>
|
||||
checkSubtypeFailure(
|
||||
typeRep<Invariant<Upper>>(), typeRep<Invariant<Middle>>());
|
||||
|
||||
// Invariant<Lower> </: Invariant<Middle>
|
||||
checkSubtypeFailure(
|
||||
typeRep<Invariant<Lower>>(), typeRep<Invariant<Middle>>());
|
||||
|
||||
// LegacyCovariant<Upper> </: LegacyCovariant<Middle>
|
||||
checkSubtypeFailure(
|
||||
typeRep<LegacyCovariant<Upper>>(), typeRep<LegacyCovariant<Middle>>());
|
||||
|
||||
// List<Covariant<Upper>> </: Iterable<Covariant<Middle>>
|
||||
checkSubtypeFailure(typeRep<List<Covariant<Upper>>>(),
|
||||
typeRep<Iterable<Covariant<Middle>>>());
|
||||
|
||||
// List<Contravariant<Lower>> </: Iterable<Contravariant<Middle>>
|
||||
checkSubtypeFailure(typeRep<List<Contravariant<Lower>>>(),
|
||||
typeRep<Iterable<Contravariant<Middle>>>());
|
||||
|
||||
// List<Invariant<Upper>> </: Iterable<Invariant<Middle>>
|
||||
checkSubtypeFailure(typeRep<List<Invariant<Upper>>>(),
|
||||
typeRep<Iterable<Invariant<Middle>>>());
|
||||
|
||||
// List<Invariant<Lower>> </: Iterable<Invariant<Middle>>
|
||||
checkSubtypeFailure(typeRep<List<Invariant<Lower>>>(),
|
||||
typeRep<Iterable<Invariant<Middle>>>());
|
||||
|
||||
// List<LegacyCovariant<Upper>> </: Iterable<LegacyCovariant<Middle>>
|
||||
checkSubtypeFailure(typeRep<List<LegacyCovariant<Upper>>>(),
|
||||
typeRep<Iterable<LegacyCovariant<Middle>>>());
|
||||
|
||||
// String -> Covariant<Upper> </: String -> Covariant<Middle>
|
||||
checkSubtypeFailure(typeRep<Covariant<Upper> Function(String)>(),
|
||||
typeRep<Covariant<Middle> Function(String)>());
|
||||
|
||||
// Covariant<Lower> -> String </: Covariant<Middle> -> String
|
||||
checkSubtypeFailure(typeRep<String Function(Covariant<Lower>)>(),
|
||||
typeRep<String Function(Covariant<Middle>)>());
|
||||
|
||||
// String -> Contravariant<Lower> </: String -> Contravariant<Middle>
|
||||
checkSubtypeFailure(typeRep<Contravariant<Lower> Function(String)>(),
|
||||
typeRep<Contravariant<Middle> Function(String)>());
|
||||
|
||||
// Contravariant<Upper> -> String </: Contravariant<Middle> -> String
|
||||
checkSubtypeFailure(typeRep<String Function(Contravariant<Upper>)>(),
|
||||
typeRep<String Function(Contravariant<Middle>)>());
|
||||
|
||||
// String -> Invariant<Upper> </: String -> Invariant<Middle>
|
||||
checkSubtypeFailure(typeRep<Invariant<Upper> Function(String)>(),
|
||||
typeRep<Invariant<Middle> Function(String)>());
|
||||
|
||||
// Invariant<Upper> -> String </: Invariant<Middle> -> String
|
||||
checkSubtypeFailure(typeRep<String Function(Invariant<Upper>)>(),
|
||||
typeRep<String Function(Invariant<Middle>)>());
|
||||
|
||||
// String -> Invariant<Lower> </: String -> Invariant<Middle>
|
||||
checkSubtypeFailure(typeRep<Invariant<Lower> Function(String)>(),
|
||||
typeRep<Invariant<Middle> Function(String)>());
|
||||
|
||||
// Invariant<Lower> -> String <: Invariant<Middle> -> String
|
||||
checkSubtypeFailure(typeRep<String Function(Invariant<Lower>)>(),
|
||||
typeRep<String Function(Invariant<Middle>)>());
|
||||
|
||||
// String -> LegacyCovariant<Upper> </: String -> LegacyCovariant<Middle>
|
||||
checkSubtypeFailure(typeRep<LegacyCovariant<Upper> Function(String)>(),
|
||||
typeRep<LegacyCovariant<Middle> Function(String)>());
|
||||
|
||||
// LegacyCovariant<Lower> -> String </: LegacyCovariant<Middle> -> String
|
||||
checkSubtypeFailure(typeRep<String Function(LegacyCovariant<Lower>)>(),
|
||||
typeRep<String Function(LegacyCovariant<Middle>)>());
|
||||
}
|
51
tests/dartdevc/variance_test.dart
Normal file
51
tests/dartdevc/variance_test.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
// 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.
|
||||
|
||||
// SharedOptions=--enable-experiment=variance
|
||||
|
||||
// Tests the emission of explicit variance modifiers.
|
||||
|
||||
import 'dart:_runtime'
|
||||
show wrapType, unwrapType, getGenericArgVariances, Variance, typeRep;
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class A<in T> {}
|
||||
|
||||
class B<out T> {}
|
||||
|
||||
class C<inout T> {}
|
||||
|
||||
class D<T> {}
|
||||
|
||||
class E<inout X, out Y, in Z> {}
|
||||
|
||||
mixin F<in T> {}
|
||||
|
||||
class G<inout T> = Object with F<T>;
|
||||
|
||||
List getVariances(Object t) {
|
||||
// TODO(nshahan) Update to handle legacy wrapper when we unfork dart:_runtime.
|
||||
var type = unwrapType(wrapType(t));
|
||||
return getGenericArgVariances(type);
|
||||
}
|
||||
|
||||
main() {
|
||||
Expect.listEquals([Variance.contravariant], getVariances(typeRep<A>()));
|
||||
|
||||
Expect.listEquals([Variance.covariant], getVariances(typeRep<B>()));
|
||||
|
||||
Expect.listEquals([Variance.invariant], getVariances(typeRep<C>()));
|
||||
|
||||
// Implicit variance is not emitted into the generated code.
|
||||
Expect.isNull(getVariances(typeRep<D>()));
|
||||
|
||||
Expect.listEquals(
|
||||
[Variance.invariant, Variance.covariant, Variance.contravariant],
|
||||
getVariances(typeRep<E>()));
|
||||
|
||||
Expect.listEquals([Variance.contravariant], getVariances(typeRep<F>()));
|
||||
|
||||
Expect.listEquals([Variance.invariant], getVariances(typeRep<G>()));
|
||||
}
|
Loading…
Reference in a new issue