1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:file/file.dart';
6import 'package:file/memory.dart';
7import 'package:path/path.dart' as path;
8import 'package:pub_semver/pub_semver.dart';
9import 'package:snippets/snippets.dart';
10import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
11
12import 'filesystem_resource_provider.dart';
13
14class FakeFlutterInformation extends FlutterInformation {
15 FakeFlutterInformation(this.flutterRoot);
16
17 final Directory flutterRoot;
18
19 @override
20 Directory getFlutterRoot() {
21 return flutterRoot;
22 }
23
24 @override
25 Map<String, dynamic> getFlutterInformation() {
26 return <String, dynamic>{
27 'flutterRoot': flutterRoot,
28 'frameworkVersion': Version(2, 10, 0),
29 'dartSdkVersion': Version(2, 12, 1),
30 };
31 }
32}
33
34void main() {
35 group('Parser', () {
36 late MemoryFileSystem memoryFileSystem = MemoryFileSystem();
37 late FlutterRepoSnippetConfiguration configuration;
38 late SnippetGenerator generator;
39 late Directory tmpDir;
40 late Directory flutterRoot;
41
42 void writeSkeleton(String type) {
43 switch (type) {
44 case 'dartpad':
45 configuration.getHtmlSkeletonFile('dartpad').writeAsStringSync('''
46<div>HTML Bits (DartPad-style)</div>
47<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id={{id}}&sample_channel={{channel}}">
48<div>More HTML Bits</div>
49''');
50 case 'sample':
51 case 'snippet':
52 configuration.getHtmlSkeletonFile(type).writeAsStringSync('''
53<div>HTML Bits</div>
54{{description}}
55<pre>{{code}}</pre>
56<pre>{{app}}</pre>
57<div>More HTML Bits</div>
58''');
59 }
60 }
61
62 setUp(() {
63 // Create a new filesystem.
64 memoryFileSystem = MemoryFileSystem();
65 tmpDir = memoryFileSystem.systemTempDirectory
66 .createTempSync('flutter_snippets_test.');
67 flutterRoot = memoryFileSystem
68 .directory(path.join(tmpDir.absolute.path, 'flutter'));
69 configuration = FlutterRepoSnippetConfiguration(
70 flutterRoot: flutterRoot, filesystem: memoryFileSystem);
71 configuration.skeletonsDirectory.createSync(recursive: true);
72 <String>['dartpad', 'sample', 'snippet'].forEach(writeSkeleton);
73 FlutterInformation.instance = FakeFlutterInformation(flutterRoot);
74 generator = SnippetGenerator(
75 configuration: configuration,
76 filesystem: memoryFileSystem,
77 flutterRoot: configuration.skeletonsDirectory.parent);
78 });
79
80 test('parses from comments', () async {
81 final File inputFile = _createSnippetSourceFile(tmpDir, memoryFileSystem);
82 final Iterable<SourceElement> elements = getFileElements(inputFile,
83 resourceProvider: FileSystemResourceProvider(memoryFileSystem));
84 expect(elements, isNotEmpty);
85 final SnippetDartdocParser sampleParser =
86 SnippetDartdocParser(memoryFileSystem);
87 sampleParser.parseFromComments(elements);
88 sampleParser.parseAndAddAssumptions(elements, inputFile);
89 expect(elements.length, equals(7));
90 int sampleCount = 0;
91 for (final SourceElement element in elements) {
92 expect(element.samples.length, greaterThanOrEqualTo(1));
93 sampleCount += element.samples.length;
94 final String code = generator.generateCode(element.samples.first);
95 expect(code, contains('// Description'));
96 expect(
97 code,
98 contains(RegExp(
99 '''^String elementName = '${element.elementName}';\$''',
100 multiLine: true)));
101 final String html = generator.generateHtml(element.samples.first);
102 expect(
103 html,
104 contains(RegExp(
105 '''^<pre>String elementName = &#39;${element.elementName}&#39;;.*\$''',
106 multiLine: true)));
107 expect(
108 html,
109 contains(
110 '<div class="snippet-description">{@end-inject-html}Description{@inject-html}</div>\n'));
111 }
112 expect(sampleCount, equals(8));
113 });
114 test('parses dartpad samples from linked file', () async {
115 final File inputFile = _createDartpadSourceFile(
116 tmpDir, memoryFileSystem, flutterRoot,
117 linked: true);
118 final Iterable<SourceElement> elements = getFileElements(inputFile,
119 resourceProvider: FileSystemResourceProvider(memoryFileSystem));
120 expect(elements, isNotEmpty);
121 final SnippetDartdocParser sampleParser =
122 SnippetDartdocParser(memoryFileSystem);
123 sampleParser.parseFromComments(elements);
124 expect(elements.length, equals(1));
125 int sampleCount = 0;
126 for (final SourceElement element in elements) {
127 expect(element.samples.length, greaterThanOrEqualTo(1));
128 sampleCount += element.samples.length;
129 final String code =
130 generator.generateCode(element.samples.first, formatOutput: false);
131 expect(code, contains('// Description'));
132 expect(
133 code,
134 contains(RegExp('^void ${element.name}Sample\\(\\) \\{.*\$',
135 multiLine: true)));
136 final String html = generator.generateHtml(element.samples.first);
137 expect(
138 html,
139 contains(RegExp(
140 '''^<iframe class="snippet-dartpad" src="https://dartpad.dev/.*sample_id=${element.name}.0.*>.*\$''',
141 multiLine: true)));
142 }
143 expect(sampleCount, equals(1));
144 });
145 test('parses assumptions', () async {
146 final File inputFile = _createSnippetSourceFile(tmpDir, memoryFileSystem);
147 final SnippetDartdocParser sampleParser =
148 SnippetDartdocParser(memoryFileSystem);
149 final List<SourceLine> assumptions =
150 sampleParser.parseAssumptions(inputFile);
151 expect(assumptions.length, equals(1));
152 expect(assumptions.first.text, equals('int integer = 3;'));
153 });
154 });
155}
156
157File _createSnippetSourceFile(Directory tmpDir, FileSystem filesystem) {
158 return filesystem.file(path.join(tmpDir.absolute.path, 'snippet_in.dart'))
159 ..createSync(recursive: true)
160 ..writeAsStringSync(r'''
161// Copyright
162
163// @dart = 2.12
164
165import 'foo.dart';
166
167// Examples can assume:
168// int integer = 3;
169
170/// Top level variable comment
171///
172/// {@tool snippet}
173/// Description
174/// ```dart
175/// String elementName = 'topLevelVariable';
176/// ```
177/// {@end-tool}
178int topLevelVariable = 4;
179
180/// Top level function comment
181///
182/// {@tool snippet}
183/// Description
184/// ```dart
185/// String elementName = 'topLevelFunction';
186/// ```
187/// {@end-tool}
188int topLevelFunction() {
189 return integer;
190}
191
192/// Class comment
193///
194/// {@tool snippet}
195/// Description
196/// ```dart
197/// String elementName = 'DocumentedClass';
198/// ```
199/// {@end-tool}
200///
201/// {@tool snippet}
202/// Description2
203/// ```dart
204/// String elementName = 'DocumentedClass';
205/// ```
206/// {@end-tool}
207class DocumentedClass {
208 /// Constructor comment
209 /// {@tool snippet}
210 /// Description
211 /// ```dart
212 /// String elementName = 'DocumentedClass';
213 /// ```
214 /// {@end-tool}
215 const DocumentedClass();
216
217 /// Named constructor comment
218 /// {@tool snippet}
219 /// Description
220 /// ```dart
221 /// String elementName = 'DocumentedClass.name';
222 /// ```
223 /// {@end-tool}
224 const DocumentedClass.name();
225
226 /// Member variable comment
227 /// {@tool snippet}
228 /// Description
229 /// ```dart
230 /// String elementName = 'DocumentedClass.intMember';
231 /// ```
232 /// {@end-tool}
233 int intMember;
234
235 /// Member comment
236 /// {@tool snippet}
237 /// Description
238 /// ```dart
239 /// String elementName = 'DocumentedClass.member';
240 /// ```
241 /// {@end-tool}
242 void member() {}
243}
244''');
245}
246
247File _createDartpadSourceFile(
248 Directory tmpDir, FileSystem filesystem, Directory flutterRoot,
249 {bool linked = false}) {
250 final File linkedFile =
251 filesystem.file(path.join(flutterRoot.absolute.path, 'linked_file.dart'))
252 ..createSync(recursive: true)
253 ..writeAsStringSync('''
254// Copyright
255
256import 'foo.dart';
257
258// Description
259
260void DocumentedClassSample() {
261 String elementName = 'DocumentedClass';
262}
263''');
264
265 final String source = linked
266 ? '''
267/// ** See code in ${path.relative(linkedFile.path, from: flutterRoot.absolute.path)} **'''
268 : '''
269/// ```dart
270/// void DocumentedClassSample() {
271/// String elementName = 'DocumentedClass';
272/// }
273/// ```''';
274
275 return filesystem.file(path.join(tmpDir.absolute.path, 'snippet_in.dart'))
276 ..createSync(recursive: true)
277 ..writeAsStringSync('''
278// Copyright
279
280// @dart = 2.12
281
282import 'foo.dart';
283
284/// Class comment
285///
286/// {@tool dartpad --template=template}
287/// Description
288$source
289/// {@end-tool}
290class DocumentedClass {}
291''');
292}
293

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com