// Copyright (c) 2018, 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. // See http://dartbug.com/33660 for details about what inspired this generator. import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math'; Random random = new Random(); int totalNodes = 0; Set seen = new Set(); main(List args) async { int maxSize; if (args.length > 0) maxSize = int.tryParse(args[0]); maxSize ??= 5; for (int i = 0; i < 2500; i++) { stdout.write("."); if (i % 75 == 74) stdout.write("\n"); totalNodes = 0; Tree tree = fuzz(1 + random.nextInt(5), 1 + random.nextInt(8), maxSize); String expected = new List.generate(totalNodes, (i) => "${i + 1}").join(" "); String asyncProgram = printProgram(tree, true, false, true, '"$expected"'); if (seen.add(asyncProgram)) { File asyncFile = new File('${maxSize}_${i}.dart') ..writeAsStringSync(asyncProgram); List run = await executeAndGetStdOut( Platform.executable, [asyncFile.path]); if (expected == run[0]) { asyncFile.deleteSync(); } else { print("\n${asyncFile.path} was not as expected!"); String name = "async_nested_${maxSize}_${i}_test.dart"; asyncFile.renameSync(name); print(" -> Created $name"); print(" (you might want to run 'dart format $name')."); } } } print(" done "); } Tree fuzz(int asyncLikely, int childrenLikely, int maxSize) { // asyncLikely = 3; // childrenLikely = 5; totalNodes++; Tree result = new Tree(); result.name = "$totalNodes"; result.async = random.nextInt(10) < asyncLikely; while (random.nextInt(10) < childrenLikely) { if (totalNodes >= maxSize) return result; result.children .add(fuzz(1 + random.nextInt(5), 1 + random.nextInt(8), maxSize)); } return result; } String printProgram(Tree tree, bool emitAsync, bool emitPrintOnCreate, bool printSimple, String expected) { StringBuffer lines = new StringBuffer(); lines.write(""" // Copyright (c) 2018, 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. // This has been automatically generated by script // "async_nested_test_generator.dart". import 'dart:async'; void main() async { """); printNode(Tree node) { if (node.async && emitAsync) { lines.write("await new Future.value("); } lines.writeln("new Node('${node.name}', ["); for (Tree child in node.children) { printNode(child); lines.write(","); } lines.writeln("])"); if (node.async && emitAsync) { lines.write(")"); } } if (expected != null) { lines.writeln('String expected = $expected;'); } lines.write("Node node = "); printNode(tree); lines.writeln(";"); if (printSimple) { lines.writeln("String actual = node.toSimpleString();"); } else { lines.writeln("String actual = node.toString();"); } lines.writeln("print(actual);"); if (expected != null) { lines.writeln(r"""if (actual != expected) { throw "Expected '$expected' but got '$actual'"; }"""); } lines.writeln(r""" } class Node { final List? nested; final String name; Node(this.name, [this.nested]) { """); if (emitPrintOnCreate) { lines.writeln(r'print("Creating $name");'); } lines.write(r""" } String toString() => '<$name:[${nested?.join(', ')}]>'; toSimpleString() { var tmp = nested?.map((child) => child.toSimpleString()); return '$name ${tmp?.join(' ')}'.trim(); } } """); return lines.toString(); } Future> executeAndGetStdOut( String executable, List arguments) async { var process = await Process.start(executable, arguments); Future> result = combine( process.stdout .transform(utf8.decoder) .transform(const LineSplitter()) .toList(), process.stderr .transform(utf8.decoder) .transform(const LineSplitter()) .toList()); int exitCode = await process.exitCode; (await result).add("Exit code: $exitCode"); return result; } Future> combine( Future> a, Future> b) async { List aDone = await a; List bDone = await b; List result = new List.from(aDone); result.addAll(bDone); return result; } class Tree { String name; bool async = false; List children = []; }