Skip to content

Commit 6d3c360

Browse files
authored
Improve mustachio builder tests; make assert on generated elements (#2427)
Improve mustachio builder tests; make assert on generated elements
1 parent 847121d commit 6d3c360

File tree

1 file changed

+103
-127
lines changed

1 file changed

+103
-127
lines changed

test/mustachio/builder_test.dart

Lines changed: 103 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:convert';
2+
import 'package:analyzer/dart/element/element.dart';
13
import 'package:build/build.dart';
24
import 'package:build_test/build_test.dart';
35
import '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+
2533
TypeMatcher<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-
4446
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+
});
5279

80+
test('builds a renderer for a class which extends Object', () async {
81+
await testMustachioBuilder('''
5382
class 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')
94123
library foo;
95124
import '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('''
121137
class FooBase {}
122-
123138
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);
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('''
140148
class 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('''
159160
abstract class Foo {
160161
Bar get bar;
161162
}
162-
163163
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);
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('''
182173
class Foo {
183174
static Bar get bar1 => Bar();
184175
Bar get _bar2 => Bar();
185176
}
186-
187177
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);
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('''
206187
abstract class Foo {
207188
void set bar1(Bar b);
208189
Bar bar2(Bar b);
209190
}
210-
211191
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);
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('''
230201
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);
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

Comments
 (0)