1+ import 'dart:convert' ;
2+ import 'package:analyzer/dart/element/element.dart' ;
13import 'package:build/build.dart' ;
24import 'package:build_test/build_test.dart' ;
35import 'package:test/test.dart' ;
@@ -22,6 +24,12 @@ class Context<T> {
2224'''
2325};
2426
27+ const _libraryFrontMatter = '''
28+ @Renderer(#renderFoo, Context<Foo>(), 'foo.html.mustache')
29+ library foo;
30+ import 'package:mustachio/annotations.dart';
31+ ''' ;
32+
2533TypeMatcher <List <int >> _containsAllOf (Object a,
2634 [Object b, Object c, Object d]) {
2735 if (d != null ) {
@@ -35,24 +43,44 @@ TypeMatcher<List<int>> _containsAllOf(Object a,
3543 }
3644}
3745
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-
4446void 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+ });
5279
80+ test ('builds a renderer for a class which extends Object' , () async {
81+ await testMustachioBuilder ('''
5382class Foo {}
54- ''' ,
55- }, outputs: {
83+ ''' , outputs: {
5684 'foo|lib/foo.renderers.dart' : _containsAllOf (
5785 // The requested 'renderFoo' function
5886 '''
@@ -86,60 +114,39 @@ class _Renderer_Object extends RendererBase<Object> {
86114 });
87115
88116 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: '''
92121@Renderer(#renderFoo, Context<Foo>(), 'foo.html.mustache')
93122@Renderer(#renderBar, Context<Bar>(), 'bar.html.mustache')
94123library foo;
95124import 'package:mustachio/annotations.dart';
125+ ''' );
126+ var renderersLibrary = await resolveGeneratedLibrary (writer);
96127
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);
111132 });
112133
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 ('''
121137class FooBase {}
122-
123138class 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);
130144 });
131145
132146 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 ('''
140148class Foo<T> {}
141- ''' ,
142- }, outputs: {
149+ ''' , outputs: {
143150 'foo|lib/foo.renderers.dart' : _containsAllOf (
144151 // The requested 'renderFoo' function
145152 'String renderFoo<T>(Foo<T> context, List<MustachioNode> ast)' ,
@@ -149,100 +156,69 @@ class Foo<T> {}
149156 });
150157
151158 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 ('''
159160abstract class Foo {
160161 Bar get bar;
161162}
162-
163163class 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);
172169 });
173170
174171 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 ('''
182173class Foo {
183174 static Bar get bar1 => Bar();
184175 Bar get _bar2 => Bar();
185176}
186-
187177class 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);
196183 });
197184
198185 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 ('''
206187abstract class Foo {
207188 void set bar1(Bar b);
208189 Bar bar2(Bar b);
209190}
210-
211191class 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);
220197 });
221198
222199 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 ('''
230201class 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);
247217 });
248218}
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