
This auto-formats all *.dart files in the repository outside of the `engine` subdirectory and enforces that these files stay formatted with a presubmit check. **Reviewers:** Please carefully review all the commits except for the one titled "formatted". The "formatted" commit was auto-generated by running `dev/tools/format.sh -a -f`. The other commits were hand-crafted to prepare the repo for the formatting change. I recommend reviewing the commits one-by-one via the "Commits" tab and avoiding Github's "Files changed" tab as it will likely slow down your browser because of the size of this PR. --------- Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
311 lines
8.6 KiB
Dart
311 lines
8.6 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
import 'package:snippets/snippets.dart';
|
|
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
|
|
|
|
import 'filesystem_resource_provider.dart';
|
|
|
|
class FakeFlutterInformation extends FlutterInformation {
|
|
FakeFlutterInformation(this.flutterRoot);
|
|
|
|
final Directory flutterRoot;
|
|
|
|
@override
|
|
Directory getFlutterRoot() {
|
|
return flutterRoot;
|
|
}
|
|
|
|
@override
|
|
Map<String, dynamic> getFlutterInformation() {
|
|
return <String, dynamic>{
|
|
'flutterRoot': flutterRoot,
|
|
'frameworkVersion': Version(2, 10, 0),
|
|
'dartSdkVersion': Version(2, 12, 1),
|
|
};
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
group('Parser', () {
|
|
late MemoryFileSystem memoryFileSystem = MemoryFileSystem();
|
|
late FlutterRepoSnippetConfiguration configuration;
|
|
late SnippetGenerator generator;
|
|
late Directory tmpDir;
|
|
late Directory flutterRoot;
|
|
|
|
void writeSkeleton(String type) {
|
|
switch (type) {
|
|
case 'dartpad':
|
|
configuration.getHtmlSkeletonFile('dartpad').writeAsStringSync('''
|
|
<div>HTML Bits (DartPad-style)</div>
|
|
<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id={{id}}&sample_channel={{channel}}"></iframe>
|
|
<div>More HTML Bits</div>
|
|
''');
|
|
case 'sample':
|
|
case 'snippet':
|
|
configuration.getHtmlSkeletonFile(type).writeAsStringSync('''
|
|
<div>HTML Bits</div>
|
|
{{description}}
|
|
<pre>{{code}}</pre>
|
|
<pre>{{app}}</pre>
|
|
<div>More HTML Bits</div>
|
|
''');
|
|
}
|
|
}
|
|
|
|
setUp(() {
|
|
// Create a new filesystem.
|
|
memoryFileSystem = MemoryFileSystem();
|
|
tmpDir = memoryFileSystem.systemTempDirectory.createTempSync('flutter_snippets_test.');
|
|
flutterRoot = memoryFileSystem.directory(path.join(tmpDir.absolute.path, 'flutter'));
|
|
configuration = FlutterRepoSnippetConfiguration(
|
|
flutterRoot: flutterRoot,
|
|
filesystem: memoryFileSystem,
|
|
);
|
|
configuration.skeletonsDirectory.createSync(recursive: true);
|
|
<String>['dartpad', 'sample', 'snippet'].forEach(writeSkeleton);
|
|
FlutterInformation.instance = FakeFlutterInformation(flutterRoot);
|
|
generator = SnippetGenerator(
|
|
configuration: configuration,
|
|
filesystem: memoryFileSystem,
|
|
flutterRoot: configuration.skeletonsDirectory.parent,
|
|
);
|
|
});
|
|
|
|
test('parses from comments', () async {
|
|
final File inputFile = _createSnippetSourceFile(tmpDir, memoryFileSystem);
|
|
final Iterable<SourceElement> elements = getFileElements(
|
|
inputFile,
|
|
resourceProvider: FileSystemResourceProvider(memoryFileSystem),
|
|
);
|
|
expect(elements, isNotEmpty);
|
|
final SnippetDartdocParser sampleParser = SnippetDartdocParser(memoryFileSystem);
|
|
sampleParser.parseFromComments(elements);
|
|
sampleParser.parseAndAddAssumptions(elements, inputFile);
|
|
expect(elements.length, equals(7));
|
|
int sampleCount = 0;
|
|
for (final SourceElement element in elements) {
|
|
expect(element.samples.length, greaterThanOrEqualTo(1));
|
|
sampleCount += element.samples.length;
|
|
final String code = generator.generateCode(element.samples.first);
|
|
expect(code, contains('// Description'));
|
|
expect(
|
|
code,
|
|
contains(
|
|
RegExp('''^String elementName = '${element.elementName}';\$''', multiLine: true),
|
|
),
|
|
);
|
|
final String html = generator.generateHtml(element.samples.first);
|
|
expect(
|
|
html,
|
|
contains(
|
|
RegExp(
|
|
'''^<pre>String elementName = '${element.elementName}';.*\$''',
|
|
multiLine: true,
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
html,
|
|
contains(
|
|
'<div class="snippet-description">{@end-inject-html}Description{@inject-html}</div>\n',
|
|
),
|
|
);
|
|
}
|
|
expect(sampleCount, equals(8));
|
|
});
|
|
test('parses dartpad samples from linked file', () async {
|
|
final File inputFile = _createDartpadSourceFile(
|
|
tmpDir,
|
|
memoryFileSystem,
|
|
flutterRoot,
|
|
linked: true,
|
|
);
|
|
final Iterable<SourceElement> elements = getFileElements(
|
|
inputFile,
|
|
resourceProvider: FileSystemResourceProvider(memoryFileSystem),
|
|
);
|
|
expect(elements, isNotEmpty);
|
|
final SnippetDartdocParser sampleParser = SnippetDartdocParser(memoryFileSystem);
|
|
sampleParser.parseFromComments(elements);
|
|
expect(elements.length, equals(1));
|
|
int sampleCount = 0;
|
|
for (final SourceElement element in elements) {
|
|
expect(element.samples.length, greaterThanOrEqualTo(1));
|
|
sampleCount += element.samples.length;
|
|
final String code = generator.generateCode(element.samples.first, formatOutput: false);
|
|
expect(code, contains('// Description'));
|
|
expect(
|
|
code,
|
|
contains(RegExp('^void ${element.name}Sample\\(\\) \\{.*\$', multiLine: true)),
|
|
);
|
|
final String html = generator.generateHtml(element.samples.first);
|
|
expect(
|
|
html,
|
|
contains(
|
|
RegExp(
|
|
'''^<iframe class="snippet-dartpad" src="https://dartpad.dev/.*sample_id=${element.name}.0.*></iframe>.*\$''',
|
|
multiLine: true,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
expect(sampleCount, equals(1));
|
|
});
|
|
test('parses assumptions', () async {
|
|
final File inputFile = _createSnippetSourceFile(tmpDir, memoryFileSystem);
|
|
final SnippetDartdocParser sampleParser = SnippetDartdocParser(memoryFileSystem);
|
|
final List<SourceLine> assumptions = sampleParser.parseAssumptions(inputFile);
|
|
expect(assumptions.length, equals(1));
|
|
expect(assumptions.first.text, equals('int integer = 3;'));
|
|
});
|
|
});
|
|
}
|
|
|
|
File _createSnippetSourceFile(Directory tmpDir, FileSystem filesystem) {
|
|
return filesystem.file(path.join(tmpDir.absolute.path, 'snippet_in.dart'))
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync(r'''
|
|
// Copyright
|
|
|
|
// @dart = 2.12
|
|
|
|
import 'foo.dart';
|
|
|
|
// Examples can assume:
|
|
// int integer = 3;
|
|
|
|
/// Top level variable comment
|
|
///
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'topLevelVariable';
|
|
/// ```
|
|
/// {@end-tool}
|
|
int topLevelVariable = 4;
|
|
|
|
/// Top level function comment
|
|
///
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'topLevelFunction';
|
|
/// ```
|
|
/// {@end-tool}
|
|
int topLevelFunction() {
|
|
return integer;
|
|
}
|
|
|
|
/// Class comment
|
|
///
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'DocumentedClass';
|
|
/// ```
|
|
/// {@end-tool}
|
|
///
|
|
/// {@tool snippet}
|
|
/// Description2
|
|
/// ```dart
|
|
/// String elementName = 'DocumentedClass';
|
|
/// ```
|
|
/// {@end-tool}
|
|
class DocumentedClass {
|
|
/// Constructor comment
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'DocumentedClass';
|
|
/// ```
|
|
/// {@end-tool}
|
|
const DocumentedClass();
|
|
|
|
/// Named constructor comment
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'DocumentedClass.name';
|
|
/// ```
|
|
/// {@end-tool}
|
|
const DocumentedClass.name();
|
|
|
|
/// Member variable comment
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'DocumentedClass.intMember';
|
|
/// ```
|
|
/// {@end-tool}
|
|
int intMember;
|
|
|
|
/// Member comment
|
|
/// {@tool snippet}
|
|
/// Description
|
|
/// ```dart
|
|
/// String elementName = 'DocumentedClass.member';
|
|
/// ```
|
|
/// {@end-tool}
|
|
void member() {}
|
|
}
|
|
''');
|
|
}
|
|
|
|
File _createDartpadSourceFile(
|
|
Directory tmpDir,
|
|
FileSystem filesystem,
|
|
Directory flutterRoot, {
|
|
bool linked = false,
|
|
}) {
|
|
final File linkedFile =
|
|
filesystem.file(path.join(flutterRoot.absolute.path, 'linked_file.dart'))
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync('''
|
|
// Copyright
|
|
|
|
import 'foo.dart';
|
|
|
|
// Description
|
|
|
|
void DocumentedClassSample() {
|
|
String elementName = 'DocumentedClass';
|
|
}
|
|
''');
|
|
|
|
final String source =
|
|
linked
|
|
? '''
|
|
/// ** See code in ${path.relative(linkedFile.path, from: flutterRoot.absolute.path)} **'''
|
|
: '''
|
|
/// ```dart
|
|
/// void DocumentedClassSample() {
|
|
/// String elementName = 'DocumentedClass';
|
|
/// }
|
|
/// ```''';
|
|
|
|
return filesystem.file(path.join(tmpDir.absolute.path, 'snippet_in.dart'))
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync('''
|
|
// Copyright
|
|
|
|
// @dart = 2.12
|
|
|
|
import 'foo.dart';
|
|
|
|
/// Class comment
|
|
///
|
|
/// {@tool dartpad --template=template}
|
|
/// Description
|
|
$source
|
|
/// {@end-tool}
|
|
class DocumentedClass {}
|
|
''');
|
|
}
|