|  | // 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. | 
|  |  | 
|  | // @dart = 2.7 | 
|  |  | 
|  | // Test of the graph segmentation algorithm used by deferred loading | 
|  | // to determine which elements can be deferred and which libraries | 
|  | // much be included in the initial download (loaded eagerly). | 
|  |  | 
|  | import 'package:async_helper/async_helper.dart'; | 
|  | import 'package:compiler/src/compiler.dart'; | 
|  | import 'package:expect/expect.dart'; | 
|  | import '../helpers/memory_compiler.dart'; | 
|  |  | 
|  | void main() { | 
|  | asyncTest(() async { | 
|  | print('--test from kernel------------------------------------------------'); | 
|  | await deferredTest1(); | 
|  | await deferredTest2(); | 
|  | await deferredTest3(); | 
|  | await deferredTest4(); | 
|  | await deferredTest5(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | deferredTest1() async { | 
|  | CompilationResult result = await runCompiler(memorySourceFiles: TEST1); | 
|  |  | 
|  | Compiler compiler = result.compiler; | 
|  | var closedWorld = compiler.backendClosedWorldForTesting; | 
|  | var env = closedWorld.elementEnvironment; | 
|  | var outputUnitForMember = closedWorld.outputUnitData.outputUnitForMember; | 
|  | var mainOutputUnit = closedWorld.outputUnitData.mainOutputUnit; | 
|  | lookupLibrary(name) => env.lookupLibrary(Uri.parse(name)); | 
|  | dynamic lib1 = lookupLibrary("memory:lib1.dart"); | 
|  | dynamic lib2 = lookupLibrary("memory:lib2.dart"); | 
|  | env.lookupLibraryMember(lib1, "foo1"); | 
|  | var foo2 = env.lookupLibraryMember(lib2, "foo2"); | 
|  |  | 
|  | Expect.notEquals(mainOutputUnit, outputUnitForMember(foo2)); | 
|  | } | 
|  |  | 
|  | deferredTest2() async { | 
|  | CompilationResult result = await runCompiler(memorySourceFiles: TEST2); | 
|  |  | 
|  | Compiler compiler = result.compiler; | 
|  | var closedWorld = compiler.backendClosedWorldForTesting; | 
|  | var env = closedWorld.elementEnvironment; | 
|  | var outputUnitForClass = closedWorld.outputUnitData.outputUnitForClass; | 
|  | var outputUnitForClassType = | 
|  | closedWorld.outputUnitData.outputUnitForClassType; | 
|  | lookupLibrary(name) => env.lookupLibrary(Uri.parse(name)); | 
|  | dynamic shared = lookupLibrary("memory:shared.dart"); | 
|  | var a = env.lookupClass(shared, "A"); | 
|  |  | 
|  | Expect.equals("OutputUnit(1, {import(def: deferred)})", | 
|  | outputUnitForClass(a).toString()); | 
|  | Expect.equals("OutputUnit(1, {import(def: deferred)})", | 
|  | outputUnitForClassType(a).toString()); | 
|  | } | 
|  |  | 
|  | deferredTest3() async { | 
|  | CompilationResult result = await runCompiler(memorySourceFiles: TEST3); | 
|  |  | 
|  | Compiler compiler = result.compiler; | 
|  | var closedWorld = compiler.backendClosedWorldForTesting; | 
|  | var env = closedWorld.elementEnvironment; | 
|  | var outputUnitForClass = closedWorld.outputUnitData.outputUnitForClass; | 
|  | var outputUnitForClassType = | 
|  | closedWorld.outputUnitData.outputUnitForClassType; | 
|  | var mainOutputUnit = closedWorld.outputUnitData.mainOutputUnit; | 
|  | lookupLibrary(name) => env.lookupLibrary(Uri.parse(name)); | 
|  | dynamic shared = lookupLibrary("memory:shared.dart"); | 
|  | var a = env.lookupClass(shared, "A"); | 
|  |  | 
|  | Expect.equals(mainOutputUnit, outputUnitForClass(a)); | 
|  | Expect.equals(mainOutputUnit, outputUnitForClassType(a)); | 
|  | } | 
|  |  | 
|  | deferredTest4() async { | 
|  | CompilationResult result = await runCompiler(memorySourceFiles: TEST4); | 
|  |  | 
|  | Compiler compiler = result.compiler; | 
|  | var closedWorld = compiler.backendClosedWorldForTesting; | 
|  | var env = closedWorld.elementEnvironment; | 
|  | var outputUnitForClass = closedWorld.outputUnitData.outputUnitForClass; | 
|  | var outputUnitForClassType = | 
|  | closedWorld.outputUnitData.outputUnitForClassType; | 
|  | var mainOutputUnit = closedWorld.outputUnitData.mainOutputUnit; | 
|  | lookupLibrary(name) => env.lookupLibrary(Uri.parse(name)); | 
|  | dynamic shared = lookupLibrary("memory:shared.dart"); | 
|  | var a = env.lookupClass(shared, "A"); | 
|  |  | 
|  | Expect.equals("OutputUnit(1, {import(def: deferred)})", | 
|  | outputUnitForClass(a).toString()); | 
|  | Expect.equals(mainOutputUnit, outputUnitForClassType(a)); | 
|  | } | 
|  |  | 
|  | deferredTest5() async { | 
|  | CompilationResult result = await runCompiler(memorySourceFiles: TEST5); | 
|  |  | 
|  | Compiler compiler = result.compiler; | 
|  | var closedWorld = compiler.backendClosedWorldForTesting; | 
|  | var env = closedWorld.elementEnvironment; | 
|  | var outputUnitForClass = closedWorld.outputUnitData.outputUnitForClass; | 
|  | var outputUnitForClassType = | 
|  | closedWorld.outputUnitData.outputUnitForClassType; | 
|  | lookupLibrary(name) => env.lookupLibrary(Uri.parse(name)); | 
|  | dynamic shared = lookupLibrary("memory:shared.dart"); | 
|  | var a = env.lookupClass(shared, "A"); | 
|  | Expect.equals( | 
|  | "OutputUnit(4, {import(def2: deferred), import(def3: deferred)})", | 
|  | outputUnitForClass(a).toString()); | 
|  | Expect.equals( | 
|  | "OutputUnit(2, {import(def1: deferred), " | 
|  | "import(def2: deferred), " | 
|  | "import(def3: deferred)})", | 
|  | outputUnitForClassType(a).toString()); | 
|  | } | 
|  |  | 
|  | // lib1 imports lib2 deferred. But mainlib never uses DeferredLibrary. | 
|  | // Test that this case works. | 
|  | const Map<String, String> TEST1 = const { | 
|  | "main.dart": """ | 
|  | library mainlib; | 
|  |  | 
|  | import 'lib1.dart' as lib1; | 
|  |  | 
|  | void main() { | 
|  | lib1.foo1(); | 
|  | } | 
|  | """, | 
|  | "lib1.dart": """ | 
|  | library lib1; | 
|  |  | 
|  | import 'lib2.dart' deferred as lib2; | 
|  |  | 
|  | void foo1() { | 
|  | lib2.loadLibrary().then((_) => lib2.foo2()); | 
|  | } | 
|  | """, | 
|  | "lib2.dart": """ | 
|  | library lib2; | 
|  |  | 
|  | void foo2() {} | 
|  | """, | 
|  | }; | 
|  |  | 
|  | // A's type should be in main. | 
|  | const Map<String, String> TEST2 = const { | 
|  | "main.dart": """ | 
|  | import 'def.dart' deferred as def; | 
|  | import 'shared.dart'; | 
|  |  | 
|  | typedef void F(x); | 
|  |  | 
|  | main() { | 
|  | print(getFoo() is F); | 
|  | def.loadLibrary().then((_) { | 
|  | def.toto(); | 
|  | }); | 
|  | } | 
|  | """, | 
|  | "def.dart": """ | 
|  | import 'shared.dart'; | 
|  |  | 
|  | toto() { print(new A()); } | 
|  | """, | 
|  | "shared.dart": """ | 
|  | class A {} | 
|  | class B extends A {} | 
|  | foo(B b) => null; | 
|  | getFoo() => foo; | 
|  | """, | 
|  | }; | 
|  |  | 
|  | // main directly uses class A from shared. A should be included in the | 
|  | // main fragment. | 
|  | const Map<String, String> TEST3 = const { | 
|  | "main.dart": """ | 
|  | import 'def.dart' deferred as def; | 
|  | import 'shared.dart'; | 
|  |  | 
|  | main() { | 
|  | print(A()); | 
|  | def.loadLibrary().then((_) { | 
|  | def.toto(); | 
|  | }); | 
|  | } | 
|  | """, | 
|  | "def.dart": """ | 
|  | import 'shared.dart'; | 
|  |  | 
|  | toto() { print(new A()); } | 
|  | """, | 
|  | "shared.dart": """ | 
|  | class A {} | 
|  | class B extends A {} | 
|  | """, | 
|  | }; | 
|  |  | 
|  | // main directly uses class A's type from shared. A's type but not class | 
|  | // should be included in main. | 
|  | const Map<String, String> TEST4 = const { | 
|  | "main.dart": """ | 
|  | import 'def.dart' deferred as def; | 
|  | import 'shared.dart'; | 
|  |  | 
|  | main() { | 
|  | var v = 5; | 
|  | print(v is A); | 
|  | def.loadLibrary().then((_) { | 
|  | def.toto(); | 
|  | }); | 
|  | } | 
|  | """, | 
|  | "def.dart": """ | 
|  | import 'shared.dart'; | 
|  |  | 
|  | toto() { print(new A()); } | 
|  | """, | 
|  | "shared.dart": """ | 
|  | class A {} | 
|  | """, | 
|  | }; | 
|  |  | 
|  | // main doesn't directly use A's class or type, but does so indirectly. | 
|  | const Map<String, String> TEST5 = const { | 
|  | "main.dart": """ | 
|  | import 'def1.dart' deferred as def1; | 
|  | import 'def2.dart' deferred as def2; | 
|  | import 'def3.dart' deferred as def3; | 
|  |  | 
|  | main() { | 
|  | def1.loadLibrary().then((_) { | 
|  | def2.loadLibrary().then((_) { | 
|  | def3.loadLibrary().then((_) { | 
|  | def1.toto(null); | 
|  | def2.toto(); | 
|  | def3.toto(null); | 
|  | }); | 
|  | }); | 
|  | }); | 
|  | } | 
|  | """, | 
|  | "def1.dart": """ | 
|  | import 'shared.dart'; | 
|  |  | 
|  | toto(x) => x is A; | 
|  | """, | 
|  | "def2.dart": """ | 
|  | import 'shared.dart'; | 
|  |  | 
|  | toto() { print(A()); } | 
|  | """, | 
|  | "def3.dart": """ | 
|  | import 'shared.dart'; | 
|  |  | 
|  | toto(x) { | 
|  | print(new A()); | 
|  | return x is A; | 
|  | } | 
|  | """, | 
|  | "shared.dart": """ | 
|  | class A {} | 
|  | """, | 
|  | }; |