Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 | 6 |
| 7 import 'package:analyzer/file_system/physical_file_system.dart'; | |
| 8 import 'package:analyzer/src/dart/sdk/sdk.dart'; | |
| 9 import 'package:front_end/compiler_options.dart'; | 7 import 'package:front_end/compiler_options.dart'; |
| 10 import 'package:front_end/incremental_kernel_generator.dart'; | 8 import 'package:front_end/incremental_kernel_generator.dart'; |
| 11 import 'package:front_end/memory_file_system.dart'; | 9 import 'package:front_end/memory_file_system.dart'; |
| 12 import 'package:kernel/ast.dart'; | 10 import 'package:kernel/ast.dart'; |
| 11 import 'package:kernel/text/ast_to_text.dart'; | |
| 13 import 'package:test/test.dart'; | 12 import 'package:test/test.dart'; |
| 14 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 13 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| 15 | 14 |
| 15 import 'src/incremental/mock_sdk.dart'; | |
| 16 | |
| 16 main() { | 17 main() { |
| 17 defineReflectiveSuite(() { | 18 defineReflectiveSuite(() { |
| 18 defineReflectiveTests(IncrementalKernelGeneratorTest); | 19 defineReflectiveTests(IncrementalKernelGeneratorTest); |
| 19 }); | 20 }); |
| 20 } | 21 } |
| 21 | 22 |
| 22 final _sdkSummary = _readSdkSummary(); | |
| 23 | |
| 24 List<int> _readSdkSummary() { | |
| 25 var resourceProvider = PhysicalResourceProvider.INSTANCE; | |
| 26 var sdk = new FolderBasedDartSdk(resourceProvider, | |
| 27 FolderBasedDartSdk.defaultSdkDirectory(resourceProvider)) | |
| 28 ..useSummary = true; | |
| 29 var path = resourceProvider.pathContext | |
| 30 .join(sdk.directory.path, 'lib', '_internal', 'strong.sum'); | |
| 31 return resourceProvider.getFile(path).readAsBytesSync(); | |
| 32 } | |
| 33 | |
| 34 @reflectiveTest | 23 @reflectiveTest |
| 35 class IncrementalKernelGeneratorTest { | 24 class IncrementalKernelGeneratorTest { |
| 36 static final sdkSummaryUri = Uri.parse('special:sdk_summary'); | |
| 37 | |
| 38 /// Virtual filesystem for testing. | 25 /// Virtual filesystem for testing. |
| 39 final fileSystem = new MemoryFileSystem(Uri.parse('file:///')); | 26 final fileSystem = new MemoryFileSystem(Uri.parse('file:///')); |
| 40 | 27 |
| 41 /// The object under test. | 28 /// The object under test. |
| 42 IncrementalKernelGenerator incrementalKernelGenerator; | 29 IncrementalKernelGenerator incrementalKernelGenerator; |
| 43 | 30 |
| 44 Future<Map<Uri, Program>> getInitialState(Uri startingUri) async { | 31 /// TODO(scheglov) Why do we return a Map? |
| 45 fileSystem.entityForUri(sdkSummaryUri).writeAsBytesSync(_sdkSummary); | 32 /// From the discussion yesterday it seems to me that we always have |
| 33 /// just one program - with all libraries with code, or with some libraries | |
| 34 /// with code and some with only outlines. | |
|
Paul Berry
2017/05/07 14:17:40
My understanding from talking to Dan Rubel and the
scheglov
2017/05/07 17:38:49
FWIW, having a kernel file per affected library wo
Paul Berry
2017/05/08 12:55:14
Agreed. The way I originally wanted to implement
| |
| 35 Future<Map<Uri, Program>> getInitialState(Uri entryPoint) async { | |
| 36 Map<String, Uri> dartLibraries = createSdkFiles(fileSystem); | |
| 37 // TODO(scheglov) Builder the SDK kernel and set it into the options. | |
| 38 | |
| 39 // TODO(scheglov) Make `.packages` file optional. | |
| 40 | |
| 46 incrementalKernelGenerator = new IncrementalKernelGenerator( | 41 incrementalKernelGenerator = new IncrementalKernelGenerator( |
| 47 startingUri, | 42 entryPoint, |
| 48 new CompilerOptions() | 43 new CompilerOptions() |
| 49 ..fileSystem = fileSystem | 44 ..fileSystem = fileSystem |
| 45 ..strongMode = true | |
| 50 ..chaseDependencies = true | 46 ..chaseDependencies = true |
| 51 ..sdkSummary = sdkSummaryUri | 47 ..dartLibraries = dartLibraries |
| 52 ..packagesFileUri = new Uri()); | 48 ..packagesFileUri = Uri.parse('file:///test/.packages')); |
| 53 return (await incrementalKernelGenerator.computeDelta()).newState; | 49 return (await incrementalKernelGenerator.computeDelta()).newState; |
| 54 } | 50 } |
| 55 | 51 |
| 56 test_incrementalUpdate_referenceToCore() async { | 52 test_updateEntryPoint() async { |
| 57 writeFiles({'/foo.dart': 'main() { print(1); }'}); | 53 writeFile('/test/.packages', 'test:lib/'); |
| 58 var fooUri = Uri.parse('file:///foo.dart'); | 54 String path = '/test/lib/test.dart'; |
| 59 var coreUri = Uri.parse('dart:core'); | 55 Uri uri = writeFile( |
| 60 var initialState = await getInitialState(fooUri); | 56 path, |
| 61 expect(initialState.keys, unorderedEquals([fooUri])); | 57 r''' |
| 58 main() { | |
| 59 var v = 1; | |
| 60 } | |
| 61 '''); | |
| 62 | 62 |
| 63 void _checkMain(Program program, int expectedArgument) { | 63 // Compute the initial state |
| 64 expect(_getLibraryUris(program), unorderedEquals([fooUri, coreUri])); | 64 { |
| 65 var mainStatements = _getProcedureStatements( | 65 Map<Uri, Program> initialState = await getInitialState(uri); |
| 66 _getProcedure(_getLibrary(program, fooUri), 'main')); | 66 expect(initialState.keys, unorderedEquals([uri])); |
| 67 expect(mainStatements, hasLength(1)); | 67 |
| 68 _checkPrintLiteralInt(mainStatements[0], expectedArgument); | 68 Library library = _getLibrary(initialState[uri], uri); |
| 69 var coreLibrary = _getLibrary(program, coreUri); | 69 expect( |
| 70 expect(coreLibrary.procedures, hasLength(1)); | 70 _getLibraryText(library), |
| 71 expect(coreLibrary.procedures[0].name.name, 'print'); | 71 r''' |
| 72 expect(coreLibrary.procedures[0].function.body, isNull); | 72 library; |
| 73 import self as self; | |
| 74 import "dart:core" as core; | |
| 75 | |
| 76 static method main() → dynamic { | |
| 77 core::int v = 1; | |
| 78 } | |
| 79 '''); | |
| 73 } | 80 } |
| 74 | 81 |
| 75 _checkMain(initialState[fooUri], 1); | 82 // Update the entry point library. |
| 76 writeFiles({'/foo.dart': 'main() { print(2); }'}); | 83 writeFile( |
| 77 incrementalKernelGenerator.invalidateAll(); | 84 path, |
| 78 var deltaProgram = await incrementalKernelGenerator.computeDelta(); | 85 r''' |
| 79 expect(deltaProgram.newState.keys, unorderedEquals([fooUri])); | 86 main() { |
| 80 _checkMain(deltaProgram.newState[fooUri], 2); | 87 var v = 2.3; |
| 88 } | |
| 89 '''); | |
| 90 | |
| 91 // The delta has the updated entry point library. | |
| 92 { | |
| 93 DeltaProgram delta = await incrementalKernelGenerator.computeDelta(); | |
| 94 expect(delta.newState.keys, unorderedEquals([uri])); | |
| 95 | |
| 96 Library library = _getLibrary(delta.newState[uri], uri); | |
| 97 expect( | |
| 98 _getLibraryText(library), | |
| 99 r''' | |
| 100 library; | |
| 101 import self as self; | |
| 102 import "dart:core" as core; | |
| 103 | |
| 104 static method main() → dynamic { | |
| 105 core::double v = 2.3; | |
| 106 } | |
| 107 '''); | |
| 108 } | |
| 81 } | 109 } |
| 82 | 110 |
| 83 test_part() async { | 111 /// Write the given [text] of the file with the given [path] into the |
| 84 writeFiles({ | 112 /// virtual filesystem. Return the URI of the file. |
| 85 '/foo.dart': 'library foo; part "bar.dart"; main() { print(1); f(); }', | 113 Uri writeFile(String path, String text) { |
| 86 '/bar.dart': 'part of foo; f() { print(2); }' | 114 Uri uri = Uri.parse('file://$path'); |
| 87 }); | 115 fileSystem.entityForUri(uri).writeAsStringSync(text); |
| 88 var fooUri = Uri.parse('file:///foo.dart'); | 116 return uri; |
| 89 var initialState = await getInitialState(fooUri); | |
| 90 expect(initialState.keys, unorderedEquals([fooUri])); | |
| 91 var library = _getLibrary(initialState[fooUri], fooUri); | |
| 92 var mainStatements = | |
| 93 _getProcedureStatements(_getProcedure(library, 'main')); | |
| 94 var fProcedure = _getProcedure(library, 'f'); | |
| 95 var fStatements = _getProcedureStatements(fProcedure); | |
| 96 expect(mainStatements, hasLength(2)); | |
| 97 _checkPrintLiteralInt(mainStatements[0], 1); | |
| 98 _checkFunctionCall(mainStatements[1], fProcedure); | |
| 99 expect(fStatements, hasLength(1)); | |
| 100 _checkPrintLiteralInt(fStatements[0], 2); | |
| 101 // TODO(paulberry): now test incremental updates | |
| 102 } | 117 } |
| 103 | 118 |
| 119 // test_part() async { | |
| 120 // writeFiles({ | |
| 121 // '/foo.dart': 'library foo; part "bar.dart"; main() { print(1); f(); }', | |
| 122 // '/bar.dart': 'part of foo; f() { print(2); }' | |
| 123 // }); | |
| 124 // var fooUri = Uri.parse('file:///foo.dart'); | |
| 125 // var initialState = await getInitialState(fooUri); | |
| 126 // expect(initialState.keys, unorderedEquals([fooUri])); | |
| 127 // var library = _getLibrary(initialState[fooUri], fooUri); | |
| 128 // var mainStatements = | |
| 129 // _getProcedureStatements(_getProcedure(library, 'main')); | |
| 130 // var fProcedure = _getProcedure(library, 'f'); | |
| 131 // var fStatements = _getProcedureStatements(fProcedure); | |
| 132 // expect(mainStatements, hasLength(2)); | |
| 133 // _checkPrintLiteralInt(mainStatements[0], 1); | |
| 134 // _checkFunctionCall(mainStatements[1], fProcedure); | |
| 135 // expect(fStatements, hasLength(1)); | |
| 136 // _checkPrintLiteralInt(fStatements[0], 2); | |
| 137 // TODO(paulberry): now test incremental updates | |
| 138 // } | |
| 139 | |
| 104 /// Write the given file contents to the virtual filesystem. | 140 /// Write the given file contents to the virtual filesystem. |
| 105 void writeFiles(Map<String, String> contents) { | 141 void writeFiles(Map<String, String> contents) { |
| 106 contents.forEach((path, text) { | 142 contents.forEach(writeFile); |
| 107 fileSystem | |
| 108 .entityForUri(Uri.parse('file://$path')) | |
| 109 .writeAsStringSync(text); | |
| 110 }); | |
| 111 } | |
| 112 | |
| 113 void _checkFunctionCall(Statement statement, Procedure expectedTarget) { | |
| 114 expect(statement, new isInstanceOf<ExpressionStatement>()); | |
| 115 var expressionStatement = statement as ExpressionStatement; | |
| 116 expect( | |
| 117 expressionStatement.expression, new isInstanceOf<StaticInvocation>()); | |
| 118 var staticInvocation = expressionStatement.expression as StaticInvocation; | |
| 119 expect(staticInvocation.target, same(expectedTarget)); | |
| 120 } | |
| 121 | |
| 122 void _checkPrintLiteralInt(Statement statement, int expectedArgument) { | |
| 123 expect(statement, new isInstanceOf<ExpressionStatement>()); | |
| 124 var expressionStatement = statement as ExpressionStatement; | |
| 125 expect( | |
| 126 expressionStatement.expression, new isInstanceOf<StaticInvocation>()); | |
| 127 var staticInvocation = expressionStatement.expression as StaticInvocation; | |
| 128 expect(staticInvocation.target.name.name, 'print'); | |
| 129 expect(staticInvocation.arguments.positional, hasLength(1)); | |
| 130 expect(staticInvocation.arguments.positional[0], | |
| 131 new isInstanceOf<IntLiteral>()); | |
| 132 var intLiteral = staticInvocation.arguments.positional[0] as IntLiteral; | |
| 133 expect(intLiteral.value, expectedArgument); | |
| 134 } | 143 } |
| 135 | 144 |
| 136 Library _getLibrary(Program program, Uri uri) { | 145 Library _getLibrary(Program program, Uri uri) { |
| 137 for (var library in program.libraries) { | 146 for (var library in program.libraries) { |
| 138 if (library.importUri == uri) return library; | 147 if (library.importUri == uri) return library; |
| 139 } | 148 } |
| 140 throw fail('No library found with URI "$uri"'); | 149 throw fail('No library found with URI "$uri"'); |
| 141 } | 150 } |
| 142 | 151 |
| 143 List<Uri> _getLibraryUris(Program program) => | 152 String _getLibraryText(Library library) { |
| 144 program.libraries.map((library) => library.importUri).toList(); | 153 StringBuffer buffer = new StringBuffer(); |
| 145 | 154 new Printer(buffer, syntheticNames: new NameSystem()) |
| 146 Procedure _getProcedure(Library library, String name) { | 155 .writeLibraryFile(library); |
| 147 for (var procedure in library.procedures) { | 156 return buffer.toString(); |
| 148 if (procedure.name.name == name) return procedure; | |
| 149 } | |
| 150 throw fail('No function declaration found with name "$name"'); | |
| 151 } | |
| 152 | |
| 153 List<Statement> _getProcedureStatements(Procedure procedure) { | |
| 154 var body = procedure.function.body; | |
| 155 expect(body, new isInstanceOf<Block>()); | |
| 156 return (body as Block).statements; | |
| 157 } | 157 } |
| 158 } | 158 } |
| OLD | NEW |