blob: a9698ed9a9bab51bf1b1bf795f5a23140f2b7c9c [file] [log] [blame]
// 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('}');
}
''');
}
}