671505c424
R=johnniwinther@google.com Review URL: https://codereview.chromium.org//818713002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@42508 260f80e4-7a28-3924-810f-c04153c831b5
2063 lines
39 KiB
Dart
2063 lines
39 KiB
Dart
// Copyright (c) 2014, 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 trydart.incremental_compilation_update_test;
|
|
|
|
import 'dart:html' hide
|
|
Element;
|
|
|
|
import 'dart:async' show
|
|
Future;
|
|
|
|
import 'package:async_helper/async_helper.dart' show
|
|
asyncTest;
|
|
|
|
import 'package:expect/expect.dart' show
|
|
Expect;
|
|
|
|
import 'package:try/src/interaction_manager.dart' show
|
|
splitLines;
|
|
|
|
import 'package:try/poi/scope_information_visitor.dart' show
|
|
ScopeInformationVisitor;
|
|
|
|
import 'sandbox.dart' show
|
|
appendIFrame,
|
|
listener;
|
|
|
|
import 'web_compiler_test_case.dart' show
|
|
WebCompilerTestCase,
|
|
WebInputProvider;
|
|
|
|
import '../poi/compiler_test_case.dart' show
|
|
CompilerTestCase;
|
|
|
|
import 'package:compiler/src/elements/elements.dart' show
|
|
Element,
|
|
LibraryElement;
|
|
|
|
import 'package:compiler/src/dart2jslib.dart' show
|
|
Compiler;
|
|
|
|
import 'package:dart2js_incremental/dart2js_incremental.dart' show
|
|
IncrementalCompilationFailed;
|
|
|
|
import 'program_result.dart';
|
|
|
|
const int TIMEOUT = 100;
|
|
|
|
const List<EncodedResult> tests = const <EncodedResult>[
|
|
// Basic hello-world test.
|
|
const EncodedResult(
|
|
const [
|
|
"main() { print('Hello, ",
|
|
const ["", "Brave New "],
|
|
"World!'); }",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['Hello, World!']),
|
|
const ProgramExpectation(
|
|
const <String>['Hello, Brave New World!']),
|
|
]),
|
|
|
|
// Test that the test framework handles more than one update.
|
|
const EncodedResult(
|
|
const [
|
|
"main() { print('",
|
|
const [
|
|
"Hello darkness, my old friend",
|
|
"I\\'ve come to talk with you again",
|
|
"Because a vision softly creeping",
|
|
],
|
|
"'); }",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['Hello darkness, my old friend']),
|
|
const ProgramExpectation(
|
|
const <String>['I\'ve come to talk with you again']),
|
|
const ProgramExpectation(
|
|
const <String>['Because a vision softly creeping']),
|
|
]),
|
|
|
|
// Test that that isolate support works.
|
|
const EncodedResult(
|
|
const [
|
|
"main(arguments) { print(",
|
|
const [
|
|
"'Hello, Isolated World!'",
|
|
"arguments"
|
|
],
|
|
"); }",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['Hello, Isolated World!']),
|
|
const ProgramExpectation(
|
|
const <String>['[]']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that a stored closure changes behavior when updated.
|
|
|
|
var closure;
|
|
|
|
foo(a, [b = 'b']) {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('$a $b');
|
|
""",
|
|
r"""
|
|
print('$b $a');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
main() {
|
|
if (closure == null) {
|
|
print('[closure] is null.');
|
|
closure = foo;
|
|
}
|
|
closure('a');
|
|
closure('a', 'c');
|
|
}
|
|
"""],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['[closure] is null.', 'a b', 'a c']),
|
|
const ProgramExpectation(
|
|
const <String>['b a', 'c a']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test modifying a static method works.
|
|
|
|
class C {
|
|
static m() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
print('v2');
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
}
|
|
main() {
|
|
C.m();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test modifying an instance method works.
|
|
|
|
class C {
|
|
m() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
print('v2');
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
}
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that a stored instance tearoff changes behavior when updated.
|
|
|
|
class C {
|
|
m() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
print('v2');
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
}
|
|
var closure;
|
|
main() {
|
|
if (closure == null) {
|
|
print('closure is null');
|
|
closure = new C().m;
|
|
}
|
|
closure();
|
|
}
|
|
""",
|
|
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['closure is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that deleting an instance method works.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
"""
|
|
m() {
|
|
print('v1');
|
|
}
|
|
""",
|
|
"""
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
try {
|
|
instance.m();
|
|
} catch (e) {
|
|
print('threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['threw']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that deleting an instance method works, even when accessed through
|
|
// super.
|
|
|
|
class A {
|
|
m() {
|
|
print('v2');
|
|
}
|
|
}
|
|
class B extends A {
|
|
""",
|
|
const [
|
|
"""
|
|
m() {
|
|
print('v1');
|
|
}
|
|
""",
|
|
"""
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
class C extends B {
|
|
m() {
|
|
super.m();
|
|
}
|
|
}
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that deleting a top-level method works.
|
|
|
|
""",
|
|
const [
|
|
"""
|
|
toplevel() {
|
|
print('v1');
|
|
}
|
|
""",
|
|
"""
|
|
""",
|
|
],
|
|
"""
|
|
class C {
|
|
m() {
|
|
try {
|
|
toplevel();
|
|
} catch (e) {
|
|
print('threw');
|
|
}
|
|
}
|
|
}
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['threw']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that deleting a static method works.
|
|
|
|
class B {
|
|
""",
|
|
const [
|
|
"""
|
|
static staticMethod() {
|
|
print('v1');
|
|
}
|
|
""",
|
|
"""
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
class C {
|
|
m() {
|
|
try {
|
|
B.staticMethod();
|
|
} catch (e) {
|
|
print('threw');
|
|
}
|
|
try {
|
|
// Ensure that noSuchMethod support is compiled. This test is not about
|
|
// adding new classes.
|
|
B.missingMethod();
|
|
print('bad');
|
|
} catch (e) {
|
|
}
|
|
}
|
|
}
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['threw']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that a newly instantiated class is handled.
|
|
|
|
class A {
|
|
m() {
|
|
print('Called A.m');
|
|
}
|
|
}
|
|
|
|
class B {
|
|
m() {
|
|
print('Called B.m');
|
|
}
|
|
}
|
|
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new A();
|
|
""",
|
|
const [
|
|
"""
|
|
""",
|
|
"""
|
|
} else {
|
|
instance = new B();
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'Called A.m']),
|
|
const ProgramExpectation(
|
|
const <String>['Called B.m']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
"""
|
|
// Test that source maps don't throw exceptions.
|
|
|
|
main() {
|
|
print('a');
|
|
""",
|
|
const [
|
|
"""
|
|
""",
|
|
"""
|
|
print('b');
|
|
print('c');
|
|
""",
|
|
],
|
|
"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['a']),
|
|
const ProgramExpectation(
|
|
const <String>['a', 'b', 'c']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that a newly instantiated class is handled.
|
|
|
|
class A {
|
|
get name => 'A.m';
|
|
|
|
m() {
|
|
print('Called $name');
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
get name => 'B.m';
|
|
}
|
|
|
|
var instance;
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new A();
|
|
""",
|
|
const [
|
|
r"""
|
|
""",
|
|
r"""
|
|
} else {
|
|
instance = new B();
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'Called A.m']),
|
|
const ProgramExpectation(
|
|
const <String>['Called B.m']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that fields of a newly instantiated class are handled.
|
|
|
|
class A {
|
|
var x;
|
|
A(this.x);
|
|
}
|
|
var instance;
|
|
foo() {
|
|
if (instance != null) {
|
|
print(instance.x);
|
|
} else {
|
|
print('v1');
|
|
}
|
|
}
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
""",
|
|
r"""
|
|
instance = new A('v2');
|
|
""",
|
|
],
|
|
r"""
|
|
foo();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that top-level functions can be added.
|
|
|
|
""",
|
|
const [
|
|
"",
|
|
r"""
|
|
foo() {
|
|
print('v2');
|
|
}
|
|
""",
|
|
],
|
|
r"""
|
|
main() {
|
|
try {
|
|
foo();
|
|
} catch(e) {
|
|
print('threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['threw']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that static methods can be added.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
"",
|
|
r"""
|
|
static foo() {
|
|
print('v2');
|
|
}
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
main() {
|
|
try {
|
|
C.foo();
|
|
} catch(e) {
|
|
print('threw');
|
|
}
|
|
}
|
|
""",
|
|
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['threw']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that instance methods can be added.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
"",
|
|
r"""
|
|
foo() {
|
|
print('v2');
|
|
}
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
|
|
try {
|
|
instance.foo();
|
|
} catch(e) {
|
|
print('threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'threw']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that top-level functions can have signature changed.
|
|
|
|
""",
|
|
const [
|
|
r"""
|
|
foo() {
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
void foo() {
|
|
print('v2');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
main() {
|
|
foo();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that static methods can have signature changed.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
r"""
|
|
static foo() {
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
static void foo() {
|
|
print('v2');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
}
|
|
|
|
main() {
|
|
C.foo();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that instance methods can have signature changed.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
r"""
|
|
foo() {
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
void foo() {
|
|
print('v2');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
|
|
instance.foo();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that adding a class is supported.
|
|
|
|
""",
|
|
const [
|
|
"",
|
|
r"""
|
|
class C {
|
|
void foo() {
|
|
print('v2');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
r"""
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
new C().foo();
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that removing a class is supported, using constructor.
|
|
|
|
""",
|
|
const [
|
|
r"""
|
|
class C {
|
|
}
|
|
""",
|
|
""
|
|
],
|
|
r"""
|
|
main() {
|
|
try {
|
|
new C();
|
|
print('v1');
|
|
} catch (e) {
|
|
print('v2');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that removing a class is supported, using a static method.
|
|
|
|
""",
|
|
const [
|
|
r"""
|
|
class C {
|
|
static m() {
|
|
print('v1');
|
|
}
|
|
}
|
|
""",
|
|
"",
|
|
],
|
|
r"""
|
|
main() {
|
|
try {
|
|
C.m();
|
|
} catch (e) {
|
|
print('v2');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that changing the supertype of a class.
|
|
|
|
class A {
|
|
m() {
|
|
print('v2');
|
|
}
|
|
}
|
|
class B extends A {
|
|
m() {
|
|
print('v1');
|
|
}
|
|
}
|
|
""",
|
|
const [
|
|
r"""
|
|
class C extends B {
|
|
""",
|
|
r"""
|
|
class C extends A {
|
|
""",
|
|
],
|
|
r"""
|
|
m() {
|
|
super.m();
|
|
}
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
instance.m();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test adding a field to a class works.
|
|
|
|
class A {
|
|
""",
|
|
const [
|
|
"",
|
|
r"""
|
|
var x;
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new A();
|
|
}
|
|
try {
|
|
instance.x = 'v2';
|
|
} catch(e) {
|
|
print('setter threw');
|
|
}
|
|
try {
|
|
print(instance.x);
|
|
} catch (e) {
|
|
print('getter threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'setter threw', 'getter threw']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test removing a field from a class works.
|
|
|
|
class A {
|
|
""",
|
|
const [
|
|
r"""
|
|
var x;
|
|
""",
|
|
"",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new A();
|
|
}
|
|
try {
|
|
instance.x = 'v1';
|
|
} catch(e) {
|
|
print('setter threw');
|
|
}
|
|
try {
|
|
print(instance.x);
|
|
} catch (e) {
|
|
print('getter threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['setter threw', 'getter threw']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that named arguments can be called.
|
|
|
|
class C {
|
|
foo({a, named: 'v1', x}) {
|
|
print(named);
|
|
}
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
""",
|
|
const [
|
|
r"""
|
|
instance.foo();
|
|
""",
|
|
r"""
|
|
instance.foo(named: 'v2');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test than named arguments can be called.
|
|
|
|
class C {
|
|
foo({a, named: 'v2', x}) {
|
|
print(named);
|
|
}
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('instance is null');
|
|
instance = new C();
|
|
}
|
|
""",
|
|
const [
|
|
r"""
|
|
instance.foo(named: 'v1');
|
|
""",
|
|
r"""
|
|
instance.foo();
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['instance is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that an instance tear-off with named parameters can be called.
|
|
|
|
class C {
|
|
foo({a, named: 'v1', x}) {
|
|
print(named);
|
|
}
|
|
}
|
|
|
|
var closure;
|
|
|
|
main() {
|
|
if (closure == null) {
|
|
print('closure is null');
|
|
closure = new C().foo;
|
|
}
|
|
""",
|
|
const [
|
|
r"""
|
|
closure();
|
|
""",
|
|
r"""
|
|
closure(named: 'v2');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['closure is null', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that a lazy static is supported.
|
|
|
|
var normal;
|
|
|
|
""",
|
|
const [
|
|
r"""
|
|
foo() {
|
|
print(normal);
|
|
}
|
|
""",
|
|
r"""
|
|
var lazy = bar();
|
|
|
|
foo() {
|
|
print(lazy);
|
|
}
|
|
|
|
bar() {
|
|
print('v2');
|
|
return 'lazy';
|
|
}
|
|
|
|
""",
|
|
],
|
|
r"""
|
|
main() {
|
|
if (normal == null) {
|
|
normal = 'v1';
|
|
} else {
|
|
normal = '';
|
|
}
|
|
foo();
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2', 'lazy']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that superclasses of directly instantiated classes are also emitted.
|
|
class A {
|
|
}
|
|
|
|
class B extends A {
|
|
}
|
|
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
new B();
|
|
print('v2');
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that interceptor classes are handled correctly.
|
|
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print('v1');
|
|
""",
|
|
r"""
|
|
['v2'].forEach(print);
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that newly instantiated superclasses are handled correctly when there
|
|
// is more than one change.
|
|
|
|
class A {
|
|
foo() {
|
|
print('Called foo');
|
|
}
|
|
|
|
bar() {
|
|
print('Called bar');
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
}
|
|
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
new B().foo();
|
|
""",
|
|
r"""
|
|
new B().foo();
|
|
""",
|
|
r"""
|
|
new A().bar();
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['Called foo']),
|
|
const ProgramExpectation(
|
|
const <String>['Called foo']),
|
|
const ProgramExpectation(
|
|
const <String>['Called bar']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that newly instantiated subclasses are handled correctly when there is
|
|
// more than one change.
|
|
|
|
class A {
|
|
foo() {
|
|
print('Called foo');
|
|
}
|
|
|
|
bar() {
|
|
print('Called bar');
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
}
|
|
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
new A().foo();
|
|
""",
|
|
r"""
|
|
new A().foo();
|
|
""",
|
|
r"""
|
|
new B().bar();
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['Called foo']),
|
|
const ProgramExpectation(
|
|
const <String>['Called foo']),
|
|
const ProgramExpectation(
|
|
const <String>['Called bar']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that constants are handled correctly.
|
|
|
|
class C {
|
|
final String value;
|
|
const C(this.value);
|
|
}
|
|
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print(const C('v1').value);
|
|
""",
|
|
r"""
|
|
print(const C('v2').value);
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that an instance field can be added to a compound declaration.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
r"""
|
|
int x;
|
|
""",
|
|
r"""
|
|
int x, y;
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('[instance] is null');
|
|
instance = new C();
|
|
instance.x = 'v1';
|
|
} else {
|
|
instance.y = 'v2';
|
|
}
|
|
try {
|
|
print(instance.x);
|
|
} catch (e) {
|
|
print('[instance.x] threw');
|
|
}
|
|
try {
|
|
print(instance.y);
|
|
} catch (e) {
|
|
print('[instance.y] threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>[
|
|
'[instance] is null', 'v1', '[instance.y] threw']),
|
|
const ProgramExpectation(
|
|
const <String>['v1', 'v2'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that an instance field can be removed from a compound declaration.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
r"""
|
|
int x, y;
|
|
""",
|
|
r"""
|
|
int x;
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('[instance] is null');
|
|
instance = new C();
|
|
instance.x = 'v1';
|
|
instance.y = 'v2';
|
|
}
|
|
try {
|
|
print(instance.x);
|
|
} catch (e) {
|
|
print('[instance.x] threw');
|
|
}
|
|
try {
|
|
print(instance.y);
|
|
} catch (e) {
|
|
print('[instance.y] threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['[instance] is null', 'v1', 'v2']),
|
|
const ProgramExpectation(
|
|
const <String>['v1', '[instance.y] threw'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that a static field can be made an instance field.
|
|
|
|
class C {
|
|
""",
|
|
|
|
const [
|
|
r"""
|
|
static int x;
|
|
""",
|
|
r"""
|
|
int x;
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('[instance] is null');
|
|
instance = new C();
|
|
C.x = 'v1';
|
|
} else {
|
|
instance.x = 'v2';
|
|
}
|
|
try {
|
|
print(C.x);
|
|
} catch (e) {
|
|
print('[C.x] threw');
|
|
}
|
|
try {
|
|
print(instance.x);
|
|
} catch (e) {
|
|
print('[instance.x] threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['[instance] is null', 'v1', '[instance.x] threw']),
|
|
const ProgramExpectation(
|
|
const <String>['[C.x] threw', 'v2'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test that instance field can be made static.
|
|
|
|
class C {
|
|
""",
|
|
const [
|
|
r"""
|
|
int x;
|
|
""",
|
|
r"""
|
|
static int x;
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
|
|
var instance;
|
|
|
|
main() {
|
|
if (instance == null) {
|
|
print('[instance] is null');
|
|
instance = new C();
|
|
instance.x = 'v1';
|
|
} else {
|
|
C.x = 'v2';
|
|
}
|
|
try {
|
|
print(C.x);
|
|
} catch (e) {
|
|
print('[C.x] threw');
|
|
}
|
|
try {
|
|
print(instance.x);
|
|
} catch (e) {
|
|
print('[instance.x] threw');
|
|
}
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['[instance] is null', '[C.x] threw', 'v1']),
|
|
const ProgramExpectation(
|
|
const <String>['v2', '[instance.x] threw'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test compound constants.
|
|
|
|
class A {
|
|
final value;
|
|
const A(this.value);
|
|
|
|
toString() => 'A($value)';
|
|
}
|
|
|
|
class B {
|
|
final value;
|
|
const B(this.value);
|
|
|
|
toString() => 'B($value)';
|
|
}
|
|
|
|
main() {
|
|
""",
|
|
const [
|
|
r"""
|
|
print(const A('v1'));
|
|
print(const B('v1'));
|
|
""",
|
|
r"""
|
|
print(const B(const A('v2')));
|
|
print(const A(const B('v2')));
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['A(v1)', 'B(v1)']),
|
|
const ProgramExpectation(
|
|
const <String>['B(A(v2))', 'A(B(v2))']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
const [
|
|
r"""
|
|
// Test constants of new classes.
|
|
|
|
class A {
|
|
final value;
|
|
const A(this.value);
|
|
|
|
toString() => 'A($value)';
|
|
}
|
|
""",
|
|
const [
|
|
"",
|
|
r"""
|
|
class B {
|
|
final value;
|
|
const B(this.value);
|
|
|
|
toString() => 'B($value)';
|
|
}
|
|
|
|
""",
|
|
],
|
|
r"""
|
|
main() {
|
|
""",
|
|
|
|
const [
|
|
r"""
|
|
print(const A('v1'));
|
|
""",
|
|
r"""
|
|
print(const A('v2'));
|
|
print(const B('v2'));
|
|
print(const B(const A('v2')));
|
|
print(const A(const B('v2')));
|
|
""",
|
|
],
|
|
r"""
|
|
}
|
|
""",
|
|
|
|
],
|
|
const <ProgramExpectation>[
|
|
const ProgramExpectation(
|
|
const <String>['A(v1)']),
|
|
const ProgramExpectation(
|
|
const <String>['A(v2)', 'B(v2)', 'B(A(v2))', 'A(B(v2))']),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
r"""
|
|
==> main.dart <==
|
|
// Test that a change in a part is handled.
|
|
library test.main;
|
|
|
|
part 'part.dart';
|
|
|
|
|
|
==> part.dart.patch <==
|
|
part of test.main;
|
|
|
|
main() {
|
|
<<<<<<<
|
|
print('Hello, World!');
|
|
=======
|
|
print('Hello, Brave New World!');
|
|
>>>>>>>
|
|
}
|
|
""",
|
|
const [
|
|
'Hello, World!',
|
|
'Hello, Brave New World!',
|
|
]),
|
|
|
|
const EncodedResult(
|
|
r"""
|
|
==> main.dart.patch <==
|
|
// Test that a change in library name is handled.
|
|
<<<<<<<
|
|
library test.main1;
|
|
=======
|
|
library test.main2;
|
|
>>>>>>>
|
|
|
|
main() {
|
|
print('Hello, World!');
|
|
}
|
|
""",
|
|
const [
|
|
'Hello, World!',
|
|
const ProgramExpectation(
|
|
const <String>['Hello, World!'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
r"""
|
|
==> main.dart.patch <==
|
|
// Test that adding an import is handled.
|
|
<<<<<<<
|
|
=======
|
|
import 'dart:core';
|
|
>>>>>>>
|
|
|
|
main() {
|
|
print('Hello, World!');
|
|
}
|
|
""",
|
|
const [
|
|
'Hello, World!',
|
|
const ProgramExpectation(
|
|
const <String>['Hello, World!'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
r"""
|
|
==> main.dart.patch <==
|
|
// Test that adding an export is handled.
|
|
<<<<<<<
|
|
=======
|
|
export 'dart:core';
|
|
>>>>>>>
|
|
|
|
main() {
|
|
print('Hello, World!');
|
|
}
|
|
""",
|
|
const [
|
|
'Hello, World!',
|
|
const ProgramExpectation(
|
|
const <String>['Hello, World!'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
r"""
|
|
==> main.dart.patch <==
|
|
// Test that adding a part is handled.
|
|
library test.main;
|
|
|
|
<<<<<<<
|
|
=======
|
|
part 'part.dart';
|
|
>>>>>>>
|
|
|
|
main() {
|
|
print('Hello, World!');
|
|
}
|
|
|
|
|
|
==> part.dart <==
|
|
part of test.main
|
|
""",
|
|
const [
|
|
'Hello, World!',
|
|
const ProgramExpectation(
|
|
const <String>['Hello, World!'],
|
|
// TODO(ahe): Shouldn't throw.
|
|
compileUpdatesShouldThrow: true),
|
|
]),
|
|
|
|
const EncodedResult(
|
|
r"""
|
|
==> main.dart <==
|
|
// Test that changes in multiple libraries is handled.
|
|
import 'library1.dart' as lib1;
|
|
import 'library2.dart' as lib2;
|
|
|
|
main() {
|
|
lib1.method();
|
|
lib2.method();
|
|
}
|
|
|
|
|
|
==> library1.dart.patch <==
|
|
library test.library1;
|
|
|
|
method() {
|
|
<<<<<<<
|
|
print('lib1.v1');
|
|
=======
|
|
print('lib1.v2');
|
|
=======
|
|
print('lib1.v3');
|
|
>>>>>>>
|
|
}
|
|
|
|
|
|
==> library2.dart.patch <==
|
|
library test.library2;
|
|
|
|
method() {
|
|
<<<<<<<
|
|
print('lib2.v1');
|
|
=======
|
|
print('lib2.v2');
|
|
=======
|
|
print('lib2.v3');
|
|
>>>>>>>
|
|
}
|
|
""",
|
|
const [
|
|
const <String>['lib1.v1', 'lib2.v1'],
|
|
const <String>['lib1.v2', 'lib2.v2'],
|
|
const <String>['lib1.v3', 'lib2.v3'],
|
|
]),
|
|
];
|
|
|
|
void main() {
|
|
listener.start();
|
|
|
|
document.head.append(lineNumberStyle());
|
|
|
|
summary = new SpanElement();
|
|
document.body.append(new HeadingElement.h1()
|
|
..appendText("Incremental compiler tests")
|
|
..append(summary));
|
|
|
|
String query = window.location.search;
|
|
int skip = 0;
|
|
if (query != null && query.length > 1) {
|
|
query = query.substring(1);
|
|
String skipParameter = Uri.splitQueryString(window.location.search)['skip'];
|
|
if (skipParameter != null) {
|
|
skip = int.parse(skipParameter);
|
|
}
|
|
String verboseParameter =
|
|
Uri.splitQueryString(window.location.search)['verbose'];
|
|
verboseStatus = verboseParameter != null;
|
|
}
|
|
testCount += skip;
|
|
|
|
return asyncTest(() => Future.forEach(tests.skip(skip), compileAndRun)
|
|
.then(updateSummary));
|
|
}
|
|
|
|
SpanElement summary;
|
|
|
|
int testCount = 1;
|
|
|
|
bool verboseStatus = false;
|
|
|
|
void updateSummary(_) {
|
|
summary.text = " (${testCount - 1}/${tests.length})";
|
|
}
|
|
|
|
Future compileAndRun(EncodedResult encodedResult) {
|
|
updateSummary(null);
|
|
List<ProgramResult> programs = encodedResult.decode();
|
|
var status = new DivElement();
|
|
document.body.append(status);
|
|
|
|
IFrameElement iframe =
|
|
appendIFrame(
|
|
'/root_dart/tests/try/web/incremental_compilation_update.html',
|
|
document.body)
|
|
..style.width = '100%'
|
|
..style.height = '600px';
|
|
|
|
return listener.expect('iframe-ready').then((_) {
|
|
ProgramResult program = programs.first;
|
|
|
|
status.append(
|
|
new HeadingElement.h2()
|
|
..appendText("Full program #${testCount++}:"));
|
|
status.append(numberedLines(program.code));
|
|
|
|
status.style.color = 'orange';
|
|
WebCompilerTestCase test = new WebCompilerTestCase(program.code);
|
|
return test.run().then((String jsCode) {
|
|
status.style.color = 'red';
|
|
var objectUrl =
|
|
Url.createObjectUrl(new Blob([jsCode], 'application/javascript'));
|
|
|
|
iframe.contentWindow.postMessage(['add-script', objectUrl], '*');
|
|
Future future =
|
|
listener.expect(program.messagesWith('iframe-dart-main-done'));
|
|
return future.then((_) {
|
|
int version = 2;
|
|
return Future.forEach(programs.skip(1), (ProgramResult program) {
|
|
|
|
status.append(new HeadingElement.h2()..appendText("Update:"));
|
|
status.append(numberedLines(program.code));
|
|
|
|
WebInputProvider inputProvider =
|
|
test.incrementalCompiler.inputProvider;
|
|
Uri base = test.scriptUri;
|
|
Map<String, String> code = program.code is String
|
|
? { 'main.dart': program.code }
|
|
: program.code;
|
|
Map<Uri, Uri> uriMap = <Uri, Uri>{};
|
|
for (String name in code.keys) {
|
|
Uri uri = base.resolve('$name?v${version++}');
|
|
inputProvider.cachedSources[uri] = new Future.value(code[name]);
|
|
uriMap[base.resolve(name)] = uri;
|
|
}
|
|
Future future = test.incrementalCompiler.compileUpdates(
|
|
uriMap, logVerbose: logger, logTime: logger);
|
|
bool compileUpdatesThrew = false;
|
|
future = future.catchError((error, trace) {
|
|
String statusMessage;
|
|
Future result;
|
|
compileUpdatesThrew = true;
|
|
if (program.compileUpdatesShouldThrow &&
|
|
error is IncrementalCompilationFailed) {
|
|
statusMessage = "Expected error in compileUpdates.";
|
|
result = null;
|
|
} else {
|
|
statusMessage = "Unexpected error in compileUpdates.";
|
|
result = new Future.error(error, trace);
|
|
}
|
|
status.append(new HeadingElement.h3()..appendText(statusMessage));
|
|
return result;
|
|
});
|
|
return future.then((String update) {
|
|
if (program.compileUpdatesShouldThrow) {
|
|
Expect.isTrue(
|
|
compileUpdatesThrew,
|
|
"Expected an exception in compileUpdates");
|
|
Expect.isNull( update, "Expected update == null");
|
|
return null;
|
|
}
|
|
print({'update': update});
|
|
iframe.contentWindow.postMessage(['apply-update', update], '*');
|
|
|
|
return listener.expect(
|
|
program.messagesWith('iframe-dart-updated-main-done'))
|
|
.then((_) {
|
|
// TODO(ahe): Enable SerializeScopeTestCase for multiple
|
|
// parts.
|
|
if (program.code is! String) return null;
|
|
return new SerializeScopeTestCase(
|
|
program.code, test.incrementalCompiler.mainApp,
|
|
test.incrementalCompiler.compiler).run();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}).then((_) {
|
|
status.style.color = 'limegreen';
|
|
|
|
// Remove the iframe and status to work around a bug in test.dart
|
|
// (https://code.google.com/p/dart/issues/detail?id=21691).
|
|
if (!verboseStatus) status.remove();
|
|
iframe.remove();
|
|
});
|
|
}
|
|
|
|
class SerializeScopeTestCase extends CompilerTestCase {
|
|
final String scopeInfo;
|
|
|
|
SerializeScopeTestCase(
|
|
String source,
|
|
LibraryElement library,
|
|
Compiler compiler)
|
|
: scopeInfo = computeScopeInfo(compiler, library),
|
|
super(source, '${library.canonicalUri}');
|
|
|
|
Future run() => loadMainApp().then(checkScopes);
|
|
|
|
void checkScopes(LibraryElement library) {
|
|
Expect.stringEquals(computeScopeInfo(compiler, library), scopeInfo);
|
|
}
|
|
|
|
static String computeScopeInfo(Compiler compiler, LibraryElement library) {
|
|
ScopeInformationVisitor visitor =
|
|
new ScopeInformationVisitor(compiler, library, 0);
|
|
|
|
visitor.ignoreImports = true;
|
|
visitor.sortMembers = true;
|
|
visitor.indented.write('[\n');
|
|
visitor.indentationLevel++;
|
|
visitor.indented;
|
|
library.accept(visitor);
|
|
library.forEachLocalMember((Element member) {
|
|
if (member.isClass) {
|
|
visitor.buffer.write(',\n');
|
|
visitor.indented;
|
|
member.accept(visitor);
|
|
}
|
|
});
|
|
visitor.buffer.write('\n');
|
|
visitor.indentationLevel--;
|
|
visitor.indented.write(']');
|
|
return '${visitor.buffer}';
|
|
}
|
|
}
|
|
|
|
void logger(x) {
|
|
print(x);
|
|
bool isCheckedMode = false;
|
|
assert(isCheckedMode = true);
|
|
int timeout = isCheckedMode ? TIMEOUT * 2 : TIMEOUT;
|
|
if (listener.elapsed > timeout) {
|
|
throw 'Test timed out.';
|
|
}
|
|
}
|
|
|
|
DivElement numberedLines(code) {
|
|
if (code is! Map) {
|
|
code = {'main.dart': code};
|
|
}
|
|
DivElement result = new DivElement();
|
|
code.forEach((String fileName, String code) {
|
|
result.append(new HeadingElement.h4()..appendText(fileName));
|
|
DivElement lines = new DivElement();
|
|
result.append(lines);
|
|
lines.classes.add("output");
|
|
|
|
for (String text in splitLines(code)) {
|
|
PreElement line = new PreElement()
|
|
..appendText(text.trimRight())
|
|
..classes.add("line");
|
|
lines.append(line);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
StyleElement lineNumberStyle() {
|
|
StyleElement style = new StyleElement()..appendText('''
|
|
h2, h3, h4 {
|
|
color: black;
|
|
}
|
|
|
|
.output {
|
|
padding: 0px;
|
|
counter-reset: line-number;
|
|
padding-bottom: 1em;
|
|
}
|
|
|
|
.line {
|
|
white-space: pre-wrap;
|
|
padding-left: 3.5em;
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.line::before {
|
|
counter-increment: line-number;
|
|
content: counter(line-number) " ";
|
|
position: absolute;
|
|
left: 0px;
|
|
width: 3em;
|
|
text-align: right;
|
|
background-color: lightgoldenrodyellow;
|
|
}
|
|
''');
|
|
style.type = 'text/css';
|
|
return style;
|
|
}
|