| // 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<String> seen = new Set<String>(); |
| |
| main(List<String> 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<String>.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<String> run = await executeAndGetStdOut( |
| Platform.executable, <String>[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<Node>? 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<List<String>> executeAndGetStdOut( |
| String executable, List<String> arguments) async { |
| var process = await Process.start(executable, arguments); |
| Future<List<String>> 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<List<String>> combine( |
| Future<List<String>> a, Future<List<String>> b) async { |
| List<String> aDone = await a; |
| List<String> bDone = await b; |
| List<String> result = new List.from(aDone); |
| result.addAll(bDone); |
| return result; |
| } |
| |
| class Tree { |
| String name; |
| bool async = false; |
| List<Tree> children = <Tree>[]; |
| } |