1+ import 'dart:io' ;
2+
13import 'package:analyzer/dart/analysis/analysis_context_collection.dart' ;
24import 'package:path/path.dart' as p;
35import 'package:test/test.dart' ;
@@ -9,7 +11,26 @@ import 'src/util.dart';
911
1012export 'src/util.dart' show applyPatches;
1113
12- /// Creates a file with the given [name] and [sourceText] using the
14+ /// Uses [suggestor] to generate a stream of patches for [context] and returns
15+ /// what the resulting file contents would be after applying all of them.
16+ ///
17+ /// Use this to test that a suggestor produces the expected result:
18+ /// test('MySuggestor', () async {
19+ /// var context = await fileContextForTest('foo.dart', 'library foo;');
20+ /// var suggestor = MySuggestor();
21+ /// var expectedOutput = '...';
22+ /// expectSuggestorGeneratesPatches(suggestor, context, expectedOutput);
23+ /// });
24+ void expectSuggestorGeneratesPatches (
25+ Suggestor suggestor, FileContext context, dynamic resultMatcher) {
26+ expect (
27+ suggestor (context)
28+ .toList ()
29+ .then ((patches) => applyPatches (context.sourceFile, patches)),
30+ completion (resultMatcher));
31+ }
32+
33+ /// Creates a temporary file with the given [name] and [sourceText] using the
1334/// `test_descriptor` package, sets up analysis for that file, and returns a
1435/// [FileContext] wrapper around it.
1536///
@@ -19,6 +40,9 @@ export 'src/util.dart' show applyPatches;
1940/// var patches = MySuggestor().generatePatches(context);
2041/// expect(patches, ...);
2142/// });
43+ ///
44+ /// See also: [PackageContextForTest] if testing [Suggestor] s that need a fully
45+ /// resolved AST from the analyzer.
2246Future <FileContext > fileContextForTest (String name, String sourceText) async {
2347 // Use test_descriptor to create the file in a temporary directory
2448 d.Descriptor descriptor;
@@ -32,27 +56,113 @@ Future<FileContext> fileContextForTest(String name, String sourceText) async {
3256 await descriptor.create ();
3357
3458 // Setup analysis for this file
35- final path = p.canonicalize (p. join (d.sandbox, name));
59+ final path = p.canonicalize (d. path ( name));
3660 final collection = AnalysisContextCollection (includedPaths: [path]);
3761
3862 return FileContext (path, collection, root: d.sandbox);
3963}
4064
41- /// Uses [suggestor] to generate a stream of patches for [context] and returns
42- /// what the resulting file contents would be after applying all of them.
65+ /// Creates a temporary directory with a pubspec using the `test_descriptor`
66+ /// package, installs dependencies with `dart pub get` , and sets up an analysis
67+ /// context for the package.
4368///
44- /// Use this to test that a suggestor produces the expected result:
69+ /// Source files can then be added to the package with [addFile] , which will
70+ /// return a [FileContext] wrapper for use in tests.
71+ ///
72+ /// Use this to setup tests for [Suggestor] s that require the resolved AST, like
73+ /// the [AstVisitingSuggestor] when `shouldResolveAst()` returns true. Doing so
74+ /// will enable the analyzer to resolve imports and symbols from other source
75+ /// files and dependencies.
4576/// test('MySuggestor', () async {
46- /// var context = await fileContextForTest('foo.dart', 'library foo;');
77+ /// var pkg = await PackageContextForTest.fromPubspec('''
78+ /// name: pkg
79+ /// version: 0.0.0
80+ /// environment:
81+ /// sdk: '>=3.0.0 <4.0.0'
82+ /// dependencies:
83+ /// meta: ^1.0.0
84+ /// ''');
85+ /// var context = await pkg.addFile('''
86+ /// import 'package:meta/meta.dart';
87+ /// @visibleForTesting var foo = true;
88+ /// ''');
4789/// var suggestor = MySuggestor();
4890/// var expectedOutput = '...';
4991/// expectSuggestorGeneratesPatches(suggestor, context, expectedOutput);
5092/// });
51- void expectSuggestorGeneratesPatches (
52- Suggestor suggestor, FileContext context, dynamic resultMatcher) {
53- expect (
54- suggestor (context)
55- .toList ()
56- .then ((patches) => applyPatches (context.sourceFile, patches)),
57- completion (resultMatcher));
93+ class PackageContextForTest {
94+ final AnalysisContextCollection _collection;
95+ final String _name;
96+ final String _root;
97+ static int _fileCounter = 0 ;
98+ static int _packageCounter = 0 ;
99+
100+ /// Creates a temporary directory named [dirName] using the `test_descriptor`
101+ /// package, installs dependencies with `dart pub get` , sets up an analysis
102+ /// context for the package, and returns a [PackageContextForTest] wrapper
103+ /// that allows you to add source files to the package and use them in tests.
104+ ///
105+ /// If [dirName] is null, a unique name will be generated.
106+ ///
107+ /// Throws an [ArgumentError] if it fails to install dependencies.
108+ static Future <PackageContextForTest > fromPubspec (
109+ String pubspecContents, [
110+ String ? dirName,
111+ ]) async {
112+ dirName ?? = 'package_${_packageCounter ++}' ;
113+
114+ await d.dir (dirName, [
115+ d.file ('pubspec.yaml' , pubspecContents),
116+ ]).create ();
117+
118+ final root = p.canonicalize (d.path (dirName));
119+ final pubGet =
120+ Process .runSync ('dart' , ['pub' , 'get' ], workingDirectory: root);
121+ if (pubGet.exitCode != 0 ) {
122+ printOnFailure ('''
123+ PROCESS: dart pub get
124+ WORKING DIR: $root
125+ STDOUT:
126+ ${pubGet .stdout }
127+ STDERR:
128+ ${pubGet .stderr }
129+ ''' );
130+ throw ArgumentError ('Failed to install dependencies from given pubspec' );
131+ }
132+ final collection = AnalysisContextCollection (includedPaths: [root]);
133+ return PackageContextForTest ._(dirName, root, collection);
134+ }
135+
136+ PackageContextForTest ._(this ._name, this ._root, this ._collection);
137+
138+ /// Creates a temporary file at the given [path] (relative to the root of this
139+ /// package) with the given [sourceText] using the `test_descriptor` package
140+ /// and returns a [FileContext] wrapper around it.
141+ ///
142+ /// If [path] is null, a unique filename will be generated.
143+ ///
144+ /// The returned [FileContext] will use the analysis context for this whole
145+ /// package rather than just this file, which enables testing of [Suggestor] s
146+ /// that require the resolved AST.
147+ ///
148+ /// See [PackageContextForTest] for an example.
149+ Future <FileContext > addFile (String sourceText, [String ? path]) async {
150+ path ?? = 'test_${_fileCounter ++}.dart' ;
151+
152+ // Use test_descriptor to create the file in a temporary directory
153+ d.Descriptor descriptor;
154+ final segments = p.split (path);
155+ // Last segment should be the file
156+ descriptor = d.file (segments.last, sourceText);
157+ // Any preceding segments (if any) are directories
158+ for (final dir in segments.reversed.skip (1 )) {
159+ descriptor = d.dir (dir, [descriptor]);
160+ }
161+ // Add the root directory.
162+ descriptor = d.dir (_name, [descriptor]);
163+
164+ await descriptor.create ();
165+ final canonicalizedPath = p.canonicalize (p.join (d.sandbox, _name, path));
166+ return FileContext (canonicalizedPath, _collection, root: _root);
167+ }
58168}
0 commit comments