1
+ import 'dart:convert' ;
2
+ import 'package:analyzer/dart/element/element.dart' ;
1
3
import 'package:build/build.dart' ;
2
4
import 'package:build_test/build_test.dart' ;
3
5
import 'package:test/test.dart' ;
@@ -22,6 +24,12 @@ class Context<T> {
22
24
'''
23
25
};
24
26
27
+ const _libraryFrontMatter = '''
28
+ @Renderer(#renderFoo, Context<Foo>(), 'foo.html.mustache')
29
+ library foo;
30
+ import 'package:mustachio/annotations.dart';
31
+ ''' ;
32
+
25
33
TypeMatcher <List <int >> _containsAllOf (Object a,
26
34
[Object b, Object c, Object d]) {
27
35
if (d != null ) {
@@ -35,24 +43,44 @@ TypeMatcher<List<int>> _containsAllOf(Object a,
35
43
}
36
44
}
37
45
38
- TypeMatcher <List <int >> _containsNoneOf (Object a, [Object b]) {
39
- return decodedMatches (b != null
40
- ? allOf (isNot (contains (a)), isNot (contains (b)))
41
- : allOf (isNot (contains (a))));
42
- }
43
-
44
46
void main () {
45
- test ('builds a renderer for a class which extends Object' , () async {
46
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
47
- ..._annotationsAsset,
48
- 'foo|lib/foo.dart' : '''
49
- @Renderer(#renderFoo, Context<Foo>(), 'foo.html.mustache')
50
- library foo;
51
- import 'package:mustachio/annotations.dart';
47
+ InMemoryAssetWriter writer;
48
+
49
+ Future <LibraryElement > resolveGeneratedLibrary (
50
+ InMemoryAssetWriter writer) async {
51
+ var rendererAsset = AssetId .parse ('foo|lib/foo.renderers.dart' );
52
+ var writtenStrings = writer.assets
53
+ .map ((id, content) => MapEntry (id.toString (), utf8.decode (content)));
54
+ return await resolveSources (writtenStrings,
55
+ (Resolver resolver) => resolver.libraryFor (rendererAsset));
56
+ }
57
+
58
+ Future <void > testMustachioBuilder (String sourceLibraryContent,
59
+ {String libraryFrontMatter = _libraryFrontMatter,
60
+ Map <String , Object > outputs}) async {
61
+ sourceLibraryContent = '''
62
+ $libraryFrontMatter
63
+ $sourceLibraryContent
64
+ ''' ;
65
+ await testBuilder (
66
+ mustachioBuilder (BuilderOptions ({})),
67
+ {
68
+ ..._annotationsAsset,
69
+ 'foo|lib/foo.dart' : sourceLibraryContent,
70
+ },
71
+ outputs: outputs,
72
+ writer: writer,
73
+ );
74
+ }
75
+
76
+ setUp (() {
77
+ writer = InMemoryAssetWriter ();
78
+ });
52
79
80
+ test ('builds a renderer for a class which extends Object' , () async {
81
+ await testMustachioBuilder ('''
53
82
class Foo {}
54
- ''' ,
55
- }, outputs: {
83
+ ''' , outputs: {
56
84
'foo|lib/foo.renderers.dart' : _containsAllOf (
57
85
// The requested 'renderFoo' function
58
86
'''
@@ -86,60 +114,39 @@ class _Renderer_Object extends RendererBase<Object> {
86
114
});
87
115
88
116
test ('builds renderers from multiple annotations' , () async {
89
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
90
- ..._annotationsAsset,
91
- 'foo|lib/foo.dart' : '''
117
+ await testMustachioBuilder ('''
118
+ class Foo {}
119
+ class Bar {}
120
+ ''' , libraryFrontMatter: '''
92
121
@Renderer(#renderFoo, Context<Foo>(), 'foo.html.mustache')
93
122
@Renderer(#renderBar, Context<Bar>(), 'bar.html.mustache')
94
123
library foo;
95
124
import 'package:mustachio/annotations.dart';
125
+ ''' );
126
+ var renderersLibrary = await resolveGeneratedLibrary (writer);
96
127
97
- class Foo {}
98
- class Bar {}
99
- ''' ,
100
- }, outputs: {
101
- 'foo|lib/foo.renderers.dart' : _containsAllOf (
102
- // The requested 'renderFoo' function
103
- 'String renderFoo(Foo context, List<MustachioNode> ast)' ,
104
- // The renderer class for Foo
105
- 'class _Renderer_Foo extends RendererBase<Foo>' ,
106
- // The requested 'renderBar' function
107
- 'String renderBar(Bar context, List<MustachioNode> ast)' ,
108
- // The renderer class for Bar
109
- 'class _Renderer_Bar extends RendererBase<Bar>' )
110
- });
128
+ expect (renderersLibrary.getTopLevelFunction ('renderFoo' ), isNotNull);
129
+ expect (renderersLibrary.getTopLevelFunction ('renderBar' ), isNotNull);
130
+ expect (renderersLibrary.getType ('_Renderer_Foo' ), isNotNull);
131
+ expect (renderersLibrary.getType ('_Renderer_Bar' ), isNotNull);
111
132
});
112
133
113
- test ('builds a renderer for a class which extends another class' , () async {
114
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
115
- ..._annotationsAsset,
116
- 'foo|lib/foo.dart' : '''
117
- @Renderer(#renderFoo, Context<Foo>(), 'bar.html.mustache')
118
- library foo;
119
- import 'package:mustachio/annotations.dart';
120
-
134
+ test ('builds a renderer for a class which is extended by a rendered class' ,
135
+ () async {
136
+ await testMustachioBuilder ('''
121
137
class FooBase {}
122
-
123
138
class Foo extends FooBase {}
124
- ''' ,
125
- }, outputs: {
126
- 'foo|lib/foo.renderers.dart' : _containsAllOf (
127
- 'String _render_FooBase(FooBase context, List<MustachioNode> ast)' ,
128
- 'class _Renderer_FooBase extends RendererBase<FooBase>' )
129
- });
139
+ ''' );
140
+ var renderersLibrary = await resolveGeneratedLibrary (writer);
141
+
142
+ expect (renderersLibrary.getTopLevelFunction ('_render_FooBase' ), isNotNull);
143
+ expect (renderersLibrary.getType ('_Renderer_FooBase' ), isNotNull);
130
144
});
131
145
132
146
test ('builds a renderer for a generic type' , () async {
133
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
134
- ..._annotationsAsset,
135
- 'foo|lib/foo.dart' : '''
136
- @Renderer(#renderFoo, Context<Foo>(), 'bar.html.mustache')
137
- library foo;
138
- import 'package:mustachio/annotations.dart';
139
-
147
+ await testMustachioBuilder ('''
140
148
class Foo<T> {}
141
- ''' ,
142
- }, outputs: {
149
+ ''' , outputs: {
143
150
'foo|lib/foo.renderers.dart' : _containsAllOf (
144
151
// The requested 'renderFoo' function
145
152
'String renderFoo<T>(Foo<T> context, List<MustachioNode> ast)' ,
@@ -149,100 +156,69 @@ class Foo<T> {}
149
156
});
150
157
151
158
test ('builds a renderer for a type found in a getter' , () async {
152
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
153
- ..._annotationsAsset,
154
- 'foo|lib/foo.dart' : '''
155
- @Renderer(#renderFoo, Context<Foo>(), 'bar.html.mustache')
156
- library foo;
157
- import 'package:mustachio/annotations.dart';
158
-
159
+ await testMustachioBuilder ('''
159
160
abstract class Foo {
160
161
Bar get bar;
161
162
}
162
-
163
163
class Bar {}
164
- ''' ,
165
- }, outputs: {
166
- 'foo|lib/foo.renderers.dart' : _containsAllOf (
167
- // The render function for Bar
168
- 'String _render_Bar(Bar context, List<MustachioNode> ast)' ,
169
- // The renderer class for Bar
170
- 'class _Renderer_Bar extends RendererBase<Bar>' )
171
- });
164
+ ''' );
165
+ var renderersLibrary = await resolveGeneratedLibrary (writer);
166
+
167
+ expect (renderersLibrary.getTopLevelFunction ('_render_Bar' ), isNotNull);
168
+ expect (renderersLibrary.getType ('_Renderer_Bar' ), isNotNull);
172
169
});
173
170
174
171
test ('skips a type found in a static or private getter' , () async {
175
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
176
- ..._annotationsAsset,
177
- 'foo|lib/foo.dart' : '''
178
- @Renderer(#renderFoo, Context<Foo>(), 'bar.html.mustache')
179
- library foo;
180
- import 'package:mustachio/annotations.dart';
181
-
172
+ await testMustachioBuilder ('''
182
173
class Foo {
183
174
static Bar get bar1 => Bar();
184
175
Bar get _bar2 => Bar();
185
176
}
186
-
187
177
class Bar {}
188
- ''' ,
189
- }, outputs: {
190
- 'foo|lib/foo.renderers.dart' : _containsNoneOf (
191
- // No render function for Bar
192
- 'String _render_Bar' ,
193
- // No renderer class for Bar
194
- 'class _Renderer_Bar extends RendererBase<Bar>' )
195
- });
178
+ ''' );
179
+ var renderersLibrary = await resolveGeneratedLibrary (writer);
180
+
181
+ expect (renderersLibrary.getTopLevelFunction ('_render_Bar' ), isNull);
182
+ expect (renderersLibrary.getType ('_Renderer_Bar' ), isNull);
196
183
});
197
184
198
185
test ('skips a type found in a setter or method' , () async {
199
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
200
- ..._annotationsAsset,
201
- 'foo|lib/foo.dart' : '''
202
- @Renderer(#renderFoo, Context<Foo>(), 'bar.html.mustache')
203
- library foo;
204
- import 'package:mustachio/annotations.dart';
205
-
186
+ await testMustachioBuilder ('''
206
187
abstract class Foo {
207
188
void set bar1(Bar b);
208
189
Bar bar2(Bar b);
209
190
}
210
-
211
191
class Bar {}
212
- ''' ,
213
- }, outputs: {
214
- 'foo|lib/foo.renderers.dart' : _containsNoneOf (
215
- // No render function for Bar
216
- 'String _render_Bar' ,
217
- // No renderer class for Bar
218
- 'class _Renderer_Bar extends RendererBase<Bar>' )
219
- });
192
+ ''' );
193
+ var renderersLibrary = await resolveGeneratedLibrary (writer);
194
+
195
+ expect (renderersLibrary.getTopLevelFunction ('_render_Bar' ), isNull);
196
+ expect (renderersLibrary.getType ('_Renderer_Bar' ), isNull);
220
197
});
221
198
222
199
test ('builds a renderer for a generic, bounded type' , () async {
223
- await testBuilder (mustachioBuilder (BuilderOptions ({})), {
224
- ..._annotationsAsset,
225
- 'foo|lib/foo.dart' : '''
226
- @Renderer(#renderFoo, Context<Foo>(), 'bar.html.mustache')
227
- library foo;
228
- import 'package:mustachio/annotations.dart';
229
-
200
+ await testMustachioBuilder ('''
230
201
class Foo<T extends num> {}
231
- ''' ,
232
- }, outputs: {
233
- 'foo|lib/foo.renderers.dart' : _containsAllOf (
234
- // The requested 'renderFoo' function
235
- 'String renderFoo<T extends num>(Foo<T> context, List<MustachioNode> ast)' ,
236
- // The renderer class for Foo
237
- '''
238
- class _Renderer_Foo<T extends num> extends RendererBase<Foo<T>> {
239
- _Renderer_Foo(Foo<T> context) : super(context);
240
- }
241
- ''' ,
242
- // The render function for num, found in Foo's type parameter bound
243
- 'String _render_num(num context, List<MustachioNode> ast)' ,
244
- // The renderer class for num
245
- 'class _Renderer_num extends RendererBase<num>' )
246
- });
202
+ ''' );
203
+ var renderersLibrary = await resolveGeneratedLibrary (writer);
204
+
205
+ var fooRenderFunction = renderersLibrary.getTopLevelFunction ('renderFoo' );
206
+ expect (fooRenderFunction.typeParameters, hasLength (1 ));
207
+ var fBound = fooRenderFunction.typeParameters.single.bound;
208
+ expect (fBound.getDisplayString (withNullability: false ), equals ('num' ));
209
+
210
+ var fooRendererClass = renderersLibrary.getType ('_Renderer_Foo' );
211
+ expect (fooRendererClass.typeParameters, hasLength (1 ));
212
+ var cBound = fooRenderFunction.typeParameters.single.bound;
213
+ expect (cBound.getDisplayString (withNullability: false ), equals ('num' ));
214
+
215
+ expect (renderersLibrary.getTopLevelFunction ('_render_num' ), isNotNull);
216
+ expect (renderersLibrary.getType ('_Renderer_num' ), isNotNull);
247
217
});
248
218
}
219
+
220
+ extension on LibraryElement {
221
+ FunctionElement getTopLevelFunction (String name) => topLevelElements
222
+ .whereType <FunctionElement >()
223
+ .firstWhere ((element) => element.name == name, orElse: () => null );
224
+ }
0 commit comments