fbf331e0dd
Change-Id: I42b4a44fd6a2197e499e8623274b3cd1a4b5556f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394003 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
211 lines
7.2 KiB
Dart
211 lines
7.2 KiB
Dart
// Copyright (c) 2023, 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 script generates a test package with a specified number of libraries,
|
|
/// classes, methods, and doc comment references, in order to test analyzer's
|
|
/// performance, scalability, and stability characteristics.
|
|
///
|
|
/// Call with `--help` to see all of the args.
|
|
library;
|
|
|
|
import 'dart:io';
|
|
import 'dart:math';
|
|
|
|
import 'package:args/args.dart';
|
|
import 'package:test_descriptor/test_descriptor.dart' as d;
|
|
|
|
void main(List<String> args) async {
|
|
// TODO(srawlins): Support multiple packages which depend on each other, in a
|
|
// DAG similar to the import graph.
|
|
var argParser =
|
|
ArgParser()
|
|
..addOption(
|
|
'library-count',
|
|
defaultsTo: '1',
|
|
help: 'the number of libraries',
|
|
)
|
|
..addOption(
|
|
'class-count',
|
|
defaultsTo: '1',
|
|
help: 'the number of classes per library',
|
|
)
|
|
..addOption(
|
|
'method-count',
|
|
defaultsTo: '1',
|
|
help: 'the number of methods per class',
|
|
)
|
|
..addOption(
|
|
'parameter-count',
|
|
defaultsTo: '1',
|
|
help: 'the number of parameters per method',
|
|
)
|
|
..addFlag('use-barrel-file', help: 'Whether to add a barrel import')
|
|
..addFlag(
|
|
'use-json-serializable',
|
|
help: 'Whether to declare @JsonSerializable classes',
|
|
);
|
|
var argResults = argParser.parse(args);
|
|
var libraryCount = int.parse(argResults['library-count'] as String);
|
|
var classCount = int.parse(argResults['class-count'] as String);
|
|
var methodCount = int.parse(argResults['method-count'] as String);
|
|
var parameterCount = int.parse(argResults['parameter-count'] as String);
|
|
var useBarrelFile = argResults['use-barrel-file'] as bool;
|
|
var useJsonSerializable = argResults['use-json-serializable'] as bool;
|
|
var testDataDir = Directory('test_data')..createSync();
|
|
var libFiles = <d.Descriptor>[];
|
|
var classCounter = 1;
|
|
var methodCounter = 1;
|
|
var middleImportIndex = libraryCount ~/ 2;
|
|
// We need a global index for the names of top-level variables, to avoid
|
|
// ambiguous elements from imports.
|
|
var topLevelVariableIndex = 1;
|
|
for (var lIndex = 1; lIndex <= libraryCount; lIndex++) {
|
|
var libraryName = 'lib$lIndex'.padLeft(3, '0');
|
|
// Each library has an index, starting at 1. The libraries depend on each
|
|
// other in tiers. The "tier" of a library is the base-2 logarithm of its
|
|
// index. Libraries in higher tiers depend on libraries in lower tiers.
|
|
// Libraries in higher tiers depend on more libraries than those in lower
|
|
// tiers.
|
|
//
|
|
// In a package with 10 libraries, we have the following tiers and
|
|
// dependencies:
|
|
// * T0: lib1 - no imports
|
|
// * T1: lib2 - imports lib1
|
|
// * T2: lib3, lib4 - each imports two libraries from T0, T1
|
|
// * T3: lib5, lib6, lib7, lib8 - each imports three libraries from T0, T1,
|
|
// and T2
|
|
// * T4: lib9, lib10 - each imports four libraries from T0, T1, T2, T3
|
|
//
|
|
// In a package with 1000 libraries, there are 11 tiers, and libraries in
|
|
// the last have 10 imports each.
|
|
// TODO(srawlins): Make the "connectedness" of the import graph
|
|
// configurable.
|
|
var importGraphTier = (log(lIndex) / ln2).ceil();
|
|
var importIndexStep =
|
|
importGraphTier == 0 ? -1 : (lIndex - 1) ~/ importGraphTier;
|
|
var content = StringBuffer();
|
|
if (useJsonSerializable) {
|
|
content.writeln("import 'package:json_annotation/json_annotation.dart';");
|
|
}
|
|
// Add imports in a library above tier 0.
|
|
if (importGraphTier > 0) {
|
|
if (useBarrelFile && lIndex > middleImportIndex) {
|
|
content.writeln(import(testPackageLibUri('barrel.dart')));
|
|
}
|
|
for (var tierIndex = 1; tierIndex <= importGraphTier; tierIndex++) {
|
|
var importIndex = tierIndex * importIndexStep;
|
|
if (useBarrelFile) {
|
|
if (lIndex <= middleImportIndex || importIndex > middleImportIndex) {
|
|
content.writeln(import(testPackageLibUri('lib$importIndex.dart')));
|
|
}
|
|
} else {
|
|
content.writeln(import(testPackageLibUri('lib$importIndex.dart')));
|
|
}
|
|
}
|
|
content.writeln();
|
|
}
|
|
|
|
if (useJsonSerializable) {
|
|
content.writeln("part '$libraryName.g.dart';");
|
|
content.writeln();
|
|
}
|
|
|
|
// Add top-level variables above tier 0.
|
|
if (importGraphTier > 0) {
|
|
for (var tierIndex = 1; tierIndex <= importGraphTier; tierIndex++) {
|
|
var importIndex = tierIndex * importIndexStep;
|
|
// We instantiate a class which is guaranteed to be found in
|
|
// `lib$importIndex.dart`.
|
|
var classReferenceIndex = classCount * importIndex;
|
|
content.writeln(
|
|
'var x$topLevelVariableIndex = C$classReferenceIndex();',
|
|
);
|
|
topLevelVariableIndex++;
|
|
}
|
|
content.writeln();
|
|
}
|
|
|
|
for (var cIndex = 1; cIndex <= classCount; cIndex++) {
|
|
content.writeln('/// Doc comment.');
|
|
if (useJsonSerializable) {
|
|
content.writeln('@JsonSerializable()');
|
|
}
|
|
content.writeln('class C$classCounter {');
|
|
if (useJsonSerializable) {
|
|
content.writeln(' C$classCounter();');
|
|
content.writeln(
|
|
' factory C$classCounter.fromJson(Map<String, dynamic> json) => '
|
|
'_\$C${classCounter}FromJson(json);',
|
|
);
|
|
content.writeln(
|
|
' Map<String, dynamic> toJson() => '
|
|
'_\$C${classCounter}ToJson(this);',
|
|
);
|
|
}
|
|
for (var mIndex = 1; mIndex <= methodCount; mIndex++) {
|
|
content.write(' void m$methodCounter(');
|
|
content.write(
|
|
List.generate(parameterCount, (pIndex) => 'int p$pIndex').join(', '),
|
|
);
|
|
content.writeln(') {}');
|
|
methodCounter++;
|
|
}
|
|
content.writeln('}');
|
|
classCounter++;
|
|
}
|
|
libFiles.add(d.file('$libraryName.dart', content.toString()));
|
|
}
|
|
|
|
if (useBarrelFile) {
|
|
// Write the barrel file, which exports the first half of the libraries.
|
|
var content = StringBuffer();
|
|
for (var j = 1; j <= middleImportIndex; j++) {
|
|
content.writeln(export(testPackageLibUri('lib$j.dart')));
|
|
}
|
|
libFiles.add(d.file('barrel.dart', content.toString()));
|
|
}
|
|
|
|
var testPackageDir = d.dir('test_package', [
|
|
d.file('pubspec.yaml', pubspec(useJsonSerializable: useJsonSerializable)),
|
|
d.dir('lib', libFiles),
|
|
]);
|
|
await testPackageDir.create(testDataDir.path);
|
|
}
|
|
|
|
String export(String uri) => "export '$uri';";
|
|
|
|
String import(String uri) => "import '$uri';";
|
|
|
|
/// Returns the text of a 'pubspec.yaml' file.
|
|
///
|
|
/// With [useJsonSerializable], several packages are added to the dependencies
|
|
/// in order to test using build_runner.
|
|
String pubspec({required bool useJsonSerializable}) {
|
|
var dependencies =
|
|
useJsonSerializable
|
|
? '''
|
|
dependencies:
|
|
json_annotation: any
|
|
json_serializable: any
|
|
'''
|
|
: '';
|
|
var devDependencies =
|
|
useJsonSerializable
|
|
? '''
|
|
dev_dependencies:
|
|
build_runner: any
|
|
'''
|
|
: '';
|
|
return '''
|
|
name: test_package
|
|
version: 0.0.1
|
|
environment:
|
|
sdk: '>=2.12.0 <3.0.0'
|
|
$dependencies
|
|
$devDependencies
|
|
''';
|
|
}
|
|
|
|
String testPackageLibUri(String path) => 'package:test_package/$path';
|