Chromium Code Reviews| 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("DART_AOT_VM", Environment.file , | |
|
Johnni Winther
2017/01/16 08:43:12
Long line.
ahe
2017/01/16 09:03:03
Done.
| |
| 131 "Please define environment variable 'DART_AOT_VM' to point to a " | |
| 132 "Dart VM that reads .dill files.", | |
| 133 (String n) => "Couldn't locate '$n'. Please check the value of " | |
| 134 "environment variable 'DART_AOT_VM', it should point to a " | |
| 135 "Dart VM that reads .dill files."); | |
| 136 Uri vm = Uri.base.resolve(vmPath); | |
| 137 | |
| 138 Uri packages = Uri.base.resolve(".packages"); | |
| 139 bool strongMode = false; | |
| 140 bool updateExpectations = environment["updateExpectations"] != "false"; | |
| 141 return constructor(suite, environment, sdk, vm, packages, strongMode, | |
| 142 createDartSdk(sdk, strongMode: strongMode), updateExpectations); | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 enum Environment { | |
| 147 directory, | |
| 148 file, | |
| 149 } | |
| 150 | |
| 151 Future<String> getEnvironmentVariable( | |
| 152 String name, Environment kind, String undefined, notFound(String n)) async { | |
| 153 String result = Platform.environment[name]; | |
| 154 if (result == null) { | |
| 155 throw undefined; | |
| 156 } | |
| 157 switch (kind) { | |
| 158 case Environment.directory: | |
| 159 if (!await new Directory(result).exists()) throw notFound(result); | |
| 160 break; | |
| 161 | |
| 162 case Environment.file: | |
| 163 if (!await new File(result).exists()) throw notFound(result); | |
| 164 break; | |
| 165 } | |
| 166 return result; | |
| 167 } | |
| 168 | |
| 169 class Kernel extends Step<TestDescription, Program, TestContext> { | |
| 170 const Kernel(); | |
| 171 | |
| 172 String get name => "kernel"; | |
| 173 | |
| 174 Future<Result<Program>> run( | |
| 175 TestDescription description, TestContext testContext) async { | |
| 176 try { | |
| 177 DartLoader loader = await testContext.createLoader(); | |
| 178 Target target = getTarget( | |
| 179 "vm", new TargetFlags(strongMode: testContext.options.strongMode)); | |
| 180 Program program = | |
| 181 loader.loadProgram(description.uri, target: target); | |
| 182 for (var error in loader.errors) { | |
| 183 return fail(program, "$error"); | |
| 184 } | |
| 185 target.transformProgram(program); | |
| 186 return pass(program); | |
| 187 } catch (e, s) { | |
| 188 return crash(e, s); | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 | |
| 194 class Print extends Step<Program, Program, dynamic> { | |
| 195 const Print(); | |
| 196 | |
| 197 String get name => "print"; | |
| 198 | |
| 199 Future<Result<Program>> run(Program program, _) async { | |
| 200 StringBuffer sb = new StringBuffer(); | |
| 201 for (Library library in program.libraries) { | |
| 202 Printer printer = new Printer(sb); | |
| 203 if (library.importUri.scheme != "dart" && | |
| 204 library.importUri.scheme != "package") { | |
| 205 printer.writeLibraryFile(library); | |
| 206 } | |
| 207 } | |
| 208 print("$sb"); | |
| 209 return pass(program); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 class Verify extends Step<Program, Program, dynamic> { | |
| 214 final bool fullCompile; | |
| 215 | |
| 216 const Verify(this.fullCompile); | |
| 217 | |
| 218 String get name => "verify"; | |
| 219 | |
| 220 Future<Result<Program>> run(Program program, TestContext testContext) async { | |
| 221 try { | |
| 222 program.accept(new VerifyingVisitor()..isOutline = !fullCompile); | |
| 223 return pass(program); | |
| 224 } catch (e, s) { | |
| 225 return new Result<Program>( | |
| 226 null, testContext.expectationSet["VerificationError"], e, s); | |
| 227 } | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 class MatchExpectation extends Step<Program, Program, dynamic> { | |
| 232 final String suffix; | |
| 233 | |
| 234 final bool updateExpectations; | |
| 235 | |
| 236 const MatchExpectation(this.suffix, {this.updateExpectations: true}); | |
|
Johnni Winther
2017/01/16 08:43:12
Weird default value given the class name.
ahe
2017/01/16 09:03:03
Good point, I've added a todo.
| |
| 237 | |
| 238 String get name => "match expectations"; | |
| 239 | |
| 240 Future<Result<Program>> run(Program program, _) async { | |
| 241 Library library = program.libraries.firstWhere( | |
| 242 (Library library) =>library.importUri.scheme != "dart"); | |
|
Johnni Winther
2017/01/16 08:43:12
`=>library` -> `=> library`
ahe
2017/01/16 09:03:03
Done.
| |
| 243 Uri uri = library.importUri; | |
| 244 StringBuffer buffer = new StringBuffer(); | |
| 245 new Printer(buffer).writeLibraryFile(library); | |
| 246 | |
| 247 File expectedFile = new File("${uri.toFilePath()}$suffix"); | |
| 248 if (await expectedFile.exists()) { | |
| 249 String expected = await expectedFile.readAsString(); | |
| 250 if (expected.trim() != "$buffer".trim()) { | |
| 251 if (!updateExpectations) { | |
| 252 String diff = await runDiff(expectedFile.uri, "$buffer"); | |
| 253 return fail(null, "$uri doesn't match ${expectedFile.uri}\n$diff"); | |
| 254 } | |
| 255 } else { | |
| 256 return pass(program); | |
| 257 } | |
| 258 } | |
| 259 if (updateExpectations) { | |
| 260 await openWrite(expectedFile.uri, (IOSink sink) { | |
| 261 sink.writeln("$buffer".trim()); | |
| 262 }); | |
| 263 return pass(program); | |
| 264 } else { | |
| 265 return fail(program, """ | |
| 266 Please create file ${expectedFile.path} with this content: | |
| 267 $buffer"""); | |
| 268 } | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 class WriteDill extends Step<Program, Uri, dynamic> { | |
| 273 const WriteDill(); | |
| 274 | |
| 275 String get name => "write .dill"; | |
| 276 | |
| 277 Future<Result<Uri>> run(Program program, _) async { | |
| 278 Directory tmp = await Directory.systemTemp.createTemp(); | |
| 279 Uri uri = tmp.uri.resolve("generated.dill"); | |
| 280 File generated = new File.fromUri(uri); | |
| 281 IOSink sink = generated.openWrite(); | |
| 282 try { | |
| 283 new BinaryPrinter(sink).writeProgramFile(program); | |
| 284 } catch (e, s) { | |
| 285 return fail(uri, e, s); | |
| 286 } finally { | |
| 287 print("Wrote `${generated.path}`"); | |
| 288 await sink.close(); | |
| 289 } | |
| 290 return pass(uri); | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 class ReadDill extends Step<Uri, Uri, dynamic> { | |
| 295 const ReadDill(); | |
| 296 | |
| 297 String get name => "read .dill"; | |
| 298 | |
| 299 Future<Result<Uri>> run(Uri uri, _) async { | |
| 300 try { | |
| 301 loadProgramFromBinary(uri.toFilePath()); | |
| 302 } catch (e, s) { | |
| 303 return fail(uri, e, s); | |
| 304 } | |
| 305 return pass(uri); | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 class Copy extends Step<Program, Program, dynamic> { | |
| 310 const Copy(); | |
| 311 | |
| 312 String get name => "copy program"; | |
| 313 | |
| 314 Future<Result<Program>> run(Program program, _) async { | |
| 315 BytesCollector sink = new BytesCollector(); | |
| 316 new BinaryPrinter(sink).writeProgramFile(program); | |
| 317 Uint8List bytes = sink.collect(); | |
| 318 BinaryLoader loader = new BinaryLoader(new Repository()); | |
| 319 return pass(new BinaryBuilder(loader, bytes).readProgramFile()); | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 class Run extends Step<Uri, int, TestContext> { | |
| 324 const Run(); | |
| 325 | |
| 326 String get name => "run"; | |
| 327 | |
| 328 bool get isAsync => true; | |
| 329 | |
| 330 bool get isRuntime => true; | |
| 331 | |
| 332 Future<Result<int>> run(Uri uri, TestContext context) async { | |
| 333 File generated = new File.fromUri(uri); | |
| 334 StdioProcess process; | |
| 335 try { | |
| 336 process = await StdioProcess.run( | |
| 337 context.vm.toFilePath(), [generated.path, "Hello, World!"]); | |
| 338 print(process.output); | |
| 339 } finally { | |
| 340 generated.parent.delete(recursive: true); | |
| 341 } | |
| 342 return process.toResult(); | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 class BytesCollector implements Sink<List<int>> { | |
| 347 final List<List<int>> lists = <List<int>>[]; | |
| 348 | |
| 349 int length = 0; | |
| 350 | |
| 351 void add(List<int> data) { | |
| 352 lists.add(data); | |
| 353 length += data.length; | |
| 354 } | |
| 355 | |
| 356 Uint8List collect() { | |
| 357 Uint8List result = new Uint8List(length); | |
| 358 int offset = 0; | |
| 359 for (List<int> list in lists) { | |
| 360 result.setRange(offset, offset += list.length, list); | |
| 361 } | |
| 362 lists.clear(); | |
| 363 length = 0; | |
| 364 return result; | |
| 365 } | |
| 366 | |
| 367 void close() {} | |
| 368 } | |
| 369 | |
| 370 Future<String> runDiff(Uri expected, String actual) async { | |
| 371 StdioProcess process = await StdioProcess.run( | |
| 372 "diff", <String>["-u", expected.toFilePath(), "-"], input: actual); | |
|
Johnni Winther
2017/01/16 08:43:12
This probably doesn't work on Windows.
ahe
2017/01/16 09:03:03
Added todo.
| |
| 373 return process.output; | |
| 374 } | |
| 375 | |
| 376 Future openWrite(Uri uri, f(IOSink sink)) async { | |
| 377 IOSink sink = new File.fromUri(uri).openWrite(); | |
| 378 try { | |
| 379 await f(sink); | |
| 380 } finally { | |
| 381 await sink.close(); | |
| 382 } | |
| 383 print("Wrote $uri"); | |
| 384 } | |
| OLD | NEW |