| // Copyright (c) 2025, 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. |
| |
| /// Returns the content of a file containing [classCount] classes. |
| /// |
| /// If [exports] are provided, the file will contain one export directive for |
| /// each element. The elements should be the text of the URI without enclosing |
| /// quotes. |
| /// |
| /// If [imports] are provided, the file will contain one import directive for |
| /// each element. The elements should be the text of the URI without enclosing |
| /// quotes. |
| /// |
| /// If a [libraryName] is provided, the file will contain a library directive |
| /// with that name. There's no way to generate a library directive without a |
| /// name. |
| /// |
| /// If a [partOf] is provided, the file will contain a part-of directive. If the |
| /// [partOf] ends with `.dart` then it is assumed to be a URI and will be |
| /// enclosed in quotes. If not, it's assumed to be a library name and is written |
| /// as-is. |
| /// |
| /// If [parts] are provided, the file will contain one part directive for each |
| /// element. The elements should be the text of the URI without enclosing |
| /// quotes. |
| String createFileContent({ |
| int classCount = CodeGenerator.classCount, |
| List<String> exports = const [], |
| List<String> imports = const [], |
| String? libraryName, |
| String? partOf, |
| List<String> parts = const [], |
| }) { |
| var generator = CodeGenerator(); |
| generator.writeClasses( |
| classCount: classCount, |
| exports: exports, |
| imports: imports, |
| libraryName: libraryName, |
| partOf: partOf, |
| parts: parts, |
| ); |
| return generator.code; |
| } |
| |
| /// A class used to generate code for a test. |
| class CodeGenerator { |
| /// The number of classes in each test file. |
| static const int classCount = 40; |
| |
| /// The buffer used to collect the code being generated. |
| final StringBuffer buffer = StringBuffer(); |
| |
| /// Whether a blank line should be added before the next top-level declaration |
| /// is written. |
| bool needsSeparator = false; |
| |
| /// The code that was generated. |
| String get code => buffer.toString(); |
| |
| /// Generate a class with the given [name]. |
| /// |
| /// The [methodCount] specifies the number of methods that should be defined |
| /// by the class. |
| void writeClass({required String name, int methodCount = 100}) { |
| if (needsSeparator) { |
| buffer.writeln(); |
| } |
| buffer.writeln('class $name {'); |
| var needsLineBeforeMember = false; |
| for (var i = 0; i < methodCount; i++) { |
| if (needsLineBeforeMember) { |
| buffer.writeln(); |
| } |
| writeMethod(name: 'm$i'); |
| needsLineBeforeMember = true; |
| } |
| buffer.writeln('}'); |
| needsSeparator = true; |
| } |
| |
| /// Generate [classCount] classes with synthetic names. |
| /// |
| /// The file will have one export for each of the unquoted URI's in [exports]. |
| /// |
| /// The file will have one part directive for each of the unquoted URI's in [parts]. |
| /// |
| /// The file will have one import for each of the unquoted URI's in [imports]. |
| /// For example, to import `dart:async`, include `'dart:async'` in the list. |
| void writeClasses({ |
| required int classCount, |
| List<String> exports = const [], |
| List<String> imports = const [], |
| String? libraryName, |
| String? partOf, |
| List<String> parts = const [], |
| }) { |
| assert( |
| libraryName == null || partOf == null, |
| 'Cannot specify both a library name and a part of name', |
| ); |
| if (libraryName != null) { |
| buffer.writeln('library $libraryName;'); |
| buffer.writeln(); |
| } |
| if (partOf != null) { |
| if (partOf.endsWith('.dart')) { |
| buffer.writeln("part of '$partOf';"); |
| } else { |
| buffer.writeln('part of $partOf;'); |
| } |
| buffer.writeln(); |
| } |
| for (var import in imports) { |
| buffer.writeln("import '$import';"); |
| } |
| if (imports.isNotEmpty) { |
| buffer.writeln(); |
| } |
| for (var export in exports) { |
| buffer.writeln("export '$export';"); |
| } |
| if (exports.isNotEmpty) { |
| buffer.writeln(); |
| } |
| for (var part in parts) { |
| buffer.writeln("part '$part';"); |
| } |
| if (parts.isNotEmpty) { |
| buffer.writeln(); |
| } |
| for (int i = 0; i < classCount; i++) { |
| writeClass(name: 'C$i'); |
| } |
| } |
| |
| /// Generate a method with the given [name]. |
| void writeMethod({required String name}) { |
| buffer.write(''' |
| void $name(StringBuffer buffer, Map<String, Object> map) { |
| buffer.write('{'); |
| for (var entry in map.entries) { |
| buffer.write(entry.key); |
| buffer.write(': '); |
| var value = entry.value; |
| if (value is Map<String, Object>) { |
| $name(buffer, value); |
| buffer.writeln(); |
| } else { |
| buffer.write(value); |
| } |
| buffer.writeln(entry.value); |
| } |
| buffer.write('}'); |
| } |
| '''); |
| } |
| } |