| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 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.md file. |
| 4 |
| 5 // TODO(ahe): Copied from closure_conversion branch of kernel, remove this file |
| 6 // when closure_conversion is merged with master. |
| 7 |
| 8 library kernel.testing.kernel_chain; |
| 9 |
| 10 import 'dart:async' show |
| 11 Future; |
| 12 |
| 13 import 'dart:io' show |
| 14 Directory, |
| 15 File, |
| 16 IOSink, |
| 17 Platform; |
| 18 |
| 19 import 'dart:typed_data' show |
| 20 Uint8List; |
| 21 |
| 22 import 'package:kernel/kernel.dart' show |
| 23 Repository, |
| 24 loadProgramFromBinary; |
| 25 |
| 26 import 'package:kernel/text/ast_to_text.dart' show |
| 27 Printer; |
| 28 |
| 29 import 'package:testing/testing.dart' show |
| 30 Result, |
| 31 StdioProcess, |
| 32 Step; |
| 33 |
| 34 import 'package:kernel/ast.dart' show |
| 35 Library, |
| 36 Program; |
| 37 |
| 38 import 'package:kernel/verifier.dart' show |
| 39 VerifyingVisitor; |
| 40 |
| 41 import 'package:kernel/binary/ast_to_binary.dart' show |
| 42 BinaryPrinter; |
| 43 |
| 44 import 'package:kernel/binary/ast_from_binary.dart' show |
| 45 BinaryBuilder; |
| 46 |
| 47 import 'package:kernel/binary/loader.dart' show |
| 48 BinaryLoader; |
| 49 |
| 50 import 'package:analyzer/src/generated/sdk.dart' show |
| 51 DartSdk; |
| 52 |
| 53 import 'package:kernel/analyzer/loader.dart' show |
| 54 DartLoader, |
| 55 DartOptions, |
| 56 createDartSdk; |
| 57 |
| 58 import 'package:kernel/target/targets.dart' show |
| 59 Target, |
| 60 TargetFlags, |
| 61 getTarget; |
| 62 |
| 63 import 'package:kernel/repository.dart' show |
| 64 Repository; |
| 65 |
| 66 import 'package:testing/testing.dart' show |
| 67 Chain, |
| 68 ChainContext, |
| 69 Result, |
| 70 StdioProcess, |
| 71 Step, |
| 72 TestDescription; |
| 73 |
| 74 import 'package:kernel/ast.dart' show |
| 75 Program; |
| 76 |
| 77 import 'package:package_config/discovery.dart' show |
| 78 loadPackagesFile; |
| 79 |
| 80 typedef Future<TestContext> TestContextConstructor( |
| 81 Chain suite, Map<String, String> environment, String sdk, Uri vm, |
| 82 Uri packages, bool strongMode, DartSdk dartSdk, bool updateExpectations); |
| 83 |
| 84 Future<bool> fileExists(Uri base, String path) async { |
| 85 return await new File.fromUri(base.resolve(path)).exists(); |
| 86 } |
| 87 |
| 88 abstract class TestContext extends ChainContext { |
| 89 final Uri vm; |
| 90 |
| 91 final Uri packages; |
| 92 |
| 93 final DartOptions options; |
| 94 |
| 95 final DartSdk dartSdk; |
| 96 |
| 97 TestContext(String sdk, this.vm, Uri packages, bool strongMode, this.dartSdk) |
| 98 : packages = packages, |
| 99 options = new DartOptions(strongMode: strongMode, sdk: sdk, |
| 100 packagePath: packages.toFilePath()); |
| 101 |
| 102 Future<DartLoader> createLoader() async { |
| 103 Repository repository = new Repository(); |
| 104 return new DartLoader(repository, options, await loadPackagesFile(packages), |
| 105 ignoreRedirectingFactories: false, dartSdk: dartSdk); |
| 106 } |
| 107 |
| 108 static Future<TestContext> create(Chain suite, |
| 109 Map<String, String> environment, |
| 110 TestContextConstructor constructor) async { |
| 111 const String suggestion = |
| 112 "Try checking the value of environment variable 'DART_AOT_SDK', " |
| 113 "it should point to a patched SDK."; |
| 114 String sdk = await getEnvironmentVariable( |
| 115 "DART_AOT_SDK", Environment.directory, |
| 116 "Please define environment variable 'DART_AOT_SDK' to point to a " |
| 117 "patched SDK.", |
| 118 (String n) => "Couldn't locate '$n'. $suggestion"); |
| 119 Uri sdkUri = Uri.base.resolve("$sdk/"); |
| 120 const String asyncDart = "lib/async/async.dart"; |
| 121 if (!await fileExists(sdkUri, asyncDart)) { |
| 122 throw "Couldn't find '$asyncDart' in '$sdk'. $suggestion"; |
| 123 } |
| 124 const String asyncSources = "lib/async/async_sources.gypi"; |
| 125 if (await fileExists(sdkUri, asyncSources)) { |
| 126 throw "Found '$asyncSources' in '$sdk', so it isn't a patched SDK. " |
| 127 "$suggestion"; |
| 128 } |
| 129 |
| 130 String vmPath = await getEnvironmentVariable( |
| 131 "DART_AOT_VM", Environment.file, |
| 132 "Please define environment variable 'DART_AOT_VM' to point to a " |
| 133 "Dart VM that reads .dill files.", |
| 134 (String n) => "Couldn't locate '$n'. Please check the value of " |
| 135 "environment variable 'DART_AOT_VM', it should point to a " |
| 136 "Dart VM that reads .dill files."); |
| 137 Uri vm = Uri.base.resolve(vmPath); |
| 138 |
| 139 Uri packages = Uri.base.resolve(".packages"); |
| 140 bool strongMode = false; |
| 141 bool updateExpectations = environment["updateExpectations"] != "false"; |
| 142 return constructor(suite, environment, sdk, vm, packages, strongMode, |
| 143 createDartSdk(sdk, strongMode: strongMode), updateExpectations); |
| 144 } |
| 145 } |
| 146 |
| 147 enum Environment { |
| 148 directory, |
| 149 file, |
| 150 } |
| 151 |
| 152 Future<String> getEnvironmentVariable( |
| 153 String name, Environment kind, String undefined, notFound(String n)) async { |
| 154 String result = Platform.environment[name]; |
| 155 if (result == null) { |
| 156 throw undefined; |
| 157 } |
| 158 switch (kind) { |
| 159 case Environment.directory: |
| 160 if (!await new Directory(result).exists()) throw notFound(result); |
| 161 break; |
| 162 |
| 163 case Environment.file: |
| 164 if (!await new File(result).exists()) throw notFound(result); |
| 165 break; |
| 166 } |
| 167 return result; |
| 168 } |
| 169 |
| 170 class Kernel extends Step<TestDescription, Program, TestContext> { |
| 171 const Kernel(); |
| 172 |
| 173 String get name => "kernel"; |
| 174 |
| 175 Future<Result<Program>> run( |
| 176 TestDescription description, TestContext testContext) async { |
| 177 try { |
| 178 DartLoader loader = await testContext.createLoader(); |
| 179 Target target = getTarget( |
| 180 "vm", new TargetFlags(strongMode: testContext.options.strongMode)); |
| 181 Program program = |
| 182 loader.loadProgram(description.uri, target: target); |
| 183 for (var error in loader.errors) { |
| 184 return fail(program, "$error"); |
| 185 } |
| 186 target.transformProgram(program); |
| 187 return pass(program); |
| 188 } catch (e, s) { |
| 189 return crash(e, s); |
| 190 } |
| 191 } |
| 192 } |
| 193 |
| 194 |
| 195 class Print extends Step<Program, Program, dynamic> { |
| 196 const Print(); |
| 197 |
| 198 String get name => "print"; |
| 199 |
| 200 Future<Result<Program>> run(Program program, _) async { |
| 201 StringBuffer sb = new StringBuffer(); |
| 202 for (Library library in program.libraries) { |
| 203 Printer printer = new Printer(sb); |
| 204 if (library.importUri.scheme != "dart" && |
| 205 library.importUri.scheme != "package") { |
| 206 printer.writeLibraryFile(library); |
| 207 } |
| 208 } |
| 209 print("$sb"); |
| 210 return pass(program); |
| 211 } |
| 212 } |
| 213 |
| 214 class Verify extends Step<Program, Program, dynamic> { |
| 215 final bool fullCompile; |
| 216 |
| 217 const Verify(this.fullCompile); |
| 218 |
| 219 String get name => "verify"; |
| 220 |
| 221 Future<Result<Program>> run(Program program, TestContext testContext) async { |
| 222 try { |
| 223 program.accept(new VerifyingVisitor()..isOutline = !fullCompile); |
| 224 return pass(program); |
| 225 } catch (e, s) { |
| 226 return new Result<Program>( |
| 227 null, testContext.expectationSet["VerificationError"], e, s); |
| 228 } |
| 229 } |
| 230 } |
| 231 |
| 232 class MatchExpectation extends Step<Program, Program, dynamic> { |
| 233 final String suffix; |
| 234 |
| 235 // TODO(ahe): This is true by default which doesn't match well with the class |
| 236 // name. |
| 237 final bool updateExpectations; |
| 238 |
| 239 const MatchExpectation(this.suffix, {this.updateExpectations: true}); |
| 240 |
| 241 String get name => "match expectations"; |
| 242 |
| 243 Future<Result<Program>> run(Program program, _) async { |
| 244 Library library = program.libraries.firstWhere( |
| 245 (Library library) => library.importUri.scheme != "dart"); |
| 246 Uri uri = library.importUri; |
| 247 StringBuffer buffer = new StringBuffer(); |
| 248 new Printer(buffer).writeLibraryFile(library); |
| 249 |
| 250 File expectedFile = new File("${uri.toFilePath()}$suffix"); |
| 251 if (await expectedFile.exists()) { |
| 252 String expected = await expectedFile.readAsString(); |
| 253 if (expected.trim() != "$buffer".trim()) { |
| 254 if (!updateExpectations) { |
| 255 String diff = await runDiff(expectedFile.uri, "$buffer"); |
| 256 return fail(null, "$uri doesn't match ${expectedFile.uri}\n$diff"); |
| 257 } |
| 258 } else { |
| 259 return pass(program); |
| 260 } |
| 261 } |
| 262 if (updateExpectations) { |
| 263 await openWrite(expectedFile.uri, (IOSink sink) { |
| 264 sink.writeln("$buffer".trim()); |
| 265 }); |
| 266 return pass(program); |
| 267 } else { |
| 268 return fail(program, """ |
| 269 Please create file ${expectedFile.path} with this content: |
| 270 $buffer"""); |
| 271 } |
| 272 } |
| 273 } |
| 274 |
| 275 class WriteDill extends Step<Program, Uri, dynamic> { |
| 276 const WriteDill(); |
| 277 |
| 278 String get name => "write .dill"; |
| 279 |
| 280 Future<Result<Uri>> run(Program program, _) async { |
| 281 Directory tmp = await Directory.systemTemp.createTemp(); |
| 282 Uri uri = tmp.uri.resolve("generated.dill"); |
| 283 File generated = new File.fromUri(uri); |
| 284 IOSink sink = generated.openWrite(); |
| 285 try { |
| 286 new BinaryPrinter(sink).writeProgramFile(program); |
| 287 } catch (e, s) { |
| 288 return fail(uri, e, s); |
| 289 } finally { |
| 290 print("Wrote `${generated.path}`"); |
| 291 await sink.close(); |
| 292 } |
| 293 return pass(uri); |
| 294 } |
| 295 } |
| 296 |
| 297 class ReadDill extends Step<Uri, Uri, dynamic> { |
| 298 const ReadDill(); |
| 299 |
| 300 String get name => "read .dill"; |
| 301 |
| 302 Future<Result<Uri>> run(Uri uri, _) async { |
| 303 try { |
| 304 loadProgramFromBinary(uri.toFilePath()); |
| 305 } catch (e, s) { |
| 306 return fail(uri, e, s); |
| 307 } |
| 308 return pass(uri); |
| 309 } |
| 310 } |
| 311 |
| 312 class Copy extends Step<Program, Program, dynamic> { |
| 313 const Copy(); |
| 314 |
| 315 String get name => "copy program"; |
| 316 |
| 317 Future<Result<Program>> run(Program program, _) async { |
| 318 BytesCollector sink = new BytesCollector(); |
| 319 new BinaryPrinter(sink).writeProgramFile(program); |
| 320 Uint8List bytes = sink.collect(); |
| 321 BinaryLoader loader = new BinaryLoader(new Repository()); |
| 322 return pass(new BinaryBuilder(loader, bytes).readProgramFile()); |
| 323 } |
| 324 } |
| 325 |
| 326 class Run extends Step<Uri, int, TestContext> { |
| 327 const Run(); |
| 328 |
| 329 String get name => "run"; |
| 330 |
| 331 bool get isAsync => true; |
| 332 |
| 333 bool get isRuntime => true; |
| 334 |
| 335 Future<Result<int>> run(Uri uri, TestContext context) async { |
| 336 File generated = new File.fromUri(uri); |
| 337 StdioProcess process; |
| 338 try { |
| 339 process = await StdioProcess.run( |
| 340 context.vm.toFilePath(), [generated.path, "Hello, World!"]); |
| 341 print(process.output); |
| 342 } finally { |
| 343 generated.parent.delete(recursive: true); |
| 344 } |
| 345 return process.toResult(); |
| 346 } |
| 347 } |
| 348 |
| 349 class BytesCollector implements Sink<List<int>> { |
| 350 final List<List<int>> lists = <List<int>>[]; |
| 351 |
| 352 int length = 0; |
| 353 |
| 354 void add(List<int> data) { |
| 355 lists.add(data); |
| 356 length += data.length; |
| 357 } |
| 358 |
| 359 Uint8List collect() { |
| 360 Uint8List result = new Uint8List(length); |
| 361 int offset = 0; |
| 362 for (List<int> list in lists) { |
| 363 result.setRange(offset, offset += list.length, list); |
| 364 } |
| 365 lists.clear(); |
| 366 length = 0; |
| 367 return result; |
| 368 } |
| 369 |
| 370 void close() {} |
| 371 } |
| 372 |
| 373 Future<String> runDiff(Uri expected, String actual) async { |
| 374 // TODO(ahe): Implement this for Windows. |
| 375 StdioProcess process = await StdioProcess.run( |
| 376 "diff", <String>["-u", expected.toFilePath(), "-"], input: actual); |
| 377 return process.output; |
| 378 } |
| 379 |
| 380 Future openWrite(Uri uri, f(IOSink sink)) async { |
| 381 IOSink sink = new File.fromUri(uri).openWrite(); |
| 382 try { |
| 383 await f(sink); |
| 384 } finally { |
| 385 await sink.close(); |
| 386 } |
| 387 print("Wrote $uri"); |
| 388 } |
| OLD | NEW |