| Index: test/dependency_graph_test.dart
|
| diff --git a/test/dependency_graph_test.dart b/test/dependency_graph_test.dart
|
| deleted file mode 100644
|
| index d7f8b0a60ed05ccdd3bffd01e7348253a33a55f2..0000000000000000000000000000000000000000
|
| --- a/test/dependency_graph_test.dart
|
| +++ /dev/null
|
| @@ -1,1251 +0,0 @@
|
| -// Copyright (c) 2015, 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 dev_compiler.test.dependency_graph_test;
|
| -
|
| -import 'package:analyzer/file_system/file_system.dart';
|
| -import 'package:analyzer/file_system/memory_file_system.dart';
|
| -import 'package:analyzer/src/generated/source.dart';
|
| -import 'package:path/path.dart' as path;
|
| -import 'package:test/test.dart';
|
| -
|
| -import 'package:dev_compiler/src/analysis_context.dart';
|
| -import 'package:dev_compiler/src/compiler.dart';
|
| -import 'package:dev_compiler/src/options.dart';
|
| -import 'package:dev_compiler/src/report.dart';
|
| -import 'package:dev_compiler/src/server/dependency_graph.dart';
|
| -
|
| -import 'testing.dart';
|
| -
|
| -void main() {
|
| - var options = new CompilerOptions(
|
| - runtimeDir: '/dev_compiler_runtime/',
|
| - sourceOptions: new SourceResolverOptions(useMockSdk: true));
|
| - MemoryResourceProvider testResourceProvider;
|
| - ResourceUriResolver testUriResolver;
|
| - var context;
|
| - var graph;
|
| -
|
| - /// Initial values for test files
|
| - var testFiles = {
|
| - '/index1.html': '''
|
| - <script src="foo.js"></script>
|
| - ''',
|
| - '/index2.html': '''
|
| - <script type="application/dart" src="a1.dart"></script>
|
| - ''',
|
| - '/index3.html': '''
|
| - <script type="application/dart" src="a2.dart"></script>
|
| - ''',
|
| - '/a1.dart': '''
|
| - library a1;
|
| - ''',
|
| - '/a2.dart': '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart';
|
| - export 'a5.dart';
|
| - part 'a6.dart';
|
| - ''',
|
| - '/a3.dart': 'library a3;',
|
| - '/a4.dart': 'library a4; export "a10.dart";',
|
| - '/a5.dart': 'library a5;',
|
| - '/a6.dart': 'part of a2;',
|
| - '/a7.dart': 'library a7;',
|
| - '/a8.dart': 'library a8; import "a8.dart";',
|
| - '/a9.dart': 'library a9; import "a8.dart";',
|
| - '/a10.dart': 'library a10;',
|
| - };
|
| -
|
| - nodeOf(String filepath) => graph.nodeFromUri(new Uri.file(filepath));
|
| -
|
| - setUp(() {
|
| - /// We completely reset the TestUriResolver to avoid interference between
|
| - /// tests (since some tests modify the state of the files).
|
| - testResourceProvider = createTestResourceProvider(testFiles);
|
| - testUriResolver = new ResourceUriResolver(testResourceProvider);
|
| - context = createAnalysisContextWithSources(options.sourceOptions,
|
| - fileResolvers: [testUriResolver]);
|
| - graph = new SourceGraph(context, new LogReporter(context), options);
|
| - });
|
| -
|
| - updateFile(Source source, [String newContents]) {
|
| - var path = testResourceProvider.pathContext.fromUri(source.uri);
|
| - if (newContents == null) newContents = source.contents.data;
|
| - testResourceProvider.updateFile(path, newContents);
|
| - }
|
| -
|
| - group('HTML deps', () {
|
| - test('initial deps', () {
|
| - var i1 = nodeOf('/index1.html');
|
| - var i2 = nodeOf('/index2.html');
|
| - expect(i1.scripts.length, 0);
|
| - expect(i2.scripts.length, 0);
|
| - i1.update();
|
| - i2.update();
|
| - expect(i1.scripts.length, 0);
|
| - expect(i2.scripts.length, 1);
|
| - expect(i2.scripts.first, nodeOf('/a1.dart'));
|
| - });
|
| -
|
| - test('add a dep', () {
|
| - // After initial load, dependencies are 0:
|
| - var node = nodeOf('/index1.html');
|
| - node.update();
|
| - expect(node.scripts.length, 0);
|
| -
|
| - // Adding the dependency is discovered on the next round of updates:
|
| - updateFile(node.source,
|
| - '<script type="application/dart" src="a2.dart"></script>');
|
| - expect(node.scripts.length, 0);
|
| - node.update();
|
| - expect(node.scripts.length, 1);
|
| - expect(node.scripts.first, nodeOf('/a2.dart'));
|
| - });
|
| -
|
| - test('add more deps', () {
|
| - // After initial load, dependencies are 1:
|
| - var node = nodeOf('/index2.html');
|
| - node.update();
|
| - expect(node.scripts.length, 1);
|
| - expect(node.scripts.first, nodeOf('/a1.dart'));
|
| -
|
| - updateFile(
|
| - node.source,
|
| - node.source.contents.data +
|
| - '<script type="application/dart" src="a2.dart"></script>');
|
| - expect(node.scripts.length, 1);
|
| - node.update();
|
| - expect(node.scripts.length, 2);
|
| - expect(node.scripts.first, nodeOf('/a1.dart'));
|
| - expect(node.scripts.last, nodeOf('/a2.dart'));
|
| - });
|
| -
|
| - test('remove all deps', () {
|
| - // After initial load, dependencies are 1:
|
| - var node = nodeOf('/index2.html');
|
| - node.update();
|
| - expect(node.scripts.length, 1);
|
| - expect(node.scripts.first, nodeOf('/a1.dart'));
|
| -
|
| - // Removing the dependency is discovered on the next round of updates:
|
| - updateFile(node.source, '');
|
| - expect(node.scripts.length, 1);
|
| - node.update();
|
| - expect(node.scripts.length, 0);
|
| - });
|
| - });
|
| -
|
| - group('Dart deps', () {
|
| - test('initial deps', () {
|
| - var a1 = nodeOf('/a1.dart');
|
| - var a2 = nodeOf('/a2.dart');
|
| - expect(a1.imports.length, 0);
|
| - expect(a1.exports.length, 0);
|
| - expect(a1.parts.length, 0);
|
| - expect(a2.imports.length, 0);
|
| - expect(a2.exports.length, 0);
|
| - expect(a2.parts.length, 0);
|
| -
|
| - a1.update();
|
| - a2.update();
|
| -
|
| - expect(a1.imports.length, 0);
|
| - expect(a1.exports.length, 0);
|
| - expect(a1.parts.length, 0);
|
| - expect(a2.imports.length, 2);
|
| - expect(a2.exports.length, 1);
|
| - expect(a2.parts.length, 1);
|
| - expect(a2.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(a2.imports.contains(nodeOf('/a4.dart')), isTrue);
|
| - expect(a2.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| - expect(a2.parts.contains(nodeOf('/a6.dart')), isTrue);
|
| - });
|
| -
|
| - test('add deps', () {
|
| - var node = nodeOf('/a1.dart');
|
| - node.update();
|
| - expect(node.imports.length, 0);
|
| - expect(node.exports.length, 0);
|
| - expect(node.parts.length, 0);
|
| -
|
| - updateFile(
|
| - node.source, 'import "a3.dart"; export "a5.dart"; part "a8.dart";');
|
| - node.update();
|
| -
|
| - expect(node.imports.length, 1);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 1);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a8.dart')), isTrue);
|
| - });
|
| -
|
| - test('remove deps', () {
|
| - var node = nodeOf('/a2.dart');
|
| - node.update();
|
| - expect(node.imports.length, 2);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 1);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.imports.contains(nodeOf('/a4.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a6.dart')), isTrue);
|
| -
|
| - updateFile(
|
| - node.source, 'import "a3.dart"; export "a7.dart"; part "a8.dart";');
|
| - node.update();
|
| -
|
| - expect(node.imports.length, 1);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 1);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a7.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a8.dart')), isTrue);
|
| - });
|
| -
|
| - test('change part to library', () {
|
| - var node = nodeOf('/a2.dart');
|
| - node.update();
|
| - expect(node.imports.length, 2);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 1);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.imports.contains(nodeOf('/a4.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a6.dart')), isTrue);
|
| -
|
| - updateFile(
|
| - node.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart';
|
| - export 'a5.dart';
|
| - import 'a6.dart'; // changed from part
|
| - ''');
|
| - var a6 = nodeOf('/a6.dart');
|
| - updateFile(a6.source, '');
|
| - node.update();
|
| -
|
| - expect(node.imports.length, 3);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 0);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.imports.contains(nodeOf('/a4.dart')), isTrue);
|
| - expect(node.imports.contains(nodeOf('/a6.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| -
|
| - expect(a6.imports.length, 0);
|
| - expect(a6.exports.length, 0);
|
| - expect(a6.parts.length, 0);
|
| - });
|
| -
|
| - test('change library to part', () {
|
| - var node = nodeOf('/a2.dart');
|
| - var a4 = nodeOf('/a4.dart');
|
| - node.update();
|
| - expect(node.imports.length, 2);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 1);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.imports.contains(nodeOf('/a4.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a6.dart')), isTrue);
|
| -
|
| - a4.update();
|
| - expect(a4.imports.length, 0);
|
| - expect(a4.exports.length, 1);
|
| - expect(a4.parts.length, 0);
|
| -
|
| - updateFile(
|
| - node.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - part 'a4.dart'; // changed from export
|
| - export 'a5.dart';
|
| - part 'a6.dart';
|
| - ''');
|
| - node.update();
|
| -
|
| - expect(node.imports.length, 1);
|
| - expect(node.exports.length, 1);
|
| - expect(node.parts.length, 2);
|
| - expect(node.imports.contains(nodeOf('/a3.dart')), isTrue);
|
| - expect(node.exports.contains(nodeOf('/a5.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a4.dart')), isTrue);
|
| - expect(node.parts.contains(nodeOf('/a6.dart')), isTrue);
|
| -
|
| - // Note, technically we never modified the contents of a4 and it contains
|
| - // an export. This is invalid Dart, but we'll let the analyzer report that
|
| - // error instead of doing so ourselves.
|
| - expect(a4.imports.length, 0);
|
| - expect(a4.exports.length, 1);
|
| - expect(a4.parts.length, 0);
|
| -
|
| - // And change it back.
|
| - updateFile(
|
| - node.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart'; // changed again
|
| - export 'a5.dart';
|
| - part 'a6.dart';
|
| - ''');
|
| - node.update();
|
| - expect(node.imports.contains(a4), isTrue);
|
| - expect(a4.imports.length, 0);
|
| - expect(a4.exports.length, 1);
|
| - expect(a4.parts.length, 0);
|
| - });
|
| - });
|
| -
|
| - group('local changes', () {
|
| - group('needs rebuild', () {
|
| - test('in HTML', () {
|
| - var node = nodeOf('/index1.html');
|
| - node.update();
|
| - expect(node.needsRebuild, isTrue);
|
| - node.needsRebuild = false;
|
| -
|
| - node.update();
|
| - expect(node.needsRebuild, isFalse);
|
| -
|
| - // For now, an empty modification is enough to trigger a rebuild
|
| - updateFile(node.source);
|
| - expect(node.needsRebuild, isFalse);
|
| - node.update();
|
| - expect(node.needsRebuild, isTrue);
|
| - });
|
| -
|
| - test('main library in Dart', () {
|
| - var node = nodeOf('/a2.dart');
|
| - var partNode = nodeOf('/a6.dart');
|
| - node.update();
|
| - expect(node.needsRebuild, isTrue);
|
| - node.needsRebuild = false;
|
| - partNode.needsRebuild = false;
|
| -
|
| - node.update();
|
| - expect(node.needsRebuild, isFalse);
|
| -
|
| - // For now, an empty modification is enough to trigger a rebuild
|
| - updateFile(node.source);
|
| - expect(node.needsRebuild, isFalse);
|
| - node.update();
|
| - expect(node.needsRebuild, isTrue);
|
| - });
|
| -
|
| - test('part of library in Dart', () {
|
| - var node = nodeOf('/a2.dart');
|
| - var importNode = nodeOf('/a3.dart');
|
| - var exportNode = nodeOf('/a5.dart');
|
| - var partNode = nodeOf('/a6.dart');
|
| - node.update();
|
| - expect(node.needsRebuild, isTrue);
|
| - node.needsRebuild = false;
|
| - partNode.needsRebuild = false;
|
| -
|
| - node.update();
|
| - expect(node.needsRebuild, isFalse);
|
| -
|
| - // Modification in imported/exported node makes no difference for local
|
| - // rebuild label (globally that's tested elsewhere)
|
| - updateFile(importNode.source);
|
| - updateFile(exportNode.source);
|
| - node.update();
|
| - expect(node.needsRebuild, isFalse);
|
| - expect(partNode.needsRebuild, isFalse);
|
| -
|
| - // Modification in part triggers change in containing library:
|
| - updateFile(partNode.source);
|
| - expect(node.needsRebuild, isFalse);
|
| - expect(partNode.needsRebuild, isFalse);
|
| - node.update();
|
| - expect(node.needsRebuild, isTrue);
|
| - expect(partNode.needsRebuild, isTrue);
|
| - });
|
| - });
|
| -
|
| - group('structure change', () {
|
| - test('no mod in HTML', () {
|
| - var node = nodeOf('/index2.html');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - node.structureChanged = false;
|
| -
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // An empty modification will not trigger a structural change
|
| - updateFile(node.source);
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| - });
|
| -
|
| - test('added scripts in HTML', () {
|
| - var node = nodeOf('/index2.html');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - expect(node.scripts.length, 1);
|
| -
|
| - node.structureChanged = false;
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // This change will not include new script tags:
|
| - updateFile(node.source, node.source.contents.data + '<div></div>');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| - expect(node.scripts.length, 1);
|
| -
|
| - updateFile(
|
| - node.source,
|
| - node.source.contents.data +
|
| - '<script type="application/dart" src="a4.dart"></script>');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - expect(node.scripts.length, 2);
|
| - });
|
| -
|
| - test('no mod in Dart', () {
|
| - var node = nodeOf('/a2.dart');
|
| - var importNode = nodeOf('/a3.dart');
|
| - var exportNode = nodeOf('/a5.dart');
|
| - var partNode = nodeOf('/a6.dart');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - node.structureChanged = false;
|
| -
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // These modifications make no difference at all.
|
| - updateFile(importNode.source);
|
| - updateFile(exportNode.source);
|
| - updateFile(partNode.source);
|
| - updateFile(node.source);
|
| -
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| - });
|
| -
|
| - test('same directives, different order', () {
|
| - var node = nodeOf('/a2.dart');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - node.structureChanged = false;
|
| -
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // modified order of imports, but structure stays the same:
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a3.dart"; '
|
| - 'export "a5.dart"; part "a6.dart";');
|
| - node.update();
|
| -
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| - });
|
| -
|
| - test('changed parts', () {
|
| - var node = nodeOf('/a2.dart');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - node.structureChanged = false;
|
| -
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // added one.
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a3.dart"; '
|
| - 'export "a5.dart"; part "a6.dart"; part "a7.dart";');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| -
|
| - // no change
|
| - node.structureChanged = false;
|
| - updateFile(node.source);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // removed one
|
| - updateFile(node.source);
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a3.dart"; '
|
| - 'export "a5.dart"; part "a7.dart";');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - });
|
| -
|
| - test('changed import', () {
|
| - var node = nodeOf('/a2.dart');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - node.structureChanged = false;
|
| -
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // added one.
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a3.dart"; import "a7.dart";'
|
| - 'export "a5.dart"; part "a6.dart";');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| -
|
| - // no change
|
| - node.structureChanged = false;
|
| - updateFile(node.source);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // removed one
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a7.dart"; '
|
| - 'export "a5.dart"; part "a6.dart";');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - });
|
| -
|
| - test('changed exports', () {
|
| - var node = nodeOf('/a2.dart');
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - node.structureChanged = false;
|
| -
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // added one.
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a3.dart";'
|
| - 'export "a5.dart"; export "a9.dart"; part "a6.dart";');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| -
|
| - // no change
|
| - node.structureChanged = false;
|
| - updateFile(node.source);
|
| - node.update();
|
| - expect(node.structureChanged, isFalse);
|
| -
|
| - // removed one
|
| - updateFile(
|
| - node.source,
|
| - 'import "a4.dart"; import "a3.dart"; '
|
| - 'export "a5.dart"; part "a6.dart";');
|
| - expect(node.structureChanged, isFalse);
|
| - node.update();
|
| - expect(node.structureChanged, isTrue);
|
| - });
|
| - });
|
| - });
|
| -
|
| - group('refresh structure and marks', () {
|
| - test('initial marks', () {
|
| - var node = nodeOf('/index3.html');
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - refreshStructureAndMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html [needs-rebuild] [structure-changed]
|
| - |-- a2.dart [needs-rebuild] [structure-changed]
|
| - | |-- a3.dart [needs-rebuild]
|
| - | |-- a4.dart [needs-rebuild] [structure-changed]
|
| - | | |-- a10.dart [needs-rebuild]
|
| - | |-- a5.dart [needs-rebuild]
|
| - | |-- a6.dart (part) [needs-rebuild]
|
| - $_RUNTIME_GRAPH_REBUILD
|
| - ''');
|
| - });
|
| -
|
| - test('cleared marks stay clear', () {
|
| - var node = nodeOf('/index3.html');
|
| - refreshStructureAndMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html [needs-rebuild] [structure-changed]
|
| - |-- a2.dart [needs-rebuild] [structure-changed]
|
| - | |-- a3.dart [needs-rebuild]
|
| - | |-- a4.dart [needs-rebuild] [structure-changed]
|
| - | | |-- a10.dart [needs-rebuild]
|
| - | |-- a5.dart [needs-rebuild]
|
| - | |-- a6.dart (part) [needs-rebuild]
|
| - $_RUNTIME_GRAPH_REBUILD
|
| - ''');
|
| - clearMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - refreshStructureAndMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| -
|
| - test('needsRebuild mark updated on local modifications', () {
|
| - var node = nodeOf('/index3.html');
|
| - refreshStructureAndMarks(node);
|
| - clearMarks(node);
|
| - var a3 = nodeOf('/a3.dart');
|
| - updateFile(a3.source);
|
| -
|
| - refreshStructureAndMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart [needs-rebuild]
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| -
|
| - test('structuredChanged mark updated on structure modifications', () {
|
| - var node = nodeOf('/index3.html');
|
| - refreshStructureAndMarks(node);
|
| - clearMarks(node);
|
| - var a5 = nodeOf('/a5.dart');
|
| - updateFile(a5.source, 'import "a8.dart";');
|
| -
|
| - refreshStructureAndMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart [needs-rebuild] [structure-changed]
|
| - | | |-- a8.dart [needs-rebuild] [structure-changed]
|
| - | | | |-- a8.dart...
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| - });
|
| -
|
| - group('server-mode', () {
|
| - setUp(() {
|
| - var opts = new CompilerOptions(
|
| - runtimeDir: '/dev_compiler_runtime/',
|
| - sourceOptions: new SourceResolverOptions(useMockSdk: true),
|
| - serverMode: true);
|
| - context = createAnalysisContextWithSources(opts.sourceOptions,
|
| - fileResolvers: [testUriResolver]);
|
| - graph = new SourceGraph(context, new LogReporter(context), opts);
|
| - });
|
| -
|
| - test('messages widget is automatically included', () {
|
| - var node = nodeOf('/index3.html');
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - $_RUNTIME_GRAPH
|
| - |-- messages_widget.js
|
| - |-- messages.css
|
| - ''');
|
| - refreshStructureAndMarks(node);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html [needs-rebuild] [structure-changed]
|
| - |-- a2.dart [needs-rebuild] [structure-changed]
|
| - | |-- a3.dart [needs-rebuild]
|
| - | |-- a4.dart [needs-rebuild] [structure-changed]
|
| - | | |-- a10.dart [needs-rebuild]
|
| - | |-- a5.dart [needs-rebuild]
|
| - | |-- a6.dart (part) [needs-rebuild]
|
| - $_RUNTIME_GRAPH_REBUILD
|
| - |-- messages_widget.js [needs-rebuild]
|
| - |-- messages.css [needs-rebuild]
|
| - ''');
|
| - });
|
| - });
|
| -
|
| - group('rebuild', () {
|
| - var results;
|
| - void addName(SourceNode n) => results.add(nameFor(n));
|
| -
|
| - bool buildNoTransitiveChange(SourceNode n) {
|
| - addName(n);
|
| - return false;
|
| - }
|
| -
|
| - bool buildWithTransitiveChange(SourceNode n) {
|
| - addName(n);
|
| - return true;
|
| - }
|
| -
|
| - setUp(() {
|
| - results = [];
|
| - });
|
| -
|
| - test('everything build on first run', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - // Note: a6.dart is not included because it built as part of a2.dart
|
| - expect(
|
| - results,
|
| - ['a3.dart', 'a10.dart', 'a4.dart', 'a5.dart', 'a2.dart']
|
| - ..addAll(runtimeFilesWithoutPath)
|
| - ..add('index3.html'));
|
| -
|
| - // Marks are removed automatically by rebuild
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| -
|
| - test('nothing to do after build', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('modified part triggers building library', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - var a6 = nodeOf('/a6.dart');
|
| - updateFile(a6.source);
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a2.dart']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('non-API change triggers build stays local', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - var a3 = nodeOf('/a3.dart');
|
| - updateFile(a3.source);
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a3.dart']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('no-API change in exported file stays local', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - // similar to the test above, but a10 is exported from a4.
|
| - var a3 = nodeOf('/a10.dart');
|
| - updateFile(a3.source);
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a10.dart']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('API change in lib, triggers build on imports', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - var a3 = nodeOf('/a3.dart');
|
| - updateFile(a3.source);
|
| - rebuild(node, buildWithTransitiveChange);
|
| - expect(results, ['a3.dart', 'a2.dart']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('API change in export, triggers build on imports', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - var a3 = nodeOf('/a10.dart');
|
| - updateFile(a3.source);
|
| - rebuild(node, buildWithTransitiveChange);
|
| -
|
| - // Node: a4.dart reexports a10.dart, but it doesn't import it, so we don't
|
| - // need to rebuild it.
|
| - expect(results, ['a10.dart', 'a2.dart']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('structural change rebuilds HTML, but skips unreachable code', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - var a2 = nodeOf('/a2.dart');
|
| - updateFile(a2.source, 'import "a4.dart";');
|
| -
|
| - var a3 = nodeOf('/a3.dart');
|
| - updateFile(a3.source);
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - // a3 will become unreachable, index3 reflects structural changes.
|
| - expect(results, ['a2.dart', 'index3.html']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - test('newly discovered files get built too', () {
|
| - var node = nodeOf('/index3.html');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - results = [];
|
| -
|
| - var a2 = nodeOf('/a2.dart');
|
| - updateFile(a2.source, 'import "a9.dart";');
|
| -
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a8.dart', 'a9.dart', 'a2.dart', 'index3.html']);
|
| -
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, []);
|
| - });
|
| -
|
| - group('file upgrades', () {
|
| - // Normally upgrading involves two changes:
|
| - // (a) change the affected file
|
| - // (b) change directive from part to import (or viceversa)
|
| - // These could happen in any order and we should reach a consistent state
|
| - // in the end.
|
| -
|
| - test('convert part to a library before updating the import', () {
|
| - var node = nodeOf('/index3.html');
|
| - var a2 = nodeOf('/a2.dart');
|
| - var a6 = nodeOf('/a6.dart');
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - // Modify the file first:
|
| - updateFile(a6.source, 'library a6; import "a5.dart";');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - // Looks to us like a change in a part, we'll report errors that the
|
| - // part is not really a part-file. Note that a6.dart is not included
|
| - // below, because we don't build it as a library.
|
| - expect(results, ['a2.dart']);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - updateFile(
|
| - a2.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart';
|
| - import 'a6.dart'; // properly import it
|
| - export 'a5.dart';
|
| - ''');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - // Note that a6 is now included, because we haven't built it as a
|
| - // library until now:
|
| - expect(results, ['a6.dart', 'a2.dart', 'index3.html']);
|
| -
|
| - updateFile(a6.source);
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a6.dart']);
|
| -
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a6.dart
|
| - | | |-- a5.dart
|
| - | |-- a5.dart...
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| -
|
| - test('convert part to a library after updating the import', () {
|
| - var node = nodeOf('/index3.html');
|
| - var a2 = nodeOf('/a2.dart');
|
| - var a6 = nodeOf('/a6.dart');
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - updateFile(
|
| - a2.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart';
|
| - import 'a6.dart'; // properly import it
|
| - export 'a5.dart';
|
| - ''');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a6.dart', 'a2.dart', 'index3.html']);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a6.dart
|
| - | |-- a5.dart
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - updateFile(a6.source, 'library a6; import "a5.dart";');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a6.dart', 'index3.html']);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a6.dart
|
| - | | |-- a5.dart
|
| - | |-- a5.dart...
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| -
|
| - test('disconnect part making it a library', () {
|
| - var node = nodeOf('/index3.html');
|
| - var a2 = nodeOf('/a2.dart');
|
| - var a6 = nodeOf('/a6.dart');
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - updateFile(
|
| - a2.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart';
|
| - export 'a5.dart';
|
| - ''');
|
| - updateFile(a6.source, 'library a6; import "a5.dart";');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - // a6 is not here, it's not reachable so we don't build it.
|
| - expect(results, ['a2.dart', 'index3.html']);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| -
|
| - test('convert a library to a part', () {
|
| - var node = nodeOf('/index3.html');
|
| - var a2 = nodeOf('/a2.dart');
|
| - var a5 = nodeOf('/a5.dart');
|
| - rebuild(node, buildNoTransitiveChange);
|
| -
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - updateFile(
|
| - a2.source,
|
| - '''
|
| - library a2;
|
| - import 'a3.dart';
|
| - import 'a4.dart';
|
| - part 'a5.dart'; // make it a part
|
| - part 'a6.dart';
|
| - ''');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a2.dart', 'index3.html']);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart (part)
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| -
|
| - updateFile(a5.source, 'part of a2;');
|
| - results = [];
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(results, ['a2.dart']);
|
| - expectGraph(
|
| - node,
|
| - '''
|
| - index3.html
|
| - |-- a2.dart
|
| - | |-- a3.dart
|
| - | |-- a4.dart
|
| - | | |-- a10.dart
|
| - | |-- a5.dart (part)
|
| - | |-- a6.dart (part)
|
| - $_RUNTIME_GRAPH
|
| - ''');
|
| - });
|
| - });
|
| -
|
| - group('represented non-existing files', () {
|
| - test('recognize locally change between existing and not-existing', () {
|
| - var n = nodeOf('/foo.dart');
|
| - expect(n.source, isNotNull);
|
| - expect(n.source.exists(), isFalse);
|
| - var source = testUriResolver.resolveAbsolute(new Uri.file('/foo.dart'));
|
| - expect(n.source, source);
|
| - updateFile(source, "hi");
|
| - expect(n.source.exists(), isTrue);
|
| - });
|
| -
|
| - test('non-existing files are tracked in dependencies', () {
|
| - var node = nodeOf('/foo.dart');
|
| - updateFile(node.source, "import 'bar.dart';");
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(node.allDeps.contains(nodeOf('/bar.dart')), isTrue);
|
| -
|
| - var source = nodeOf('/bar.dart').source;
|
| - updateFile(source, "hi");
|
| - results = [];
|
| - rebuild(node, buildWithTransitiveChange);
|
| - expect(results, ['bar.dart', 'foo.dart']);
|
| - });
|
| - });
|
| -
|
| - group('null for non-existing files', () {
|
| - setUp(() {
|
| - context = createAnalysisContextWithSources(options.sourceOptions,
|
| - fileResolvers: [testUriResolver]);
|
| - graph = new SourceGraph(context, new LogReporter(context), options);
|
| - });
|
| -
|
| - test('recognize locally change between existing and not-existing', () {
|
| - var n = nodeOf('/foo.dart');
|
| - expect(n.source.exists(), isFalse);
|
| - var source =
|
| - testResourceProvider.newFile('/foo.dart', 'hi').createSource();
|
| - expect(
|
| - testUriResolver.resolveAbsolute(new Uri.file('/foo.dart')), source);
|
| - expect(n.source, source);
|
| - expect(n.source.exists(), isTrue);
|
| - n.update();
|
| - expect(n.needsRebuild, isTrue);
|
| - });
|
| -
|
| - test('non-existing files are tracked in dependencies', () {
|
| - testResourceProvider
|
| - .newFile('/foo.dart', "import 'bar.dart';")
|
| - .createSource();
|
| - var node = nodeOf('/foo.dart');
|
| - rebuild(node, buildNoTransitiveChange);
|
| - expect(node.allDeps.length, 1);
|
| - expect(node.allDeps.contains(nodeOf('/bar.dart')), isTrue);
|
| - expect(nodeOf('/bar.dart').source.exists(), isFalse);
|
| -
|
| - testResourceProvider.newFile('/bar.dart', 'hi').createSource();
|
| - results = [];
|
| - rebuild(node, buildWithTransitiveChange);
|
| - expect(results, ['bar.dart', 'foo.dart']);
|
| - });
|
| - });
|
| - });
|
| -}
|
| -
|
| -expectGraph(SourceNode node, String expectation) {
|
| - expect(printReachable(node), equalsIgnoringWhitespace(expectation));
|
| -}
|
| -
|
| -nameFor(SourceNode node) => path.basename(node.uri.path);
|
| -printReachable(SourceNode node) {
|
| - var seen = new Set();
|
| - var sb = new StringBuffer();
|
| - helper(n, {indent: 0}) {
|
| - if (indent > 0) {
|
| - sb..write("| " * (indent - 1))..write("|-- ");
|
| - }
|
| - sb.write(nameFor(n));
|
| - if (seen.contains(n)) {
|
| - sb.write('...\n');
|
| - return;
|
| - }
|
| - seen.add(n);
|
| - sb
|
| - ..write(' ')
|
| - ..write(n.needsRebuild ? '[needs-rebuild] ' : '')
|
| - ..write(n.structureChanged ? '[structure-changed] ' : ' ')
|
| - ..write('\n');
|
| - n.depsWithoutParts.forEach((e) => helper(e, indent: indent + 1));
|
| - if (n is DartSourceNode) {
|
| - n.parts.forEach((e) {
|
| - sb
|
| - ..write("| " * indent)
|
| - ..write("|-- ")
|
| - ..write(nameFor(e))
|
| - ..write(" (part) ")
|
| - ..write(e.needsRebuild ? '[needs-rebuild] ' : '')
|
| - ..write(e.structureChanged ? '[structure-changed] ' : ' ')
|
| - ..write('\n');
|
| - });
|
| - }
|
| - }
|
| - helper(node);
|
| - return sb.toString();
|
| -}
|
| -
|
| -final runtimeFilesWithoutPath = defaultRuntimeFiles
|
| - .map((f) => f.replaceAll('dart/', ''))
|
| - .toList(growable: false);
|
| -final _RUNTIME_GRAPH = runtimeFilesWithoutPath.map((s) => '|-- $s').join('\n');
|
| -final _RUNTIME_GRAPH_REBUILD =
|
| - runtimeFilesWithoutPath.map((s) => '|-- $s [needs-rebuild]').join('\n');
|
|
|